[groovy2] 01/19: Imported Upstream version 2.4.3

komal sukhani komal-guest at moszumanska.debian.org
Sat Jun 20 16:08:39 UTC 2015


This is an automated email from the git hooks/post-receive script.

komal-guest pushed a commit to branch master
in repository groovy2.

commit 50ab91373df3510e559d27dd16b61e87059fa408
Author: komal <komaldsukhani at gmail.com>
Date:   Tue Jun 16 12:32:39 2015 +0530

    Imported Upstream version 2.4.3
---
 LICENSE                                            |  202 +
 LICENSE.txt                                        |   15 -
 NOTICE                                             |   14 +
 NOTICE.txt                                         |   14 -
 README.adoc                                        |   10 +-
 bintray.properties                                 |    4 -
 build.gradle                                       |   68 +-
 .../binarycompatibility/binarycompat-report.groovy |  153 +
 config/checkstyle/checkstyle-frames.xsl            |  394 --
 config/checkstyle/checkstyle-report.groovy         |  154 +
 config/checkstyle/checkstyle.xml                   |   13 +
 gradle.properties                                  |    6 +-
 gradle.properties.gz                               |  Bin 210 -> 0 bytes
 gradle/LICENSE.txt                                 |   13 +
 gradle/asciidoctor.gradle                          |  150 +-
 gradle/assemble.gradle                             |   55 +-
 gradle/backports.gradle                            |   20 +-
 gradle/binarycompatibility.gradle                  |  204 +
 gradle/bintray.gradle                              |   12 +-
 gradle/docs.gradle                                 |   37 +-
 gradle/indy.gradle                                 |   49 +-
 gradle/jacoco/jacoco.gradle                        |   61 +
 gradle/jacoco/jacocofix.gradle                     |   23 +
 gradle/pomconfigurer.gradle                        |    5 +-
 gradle/quality.gradle                              |   94 +-
 gradle/test.gradle                                 |    5 +-
 gradle/upload.gradle                               |    8 +
 gradle/wrapper/gradle-wrapper.jar                  |  Bin 0 -> 50527 bytes
 gradle/wrapper/gradle-wrapper.properties           |    2 +-
 lib/openbeans-1.0.jar                              |  Bin 0 -> 221958 bytes
 security/GroovyJarTest.jar                         |  Bin 0 -> 2588 bytes
 src/examples/astbuilder/Main.groovy                |   15 +
 src/examples/astbuilder/MainExample.groovy         |   15 +
 src/examples/astbuilder/MainIntegrationTest.groovy |   15 +
 src/examples/astbuilder/MainTransformation.groovy  |   15 +
 src/examples/commandLineTools/AntMap.groovy        |   17 +-
 src/examples/commandLineTools/BigTests.groovy      |   17 +-
 src/examples/commandLineTools/Reflections.groovy   |   15 +
 .../commandLineTools/SimpleWebServer.groovy        |   15 +
 src/examples/console/MortgageCalculator.groovy     |   15 +
 src/examples/console/knowYourTables.groovy         |   15 +
 src/examples/console/thinkOfANumber.groovy         |   15 +
 src/examples/groovy/j2ee/CreateData.groovy         |   15 +
 src/examples/groovy/swing/MyTableModel.java        |   15 +
 src/examples/groovy/swing/SwingDemo.groovy         |   15 +
 src/examples/groovy/swing/TableDemo.groovy         |   15 +
 src/examples/groovy/swing/TableLayoutDemo.groovy   |   15 +
 src/examples/groovy2d/paintingByNumbers.groovy     |   15 +
 src/examples/groovyShell/ArithmeticShell.groovy    |   15 +
 .../groovyShell/ArithmeticShellTest.groovy         |   15 +
 src/examples/groovyShell/BlacklistingShell.groovy  |   15 +
 .../groovyShell/BlacklistingShellTest.groovy       |   15 +
 .../grails/compiler/injection/DomainClass.java     |   15 +
 src/examples/osgi/build.properties                 |   16 +
 .../org/codehaus/groovy/osgi/Activator.groovy      |   15 +
 .../org/codehaus/groovy/osgi/GroovyGreeter.groovy  |   15 +
 .../codehaus/groovy/osgi/GroovyGreeterImpl.groovy  |   15 +
 src/examples/searchEngine/Indexer.groovy           |   15 +
 src/examples/searchEngine/Searcher.groovy          |   15 +
 src/examples/swing/BloglinesClient.groovy          |   15 +
 src/examples/swing/ModelNodeExample.groovy         |   15 +
 src/examples/swing/RegexCoach.groovy               |   15 +
 src/examples/swing/RegexCoachController.groovy     |   15 +
 src/examples/swing/RegexCoachView.groovy           |   15 +
 src/examples/swing/Widgets.groovy                  |   15 +
 .../swing/binding/caricature/Caricature.groovy     |   15 +
 .../swing/binding/caricature/JCaricature.java      |   15 +
 src/examples/swing/greet/Greet.groovy              |   15 +
 src/examples/swing/greet/TwitterAPI.groovy         |   15 +
 src/examples/swing/greet/View.groovy               |   15 +
 src/examples/swing/timelog/TimeLogMain.groovy      |   15 +
 src/examples/swing/timelog/TimeLogModel.groovy     |   15 +
 src/examples/swing/timelog/TimeLogView.groovy      |   15 +
 .../global/CompiledAtASTTransformation.groovy      |   15 +
 .../transforms/global/CompiledAtExample.groovy     |   15 +
 .../global/CompiledAtIntegrationTest.groovy        |   15 +
 .../global/LoggingASTTransformation.groovy         |   15 +
 .../transforms/global/LoggingExample.groovy        |   15 +
 .../local/LoggingASTTransformation.groovy          |   15 +
 .../transforms/local/LoggingExample.groovy         |   15 +
 src/examples/transforms/local/WithLogging.groovy   |   15 +
 .../groovlet-examples/WEB-INF/groovy/Animal.groovy |   15 +
 .../WEB-INF/groovy/zoo/Fish.groovy                 |   17 +-
 .../WEB-INF/groovy/zoo/fish/Shark.groovy           |   17 +-
 .../WEB-INF/groovy/zoo/fish/Trout.groovy           |   17 +-
 .../webapps/groovlet-examples/codehaus-style.css   |   15 +
 .../webapps/groovlet-examples/hello/hello.groovy   |   15 +
 .../webapps/groovlet-examples/index.groovy         |   15 +
 .../zoo/HommingbergerGepardenforelle.groovy        |   15 +
 .../webapps/groovlet-examples/zoo/visit.groovy     |   15 +
 .../webapps/groovlet-examples/zoo/zoo.groovy       |   15 +
 .../template-examples/3.times.HelloWorld.html      |   17 +
 src/main/META-INF/groovy-release-info.properties   |   16 +
 .../groovy/beans/BindableASTTransformation.java    |   16 +-
 .../groovy/beans/VetoableASTTransformation.java    |   16 +-
 .../groovy/grape/GrabAnnotationTransformation.java |   34 +-
 src/main/groovy/grape/GrapeIvy.groovy              |   17 +-
 src/main/groovy/lang/BenchmarkInterceptor.java     |   22 +-
 src/main/groovy/lang/DelegatesTo.java              |   12 +
 src/main/groovy/lang/ExpandoMetaClass.java         |   25 +-
 src/main/groovy/lang/GString.java                  |   15 +-
 src/main/groovy/lang/Grab.java                     |   13 +-
 src/main/groovy/lang/GrabExclude.java              |    4 +-
 src/main/groovy/lang/GrabResolver.java             |   24 +-
 src/main/groovy/lang/GroovyClassLoader.java        |   96 +-
 src/main/groovy/lang/GroovyShell.java              |   40 +-
 src/main/groovy/lang/MetaClassImpl.java            |  206 +-
 src/main/groovy/lang/ObjectRange.java              |    4 +-
 src/main/groovy/lang/Tuple.java                    |   31 +-
 src/main/groovy/lang/Tuple2.java                   |   35 +
 src/main/groovy/transform/AutoClone.java           |    6 +-
 src/main/groovy/transform/CompileStatic.java       |   12 +
 src/main/groovy/transform/InheritConstructors.java |   17 +-
 src/main/groovy/transform/PackageScope.java        |   18 +-
 src/main/groovy/transform/PackageScopeTarget.java  |    9 +-
 src/main/groovy/transform/SelfType.java            |   79 +
 src/main/groovy/transform/ToString.java            |   12 +-
 src/main/groovy/transform/Undefined.java           |   31 +
 src/main/groovy/transform/builder/Builder.java     |   14 +-
 .../groovy/transform/builder/DefaultStrategy.java  |  101 +-
 .../transform/builder/InitializerStrategy.java     |  202 +-
 src/main/groovy/transform/stc/FromString.java      |   76 +-
 .../groovy/transform/stc/MapEntryOrKeyValue.java   |    4 +-
 src/main/groovy/util/ConfigObject.java             |   37 +-
 src/main/groovy/util/DelegatingScript.java         |    2 +-
 src/main/groovy/util/FileTreeBuilder.groovy        |  181 +
 src/main/groovy/util/GroovyScriptEngine.java       |   82 +-
 src/main/groovy/util/ObservableMap.java            |    4 +-
 src/main/groovy/util/OrderBy.java                  |   22 +-
 src/main/groovy/util/PermutationGenerator.java     |    6 +
 src/main/groovy/util/ProxyGenerator.java           |   15 +-
 .../codehaus/groovy/antlr/AntlrParserPlugin.java   |    3 +-
 src/main/org/codehaus/groovy/antlr/groovy.g        |   11 +-
 .../groovy/antlr/java/Java2GroovyMain.java         |  165 +-
 .../groovy/antlr/java/Java2GroovyProcessor.java    |  184 +
 src/main/org/codehaus/groovy/ast/ASTNode.java      |   15 +
 src/main/org/codehaus/groovy/ast/ClassHelper.java  |    3 +-
 src/main/org/codehaus/groovy/ast/ClassNode.java    |   20 +
 src/main/org/codehaus/groovy/ast/GenericsType.java |    2 +
 .../groovy/ast/MixinASTTransformation.java         |    2 +-
 src/main/org/codehaus/groovy/ast/ModuleNode.java   |   24 +-
 .../ast/builder/AstBuilderTransformation.java      |   36 +-
 .../ast/builder/AstSpecificationCompiler.groovy    |  322 +-
 .../groovy/ast/expr/ConstantExpression.java        |    2 +
 .../org/codehaus/groovy/ast/stmt/Statement.java    |   33 +-
 .../codehaus/groovy/ast/tools/ClosureUtils.java    |   68 +
 .../codehaus/groovy/ast/tools/GenericsUtils.java   |  184 +-
 .../groovy/ast/tools/WideningCategories.java       |    3 +
 .../groovy/classgen/AsmClassGenerator.java         |   48 +-
 .../groovy/classgen/ClassCompletionVerifier.java   |   84 +-
 .../org/codehaus/groovy/classgen/EnumVisitor.java  |    6 +-
 .../codehaus/groovy/classgen/GeneratorContext.java |   73 +-
 .../classgen/InnerClassCompletionVisitor.java      |    5 +-
 .../org/codehaus/groovy/classgen/ReturnAdder.java  |   14 +
 .../groovy/classgen/VariableScopeVisitor.java      |    9 +-
 .../org/codehaus/groovy/classgen/Verifier.java     |   67 +-
 .../classgen/asm/BinaryExpressionHelper.java       |    2 +-
 .../groovy/classgen/asm/BytecodeDumper.java        |   49 +
 .../groovy/classgen/asm/BytecodeHelper.java        |    5 +-
 .../groovy/classgen/asm/CallSiteWriter.java        |    8 +-
 .../groovy/classgen/asm/ClosureWriter.java         |    6 +-
 .../codehaus/groovy/classgen/asm/CompileStack.java |   57 +-
 .../groovy/classgen/asm/InvocationWriter.java      |   93 +-
 .../codehaus/groovy/classgen/asm/MopWriter.java    |   38 +-
 .../codehaus/groovy/classgen/asm/OperandStack.java |    5 +-
 .../classgen/asm/OptimizingStatementWriter.java    |   22 +-
 .../groovy/classgen/asm/StatementWriter.java       |    8 +-
 .../groovy/classgen/asm/WriterController.java      |    5 +
 .../asm/sc/StaticCompilationMopWriter.java         |   59 +
 .../classgen/asm/sc/StaticInvocationWriter.java    |   77 +-
 .../asm/sc/StaticPropertyAccessHelper.java         |  130 +
 ...icTypesBinaryExpressionMultiTypeDispatcher.java |  123 +-
 .../classgen/asm/sc/StaticTypesCallSiteWriter.java |  126 +-
 .../classgen/asm/sc/StaticTypesClosureWriter.java  |    4 +-
 .../asm/sc/StaticTypesStatementWriter.java         |  177 +-
 .../classgen/asm/sc/StaticTypesTypeChooser.java    |    4 +
 .../codehaus/groovy/control/BytecodeProcessor.java |   20 +
 .../codehaus/groovy/control/ClassNodeResolver.java |    3 +-
 .../codehaus/groovy/control/CompilationUnit.java   |    5 +
 .../groovy/control/CompilerConfiguration.java      |   10 +
 .../org/codehaus/groovy/control/LabelVerifier.java |   31 +-
 .../codehaus/groovy/control/OptimizerVisitor.java  |    4 +-
 .../codehaus/groovy/control/ResolveVisitor.java    |  102 +-
 .../groovy/control/StaticImportVisitor.java        |    2 +
 .../codehaus/groovy/reflection/CachedClass.java    |   21 +-
 .../org/codehaus/groovy/reflection/ClassInfo.java  |  168 +-
 .../groovy/reflection/GroovyClassValue.java        |   18 +
 .../groovy/reflection/GroovyClassValueFactory.java |   36 +
 .../reflection/GroovyClassValuePreJava7.java       |   76 +
 .../groovy/reflection/android/AndroidSupport.java  |   35 +
 .../reflection/stdclasses/CachedSAMClass.java      |    5 +-
 .../reflection/v7/GroovyClassValueJava7.java       |   20 +
 .../codehaus/groovy/runtime/ConversionHandler.java |   34 +-
 .../groovy/runtime/DefaultGroovyMethods.java       | 4547 +++++++++++++++++---
 .../runtime/DefaultGroovyMethodsSupport.java       |   11 +-
 .../groovy/runtime/DefaultGroovyStaticMethods.java |   39 +-
 .../codehaus/groovy/runtime/IOGroovyMethods.java   |   52 +-
 .../org/codehaus/groovy/runtime/InvokerHelper.java |   43 +-
 .../codehaus/groovy/runtime/MetaClassHelper.java   |   30 +-
 .../org/codehaus/groovy/runtime/MethodClosure.java |    3 +-
 .../codehaus/groovy/runtime/MethodRankHelper.java  |    5 +-
 .../groovy/runtime/NumberAwareComparator.java      |   11 +-
 .../groovy/runtime/ProcessGroovyMethods.java       |    4 +
 .../groovy/runtime/ProxyGeneratorAdapter.java      |   16 +-
 .../groovy/runtime/ResourceGroovyMethods.java      |    4 +-
 .../groovy/runtime/ScriptBytecodeAdapter.java      |   72 +-
 .../groovy/runtime/StringGroovyMethods.java        | 2320 +++++-----
 .../groovy/runtime/callsite/AbstractCallSite.java  |   78 +-
 .../groovy/runtime/callsite/CallSiteGenerator.java |   12 +-
 .../callsite/GetEffectivePojoPropertySite.java     |    2 +-
 .../runtime/callsite/PogoGetPropertySite.java      |    4 +-
 .../groovy/runtime/m12n/ExtensionModule.java       |    8 +
 .../codehaus/groovy/runtime/memoize/Memoize.java   |    4 +-
 .../groovy/runtime/metaclass/ClosureMetaClass.java |   20 +-
 .../runtime/metaclass/ClosureMetaMethod.java       |    3 +-
 .../runtime/metaclass/MetaClassRegistryImpl.java   |   14 +-
 .../metaclass/MixinInstanceMetaProperty.java       |    2 +-
 .../runtime/metaclass/MultipleSetterProperty.java  |   86 +
 .../metaclass/ThreadManagedMetaBeanProperty.java   |    2 +-
 .../runtime/powerassert/AssertionRenderer.java     |   13 +-
 .../typehandling/DefaultTypeTransformation.java    |   83 +-
 .../runtime/typehandling/ShortTypeHandling.java    |    2 +-
 src/main/org/codehaus/groovy/tools/RootLoader.java |    3 +-
 .../org/codehaus/groovy/tools/StringHelper.java    |    2 +-
 .../tools/javac/JavaAwareCompilationUnit.java      |   11 +-
 .../tools/javac/JavaStubCompilationUnit.java       |    3 +-
 .../groovy/tools/javac/JavaStubGenerator.java      |   85 +-
 src/main/org/codehaus/groovy/tools/shell/IO.java   |    3 +-
 .../groovy/transform/ASTTestTransformation.groovy  |   10 +-
 .../transform/AbstractASTTransformation.java       |   29 +-
 .../transform/AutoCloneASTTransformation.java      |   81 +-
 .../transform/BaseScriptASTTransformation.java     |   10 +
 .../groovy/transform/BuilderASTTransformation.java |    5 +
 .../transform/CategoryASTTransformation.java       |    2 +-
 ...onditionalInterruptibleASTTransformation.groovy |   29 +-
 .../transform/DelegateASTTransformation.java       |   84 +-
 .../transform/ImmutableASTTransformation.java      |    8 +-
 .../InheritConstructorsASTTransformation.java      |   29 +-
 .../transform/MemoizedASTTransformation.java       |    9 +-
 .../groovy/transform/NewifyASTTransformation.java  |    5 +
 .../transform/PackageScopeASTTransformation.java   |    7 +
 .../transform/SynchronizedASTTransformation.java   |   12 +-
 .../transform/ToStringASTTransformation.java       |   28 +-
 .../transform/sc/StaticCompilationVisitor.java     |   99 +-
 .../transform/sc/StaticCompileTransformation.java  |    3 +-
 .../transform/sc/TemporaryVariableExpression.java  |   74 +
 .../transformers/BinaryExpressionTransformer.java  |  226 +-
 .../sc/transformers/CastExpressionOptimizer.java   |   77 +
 .../MethodCallExpressionTransformer.java           |   35 +
 .../transformers/StaticCompilationTransformer.java |   19 +-
 .../VariableExpressionTransformer.java             |   41 +-
 .../stc/AbstractTypeCheckingExtension.java         |    4 +
 .../stc/DefaultTypeCheckingExtension.java          |    5 +-
 .../stc/GroovyTypeCheckingExtensionSupport.java    |   37 +-
 .../transform/stc/StaticTypeCheckingSupport.java   |   91 +-
 .../transform/stc/StaticTypeCheckingVisitor.java   |  831 ++--
 .../groovy/transform/stc/StaticTypesMarker.java    |    3 +-
 .../transform/stc/TraitTypeCheckingExtension.java  |   46 +
 .../groovy/transform/stc/UnionTypeClassNode.java   |    2 +-
 .../transform/trait/SuperCallTraitTransformer.java |   46 +
 .../transform/trait/TraitASTTransformation.java    |  123 +-
 .../groovy/transform/trait/TraitComposer.java      |   98 +-
 .../transform/trait/TraitReceiverTransformer.java  |  192 +-
 .../codehaus/groovy/transform/trait/Traits.java    |   79 +-
 src/main/org/codehaus/groovy/util/FastArray.java   |    6 +
 .../org/codehaus/groovy/vmplugin/VMPlugin.java     |   26 +
 .../codehaus/groovy/vmplugin/VMPluginFactory.java  |    2 +-
 .../org/codehaus/groovy/vmplugin/v5/Java5.java     |   15 +
 .../org/codehaus/groovy/vmplugin/v6/Java6.java     |    5 +
 .../org/codehaus/groovy/vmplugin/v7/Java7.java     |   70 +
 .../org/codehaus/groovy/vmplugin/v7/Selector.java  |    7 +-
 src/resources/groovy/grape/defaultGrapeConfig.xml  |    2 +-
 src/spec/assets/img/console1.png                   |  Bin 0 -> 111912 bytes
 src/spec/assets/img/console2.png                   |  Bin 0 -> 95044 bytes
 src/spec/assets/img/console3.png                   |  Bin 0 -> 93569 bytes
 src/spec/assets/img/console5.png                   |  Bin 0 -> 68479 bytes
 src/spec/assets/img/console6.png                   |  Bin 0 -> 74437 bytes
 src/spec/assets/img/console7.png                   |  Bin 0 -> 70660 bytes
 src/spec/assets/img/example1.png                   |  Bin 0 -> 62930 bytes
 src/spec/assets/img/example10.png                  |  Bin 0 -> 82936 bytes
 src/spec/assets/img/example11.png                  |  Bin 0 -> 95471 bytes
 src/spec/assets/img/example12.png                  |  Bin 0 -> 64916 bytes
 src/spec/assets/img/example13.png                  |  Bin 0 -> 71409 bytes
 src/spec/assets/img/example14.png                  |  Bin 0 -> 67945 bytes
 src/spec/assets/img/example15.png                  |  Bin 0 -> 109440 bytes
 src/spec/assets/img/example16.png                  |  Bin 0 -> 114413 bytes
 src/spec/assets/img/example17.png                  |  Bin 0 -> 74161 bytes
 src/spec/assets/img/example18.png                  |  Bin 0 -> 82115 bytes
 src/spec/assets/img/example19.png                  |  Bin 0 -> 31915 bytes
 src/spec/assets/img/example2.png                   |  Bin 0 -> 50169 bytes
 src/spec/assets/img/example4.png                   |  Bin 0 -> 117382 bytes
 src/spec/assets/img/example5.png                   |  Bin 0 -> 140448 bytes
 src/spec/assets/img/example7.png                   |  Bin 0 -> 29789 bytes
 src/spec/assets/img/example8.png                   |  Bin 0 -> 146470 bytes
 src/spec/assets/img/example9.png                   |  Bin 0 -> 113690 bytes
 src/spec/assets/img/github1.png                    |  Bin 0 -> 87356 bytes
 src/spec/assets/img/github2.png                    |  Bin 0 -> 120646 bytes
 src/spec/assets/img/github3.png                    |  Bin 0 -> 47303 bytes
 src/spec/assets/img/github4.png                    |  Bin 0 -> 139616 bytes
 src/spec/assets/img/github5.png                    |  Bin 0 -> 56680 bytes
 src/spec/assets/img/github6.png                    |  Bin 0 -> 100961 bytes
 src/spec/assets/img/githubfork.png                 |  Bin 0 -> 73212 bytes
 src/spec/assets/img/githubhomepanel.png            |  Bin 0 -> 125528 bytes
 src/spec/assets/img/githubsearch.png               |  Bin 0 -> 56287 bytes
 src/spec/assets/img/groovy.png                     |  Bin 0 -> 57425 bytes
 src/spec/assets/img/groovy1.png                    |  Bin 0 -> 38285 bytes
 src/spec/assets/img/repolist.png                   |  Bin 0 -> 36749 bytes
 src/spec/assets/img/teamcity.png                   |  Bin 0 -> 4808 bytes
 src/spec/doc/assets/img/gconsole-toolbar.png       |  Bin 0 -> 7163 bytes
 src/spec/doc/assets/img/groovysh2.jpg              |  Bin 57333 -> 0 bytes
 src/spec/doc/assets/img/groovysh3.jpg              |  Bin 20347 -> 0 bytes
 src/spec/doc/assets/img/groovysh4.jpg              |  Bin 44163 -> 0 bytes
 src/spec/doc/contributors.adoc                     |   29 +
 src/spec/doc/core-closures.adoc                    |  554 ++-
 src/spec/doc/core-differences-java.adoc            |   56 +
 src/spec/doc/core-domain-specific-languages.adoc   |  406 +-
 src/spec/doc/core-gdk.adoc                         |    8 +-
 src/spec/doc/core-getting-started.adoc             |   40 +-
 src/spec/doc/core-metaprogramming.adoc             |  513 ++-
 src/spec/doc/core-object-orientation.adoc          |  770 +++-
 src/spec/doc/core-operators.adoc                   |  166 +-
 src/spec/doc/core-program-structure.adoc           |  197 +-
 src/spec/doc/core-semantics.adoc                   |  426 +-
 src/spec/doc/core-syntax.adoc                      |  264 +-
 src/spec/doc/core-testing-guide.adoc               |   66 +-
 src/spec/doc/core-traits.adoc                      |  101 +-
 src/spec/doc/design-pattern-adapter.adoc           |    2 +-
 src/spec/doc/design-pattern-bouncer.adoc           |    2 +-
 .../design-pattern-chain-of-responsibility.adoc    |    6 +-
 src/spec/doc/design-pattern-composite.adoc         |    4 +-
 src/spec/doc/design-pattern-decorator.adoc         |   28 +-
 src/spec/doc/design-pattern-flyweight.adoc         |    2 +-
 src/spec/doc/design-pattern-in-groovy.adoc         |   40 +-
 src/spec/doc/design-pattern-iterator.adoc          |    4 +-
 src/spec/doc/design-pattern-loan-my-resource.adoc  |    6 +-
 src/spec/doc/design-pattern-null-object.adoc       |   14 +-
 src/spec/doc/design-pattern-pimp-my-library.adoc   |    4 +-
 src/spec/doc/design-pattern-singleton.adoc         |   24 +-
 src/spec/doc/design-pattern-state.adoc             |    6 +-
 src/spec/doc/design-pattern-strategy.adoc          |    2 +-
 src/spec/doc/design-pattern-template-method.adoc   |    2 +-
 src/spec/doc/design-pattern-visitor.adoc           |   20 +-
 src/spec/doc/grape.adoc                            |    6 +-
 src/spec/doc/groovy-contributions.adoc             | 1237 ++++++
 src/spec/doc/guide-integrating.adoc                |   11 +-
 src/spec/doc/index.adoc                            |   82 +-
 src/spec/doc/invokedynamic-support.adoc            |    4 +-
 src/spec/doc/license-contributors.adoc             |   21 -
 src/spec/doc/license.adoc                          |    6 +
 src/spec/doc/style-guide.adoc                      |  682 +++
 src/spec/doc/template-engines.adoc                 |  147 -
 src/spec/doc/tools-groovyc.adoc                    |  165 +-
 src/spec/doc/tools-groovyconsole.adoc              |  188 -
 src/spec/doc/tools-groovydoc.adoc                  |  214 -
 src/spec/doc/tools-groovyeclipse.adoc              |  156 +-
 src/spec/doc/tools-groovysh.adoc                   |  592 ---
 src/spec/doc/tools-ide.adoc                        |    6 +-
 src/spec/doc/type-checking-extensions.adoc         | 1073 +++++
 src/spec/doc/windows-nsis-installer.adoc           |    6 +-
 src/spec/doc/working-with-collections.adoc         |  443 ++
 src/spec/doc/working-with-io.adoc                  |  279 ++
 .../org.codehaus.groovy.runtime.ExtensionModule    |   11 +-
 ...org.codehaus.groovy.runtime.ExtensionModuleSpec |   38 +
 src/spec/test-resources/aftermethodcall.groovy     |   26 +
 src/spec/test-resources/aftervisitclass.groovy     |   26 +
 src/spec/test-resources/aftervisitmethod.groovy    |   37 +
 src/spec/test-resources/ambiguousmethods.groovy    |   22 +
 src/spec/test-resources/beforemethodcall.groovy    |   25 +
 src/spec/test-resources/beforevisitclass.groovy    |   26 +
 src/spec/test-resources/beforevisitmethod.groovy   |   24 +
 src/spec/test-resources/finish.groovy              |   22 +
 .../test-resources/incompatibleassignment.groovy   |   25 +
 src/spec/test-resources/methodnotfound.groovy      |   31 +
 src/spec/test-resources/newmethod.groovy           |   25 +
 src/spec/test-resources/onmethodselection.groovy   |   28 +
 src/spec/test-resources/robotextension.groovy      |   25 +
 src/spec/test-resources/robotextension2.groovy     |   32 +
 src/spec/test-resources/robotextension3.groovy     |   30 +
 src/spec/test-resources/scoping.groovy             |   35 +
 src/spec/test-resources/scoping_alt.groovy         |   40 +
 src/spec/test-resources/selfcheck.groovy           |   32 +
 src/spec/test-resources/setup.groovy               |   21 +
 src/spec/test-resources/unresolvedattribute.groovy |   24 +
 src/spec/test-resources/unresolvedproperty.groovy  |   27 +
 src/spec/test-resources/unresolvedvariable.groovy  |   24 +
 src/spec/test/BaseScriptSpecTest.groovy            |  139 +
 src/spec/test/ClassTest.groovy                     |  774 ++++
 src/spec/test/ClosuresSpecTest.groovy              |  520 +++
 .../test/CodeGenerationASTTransformsTest.groovy    |   61 +-
 src/spec/test/CoercionTest.groovy                  |   15 +
 .../CompilerDirectivesASTTransformsTest.groovy     |   16 +
 src/spec/test/CustomizersTest.groovy               |   20 +-
 .../DeclarativeConcurrencyASTTransformsTest.groovy |   15 +
 src/spec/test/DelegatesToSpecTest.groovy           |   59 +
 src/spec/test/DesignPatternsTest.groovy            |   15 +
 src/spec/test/DifferencesFromJavaTest.groovy       |   48 +-
 src/spec/test/IntegrationTest.groovy               |    3 +-
 src/spec/test/OperatorsTest.groovy                 |  170 +-
 src/spec/test/PackageTest.groovy                   |  215 +-
 .../test/SaferScriptingASTTransformsTest.groovy    |   14 +-
 src/spec/test/ScriptsAndClassesSpecTest.groovy     |  102 +
 src/spec/test/SemanticsTest.groovy                 |   15 +
 src/spec/test/SyntaxTest.groovy                    |   25 +-
 src/spec/test/TemplateEnginesTest.groovy           |  146 -
 src/spec/test/TestingASTTransformsTest.groovy      |   59 +
 src/spec/test/TraitsSpecificationTest.groovy       |  166 +-
 src/spec/test/asciidoctor/Utils.groovy             |   40 +
 src/spec/test/builder/BuilderSupportTest.groovy    |  113 +
 .../test/builder/ObjectGraphBuilderTest.groovy     |  183 +
 src/spec/test/gdk/ConfigSlurperTest.groovy         |   15 +
 src/spec/test/gdk/ExpandoTest.groovy               |   15 +
 src/spec/test/gdk/ObservableTest.groovy            |   15 +
 .../test/gdk/WorkingWithCollectionsTest.groovy     |  733 ++++
 src/spec/test/gdk/WorkingWithIOSpecTest.groovy     |  384 ++
 .../test/metaprogramming/ASTXFormSpecTest.groovy   |  314 ++
 src/spec/test/metaprogramming/CategoryTest.groovy  |   15 +
 .../MethodPropertyMissingTest.groovy               |   15 +
 .../test/metaprogramming/MyTransformToDebug.groovy |   24 +
 src/spec/test/objectorientation/MethodsTest.groovy |  102 +
 src/spec/test/semantics/GPathTest.groovy           |   83 +
 src/spec/test/semantics/LabelsTest.groovy          |   45 +
 src/spec/test/semantics/OptionalityTest.groovy     |   87 +
 src/spec/test/semantics/PowerAssertTest.groovy     |   73 +
 src/spec/test/semantics/TheGroovyTruthTest.groovy  |   89 +
 src/spec/test/support/MaxRetriesExtension.groovy   |   15 +
 src/spec/test/thirdpartylib/MultiplyTwo.groovy     |   29 +-
 src/spec/test/typing/PrecompiledExtension.groovy   |   33 +
 src/spec/test/typing/PrecompiledJavaExtension.java |   44 +
 src/spec/test/typing/Robot.groovy                  |   23 +
 .../typing/TypeCheckingExtensionSpecTest.groovy    |  467 ++
 .../org.codehaus.groovy.runtime.ExtensionModule    |    0
 .../services/org.codehaus.groovy.source.Extensions |    0
 .../groovy/transform/sc/MixedMode.groovy           |   15 +
 .../groovy/transform/sc/MixedMode2.groovy          |   15 +
 .../transform/sc/MixedModeDynamicBuilder.groovy    |   15 +
 .../transform/stc/AnnotatedByTestExtension.groovy  |   15 +
 .../stc/ArgumentsTestingTestExtension.groovy       |   15 +
 .../stc/BeforeAfterClassTestExtension.groovy       |   15 +
 .../transform/stc/DelegatesToTestExtension.groovy  |   15 +
 .../transform/stc/FinishTestExtension.groovy       |   15 +
 .../stc/FirstArgumentsTestingTestExtension.groovy  |   15 +
 .../transform/stc/Groovy6047Extension.groovy       |   15 +
 .../stc/IncompatibleAssignmentTestExtension.groovy |   15 +
 .../stc/IncompatibleReturnTypeTestExtension.groovy |   15 +
 .../stc/MissingMethod1TestExtension.groovy         |   15 +
 .../stc/MissingMethod2TestExtension.groovy         |   15 +
 .../NewMethodAndIsGeneratedTestExtension.groovy    |   15 +
 .../stc/NthArgumentTestingTestExtension.groovy     |   15 +
 .../stc/OnMethodSelectionTestExtension.groovy      |   15 +
 .../stc/PrefixChangerTestExtension.groovy          |   15 +
 .../groovy/transform/stc/RobotMove.groovy          |   15 +
 .../stc/ScopeEnterExitTestExtension.groovy         |   15 +
 .../groovy/transform/stc/SetupTestExtension.groovy |   15 +
 .../transform/stc/SilentTestExtension.groovy       |   15 +
 .../groovy/transform/stc/SprintfExtension.groovy   |   15 +
 .../UndefinedVariableNoHandleTestExtension.groovy  |   15 +
 .../stc/UndefinedVariableTestExtension.groovy      |   15 +
 .../stc/UnresolvedAttributeTestExtension.groovy    |   15 +
 .../stc/UnresolvedPropertyTestExtension.groovy     |   15 +
 .../stc/UpperCaseMethodTest1Extension.groovy       |   15 +
 .../stc/UpperCaseMethodTest2Extension.groovy       |   15 +
 .../stc/UpperCaseMethodTest3Extension.groovy       |   15 +
 .../1.0.7225-test/module-test-1.0.7225-test.jar    |  Bin 0 -> 2541 bytes
 .../module-test/1.2-test/module-test-1.2-test.jar  |  Bin 0 -> 3326 bytes
 .../circularLanguageReference/Rectangle.groovy     |   15 +
 .../circularLanguageReference/Shape.java           |   15 +
 .../circularLanguageReference/Square.java          |   15 +
 .../somepackage/GroovyPogo.groovy                  |   15 +
 .../somepackage/JavaBean.java                      |   15 +
 .../AnnotationClosureExhaustiveTestSupport.groovy  |   15 +
 ...nClosureJavaCompatibilityParameterizedTest.java |   15 +
 .../AnnotationClosureJavaCompatibilityTest.java    |   15 +
 .../closures/AnnotationClosureOwnerCallTest.groovy |   15 +
 .../AnnotationClosureThisObjectCallTest.groovy     |   15 +
 .../AnnotationClosureUnqualifiedCallTest.groovy    |   15 +
 .../AnnotationClosureWithNonLocalVariable.groovy   |   15 +
 .../AnnotationClosureWithParametersTest.groovy     |   15 +
 .../closures/JavaAnnotationWithClassElement.java   |   15 +
 ...avaAnnotationWithClassElementParameterized.java |   15 +
 .../annotations/closures/JavaCompatibility.groovy  |   15 +
 .../closures/JavaCompatibilityParameterized.groovy |   15 +
 src/test/gls/ch06/s05/GName1Test.groovy            |   15 +
 src/test/gls/ch06/s05/JName1Test.java              |   15 +
 src/test/gls/ch06/s05/testClasses/Tt1.java         |   15 +
 src/test/gls/enums/EnumTest.groovy                 |   14 +
 src/test/gls/generics/GenericsTest.groovy          |   14 +
 src/test/gls/generics/GenericsTestBase.java        |    3 +-
 src/test/gls/innerClass/InnerClassTest.groovy      |   56 +-
 src/test/gls/innerClass/InnerInterfaceTest.groovy  |   47 +
 .../gls/invocation/ClassDuplicationTest.groovy     |   15 +
 .../invocation/ConstructorDelegationTest.groovy    |   36 +
 .../gls/property/MetaClassOverridingTest.groovy    |   15 +
 src/test/gls/scope/ClassVariableHidingTest.groovy  |   15 +
 src/test/gls/scope/FinalAccessTest.groovy          |   15 +
 src/test/gls/scope/StaticScopeTest.groovy          |   15 +
 src/test/gls/scope/VariablePrecedenceTest.groovy   |   15 +
 src/test/gls/sizelimits/StringSizeTest.groovy      |   15 +
 src/test/gls/statements/DeclarationTest.groovy     |   15 +
 .../MultipleAssignmentDeclarationTest.groovy       |   15 +
 .../gls/statements/MultipleAssignmentTest.groovy   |   15 +
 src/test/gls/statements/ReturnTest.groovy          |   35 +
 src/test/gls/syntax/AssertTest.groovy              |   15 +
 src/test/gls/syntax/BinaryLiteralTest.groovy       |   15 +
 src/test/gls/syntax/Gep3OrderDslTest.groovy        |   15 +
 src/test/gls/syntax/Gep3Test.groovy                |   15 +
 src/test/gls/syntax/NumberLiteralTest.groovy       |   15 +
 .../gls/syntax/OldClosureSyntaxRemovalTest.groovy  |   15 +
 .../gls/syntax/OldPropertySyntaxRemovalTest.groovy |   15 +
 src/test/gls/syntax/OldSpreadTest.groovy           |   15 +
 src/test/gls/syntax/ParsingTest.groovy             |   15 +
 src/test/gls/syntax/UnderscoreInNumbersTest.groovy |   15 +
 .../types/BooleanExpressionConversionTest.groovy   |   15 +
 src/test/gls/types/GroovyCastTest.groovy           |   15 +
 src/test/gls/types/OperationsResultTypeTest.groovy |   15 +
 src/test/groovy/AmbiguousInvocationTest.groovy     |   15 +
 src/test/groovy/ArrayAutoboxingTest.groovy         |   15 +
 src/test/groovy/ArrayCoerceTest.groovy             |   15 +
 src/test/groovy/ArrayParamMethodTest.groovy        |   15 +
 src/test/groovy/ArrayTest.groovy                   |   61 +
 src/test/groovy/ArrayTypeTest.groovy               |   15 +
 src/test/groovy/AsTest.groovy                      |   15 +
 src/test/groovy/Bar.groovy                         |   15 +
 src/test/groovy/Base64Test.groovy                  |   15 +
 src/test/groovy/BinaryStreamsTest.groovy           |   15 +
 src/test/groovy/BreakContinueLabelTest.groovy      |   61 +-
 src/test/groovy/CallInnerClassCtorTest.groovy      |   15 +
 src/test/groovy/CategoryTest.groovy                |   15 +
 src/test/groovy/ChainedAssignmentTest.groovy       |   15 +
 src/test/groovy/ClassExpressionTest.groovy         |   15 +
 src/test/groovy/ClassLoaderBug.groovy              |   15 +
 src/test/groovy/ClosureCloneTest.groovy            |   15 +
 src/test/groovy/ClosureDefaultParameterTest.groovy |   15 +
 src/test/groovy/ClosureInStaticMethodTest.groovy   |   15 +
 src/test/groovy/ClosureMethodCallTest.groovy       |   15 +
 src/test/groovy/ClosureReturnTest.groovy           |   15 +
 .../ClosureReturnWithoutReturnStatementTest.groovy |   15 +
 src/test/groovy/ClosureSugarTest.groovy            |   15 +
 src/test/groovy/ClosureTest.groovy                 |   18 +
 .../groovy/ClosureWithEmptyParametersTest.groovy   |   15 +
 src/test/groovy/CollateTest.groovy                 |   16 +
 src/test/groovy/CompareEqualsTest.groovy           |   15 +
 src/test/groovy/CompareTypesTest.groovy            |   15 +
 src/test/groovy/CompileOrderTest.groovy            |   15 +
 src/test/groovy/CompilerErrorTest.groovy           |   15 +
 src/test/groovy/Constructor2Test.groovy            |   15 +
 src/test/groovy/ConstructorTest.groovy             |   15 +
 src/test/groovy/CurlyBracketLayoutTest.groovy      |   15 +
 src/test/groovy/DoWhileLoopTest.groovy             |   15 +
 src/test/groovy/DollarEscapingTest.groovy          |   15 +
 src/test/groovy/DownUpStepTest.groovy              |   15 +
 src/test/groovy/DummyInterface.java                |   15 +
 src/test/groovy/DynamicMemberTest.groovy           |   15 +
 src/test/groovy/EscapedUnicodeTest.groovy          |   15 +
 src/test/groovy/Foo.groovy                         |   15 +
 src/test/groovy/GroovyClosureMethodsTest.groovy    |   15 +
 src/test/groovy/GroovyInterceptableTest.groovy     |   15 +
 src/test/groovy/GroovyMethodsTest.groovy           |  550 ++-
 src/test/groovy/HexTest.groovy                     |   15 +
 .../groovy/InvokeNormalMethodsFirstTest.groovy     |   15 +
 src/test/groovy/JavaClass.java                     |   15 +
 src/test/groovy/JointGroovy.groovy                 |   15 +
 src/test/groovy/JointJava.java                     |   15 +
 src/test/groovy/LeftShiftTest.groovy               |   15 +
 src/test/groovy/ListTest.groovy                    |   52 +-
 src/test/groovy/LiteralTypesTest.groovy            |   15 +
 src/test/groovy/LittleClosureTest.groovy           |   15 +
 src/test/groovy/LocalVariableTest.groovy           |   15 +
 src/test/groovy/LogicTest.groovy                   |   15 +
 src/test/groovy/LoopBreakTest.groovy               |   15 +
 src/test/groovy/MapPropertyTest.groovy             |   15 +
 src/test/groovy/MapTest.groovy                     |   15 +
 src/test/groovy/MethodCallTest.groovy              |   15 +
 .../groovy/MethodCallWithoutParenthesisTest.groovy |   15 +
 .../MethodParameterAccessWithinClosureTest.groovy  |   15 +
 src/test/groovy/MinMaxTest.groovy                  |   15 +
 src/test/groovy/MinusEqualsTest.groovy             |   15 +
 src/test/groovy/ModifiersTest.groovy               |   15 +
 src/test/groovy/ModuloTest.groovy                  |   15 +
 src/test/groovy/MultilineStringTest.groovy         |   15 +
 src/test/groovy/MultiplyDivideEqualsTest.groovy    |   15 +
 src/test/groovy/NamedParameterTest.groovy          |   15 +
 src/test/groovy/NestedClassTest.groovy             |   15 +
 src/test/groovy/NewExpressionTest.groovy           |   15 +
 src/test/groovy/NoPackageTest.groovy               |   15 +
 src/test/groovy/NullPropertyTest.groovy            |   15 +
 src/test/groovy/NumberMathTest.groovy              |   15 +
 src/test/groovy/OuterUser.java                     |   15 +
 src/test/groovy/OverloadInvokeMethodTest.groovy    |   15 +
 src/test/groovy/OverridePropertyGetterTest.groovy  |   15 +
 src/test/groovy/PlusEqualsTest.groovy              |   15 +
 src/test/groovy/PostfixTest.groovy                 |   15 +
 src/test/groovy/PrefixTest.groovy                  |   15 +
 src/test/groovy/PrimitiveArraysTest.groovy         |   15 +
 src/test/groovy/PrimitiveDefaultValueTest.groovy   |   15 +
 src/test/groovy/PrimitiveTypeFieldTest.groovy      |   15 +
 src/test/groovy/PrintTest.groovy                   |   15 +
 ...ateVariableAccessFromAnotherInstanceTest.groovy |   15 +
 src/test/groovy/ProcessTest.groovy                 |   15 +
 src/test/groovy/PropertyTest.groovy                |   46 +-
 src/test/groovy/PropertyWithoutDotTest.groovy      |   15 +
 src/test/groovy/ReadLineTest.groovy                |   21 +-
 src/test/groovy/ReturnTest.groovy                  |   15 +
 src/test/groovy/SafeNavigationTest.groovy          |   15 +
 src/test/groovy/SampleMain.groovy                  |   15 +
 src/test/groovy/SetTest.groovy                     |    6 +-
 src/test/groovy/SimplePostfixTest.groovy           |   15 +
 src/test/groovy/SingletonBugTest.groovy            |   15 +
 src/test/groovy/SliceTest.groovy                   |   15 +
 src/test/groovy/SomeClass.java                     |   15 +
 src/test/groovy/SortTest.groovy                    |   15 +
 src/test/groovy/SqlDateTest.groovy                 |   15 +
 src/test/groovy/StaticImportTarget.groovy          |   15 +
 src/test/groovy/StaticMessageTest.groovy           |   15 +
 src/test/groovy/StaticThisTest.groovy              |   13 +
 src/test/groovy/StringBufferTest.groovy            |   15 +
 src/test/groovy/StringTest.groovy                  |   10 +
 src/test/groovy/SubscriptTest.groovy               |   32 +-
 src/test/groovy/SwitchTest.groovy                  |   15 +
 .../groovy/SwitchWithDifferentTypesTest.groovy     |   15 +
 src/test/groovy/TestInterruptor.java               |   15 +
 src/test/groovy/TextPropertyTest.groovy            |   15 +
 src/test/groovy/ToArrayBugTest.groovy              |   15 +
 src/test/groovy/TripleQuotedStringTest.groovy      |   15 +
 src/test/groovy/TypesafeMethodTest.groovy          |   15 +
 src/test/groovy/UnitTestAsScriptTest.groovy        |   15 +
 src/test/groovy/UnsafeNavigationTest.groovy        |   15 +
 src/test/groovy/VArgsTest.groovy                   |   15 +
 src/test/groovy/ValidNameTest.groovy               |   15 +
 src/test/groovy/VarargsMethodTest.groovy           |   15 +
 src/test/groovy/VerbatimGStringTest.groovy         |   15 +
 src/test/groovy/WhileLoopTest.groovy               |   15 +
 src/test/groovy/annotations/MyClass.groovy         |   15 +
 .../annotations/ParameterAnnotationTest.groovy     |   15 +
 src/test/groovy/annotations/package-info.groovy    |   15 +
 src/test/groovy/beans/BindableTest.groovy          |   16 +-
 src/test/groovy/beans/ListenerListHelper.groovy    |   15 +
 src/test/groovy/benchmarks/createLoop.groovy       |   15 +
 src/test/groovy/benchmarks/loop.groovy             |   15 +
 src/test/groovy/benchmarks/loop2.groovy            |   15 +
 .../groovy/bugs/AmbiguousListOrMethodTest.groovy   |   15 +
 src/test/groovy/bugs/ArrayMethodCallBug.groovy     |   15 +
 src/test/groovy/bugs/AsBoolBug.groovy              |   15 +
 .../bugs/AssignmentInsideExpressionBug.groovy      |   15 +
 .../groovy/bugs/AttributeSetExpressionBug.groovy   |   15 +
 .../groovy/bugs/AutoboxingOfComparisonsBug.groovy  |   15 +
 .../bugs/BadLineNumberOnExceptionBugTest.groovy    |   15 +
 src/test/groovy/bugs/BenchmarkBug.groovy           |   15 +
 src/test/groovy/bugs/BooleanBug.groovy             |   15 +
 src/test/groovy/bugs/ByteIndexBug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode2Bug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode3Bug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode4Bug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode5Bug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode6Bug.groovy           |   15 +
 src/test/groovy/bugs/Bytecode7Bug.groovy           |   15 +
 src/test/groovy/bugs/BytecodeBug.groovy            |   15 +
 .../bugs/CallingClosuresWithClosuresBug.groovy     |   15 +
 .../groovy/bugs/CastWhenUsingClosuresBug.groovy    |   15 +
 .../groovy/bugs/ClassGeneratorFixesTest.groovy     |   15 +
 src/test/groovy/bugs/ClassInNamedParamsBug.groovy  |   15 +
 src/test/groovy/bugs/ClosureInClosureBug.groovy    |   15 +
 .../groovy/bugs/ClosureParameterPassingBug.groovy  |   15 +
 .../groovy/bugs/ClosureTypedVariableBug.groovy     |   15 +
 src/test/groovy/bugs/ClosureVariableBug.groovy     |   15 +
 .../bugs/ClosureWithBitwiseDefaultParamTest.groovy |   15 +
 .../bugs/ClosureWithStaticVariablesBug.groovy      |   15 +
 src/test/groovy/bugs/ConstructorBug.groovy         |   15 +
 src/test/groovy/bugs/ConstructorThisCallBug.groovy |   15 +
 src/test/groovy/bugs/DefVariableBug.groovy         |   15 +
 .../bugs/DirectMethodCallWithVargsTest.groovy      |   15 +
 src/test/groovy/bugs/FullyQualifiedClassBug.groovy |   15 +
 .../bugs/FullyQualifiedMethodReturnTypeBug.groovy  |   15 +
 .../bugs/FullyQualifiedVariableTypeBug.groovy      |   15 +
 src/test/groovy/bugs/G3839A1.java                  |   15 +
 src/test/groovy/bugs/G3839A2.java                  |   15 +
 src/test/groovy/bugs/G3839A3.java                  |   15 +
 src/test/groovy/bugs/G3839A4.java                  |   15 +
 src/test/groovy/bugs/G3839Transform1.java          |   15 +
 src/test/groovy/bugs/G3839Transform2.java          |   15 +
 src/test/groovy/bugs/G3839Transform3.java          |   15 +
 src/test/groovy/bugs/GROOVY3934Helper.groovy       |   15 +
 src/test/groovy/bugs/Groovy1018_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1059_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1407_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1462_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1465Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy1593.groovy             |   15 +
 src/test/groovy/bugs/Groovy1617_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1706_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy1759_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy2348Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2350Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2351Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2365Base.groovy         |   15 +
 src/test/groovy/bugs/Groovy2365Bug.java            |   15 +
 src/test/groovy/bugs/Groovy2391Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy239_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2432Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2490Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy252_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2553Bug.java            |   15 +
 src/test/groovy/bugs/Groovy2556Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2557Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2558Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2666Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2706Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy278_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2801Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2816Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2849Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy2949Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3069Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3135Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3139Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3156And2621Bug.groovy   |   15 +
 src/test/groovy/bugs/Groovy3163Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3175_Bug.groovy         |   15 +
 src/test/groovy/bugs/Groovy3205Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3208Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3235Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3238Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy325_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3304Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3305Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3335Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3389Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3403Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3405Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3410Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3424Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3426Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3462Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3464Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3465Helper.groovy       |   15 +
 src/test/groovy/bugs/Groovy3498Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3509Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3511Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3519Bug.groovy          |   60 +
 src/test/groovy/bugs/Groovy3574Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3645Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3719Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3719Bug_script.groovy   |   15 +
 src/test/groovy/bugs/Groovy3720Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3723Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3749Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3770Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3776Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3784Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3789Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3801Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3817Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3818Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3827Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3830Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3831Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3834Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3839Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3852Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3857Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3863Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3868Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3871Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3873Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3876Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3894Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy389_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3904Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3949Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy3989Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4025Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4035Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4038Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4043Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4046Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4069Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4075Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4078Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4080Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4081Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4145.groovy             |   15 +
 src/test/groovy/bugs/Groovy4206Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4243Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4247Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4257Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4386_Bug.groovy         |   13 +-
 src/test/groovy/bugs/Groovy4415Bug.groovy          |   15 +
 ...Groovy4457GenericTypeDeclarationLeakTest.groovy |   15 +
 src/test/groovy/bugs/Groovy4471Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy4861Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5025Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5061.groovy             |   15 +
 src/test/groovy/bugs/Groovy5101Test.groovy         |   15 +
 src/test/groovy/bugs/Groovy5109Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5122Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5137Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5150Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5152Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5185Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5193Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5210Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5212Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5259Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5260Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5267Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5272Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy5285Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6374Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6508Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy662Bug.groovy           |   15 +
 src/test/groovy/bugs/Groovy662_JavaClass.java      |   15 +
 src/test/groovy/bugs/Groovy666_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy674_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6755Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6786Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6804Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy6841Bug.groovy          |   51 +
 src/test/groovy/bugs/Groovy7081Bug.groovy          |   65 +
 src/test/groovy/bugs/Groovy770_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy831_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy872Bug.groovy           |   15 +
 src/test/groovy/bugs/Groovy965_Bug.groovy          |   15 +
 src/test/groovy/bugs/Groovy996_Bug.groovy          |   15 +
 src/test/groovy/bugs/GroovyInnerEnumBug.groovy     |   15 +
 src/test/groovy/bugs/GuillaumesBug.groovy          |   15 +
 src/test/groovy/bugs/GuillaumesMapBug.groovy       |   15 +
 .../groovy/bugs/InconsistentStackHeightBug.groovy  |   15 +
 src/test/groovy/bugs/InterfaceImplBug.groovy       |   15 +
 ...vokeNormalMethodFromBuilder_Groovy657Bug.groovy |   15 +
 .../groovy/bugs/IterateOverCustomTypeBug.groovy    |   15 +
 src/test/groovy/bugs/MarkupAndMethodBug.groovy     |   15 +
 ...MethodCallWithoutParensInStaticMethodBug.groovy |   15 +
 src/test/groovy/bugs/MethodClosureTest.groovy      |   15 +
 src/test/groovy/bugs/MethodDispatchBug.groovy      |   15 +
 src/test/groovy/bugs/MethodPointerBug.groovy       |   15 +
 src/test/groovy/bugs/MorgansBug.groovy             |   15 +
 src/test/groovy/bugs/MyConstants4272.java          |   15 +
 .../bugs/MyConstantsASTTransformation4272.groovy   |   15 +
 .../groovy/bugs/NullAsBooleanCoercionTest.groovy   |   15 +
 src/test/groovy/bugs/NullCompareBug.groovy         |   15 +
 src/test/groovy/bugs/POJOCallSiteBug.groovy        |   15 +
 src/test/groovy/bugs/POJOCallSiteBugFoo.java       |   15 +
 src/test/groovy/bugs/PrimitivePropertyBug.groovy   |   15 +
 src/test/groovy/bugs/PrintlnWithNewBug.groovy      |   15 +
 src/test/groovy/bugs/PropertyNameBug.groovy        |   15 +
 src/test/groovy/bugs/RodsBooleanBug.groovy         |   15 +
 src/test/groovy/bugs/RodsBug.groovy                |   15 +
 .../groovy/bugs/RussellsOptionalParenTest.groovy   |   15 +
 src/test/groovy/bugs/SingleEvalTest.groovy         |   15 +
 .../groovy/bugs/StaticClosurePropertyBug.groovy    |   15 +
 src/test/groovy/bugs/StaticMethodCallBug.groovy    |   15 +
 src/test/groovy/bugs/StaticMethodImportBug.groovy  |   15 +
 .../bugs/StaticMethodImportGroovy935Bug.groovy     |   15 +
 src/test/groovy/bugs/StaticPropertyBug.groovy      |   15 +
 .../groovy/bugs/SubscriptAndExpressionBug.groovy   |   15 +
 .../bugs/SubscriptOnPrimitiveTypeArrayBug.groovy   |   15 +
 .../groovy/bugs/SubscriptOnStringArrayBug.groovy   |   15 +
 src/test/groovy/bugs/TernaryOperatorTest.groovy    |   15 +
 src/test/groovy/bugs/TryCatch2Bug.groovy           |   15 +
 src/test/groovy/bugs/TryCatchBug.groovy            |   15 +
 src/test/groovy/bugs/UnknownVariableBug.groovy     |   15 +
 src/test/groovy/bugs/UseClosureInClosureBug.groovy |   15 +
 src/test/groovy/bugs/UseStaticInClosureBug.groovy  |   15 +
 src/test/groovy/bugs/VariablePrecedence.groovy     |   15 +
 src/test/groovy/bugs/VariablePrecedenceTest.groovy |   15 +
 src/test/groovy/bugs/VariableScopingBug.groovy     |   15 +
 src/test/groovy/bugs/VerifyErrorBug.groovy         |   15 +
 src/test/groovy/bugs/WriteOnlyPropertyBug.groovy   |   15 +
 src/test/groovy/bugs/ZoharsBug.groovy              |   15 +
 src/test/groovy/bugs/bug1567_script.groovy         |   15 +
 .../groovy/execute/ExecuteTest_LinuxSolaris.groovy |   17 +-
 src/test/groovy/gpath/NodeGPathTest.groovy         |   15 +
 src/test/groovy/grape/GrapeClassLoaderTest.groovy  |   15 +
 src/test/groovy/io/PlatformLineWriterTest.java     |   15 +
 .../groovy/lang/BenchmarkInterceptorTest.groovy    |   15 +
 src/test/groovy/lang/CharacterRangeTest.java       |   15 +
 src/test/groovy/lang/ClassReloadingTest.groovy     |   72 +
 .../groovy/lang/DelegatingMetaClassTest.groovy     |   15 +
 src/test/groovy/lang/EmptyRangeTest.java           |   15 +
 src/test/groovy/lang/ExceptionTest.groovy          |   15 +
 src/test/groovy/lang/Groovy3406Test.groovy         |   15 +
 src/test/groovy/lang/GroovyClassLoaderTest.groovy  |   11 +
 src/test/groovy/lang/GroovyShellTest2.groovy       |   94 +
 src/test/groovy/lang/GroovySystemTest.groovy       |   15 +
 .../groovy/lang/InnerClassResolvingTest.groovy     |   15 +
 src/test/groovy/lang/MetaClassRegistryTest.groovy  |   15 +
 src/test/groovy/lang/MixinTest.groovy              |    2 +
 .../groovy/lang/ReferenceSerializationTest.groovy  |   15 +
 src/test/groovy/lang/ScriptCacheTest.groovy        |   15 +
 src/test/groovy/lang/ScriptIntegerDivideTest.java  |   15 +
 .../lang/ScriptSourcePositionInAstTest.groovy      |   15 +
 src/test/groovy/lang/ScriptTest.java               |    8 +
 src/test/groovy/lang/StringConcatTest.groovy       |   15 +
 src/test/groovy/lang/StripMarginTest.groovy        |   15 +
 src/test/groovy/lang/SyntheticReturnTest.groovy    |   15 +
 src/test/groovy/lang/TupleTest.java                |   10 +
 .../groovy/lang/gcldeadlock/DeadlockBugUtil.groovy |   15 +
 .../gcldeadlock/GroovyClassLoaderDeadlockTest.java |   15 +
 src/test/groovy/lang/gcldeadlock/script0.groovy    |   15 +
 src/test/groovy/lang/gcldeadlock/script1.groovy    |   15 +
 src/test/groovy/mock/example/CheeseSlicer.groovy   |   15 +
 src/test/groovy/mock/example/SandwichMaker.groovy  |   15 +
 .../groovy/mock/example/SandwichMakerTest.groovy   |   15 +
 src/test/groovy/mock/interceptor/Caller.groovy     |   15 +
 .../groovy/mock/interceptor/Collaborator.groovy    |   15 +
 .../groovy/mock/interceptor/HalfMockTest.groovy    |   15 +
 .../groovy/mock/interceptor/IteratorCounter.java   |   15 +
 .../groovy/mock/interceptor/MockForJavaTest.groovy |   15 +
 .../mock/interceptor/MockNestedCallTest.groovy     |   15 +
 .../mock/interceptor/MockSingleCallTest.groovy     |   15 +
 .../mock/interceptor/MockWithZeroRangeTest.groovy  |   15 +
 .../groovy/mock/interceptor/StubForJavaTest.groovy |   15 +
 src/test/groovy/mock/interceptor/StubTest.groovy   |   15 +
 .../groovy/operator/BitwiseOperatorsTest.groovy    |   15 +
 .../groovy/operator/IntegerOperatorsTest.groovy    |   15 +
 src/test/groovy/operator/MyColor.groovy            |   15 +
 src/test/groovy/operator/MyColorCategory.groovy    |   15 +
 .../operator/MyColorOperatorOverloadingTest.groovy |   15 +
 src/test/groovy/operator/NegateListsTest.groovy    |   15 +
 src/test/groovy/operator/PowerOperatorsTest.groovy |   15 +
 .../groovy/operator/SpreadListOperatorTest.groovy  |   15 +
 .../groovy/operator/SpreadMapOperatorTest.groovy   |   15 +
 .../groovy/operator/TernaryOperatorsTest.groovy    |   15 +
 .../groovy/operator/UnaryMinusNumberTests.groovy   |   15 +
 .../groovy/operator/UnaryMinusOperatorTest.groovy  |   15 +
 .../bugs/CustomMetaClassTestMetaClass.groovy       |   15 +
 src/test/groovy/script/CallAnotherScript.groovy    |   15 +
 src/test/groovy/script/ClassWithScript.groovy      |   15 +
 src/test/groovy/script/EvalInScript.groovy         |   15 +
 src/test/groovy/script/HelloWorld.groovy           |   15 +
 src/test/groovy/script/HelloWorld2.groovy          |   15 +
 src/test/groovy/script/MethodTestScript.groovy     |   15 +
 src/test/groovy/script/PackageScript.groovy        |   15 +
 src/test/groovy/script/ScriptWithFunctions.groovy  |   15 +
 src/test/groovy/script/ShowArgs.groovy             |   15 +
 .../script/StreamClassloaderInScriptTest.groovy    |   15 +
 src/test/groovy/script/UseClosureInScript.groovy   |   15 +
 src/test/groovy/security/RunOneGroovyScript.java   |   15 +
 src/test/groovy/security/SecurityTest.java         |   15 +
 src/test/groovy/security/SecurityTestSupport.java  |   15 +
 src/test/groovy/security/SignedJarTest.java        |   15 +
 src/test/groovy/time/DurationTest.groovy           |   15 +
 .../transform/AnnotationCollectorTest.groovy       |   15 +
 src/test/groovy/transform/LazyTest.groovy          |   15 +
 src/test/groovy/transform/ReadWriteLockTest.groovy |   15 +
 .../groovy/transform/ThreadInterruptTest.groovy    |   17 +-
 .../stc/ArraysAndCollectionsSTCTest.groovy         |   12 +
 src/test/groovy/transform/stc/BugsSTCTest.groovy   |   15 +
 .../groovy/transform/stc/ClosuresSTCTest.groovy    |    2 +-
 .../transform/stc/ConstructorsSTCTest.groovy       |   15 +
 .../groovy/transform/stc/DelegatesToSTCTest.groovy |   56 +
 .../stc/FieldsAndPropertiesSTCTest.groovy          |  153 +
 src/test/groovy/transform/stc/Groovy7184Bug.groovy |   31 +
 .../stc/PrecompiledExtensionNotExtendingDSL.groovy |   43 +
 .../groovy/transform/stc/STCAssignmentTest.groovy  |   29 +-
 .../stc/TypeCheckingExtensionsTest.groovy          |   12 +
 src/test/groovy/transform/stc/package.html         |   17 +
 src/test/groovy/tree/ClosureClassLoaderBug.groovy  |   15 +
 src/test/groovy/tree/NavigationTest.groovy         |   15 +
 src/test/groovy/tree/NestedClosureBugTest.groovy   |   15 +
 src/test/groovy/tree/SmallTreeTest.groovy          |   15 +
 src/test/groovy/tree/TreeTest.groovy               |   15 +
 src/test/groovy/tree/VerboseTreeTest.groovy        |   15 +
 src/test/groovy/txn/TransactionBean.java           |   15 +
 src/test/groovy/txn/TransactionBuilder.java        |   15 +
 src/test/groovy/ui/GroovyMainTest.groovy           |   15 +
 src/test/groovy/util/BuilderSupportTest.groovy     |   15 +
 src/test/groovy/util/ConfigObjectTest.groovy       |   13 +
 src/test/groovy/util/EvalTest.java                 |   15 +
 src/test/groovy/util/FileTreeBuilderTest.groovy    |  120 +
 src/test/groovy/util/GroovyCollectionsTest.groovy  |    4 +
 .../util/GroovyScriptEngineReloadingTest.groovy    |   15 +
 src/test/groovy/util/IndentPrinterTest.groovy      |   15 +
 src/test/groovy/util/ObjectGraphBuilderTest.groovy |   15 +
 .../groovy/util/ProxyGeneratorAdapterTest.groovy   |   28 +
 src/test/groovy/util/ProxyTest.groovy              |   15 +
 src/test/groovy/util/ResourceBundleTest.groovy     |   15 +
 src/test/groovy/util/i18n.properties               |   16 +
 src/test/groovy/util/i18n_en.properties            |   16 +
 src/test/groovy/util/i18n_fr.properties            |   16 +
 src/test/groovy/util/logging/CommonsTest.groovy    |   15 +
 src/test/groovy/util/logging/Log4j2Test.groovy     |   23 +-
 src/test/groovy/util/logging/Log4jTest.groovy      |   15 +
 src/test/groovy/util/logging/LogTest.groovy        |   15 +
 src/test/groovy/util/logging/Slf4jTest.groovy      |   15 +
 src/test/groovy/util/system.properties             |   16 +
 src/test/groovy/xml/XmlAssert.java                 |   15 +
 src/test/indy/IndyUsageTest.groovy                 |   15 +
 .../ClosureAndInnerClassNodeStructureTest.groovy   |   63 +-
 .../groovy/antlr/treewalker/Java2GroovyTest.java   |    8 +-
 src/test/org/codehaus/groovy/ast/ASTTest.java      |   15 +
 .../groovy/ast/CodeVisitorSupportTest.groovy       |   15 +
 .../groovy/ast/LazyInitOnClassNodeTest.groovy      |   15 +
 .../org/codehaus/groovy/ast/LineColumnChecker.java |   15 +
 .../org/codehaus/groovy/ast/MethodNodeTest.groovy  |   15 +
 .../groovy/ast/VariableExpressionTest.java         |   15 +
 .../builder/AstBuilderFromSpecificationTest.groovy |  179 +-
 .../groovy/ast/expr/ClosureExpressionTest.groovy   |   15 +
 .../groovy/ast/expr/MapExpressionTest.groovy       |   15 +
 .../ast/expr/MethodCallExpressionTest.groovy       |   15 +
 .../groovy/ast/expr/PropertyExpressionTest.groovy  |   15 +
 .../groovy/ast/source/Groovy3049Test.groovy        |   15 +
 .../groovy/ast/source/Groovy3050Test.groovy        |   15 +
 .../groovy/ast/source/Groovy3051Test.groovy        |   15 +
 .../groovy/ast/source/SourceBaseTestCase.groovy    |   15 +
 .../groovy/ast/tools/WideningCategoriesTest.groovy |    9 +
 .../groovy/benchmarks/alioth/binarytrees.groovy    |   15 +
 .../groovy/benchmarks/alioth/fannkuch.groovy       |   15 +
 .../groovy/benchmarks/alioth/partialsums.groovy    |   15 +
 .../groovy/benchmarks/alioth/rayTracer.groovy      |   15 +
 .../groovy/benchmarks/alioth/recursive.groovy      |   15 +
 .../groovy/benchmarks/alioth/spectralnorm.groovy   |   15 +
 .../groovy/benchmarks/vm5/b2394/Builder.java       |   15 +
 .../codehaus/groovy/benchmarks/vm5/b2394/Main.java |   15 +
 .../benchmarks/vm5/b2394/ScriptLauncher.java       |   28 +-
 .../groovy/benchmarks/vm5/b2394/script120.groovy   |   15 +
 .../groovy/benchmarks/vm5/b2394/script240.groovy   |   15 +
 .../groovy/benchmarks/vm5/b2394/script30.groovy    |   15 +
 .../groovy/benchmarks/vm5/b2394/script300.groovy   |   15 +
 .../vm5/b2394/script300WithCategory.groovy         |   15 +
 .../groovy/benchmarks/vm5/b2394/script60.groovy    |   15 +
 .../org/codehaus/groovy/benchmarks/vm5/psum.java   |   15 +
 .../groovy/benchmarks/vm5/spectralnorm.java        |   15 +
 .../groovy/classgen/GenericsGenTest.groovy         |    2 +-
 .../classgen/asm/AbstractBytecodeTestCase.groovy   |   15 +
 .../classgen/asm/BinaryOperationsTest.groovy       |   15 +
 .../classgen/asm/DirectMethodCallTest.groovy       |   15 +
 .../groovy/classgen/asm/HotSwapTest.groovy         |   19 +-
 .../asm/InstructionSequenceHelperClassTest.groovy  |   15 +
 .../groovy/classgen/asm/MethodPatternsTest.groovy  |    9 +
 .../classgen/asm/PrintlnLoadsAConstantTest.groovy  |   15 +
 .../ArraysAndCollectionsStaticCompileTest.groovy   |    9 +
 .../sc/FieldsAndPropertiesStaticCompileTest.groovy |   90 +-
 .../asm/sc/Groovy7222OptimizationsTest.groovy      |  108 +
 .../asm/sc/MethodCallsStaticCompilationTest.groovy |   48 +
 .../classgen/asm/sc/StaticCompilationTest.groovy   |  317 ++
 .../asm/sc/StaticCompilationTestSupport.groovy     |    9 +-
 .../asm/sc/StaticCompileArrayLengthAndGet.groovy   |   15 +
 .../sc/StaticCompileCastOptimizationTest.groovy    |   99 +
 .../asm/sc/StaticCompileClosureCallTest.groovy     |   15 +
 .../asm/sc/StaticCompileComparisonTest.groovy      |   15 +
 .../asm/sc/StaticCompileDGMMethodTest.groovy       |   15 +
 .../asm/sc/StaticCompileFieldAccessTest.groovy     |   15 +
 .../asm/sc/StaticCompileFlowTypingTest.groovy      |   15 +
 .../asm/sc/StaticCompileInnerClassTest.groovy      |   15 +
 .../classgen/asm/sc/StaticCompileMathTest.groovy   |   15 +
 ...StaticCompileNullCompareOptimizationTest.groovy |   15 +
 .../asm/sc/StaticCompilePostfixPrefixTest.groovy   |   15 +
 .../TupleConstructorStaticCompilationTest.groovy   |   15 +
 .../classgen/asm/sc/bugs/Groovy6240Bug.groovy      |   67 +
 .../classgen/asm/sc/bugs/Groovy6411Bug.groovy      |   15 +
 .../classgen/asm/sc/bugs/Groovy6757Bug.groovy      |   63 +
 .../classgen/asm/sc/bugs/Groovy7039Bug.groovy      |   74 +
 .../classgen/asm/sc/bugs/Groovy7041Bug.groovy      |   35 +
 .../classgen/asm/sc/bugs/Groovy7042Bug.groovy      |   46 +
 .../classgen/asm/sc/bugs/Groovy7072Bug.groovy      |   34 +
 .../classgen/asm/sc/bugs/Groovy7075Bug.groovy      |   45 +
 .../classgen/asm/sc/bugs/Groovy7093Bug.groovy      |   35 +
 .../classgen/asm/sc/bugs/Groovy7098Bug.groovy      |   62 +
 .../classgen/asm/sc/bugs/Groovy7133Bug.groovy      |   39 +
 .../classgen/asm/sc/bugs/Groovy7138Bug.groovy      |   62 +
 .../classgen/asm/sc/bugs/Groovy7145Bug.groovy      |   62 +
 .../classgen/asm/sc/bugs/Groovy7149Bug.groovy      |   57 +
 .../classgen/asm/sc/bugs/Groovy7169Bug.groovy      |   46 +
 .../classgen/asm/sc/bugs/Groovy7210Bug.groovy      |   34 +
 .../classgen/asm/sc/bugs/Groovy7211Bug.groovy      |   41 +
 .../classgen/asm/sc/bugs/Groovy7242Bug.groovy      |   81 +
 .../classgen/asm/sc/bugs/Groovy7276Bug.groovy      |   92 +
 .../classgen/asm/sc/bugs/Groovy7298Bug.groovy      |   43 +
 .../classgen/asm/sc/bugs/Groovy7300Bug.groovy      |   77 +
 .../classgen/asm/sc/bugs/Groovy7307Bug.groovy      |   46 +
 .../classgen/asm/sc/bugs/Groovy7316Bug.groovy      |   56 +
 .../classgen/asm/sc/bugs/Groovy7322Bug.groovy      |   62 +
 .../classgen/asm/sc/bugs/Groovy7324Bug.groovy      |   74 +
 .../classgen/asm/sc/bugs/Groovy7325Bug.groovy      |   40 +
 .../classgen/asm/sc/bugs/Groovy7327Bug.groovy      |   39 +
 .../classgen/asm/sc/bugs/Groovy7333Bug.groovy      |   38 +
 .../classgen/asm/sc/bugs/Groovy7343Bug.groovy      |   46 +
 .../classgen/asm/sc/bugs/Groovy7355Bug.groovy      |   42 +
 .../classgen/asm/sc/bugs/Groovy7356Bug.groovy      |   68 +
 .../classgen/asm/sc/bugs/Groovy7357Bug.groovy      |   47 +
 .../classgen/asm/sc/bugs/Groovy7358Bug.groovy      |   54 +
 .../classgen/asm/sc/bugs/Groovy7361Bug.groovy      |   60 +
 .../classgen/asm/sc/bugs/Groovy7364Bug.groovy      |   38 +
 .../asm/sc/bugs/support/Groovy7133Support.java     |   25 +
 .../ASTTransformationCustomizerTest.groovy         |    2 +-
 .../groovy/control/io/FileReaderTest.groovy        |   15 +
 .../groovy/control/io/NullWriterTest.groovy        |   15 +
 .../control/io/StringReaderSourceTest.groovy       |   15 +
 .../groovy/dummy/ClassWithStaticMethod.groovy      |   15 +
 src/test/org/codehaus/groovy/dummy/FooHandler.java |   15 +
 .../reflection/GroovyClassValueFactoryTest.groovy  |   43 +
 .../codehaus/groovy/reflection/WeakMapTest.groovy  |   15 +
 .../groovy/runtime/AppendableDgmMethodsTest.groovy |    4 +-
 .../runtime/CustomBooleanCoercionTest.groovy       |   15 +
 .../org/codehaus/groovy/runtime/DateGDKTest.groovy |   13 +-
 .../groovy/runtime/DefaultGroovyMethodsTest.groovy |  184 +
 .../groovy/runtime/DefaultGroovyMethodsTest.java   |  188 -
 .../runtime/DefaultGroovyStaticMethodsTest.java    |   35 +
 .../groovy/runtime/DirectoryDeleteTest.groovy      |   15 +
 .../codehaus/groovy/runtime/EachLineTest.groovy    |   15 +
 .../groovy/runtime/FileLeftShiftTest.groovy        |   15 +
 .../groovy/runtime/GroovyCategoryTest.groovy       |   15 +
 .../groovy/runtime/InterfaceConversionTest.groovy  |   18 +-
 .../codehaus/groovy/runtime/InvokerHelperTest.java |   15 +
 .../groovy/runtime/MetaClassHelperTest.java        |   15 +
 .../org/codehaus/groovy/runtime/MinusTest.groovy   |   15 +
 .../codehaus/groovy/runtime/NullObjectTest.groovy  |   15 +
 .../groovy/runtime/PerInstanceMetaClassTest.groovy |   15 +
 .../codehaus/groovy/runtime/StaticInitTest.java    |   15 +
 .../m12n/ExtensionModuleHelperForTests.groovy      |    8 +-
 .../groovy/runtime/m12n/ExtensionModuleTest.groovy |   24 +
 .../runtime/memoize/AbstractMemoizeTestCase.groovy |   15 +
 .../groovy/runtime/memoize/CacheCleanupTest.groovy |   15 +
 .../memoize/LRUProtectionStorageTest.groovy        |   15 +
 .../runtime/memoize/MemoizeAtLeastTest.groovy      |   15 +
 .../runtime/memoize/MemoizeAtMostTest.groovy       |   15 +
 .../runtime/memoize/MemoizeBetweenTest.groovy      |   15 +
 .../groovy/runtime/memoize/MemoizeTest.groovy      |   37 +
 .../groovy/runtime/memoize/NullValueTest.groovy    |   15 +
 .../runtime/trampoline/TrampolineTest.groovy       |   15 +
 src/test/org/codehaus/groovy/syntax/TokenTest.java |   15 +
 .../codehaus/groovy/tools/DocGeneratorMain.java    |   15 +
 .../groovy/tools/LoaderConfigurationTest.groovy    |   15 +
 .../codehaus/groovy/tools/MetaBuilderTest.groovy   |   15 +
 .../codehaus/groovy/tools/StringHelperTest.groovy  |   15 +
 .../codehaus/groovy/tools/TestDgmConverter.java    |   15 +
 .../org/codehaus/groovy/tools/UtilitiesTest.groovy |   15 +
 .../codehaus/groovy/tools/gse/DependencyTest.java  |   15 +
 .../AbstractGenericGroovySuperclass.groovy         |   15 +
 .../rootloadersync/AbstractGroovySuperclass.groovy |   15 +
 .../ConcreteGenericJavaSubclass.java               |   15 +
 .../tools/rootloadersync/ConcreteJavaSubclass.java |   15 +
 .../OtherConcreteGenericJavaSubclass.java          |   15 +
 .../rootloadersync/OtherConcreteJavaSubclass.java  |   15 +
 .../rootloadersync/SubclassingInGroovyTest.groovy  |   15 +
 .../rootloadersync/SubclassingInJavaTest.java      |   15 +
 .../AnnotationCollectorStubTest.groovy             |   67 +
 ...adGenericsExpansionOnInnerClassStubsTest.groovy |   15 +
 ...alueReturnTypeShouldUseGenericsStubsTest.groovy |   15 +
 .../EnsureClassAnnotationPresentInStubTest.groovy  |   15 +
 .../tools/stubgenerator/Groovy7052Bug.groovy       |   46 +
 .../tools/stubgenerator/Groovy7113Bug.groovy       |   67 +
 ...stForGenericReturnValueOfMethodStubsTest.groovy |   15 +
 .../groovy/transform/BuilderTransformTest.groovy   |  107 +-
 .../CanonicalComponentsTransformTest.groovy        |   51 +
 .../groovy/transform/DelegateTransformTest.groovy  |  104 +
 .../InheritConstructorsTransformTest.groovy        |   53 +
 .../groovy/transform/LocalASTTransformTest.groovy  |   15 +
 .../transform/MemoizedASTTransformationTest.groovy |   24 +
 .../groovy/transform/NewifyTransformTest.groovy    |   10 +
 .../transform/PackageScopeTransformTest.groovy     |   22 +-
 .../transform/SynchronizedTransformTest.groovy     |   64 +-
 .../groovy/transform/ToStringTransformTest.groovy  |   21 +
 .../groovy/transform/stc/SignatureCodecTest.groovy |   15 +
 .../transform/tailrec/TailRecursiveExamples.groovy |   15 +
 .../TernaryToIfStatementConverterTest.groovy       |   15 +
 .../groovy/transform/traitx/Groovy6697Bug.groovy   |  149 +
 .../groovy/transform/traitx/Groovy6741Bug.groovy   |   36 +
 .../groovy/transform/traitx/Groovy7011Bug.groovy   |   98 +
 .../groovy/transform/traitx/Groovy7190Bug.groovy   |   45 +
 .../groovy/transform/traitx/Groovy7196Bug.groovy   |   29 +
 .../transform/traitx/Groovy7196SupportTrait.groovy |   21 +
 .../traitx/Groovy7196SupportTraitImpl.groovy       |   20 +
 .../groovy/transform/traitx/Groovy7206Bug.groovy   |   89 +
 .../groovy/transform/traitx/Groovy7213Bug.groovy   |   36 +
 .../groovy/transform/traitx/Groovy7214Bug.groovy   |   38 +
 .../groovy/transform/traitx/Groovy7215Bug.groovy   |   45 +
 .../transform/traitx/Groovy7215SupportTrait.groovy |   23 +
 .../groovy/transform/traitx/Groovy7217Bug.groovy   |   49 +
 .../groovy/transform/traitx/Groovy7255Bug.groovy   |   36 +
 .../groovy/transform/traitx/Groovy7269Bug.groovy   |   58 +
 .../groovy/transform/traitx/Groovy7275Bug.groovy   |   43 +
 .../groovy/transform/traitx/Groovy7285Bug.groovy   |   60 +
 .../traitx/TraitASTTransformationTest.groovy       |  326 +-
 .../groovy/util/ManagedLinkedlistTest.groovy       |   15 +
 subprojects/groovy-ant/build.gradle                |    2 +
 .../src/main/java/groovy/util/AntBuilder.java      |   30 +-
 .../main/java/org/codehaus/groovy/ant/Groovy.java  |    3 +-
 .../main/java/org/codehaus/groovy/ant/Groovyc.java |    3 +-
 .../main/java/org/codehaus/groovy/ant/package.html |   17 +
 .../groovy-ant/src/spec/doc/ant-builder.adoc       |   71 +
 .../groovy-ant/src/spec/test/AntBuilderTest.groovy |  105 +
 .../spec/test/builder/AntBuilderSpecTest.groovy    |  152 +
 .../org/codehaus/groovy/ant/GroovycTest.xml        |    2 +-
 .../src/test/groovy/groovy/util/AntTest.groovy     |   36 +
 .../src/test/groovy/groovy/util/SpoofTask.java     |   15 +
 .../groovy/groovy/util/SpoofTaskContainer.java     |   15 +
 .../codehaus/groovy/ant/GroovyTest2Class.groovy    |   15 +
 subprojects/groovy-bsf/build.gradle                |    2 +-
 .../main/java/org/codehaus/groovy/bsf/package.html |   17 +
 .../groovy-bsf/src/spec/doc/integrating-bsf.adoc   |   10 +-
 .../inspect/swingui/AstNodeToScriptAdapter.groovy  |    4 +-
 .../groovy/groovy/inspect/swingui/package.html     |   17 +
 .../src/main/groovy/groovy/ui/package.html         |   17 +
 .../src/main/groovy/groovy/ui/text/package.html    |   17 +
 .../groovy/groovy/ui/view/BasicStatusBar.groovy    |    2 +-
 .../src}/spec/doc/assets/img/GroovyConsole.gif     |  Bin
 .../src}/spec/doc/assets/img/astbrowser.png        |  Bin
 .../spec/doc/assets/img/gconsole-sc-with-visu.png  |  Bin
 .../doc/assets/img/gconsole-sc-without-visu.png    |  Bin
 .../src/spec/doc/groovy-console.adoc               |  187 +
 .../swingui/AstNodeToScriptAdapterTest.groovy      |    6 +-
 .../groovy/swing/SwingBuilderConsoleTest.groovy    |   15 +
 .../ui/HistoryRecordGetTextToRunTests.groovy       |   15 +
 .../org/codehaus/groovy/tools/DocGenerator.groovy  |   15 +-
 .../resources/org/codehaus/groovy/tools/index.html |   17 +
 .../codehaus/groovy/tools/overview-summary.html    |   17 +
 .../org/codehaus/groovy/tools/stylesheet.css       |   15 +
 .../groovy/tools/template.allclasses-frame.html    |   17 +
 .../org/codehaus/groovy/tools/template.class.html  |   17 +
 .../codehaus/groovy/tools/template.index-all.html  |   17 +
 .../groovy/tools/template.overview-frame.html      |   17 +
 .../groovy/tools/template.package-frame.html       |   17 +
 .../org/codehaus/groovy/groovydoc/package.html     |   17 +
 .../tools/groovydoc/GroovyRootDocBuilder.java      |    8 +-
 .../tools/groovydoc/SimpleGroovyClassDoc.java      |    8 +-
 .../groovydoc/SimpleGroovyClassDocAssembler.java   |   33 +-
 .../codehaus/groovy/tools/groovydoc/package.html   |   17 +
 .../gstringTemplates/classLevel/classDocName.html  |   19 +-
 .../packageLevel/package-frame.html                |   17 +
 .../packageLevel/package-summary.html              |   24 +-
 .../topLevel/allclasses-frame.html                 |   17 +
 .../gstringTemplates/topLevel/deprecated-list.html |   17 +
 .../gstringTemplates/topLevel/help-doc.html        |   17 +
 .../gstringTemplates/topLevel/index-all.html       |   17 +
 .../groovydoc/gstringTemplates/topLevel/index.html |   17 +
 .../gstringTemplates/topLevel/overview-frame.html  |   17 +
 .../topLevel/overview-summary.html                 |   17 +
 .../gstringTemplates/topLevel/stylesheet.css       |   15 +
 .../groovy-groovydoc/src/spec/doc/groovydoc.adoc   |  218 +
 .../groovy/tools/groovydoc/GroovyDocToolTest.java  |   82 +-
 .../groovydoc/GroovyDocToolTestSampleGroovy.groovy |   15 +
 .../groovydoc/testfiles/ExampleVisibilityG.groovy  |   38 +
 .../groovydoc/testfiles/ExampleVisibilityJ.java    |   36 +
 .../GroovyClassWithMultipleInterfaces.groovy       |   15 +
 .../groovydoc/testfiles/GroovyInterface1.groovy    |   15 +
 .../GroovyInterfaceWithMultipleInterfaces.groovy   |   15 +
 .../testfiles/JavaClassWithMultipleInterfaces.java |   15 +
 .../tools/groovydoc/testfiles/JavaInterface1.java  |   15 +
 .../JavaInterfaceWithMultipleInterfaces.java       |   15 +
 .../staticInit/GroovyWithFailingStaticInit.groovy  |   25 +
 .../staticInit/JavaWithFailingStaticInit.java      |   28 +
 .../UsesClassesWithFailingStaticInit.groovy        |   24 +
 .../test/resources/groovydoc/groovyDocTests.xml    |   12 +-
 .../tools/groovydoc/testfiles/classDocName.html    |   17 +
 .../groovy/tools/shell/AnsiDetector.groovy         |    7 +-
 .../org/codehaus/groovy/tools/shell/Command.groovy |   25 +-
 .../groovy/tools/shell/CommandAlias.groovy         |   30 +-
 .../groovy/tools/shell/CommandException.groovy     |   22 +-
 .../groovy/tools/shell/CommandRegistry.groovy      |   46 +-
 .../groovy/tools/shell/CommandSupport.groovy       |   63 +-
 .../tools/shell/ComplexCommandSupport.groovy       |   57 +-
 .../codehaus/groovy/tools/shell/Groovysh.groovy    |  366 +-
 .../tools/shell/InteractiveShellRunner.groovy      |   73 +-
 .../codehaus/groovy/tools/shell/Interpreter.groovy |   15 +-
 .../org/codehaus/groovy/tools/shell/Main.groovy    |  188 +-
 .../org/codehaus/groovy/tools/shell/Parser.groovy  |   54 +-
 .../PatchedCandidateListCompletionHandler.groovy   |  110 +
 .../groovy/tools/shell/PatchedConsoleReader.groovy |  106 +
 .../org/codehaus/groovy/tools/shell/Shell.groovy   |   70 +-
 .../codehaus/groovy/tools/shell/ShellRunner.groovy |   39 +-
 .../tools/shell/commands/AliasCommand.groovy       |   59 +-
 .../tools/shell/commands/ClearCommand.groovy       |    5 +-
 .../tools/shell/commands/DisplayCommand.groovy     |    5 +-
 .../groovy/tools/shell/commands/DocCommand.groovy  |   34 +-
 .../groovy/tools/shell/commands/EditCommand.groovy |   37 +-
 .../groovy/tools/shell/commands/ExitCommand.groovy |    7 +-
 .../groovy/tools/shell/commands/HelpCommand.groovy |   35 +-
 .../tools/shell/commands/HistoryCommand.groovy     |   15 +-
 .../tools/shell/commands/ImportCommand.groovy      |   88 +-
 .../tools/shell/commands/InspectCommand.groovy     |   34 +-
 .../groovy/tools/shell/commands/LoadCommand.groovy |   23 +-
 .../tools/shell/commands/PurgeCommand.groovy       |   24 +-
 .../tools/shell/commands/RecordCommand.groovy      |   20 +-
 .../tools/shell/commands/RegisterCommand.groovy    |   11 +-
 .../groovy/tools/shell/commands/SaveCommand.groovy |   17 +-
 .../groovy/tools/shell/commands/SetCommand.groovy  |   23 +-
 .../groovy/tools/shell/commands/ShowCommand.groovy |   22 +-
 .../shell/completion/CommandNameCompleter.groovy   |   21 +-
 .../completion/CustomClassSyntaxCompletor.groovy   |   12 +-
 .../shell/completion/FileNameCompleter.groovy      |   51 +-
 .../shell/completion/GroovySyntaxCompletor.groovy  |   90 +-
 .../shell/completion/IdentifierCompletor.groovy    |    6 +-
 .../shell/completion/ImportsSyntaxCompletor.groovy |   50 +-
 .../completion/InfixKeywordSyntaxCompletor.groovy  |   14 +-
 .../shell/completion/KeywordSyntaxCompletor.groovy |  114 +-
 .../completion/NavigablePropertiesCompleter.groovy |   62 +-
 .../ReflectionCompletionCandidate.groovy           |   76 +
 .../shell/completion/ReflectionCompletor.groovy    |  286 +-
 .../completion/StricterArgumentCompleter.groovy    |   15 +
 .../completion/VariableSyntaxCompletor.groovy      |   18 +-
 .../tools/shell/util/CommandArgumentParser.groovy  |  107 +
 .../shell/util/CurlyCountingGroovyLexer.groovy     |   19 +-
 .../groovy/tools/shell/util/HelpFormatter.groovy   |   45 +-
 .../groovy/tools/shell/util/JAnsiHelper.groovy     |   40 +
 .../tools/shell/util/NoExitSecurityManager.groovy  |   20 +-
 .../groovy/tools/shell/util/PackageHelper.groovy   |  382 +-
 .../tools/shell/util/PackageHelperImpl.groovy      |  454 ++
 .../tools/shell/util/ScriptVariableAnalyzer.groovy |  112 +
 .../groovy/tools/shell/util/SimpleCompletor.groovy |   96 +-
 .../tools/shell/util/WrappedInputStream.groovy     |   32 +-
 .../tools/shell/util/XmlCommandRegistrar.groovy    |   53 +-
 .../codehaus/groovy/tools/shell/Main.properties    |    4 +-
 .../groovy-groovysh/src/spec/doc/groovysh.adoc     |  586 +++
 .../groovy/tools/shell/AllCompletorsTest.groovy    |   81 +-
 .../groovy/tools/shell/CommandCompletorTest.groovy |   35 +-
 .../groovy/tools/shell/CompletorTestSupport.groovy |   15 +-
 .../groovy/tools/shell/ErrorDisplayTest.groovy     |   15 +-
 .../groovy/tools/shell/GroovyshParsersTest.groovy  |   37 +
 .../groovy/tools/shell/GroovyshTest.groovy         |  350 +-
 .../groovy/tools/shell/ImportCompletorTest.groovy  |  447 +-
 .../groovy/tools/shell/ShellRunnerTest.groovy      |   51 +-
 .../tools/shell/ShellRunnerTestSupport.groovy      |   14 +-
 .../codehaus/groovy/tools/shell/ShellTest.groovy   |   22 +-
 .../tools/shell/commands/CommandTestSupport.groovy |    5 +-
 .../commands/ComplexCommandSupportTest.groovy      |  109 +-
 .../tools/shell/commands/DocCommandTest.groovy     |   79 +-
 .../tools/shell/commands/EditCommandTest.groovy    |   18 +-
 .../tools/shell/commands/ExitCommandTest.groovy    |    2 +-
 .../tools/shell/commands/HistoryCommandTest.groovy |   53 +-
 .../tools/shell/commands/ImportCommandTest.groovy  |   11 +-
 .../tools/shell/commands/RecordCommandTest.groovy  |    2 +-
 .../tools/shell/commands/SetCommandTest.groovy     |   18 +-
 .../completion/CustomClassCompletorTest.groovy     |   19 +-
 .../shell/completion/FileNameCompleterTest.groovy  |   39 +
 .../completion/GroovySyntaxCompletorTest.groovy    |  180 +-
 .../completion/ImportsSyntaxCompletorTest.groovy   |   82 +-
 .../shell/completion/KeywordCompletorTest.groovy   |   58 +-
 .../NavigablePropertiesCompleterTest.groovy        |   38 +-
 .../completion/ReflectionCompletorTest.groovy      |  196 +-
 .../tools/shell/completion/TokenUtilTest.groovy    |   30 +-
 .../shell/completion/VariableCompletorTest.groovy  |   32 +-
 .../groovy/tools/shell/expr/ExprTestSupport.groovy |    5 +-
 .../shell/util/CommandArgumentParserTest.groovy    |   51 +
 .../shell/util/CurlyCountingGroovyLexerTest.groovy |   42 +-
 .../tools/shell/util/MessageSourceTest.groovy      |    8 +-
 .../tools/shell/util/PackageHelperImplTest.groovy  |   59 +
 .../tools/shell/util/PackageHelperTest.groovy      |   59 -
 .../shell/util/ScriptVariableAnalyzerTest.groovy   |   61 +
 .../tools/shell/util/WrappedInputStreamTest.groovy |   58 +-
 subprojects/groovy-jmx/src/spec/doc/jmx.adoc       |  135 +-
 .../groovy-jmx/src/spec/test/JmxTest.groovy        |   15 +
 .../java/groovy/jmx/builder/MockJmxListener.java   |   15 +
 .../src/main/groovy/groovy/json/JsonBuilder.groovy |  311 --
 .../groovy/groovy/json/StreamingJsonBuilder.groovy |  349 --
 .../java/groovy/json/DateFormatThreadLocal.java    |   37 -
 .../src/main/java/groovy/json/JsonBuilder.java     |  360 ++
 .../src/main/java/groovy/json/JsonLexer.java       |   13 +-
 .../src/main/java/groovy/json/JsonOutput.java      |   16 +-
 .../src/main/java/groovy/json/JsonParser.java      |   18 +-
 .../src/main/java/groovy/json/JsonParserType.java  |    7 +-
 .../src/main/java/groovy/json/JsonSlurper.java     |   76 +-
 .../main/java/groovy/json/JsonSlurperClassic.java  |   18 +-
 .../src/main/java/groovy/json/JsonToken.java       |    5 +-
 .../src/main/java/groovy/json/JsonTokenType.java   |    4 +-
 .../java/groovy/json/StreamingJsonBuilder.java     |  421 ++
 .../main/java/groovy/json/StringEscapeUtils.java   |   30 +-
 .../java/groovy/json/internal/BaseJsonParser.java  |   14 +-
 .../java/groovy/json/internal/ByteScanner.java     |    3 -
 .../src/main/java/groovy/json/internal/Cache.java  |    1 +
 .../main/java/groovy/json/internal/CharBuf.java    |   80 +-
 .../java/groovy/json/internal/CharScanner.java     |   64 +-
 .../groovy/json/internal/CharSequenceValue.java    |   12 -
 .../src/main/java/groovy/json/internal/Chr.java    |    5 -
 .../src/main/java/groovy/json/internal/Dates.java  |   15 -
 .../main/java/groovy/json/internal/Exceptions.java |   12 -
 .../java/groovy/json/internal/FastStringUtils.java |    6 +-
 .../src/main/java/groovy/json/internal/IO.java     |    7 +-
 .../java/groovy/json/internal/JsonFastParser.java  |   14 +-
 .../groovy/json/internal/JsonParserCharArray.java  |   31 +-
 .../java/groovy/json/internal/JsonParserLax.java   |   69 +-
 .../internal/JsonParserUsingCharacterSource.java   |   25 -
 .../groovy/json/internal/JsonStringDecoder.java    |    6 +-
 .../main/java/groovy/json/internal/LazyMap.java    |   27 +-
 .../java/groovy/json/internal/LazyValueMap.java    |   21 +-
 .../java/groovy/json/internal/MapItemValue.java    |    4 -
 .../java/groovy/json/internal/NumberValue.java     |   21 +-
 .../json/internal/ReaderCharacterSource.java       |   13 +-
 .../java/groovy/json/internal/SimpleCache.java     |    4 -
 .../src/main/java/groovy/json/internal/Sys.java    |   57 +-
 .../java/groovy/json/internal/ValueContainer.java  |    5 -
 .../main/java/groovy/json/internal/ValueList.java  |    6 -
 .../main/java/groovy/json/internal/ValueMap.java   |    1 -
 .../java/groovy/json/internal/ValueMapImpl.java    |    2 -
 .../groovy-json/src/spec/doc/json-builder.adoc     |   22 +
 .../groovy-json/src/spec/doc/json-userguide.adoc   |  175 +-
 .../src/spec/doc/streaming-jason-builder.adoc      |   26 +
 .../src/spec/test/JsonBuilderTest2.groovy          |   77 +
 .../src/spec/test/StreamingJsonBuilderTest2.groovy |   79 +
 .../src/spec/test/json/JsonBuilderTest.groovy      |   69 +
 .../groovy-json/src/spec/test/json/JsonTest.groovy |  109 +
 .../spec/test/json/StreamingJsonBuilderTest.groovy |   73 +
 .../src/test/groovy/groovy/json/CharBufTest.groovy |   39 +-
 .../groovy/json/DateFormatThreadLocalTest.groovy   |   33 -
 .../src/test/groovy/groovy/json/IOTest.groovy      |  113 +
 .../test/groovy/groovy/json/JsonBuilderTest.groovy |   21 +-
 .../test/groovy/groovy/json/JsonLexerTest.groovy   |    6 +-
 .../test/groovy/groovy/json/JsonOutputTest.groovy  |  107 +-
 .../groovy/json/JsonSlurperCharSourceTest.groovy   |   17 +-
 .../groovy/json/JsonSlurperIndexOverlayTest.groovy |   17 +-
 .../groovy/groovy/json/JsonSlurperLaxTest.groovy   |   58 +-
 .../test/groovy/groovy/json/JsonSlurperTest.groovy |   31 +-
 .../groovy/groovy/json/JsonTokenTypeTest.groovy    |   50 +-
 .../groovy/groovy/json/JsonTokenValueTest.groovy   |    3 -
 .../groovy/groovy/json/RealJsonPayloadsTest.groovy |    2 -
 .../groovy/json/StreamingJsonBuilderTest.groovy    |   71 +-
 .../groovy/json/internal/CharScannerTest.groovy    |   43 +-
 .../groovy/groovy/json/internal/ChrTest.groovy     |    1 -
 .../FastStringUtilsUnsafeDisabledTest.groovy       |    1 +
 .../groovy/groovy/json/internal/LazyMapTest.groovy |   50 +
 .../json/internal/ReaderCharacterSourceTest.groovy |   38 +
 .../groovy/jsr223/GroovyScriptEngineImpl.java      |    3 +-
 .../src/spec/doc/integrating-jsr223.adoc           |   14 +-
 .../org/codehaus/groovy/jsr223/SugarTest.groovy    |   15 +
 .../groovy/jsr223/vm6/JavascriptTest.groovy        |   15 +
 .../codehaus/groovy/jsr223/JSR223SecurityTest.java |   15 +
 subprojects/groovy-nio/build.gradle                |    2 +-
 .../codehaus/groovy/runtime/NioGroovyMethods.java  |  176 +-
 .../org/codehaus/groovy/runtime/WritablePath.java  |    8 +-
 .../groovy/runtime/NioGroovyMethodsTest.groovy     |  282 +-
 subprojects/groovy-servlet/build.gradle            |    1 +
 .../java/groovy/servlet/AbstractHttpServlet.java   |   18 +-
 .../main/java/groovy/servlet/ServletBinding.java   |    9 +-
 .../main/java/groovy/servlet/ServletCategory.java  |    1 -
 .../main/java/groovy/servlet/TemplateServlet.java  |    5 -
 .../src/main/java/groovy/servlet/package.html      |   17 +
 .../src/spec/doc/servlet-userguide.adoc            |   73 +
 .../src/spec/test/servlet/GroovyServletTest.groovy |   73 +
 .../groovy/servlet/AbstractHttpServletTest.groovy  |  215 +-
 .../groovy/servlet/ServletBindingTest.groovy       |  137 +-
 .../java/groovy/servlet/GroovyServletTest.java     |   15 +
 .../src/main/java/groovy/sql/DataSet.java          |    4 +-
 .../java/groovy/sql/ResultSetMetaDataWrapper.java  |    3 +-
 .../groovy-sql/src/main/java/groovy/sql/Sql.java   |    2 +
 .../src/main/java/groovy/sql/package.html          |   17 +
 subprojects/groovy-swing/build.gradle              |    4 +-
 .../main/groovy/groovy/swing/binding/package.html  |   17 +
 .../main/groovy/groovy/swing/factory/package.html  |   17 +
 .../src/main/groovy/groovy/swing/impl/package.html |   17 +
 .../src/main/groovy/groovy/swing/package.html      |   17 +
 .../src/main/java/groovy/model/package.html        |   17 +
 .../groovy/binding/ClosureSourceBinding.java       |    4 +-
 .../java/org/codehaus/groovy/binding/package.html  |   17 +
 .../groovy/runtime/SwingGroovyMethods.java         |   14 +-
 .../src/spec/assets/img/SwingBuilder001.gif        |  Bin 0 -> 1643 bytes
 .../groovy-swing/src/spec/doc/swing-builder.adoc   |   38 +
 .../src/spec/test/SwingBuilderTest.groovy          |   98 +
 .../test/groovy/groovy/model/TableModelTest.groovy |   15 +
 subprojects/groovy-templates/build.gradle          |    4 +
 .../groovy/groovy/text/GStringTemplateEngine.java  |    4 +-
 .../groovy/text/StreamingTemplateEngine.java       |  970 +++++
 .../groovy/text/TemplateExecutionException.java    |   52 +
 .../groovy/groovy/text/TemplateParseException.java |   56 +
 .../groovy/text/markup/MarkupTemplateEngine.java   |   12 +-
 .../main/groovy/groovy/text/markup/package.html    |   17 +
 .../src/main/groovy/groovy/text/package.html       |   17 +
 .../src/spec/doc/markup-template-engine.adoc       |  162 +-
 .../src/spec/doc/template-engines.adoc             |  159 +
 .../spec/test/MarkupTemplateEngineSpecTest.groovy  |   15 +
 .../src/spec/test/MyTemplate.groovy                |   15 +
 .../src/spec/test/TemplateEnginesTest.groovy       |  192 +
 .../groovy/SimpleGStringTemplateEngineTest.groovy  |   15 +
 .../groovy/groovy/text/SimpleTemplateTest.groovy   |   15 +
 .../StreamingTemplateEngineSpecification.groovy    |  418 ++
 .../groovy/text/StreamingTemplateEngineTest.groovy |  459 ++
 .../groovy/text/markup/TemplateResourceTest.groovy |   50 +
 .../java/groovy/text/XmlTemplateEngineTest.java    |   15 +
 subprojects/groovy-test/build.gradle               |    4 +-
 .../groovy/groovy/mock/interceptor/package.html    |   17 +
 .../main/groovy/groovy/util/StringTestUtil.groovy  |   15 +
 .../src/test/groovy/GroovyTestCaseTest.groovy      |   15 +
 .../groovy/lang/GroovyLogTestCaseTest.groovy       |   15 +
 .../util/suite/ATestScriptThatsNoTestCase.groovy   |   15 +
 subprojects/groovy-testng/build.gradle             |    4 +-
 .../java/groovy/util/slurpersupport/package.html   |   17 +
 .../src/main/java/groovy/xml/MarkupBuilder.java    |    2 +-
 .../java/groovy/xml/NamespaceBuilderSupport.java   |   39 +-
 .../src/main/java/groovy/xml/dom/package.html      |   17 +
 .../src/main/java/groovy/xml/package.html          |   17 +
 .../groovy/xml/streamingmarkupsupport/package.html |   17 +
 .../groovy-xml/src/spec/doc/xml-userguide.adoc     |  558 +++
 .../groovy-xml/src/spec/test/DomBuilderTest.groovy |   82 +
 .../src/spec/test/MarkupBuilderTest2.groovy        |  195 +
 .../groovy-xml/src/spec/test/SaxBuilderTest.groovy |   79 +
 .../spec/test/StreamingMarkupBuilderTest2.groovy   |   80 +
 .../src/spec/test/UserGuideDOMCategory.groovy      |   59 +
 .../spec/test/UserGuideMarkupBuilderTest.groovy    |  220 +
 .../UserGuideStreamingMarkupBuilderTest.groovy     |   67 +
 .../src/spec/test/UserGuideXmlParserTest.groovy    |  122 +
 .../src/spec/test/UserGuideXmlSlurperTest.groovy   |  176 +
 .../src/spec/test/UserGuideXmlUtilTest.groovy      |   53 +
 .../test/groovy/groovy/bugs/StaticMarkupBug.groovy |   15 +
 .../src/test/groovy/groovy/util/CustomNode.java    |   15 +
 .../test/groovy/groovy/util/CustomXmlParser.java   |   15 +
 .../groovy/groovy/util/XmlNodePrinterTest.groovy   |   15 +
 .../test/groovy/groovy/util/XmlSlurperTest.groovy  |   22 +-
 .../src/test/groovy/groovy/xml/DOMTest.groovy      |   15 +
 .../test/groovy/groovy/xml/FactorySupportTest.java |   15 +
 .../groovy/xml/MixedMarkupTestSupport.groovy       |   15 +
 .../groovy/xml/NamespaceNodeGPathTest.groovy       |   15 +
 .../groovy/groovy/xml/NamespaceNodeTest.groovy     |   54 +
 .../src/test/groovy/groovy/xml/SAXTest.groovy      |   15 +
 .../groovy/groovy/xml/TraversalTestSupport.groovy  |   15 +
 .../groovy/xml/UseMarkupWithWriterScript.groovy    |   15 +
 .../src/test/groovy/groovy/xml/XmlUtilTest.groovy  |   15 +
 .../groovy/benchmarks/BuilderPerfTest.groovy       |   15 +
 .../src/test/groovy/script/AtomTestScript.groovy   |   15 +
 .../src/test/groovy/util/NavToWiki.groovy          |   15 +
 1508 files changed, 56006 insertions(+), 11662 deletions(-)

diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..7a4a3ea
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+                                 Apache License
+                           Version 2.0, January 2004
+                        http://www.apache.org/licenses/
+
+   TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+   1. Definitions.
+
+      "License" shall mean the terms and conditions for use, reproduction,
+      and distribution as defined by Sections 1 through 9 of this document.
+
+      "Licensor" shall mean the copyright owner or entity authorized by
+      the copyright owner that is granting the License.
+
+      "Legal Entity" shall mean the union of the acting entity and all
+      other entities that control, are controlled by, or are under common
+      control with that entity. For the purposes of this definition,
+      "control" means (i) the power, direct or indirect, to cause the
+      direction or management of such entity, whether by contract or
+      otherwise, or (ii) ownership of fifty percent (50%) or more of the
+      outstanding shares, or (iii) beneficial ownership of such entity.
+
+      "You" (or "Your") shall mean an individual or Legal Entity
+      exercising permissions granted by this License.
+
+      "Source" form shall mean the preferred form for making modifications,
+      including but not limited to software source code, documentation
+      source, and configuration files.
+
+      "Object" form shall mean any form resulting from mechanical
+      transformation or translation of a Source form, including but
+      not limited to compiled object code, generated documentation,
+      and conversions to other media types.
+
+      "Work" shall mean the work of authorship, whether in Source or
+      Object form, made available under the License, as indicated by a
+      copyright notice that is included in or attached to the work
+      (an example is provided in the Appendix below).
+
+      "Derivative Works" shall mean any work, whether in Source or Object
+      form, that is based on (or derived from) the Work and for which the
+      editorial revisions, annotations, elaborations, or other modifications
+      represent, as a whole, an original work of authorship. For the purposes
+      of this License, Derivative Works shall not include works that remain
+      separable from, or merely link (or bind by name) to the interfaces of,
+      the Work and Derivative Works thereof.
+
+      "Contribution" shall mean any work of authorship, including
+      the original version of the Work and any modifications or additions
+      to that Work or Derivative Works thereof, that is intentionally
+      submitted to Licensor for inclusion in the Work by the copyright owner
+      or by an individual or Legal Entity authorized to submit on behalf of
+      the copyright owner. For the purposes of this definition, "submitted"
+      means any form of electronic, verbal, or written communication sent
+      to the Licensor or its representatives, including but not limited to
+      communication on electronic mailing lists, source code control systems,
+      and issue tracking systems that are managed by, or on behalf of, the
+      Licensor for the purpose of discussing and improving the Work, but
+      excluding communication that is conspicuously marked or otherwise
+      designated in writing by the copyright owner as "Not a Contribution."
+
+      "Contributor" shall mean Licensor and any individual or Legal Entity
+      on behalf of whom a Contribution has been received by Licensor and
+      subsequently incorporated within the Work.
+
+   2. Grant of Copyright License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      copyright license to reproduce, prepare Derivative Works of,
+      publicly display, publicly perform, sublicense, and distribute the
+      Work and such Derivative Works in Source or Object form.
+
+   3. Grant of Patent License. Subject to the terms and conditions of
+      this License, each Contributor hereby grants to You a perpetual,
+      worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+      (except as stated in this section) patent license to make, have made,
+      use, offer to sell, sell, import, and otherwise transfer the Work,
+      where such license applies only to those patent claims licensable
+      by such Contributor that are necessarily infringed by their
+      Contribution(s) alone or by combination of their Contribution(s)
+      with the Work to which such Contribution(s) was submitted. If You
+      institute patent litigation against any entity (including a
+      cross-claim or counterclaim in a lawsuit) alleging that the Work
+      or a Contribution incorporated within the Work constitutes direct
+      or contributory patent infringement, then any patent licenses
+      granted to You under this License for that Work shall terminate
+      as of the date such litigation is filed.
+
+   4. Redistribution. You may reproduce and distribute copies of the
+      Work or Derivative Works thereof in any medium, with or without
+      modifications, and in Source or Object form, provided that You
+      meet the following conditions:
+
+      (a) You must give any other recipients of the Work or
+          Derivative Works a copy of this License; and
+
+      (b) You must cause any modified files to carry prominent notices
+          stating that You changed the files; and
+
+      (c) You must retain, in the Source form of any Derivative Works
+          that You distribute, all copyright, patent, trademark, and
+          attribution notices from the Source form of the Work,
+          excluding those notices that do not pertain to any part of
+          the Derivative Works; and
+
+      (d) If the Work includes a "NOTICE" text file as part of its
+          distribution, then any Derivative Works that You distribute must
+          include a readable copy of the attribution notices contained
+          within such NOTICE file, excluding those notices that do not
+          pertain to any part of the Derivative Works, in at least one
+          of the following places: within a NOTICE text file distributed
+          as part of the Derivative Works; within the Source form or
+          documentation, if provided along with the Derivative Works; or,
+          within a display generated by the Derivative Works, if and
+          wherever such third-party notices normally appear. The contents
+          of the NOTICE file are for informational purposes only and
+          do not modify the License. You may add Your own attribution
+          notices within Derivative Works that You distribute, alongside
+          or as an addendum to the NOTICE text from the Work, provided
+          that such additional attribution notices cannot be construed
+          as modifying the License.
+
+      You may add Your own copyright statement to Your modifications and
+      may provide additional or different license terms and conditions
+      for use, reproduction, or distribution of Your modifications, or
+      for any such Derivative Works as a whole, provided Your use,
+      reproduction, and distribution of the Work otherwise complies with
+      the conditions stated in this License.
+
+   5. Submission of Contributions. Unless You explicitly state otherwise,
+      any Contribution intentionally submitted for inclusion in the Work
+      by You to the Licensor shall be under the terms and conditions of
+      this License, without any additional terms or conditions.
+      Notwithstanding the above, nothing herein shall supersede or modify
+      the terms of any separate license agreement you may have executed
+      with Licensor regarding such Contributions.
+
+   6. Trademarks. This License does not grant permission to use the trade
+      names, trademarks, service marks, or product names of the Licensor,
+      except as required for reasonable and customary use in describing the
+      origin of the Work and reproducing the content of the NOTICE file.
+
+   7. Disclaimer of Warranty. Unless required by applicable law or
+      agreed to in writing, Licensor provides the Work (and each
+      Contributor provides its Contributions) on an "AS IS" BASIS,
+      WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+      implied, including, without limitation, any warranties or conditions
+      of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+      PARTICULAR PURPOSE. You are solely responsible for determining the
+      appropriateness of using or redistributing the Work and assume any
+      risks associated with Your exercise of permissions under this License.
+
+   8. Limitation of Liability. In no event and under no legal theory,
+      whether in tort (including negligence), contract, or otherwise,
+      unless required by applicable law (such as deliberate and grossly
+      negligent acts) or agreed to in writing, shall any Contributor be
+      liable to You for damages, including any direct, indirect, special,
+      incidental, or consequential damages of any character arising as a
+      result of this License or out of the use or inability to use the
+      Work (including but not limited to damages for loss of goodwill,
+      work stoppage, computer failure or malfunction, or any and all
+      other commercial damages or losses), even if such Contributor
+      has been advised of the possibility of such damages.
+
+   9. Accepting Warranty or Additional Liability. While redistributing
+      the Work or Derivative Works thereof, You may choose to offer,
+      and charge a fee for, acceptance of support, warranty, indemnity,
+      or other liability obligations and/or rights consistent with this
+      License. However, in accepting such obligations, You may act only
+      on Your own behalf and on Your sole responsibility, not on behalf
+      of any other Contributor, and only if You agree to indemnify,
+      defend, and hold each Contributor harmless for any liability
+      incurred by, or claims asserted against, such Contributor by reason
+      of your accepting any such warranty or additional liability.
+
+   END OF TERMS AND CONDITIONS
+
+   APPENDIX: How to apply the Apache License to your work.
+
+      To apply the Apache License to your work, attach the following
+      boilerplate notice, with the fields enclosed by brackets "[]"
+      replaced with your own identifying information. (Don't include
+      the brackets!)  The text should be enclosed in the appropriate
+      comment syntax for the file format. We also recommend that a
+      file or class name and description of purpose be included on the
+      same "printed page" as the copyright notice for easier
+      identification within third-party archives.
+
+   Copyright [yyyy] [name of copyright owner]
+
+   Licensed under the Apache License, Version 2.0 (the "License");
+   you may not use this file except in compliance with the License.
+   You may obtain a copy of the License at
+
+       http://www.apache.org/licenses/LICENSE-2.0
+
+   Unless required by applicable law or agreed to in writing, software
+   distributed under the License is distributed on an "AS IS" BASIS,
+   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+   See the License for the specific language governing permissions and
+   limitations under the License.
\ No newline at end of file
diff --git a/LICENSE.txt b/LICENSE.txt
deleted file mode 100644
index e0908d4..0000000
--- a/LICENSE.txt
+++ /dev/null
@@ -1,15 +0,0 @@
-/*
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- *
- */
- 
\ No newline at end of file
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..4fb9b5c
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,14 @@
+   =========================================================================
+   ==  NOTICE file corresponding to the section 4 d of                    ==
+   ==  the Apache License, Version 2.0,                                   ==
+   ==  in this case for the Groovy Language distribution.                 ==
+   =========================================================================
+
+   Groovy Language
+   Copyright 2003-2015 The respective authors and developers
+   Developers and Contributors are listed in the project POM file
+   and Gradle build file
+
+   This product includes software developed by
+   The Groovy community (http://groovy.codehaus.org/).
+
diff --git a/NOTICE.txt b/NOTICE.txt
deleted file mode 100644
index a8870f2..0000000
--- a/NOTICE.txt
+++ /dev/null
@@ -1,14 +0,0 @@
-   =========================================================================
-   ==  NOTICE file corresponding to the section 4 d of                    ==
-   ==  the Apache License, Version 2.0,                                   ==
-   ==  in this case for the Groovy Language distribution.                 ==
-   =========================================================================
-
-   Groovy Language
-   Copyright 2003-2014 The respective authors and developers
-   Developers and Contributors are listed in the project POM file
-   and Gradle build file
-
-   This product includes software developed by
-   The Groovy community (http://groovy.codehaus.org/).
-
diff --git a/README.adoc b/README.adoc
index 4705d62..beda68b 100644
--- a/README.adoc
+++ b/README.adoc
@@ -23,7 +23,7 @@ It also increases developer productivity by reducing scaffolding code when devel
 
 == Downloading
 
-Latest Groovy version is availble on Bintray image:{bintray-latest-version-image}[Bintray latest version, link={bintray-latest-version-link}]
+Latest Groovy version is available on Bintray image:{bintray-latest-version-image}[Bintray latest version, link={bintray-latest-version-link}]
 
 Binary distribution links are on the package page.
 
@@ -49,6 +49,10 @@ To build everything and launch unit tests, use
 
     ./gradlew test
 
+If you want to launch one unit test, use this. <TestClassName> is like `groovy.GroovyMethodsTest`.
+
+    ./gradlew :test --tests <TestClassName>
+
 To build from IntelliJ IDEA
 
     ./gradlew jarAll idea
@@ -59,7 +63,7 @@ To build from Eclipse
 
     ./gradlew jarAll eclipse
 
-Then open the generated project and the generated subprojects in Eclipse.
+Then open the generated project and the generated subprojects in Eclipse. But be aware that Eclipse tends to be more limited in its ability to reproduce a gradle build structure. The generated project files may contain a circular dependency which may or may not prevent Eclipse from using them. It depends on the Eclipse version, if this is an issue or not.
 
 == InvokeDynamic support
 
@@ -73,7 +77,7 @@ Please note that the following Gradle tasks generate both indy and non indy vari
 * install
 * uploadArchives
 
-== Continuous Integration
+== Continuous Integration Server
 
 The official CI server runs {groovy-ci}[here] (login as user guest and leave the password blank) and is sponsored by http://www.jetbrains.com[JetBrains].
 
diff --git a/bintray.properties b/bintray.properties
deleted file mode 100644
index a2868c2..0000000
--- a/bintray.properties
+++ /dev/null
@@ -1,4 +0,0 @@
-bintrayUser=groovy-operator
-bintrayPassword=1de8a6aa484addc47e3e225f6d73a8bec96a886d
-centralUser=zLMPZSXG
-centralKey=PivQ1sQ0IYTw8GaeH3Gx5eK2MCKpe8jxpah5u5SLGzMv
diff --git a/build.gradle b/build.gradle
index cc277b2..b749570 100644
--- a/build.gradle
+++ b/build.gradle
@@ -1,10 +1,3 @@
-apply from: 'gradle/filter.gradle'
-apply from: 'gradle/indy.gradle'
-
-if (JavaVersion.current().java6Compatible) {
-    apply from: 'gradle/bintray.gradle'
-}
-
 buildscript {
     repositories {
         jcenter()
@@ -15,14 +8,23 @@ buildscript {
     }
 
     dependencies {
-        classpath 'org.asciidoctor:asciidoctor-gradle-plugin:0.7.3'
-        classpath 'net.saliman:gradle-cobertura-plugin:1.1.2'
+        classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.2'
         classpath 'org.jfrog.buildinfo:build-info-extractor-gradle:2.2.3'
+        //classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.1.1'
     }
 }
 
+plugins {
+    //id "com.github.hierynomus.license" version "0.11.0"
+}
+
+apply from: 'gradle/filter.gradle'
+apply from: 'gradle/indy.gradle'
+apply from: 'gradle/bintray.gradle'
+
 File javaHome = new File(System.getProperty('java.home'))
 logger.lifecycle "Using Java from $javaHome (version ${System.getProperty('java.version')})"
+indyBanner()
 
 // TODO use antlr plugin
 //apply plugin: 'antlr'
@@ -42,7 +44,9 @@ allprojects {
 
     apply plugin: 'groovy'
     apply from: "${rootProject.projectDir}/gradle/indy.gradle"
-    apply from: "${rootProject.projectDir}/gradle/asciidoctor.gradle"
+    if (JavaVersion.current().java7Compatible) {
+        apply from: "${rootProject.projectDir}/gradle/asciidoctor.gradle"
+    }
 }
 
 // todo: use the conventional "resources" directory for classpath resources
@@ -81,9 +85,8 @@ subprojects {
 
 repositories {
     // todo Some repos are needed only for some configs. Declare them just for the configuration once Gradle allows this.
-//    mavenCentral() // default, tools
     maven { url 'http://www.aQute.biz/repo' } // tools
-    maven { url 'http://repository.jboss.org/maven2' } // examples, tools
+    maven { url 'http://repository.jboss.org/nexus/content/groups/m2-release-proxy' } // examples, tools
 }
 
 // todo do we need compile and runtime scope for examples?
@@ -97,7 +100,7 @@ configurations {
 }
 
 ext {
-    antVersion = '1.9.3'
+    antVersion = '1.9.4'
     asmVersion = '5.0.3'
     antlrVersion = '2.7.7'
     bndVersion = '0.0.401'
@@ -105,21 +108,21 @@ ext {
     coberturaVersion = '1.9.4.1'
     commonsCliVersion = '1.2'
     commonsHttpClientVersion = '3.1'
-    eclipseOsgiVersion = '3.5.0.v20090520'
+    eclipseOsgiVersion = '3.9.1-v20140110-1610'
     gparsVersion = '1.2.1'
-    ivyVersion = '2.3.0'
+    ivyVersion = '2.4.0'
     jansiVersion = '1.11'
     jarjarVersion = '1.3'
-    jlineVersion = '2.11'
+    jlineVersion = '2.12'
     jmockVersion = '1.2.0'
-    logbackVersion = '1.0.13'
+    logbackVersion = '1.1.2'
     log4jVersion = '1.2.17'
-    log4j2Version = '2.0-rc1'
-    luceneVersion = '4.3.1'
+    log4j2Version = '2.1'
+    luceneVersion = '4.7.2'
     openejbVersion = '1.0'
     qdoxVersion = '1.12.1'
     simianVersion = '2.2.4'
-    slf4jVersion = '1.7.5'
+    slf4jVersion = '1.7.6'
     xmlunitVersion = '1.5'
     xstreamVersion = '1.4.7'
 }
@@ -139,22 +142,13 @@ dependencies {
         exclude(group: 'junit', module: 'junit')
         exclude(group: 'jmock', module: 'jmock')
     }
+    compile files("lib/openbeans-1.0.jar")
     compile "org.fusesource.jansi:jansi:$jansiVersion"
     compile("org.apache.ivy:ivy:$ivyVersion") {
         transitive = false
     }
     compile files("${buildDir}/generated-classes")
 
-    compile "commons-cli:commons-cli:$commonsCliVersion"
-    compile("com.thoughtworks.xstream:xstream:$xstreamVersion") {
-        exclude(group: 'xpp3', module: 'xpp3_min')
-        exclude(group: 'junit', module: 'junit')
-        exclude(group: 'jmock', module: 'jmock')
-    }
-    compile "org.fusesource.jansi:jansi:$jansiVersion"
-    compile("org.apache.ivy:ivy:$ivyVersion") {
-        transitive = false
-    }
     runtime("org.codehaus.gpars:gpars:$gparsVersion") {
         exclude(group: 'org.codehaus.groovy', module: 'groovy-all')
     }
@@ -223,7 +217,7 @@ sourceSets {
             }.visit { details ->
                 exclude "groovy/ui/$details.path"
             }
-            if (!useIndy()) {
+            if (!JavaVersion.current().isJava7Compatible()) {
                 exclude '**/indy/*'
                 exclude '**/v7/*'
                 exclude '**/vm7/*'
@@ -234,7 +228,7 @@ sourceSets {
                     'src/main',
                     "$generatedDirectory/src/main"
             ]
-            if (!useIndy()) {
+            if (!JavaVersion.current().isJava7Compatible()) {
                 exclude '**/indy/*'
                 exclude '**/v7/*'
                 exclude '**/vm7/*'
@@ -281,7 +275,7 @@ sourceSets {
         resources {
             srcDirs = ['src/examples']
         }
-        compileClasspath = configurations.examplesRuntime + sourceSets.main.output
+        compileClasspath = configurations.examplesRuntime + sourceSets.main.output + project(':groovy-xml').sourceSets.main.output
         output.classesDir = "$buildDir/examples-classes" as File
     }
 }
@@ -394,8 +388,13 @@ compileGroovy.dependsOn bootstrapJar
 
 allprojects {
 
+    tasks.withType(JavaCompile) {
+        options.encoding = 'UTF-8'
+    }
+
     tasks.withType(GroovyCompile) {
         groovyOptions.fork(memoryMaximumSize: groovycMain_mx)
+        groovyOptions.encoding = 'UTF-8'
         groovyClasspath = files(
                 rootProject.compileJava.classpath,
                 rootProject.bootstrapJar.archivePath
@@ -411,7 +410,7 @@ allprojects {
             sourceCompatibility = 1.7
             targetCompatibility = 1.7
         }
-        tasks.withType(Compile) {
+        tasks.withType(JavaCompile) {
             sourceCompatibility = 1.7
             targetCompatibility = 1.7
         }
@@ -433,6 +432,7 @@ apply from: 'gradle/upload.gradle'
 apply from: 'gradle/idea.gradle'
 apply from: 'gradle/eclipse.gradle'
 apply from: 'gradle/codehaus.gradle'
+apply from: 'gradle/quality.gradle'
 // If a local configuration file for tweaking the build is present, apply it
 if (file('user.gradle').exists()) {
     apply from: 'user.gradle'
diff --git a/config/binarycompatibility/binarycompat-report.groovy b/config/binarycompatibility/binarycompat-report.groovy
new file mode 100644
index 0000000..9e3e663
--- /dev/null
+++ b/config/binarycompatibility/binarycompat-report.groovy
@@ -0,0 +1,153 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * A template which generates an HTML report from the bincompat XML report
+ */
+modelTypes = {
+    String title
+    String baseline
+    String archive
+    Map<String,Map<String,List<String>>> violations
+}
+
+def severityMapping = [
+        error  : 'danger',
+        warning: 'warning',
+        info   : 'info',
+        ignore : 'success'
+]
+
+yieldUnescaped '<!DOCTYPE html>'
+
+
+html {
+    head {
+        meta 'charset': "utf-8"
+        meta 'http-equiv': "content-type", content: "text/html; charset=utf-8"
+        meta 'http-equiv': "X-UA-Compatible", content: "IE=edge"
+        meta name: "viewport", content: "width=device-width, initial-scale=1"
+
+        title(title)
+        link href: "http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css", rel: "stylesheet"
+        link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css", rel: "stylesheet"
+        link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css", rel: "stylesheet"
+    }
+
+    body {
+        div(class:'navbar navbar-inverse navbar-fixed-top', role:'navigation') {
+            div(class:'container') {
+                div(class:'navbar-header') {
+                    button(type:'button', class:'navbar-toggle', 'data-toggle':'collapse', 'data-target':'navbar-collaspe') {
+                        span(class:'sr-only', 'Toggle navigation')
+                        span(class:'icon-bar'){}
+                        span(class:'icon-bar'){}
+                        span(class:'icon-bar'){}
+                    }
+                    a(class:'navbar-brand',href:'#', 'Binary compatibility report')
+                }
+                div(class:'navbar-collapse collapse') {
+                    ul(class:"nav navbar-nav") {
+                        li(class: 'dropdown') {
+                            a(id: 'severityDropdown', href: '#', class: 'dropdown-toggle', 'data-toggle': 'dropdown', 'Severity <span class="caret"></span>')
+                            ul(class: "dropdown-menu dropdown-severity", role: "menu") {
+                                li(role: 'presentation', class: 'active') {
+                                    a(role: 'menuitem', tabindex: '-1', href: '#', 'All levels')
+                                }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Error') }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Warning') }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Info') }
+                            }
+                        }
+
+                    }
+                }
+            }
+        }
+
+
+        div(class: 'container') {
+            div(class:'jumbotron') {
+                div(class:'container') {
+                    div(class: 'page-header') {
+                        h1 'Binary compatibility'
+                        p "Comparing ${archive} to reference ${baseline}"
+                        p {
+                            yield "Be warned that this report is not perfect and depends on what "
+                            a(href: 'https://github.com/siom79/japicmp', 'JApicmp')
+                            yield " is capable to detect."
+                        }
+                    }
+                }
+            }
+            violations.each { fqcn, classViolations ->
+                def errors = classViolations.keySet()
+                def severities = errors.collect { "severity-${it}" }
+                div(class: "panel panel-default ${severities.join(' ')}") {
+                    div(class: "panel-heading") {
+                        h3(class: 'panel-title', "Class $fqcn")
+                    }
+                    div(class: 'panel-body') {
+                        table(class: "table table-striped table-bordered") {
+                            tbody {
+                                classViolations.each { err, list ->
+                                    list.each { item ->
+                                        tr(class: "bincompat-error severity-${err}") {
+                                            td {
+                                                h4 {
+                                                    span(class: "label label-${severityMapping[err]}", err.capitalize())
+                                                }
+                                            }
+                                            td { span(item) }
+                                        }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            script(src: "http://code.jquery.com/jquery-1.11.0.min.js") {}
+            script(src: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js") {}
+            script {
+                yieldUnescaped '''
+$(document).ready(function () {
+        var severity = null;
+        doFilter();
+        function doFilter() {
+          var severityClass = "severity-" + severity;
+          $('.panel').hide();
+          $('.bincompat-error').hide();
+          $('.bincompat-error').filter(function () {
+              return (severity==null || $(this).hasClass(severityClass));
+          }).show();
+          $('.panel').filter(function () {
+              return (severity==null || $(this).hasClass(severityClass));
+          }).show();
+        }
+        $(".dropdown-severity li a").click(function() {
+          severity = $(this).text().toLowerCase();
+          if (severity==="all levels") {
+            severity = null;
+          }
+          doFilter();
+        });
+});'''
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle-frames.xsl b/config/checkstyle/checkstyle-frames.xsl
deleted file mode 100644
index 2430f08..0000000
--- a/config/checkstyle/checkstyle-frames.xsl
+++ /dev/null
@@ -1,394 +0,0 @@
-<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"
-    xmlns:lxslt="http://xml.apache.org/xslt"
-    xmlns:redirect="http://xml.apache.org/xalan/redirect"
-    extension-element-prefixes="redirect">
-
-<!--
- The Apache Software License, Version 1.1
-
- Copyright (c) 2002 The Apache Software Foundation.  All rights
- reserved.
-
- Redistribution and use in source and binary forms, with or without
- modification, are permitted provided that the following conditions
- are met:
-
- 1. Redistributions of source code must retain the above copyright
-    notice, this list of conditions and the following disclaimer.
-
- 2. Redistributions in binary form must reproduce the above copyright
-    notice, this list of conditions and the following disclaimer in
-    the documentation and/or other materials provided with the
-    distribution.
-
- 3. The end-user documentation included with the redistribution, if
-    any, must include the following acknowlegement:
-       "This product includes software developed by the
-        Apache Software Foundation (http://www.apache.org/)."
-    Alternately, this acknowlegement may appear in the software itself,
-    if and wherever such third-party acknowlegements normally appear.
-
- 4. The names "The Jakarta Project", "Ant", and "Apache Software
-    Foundation" must not be used to endorse or promote products derived
-    from this software without prior written permission. For written
-    permission, please contact apache at apache.org.
-
- 5. Products derived from this software may not be called "Apache"
-    nor may "Apache" appear in their names without prior written
-    permission of the Apache Group.
-
- THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
- WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
- DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
- ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
- LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
- USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
- ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
- OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
- OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- SUCH DAMAGE.
- ====================================================================
-
- This software consists of voluntary contributions made by many
- individuals on behalf of the Apache Software Foundation.  For more
- information on the Apache Software Foundation, please see
- <http://www.apache.org/>.
- -->
-
-    <xsl:output method="html" indent="yes" encoding="US-ASCII"/>
-    <xsl:decimal-format decimal-separator="." grouping-separator="," />
-
-    <xsl:key name="files" match="file" use="@name"/>
-    <xsl:key name="errorfiles" match="file[count(error)>0]" use="@name"/>
-    <xsl:key name="violations" match="file/error" use="@source"/>
-
-    <xsl:param name="output.dir" select="'.'"/>
-
-	<xsl:variable name="allFiles" select="/checkstyle/file[@name and generate-id(.) = generate-id(key('files', @name))]"/>
-	<xsl:variable name="allFilesWithError" select="/checkstyle/file[@name and generate-id(.) = generate-id(key('errorfiles', @name))]"/>
-
-    <xsl:template match="checkstyle">
-        <!-- create the index.html -->
-        <redirect:write file="{$output.dir}/index.html">
-            <xsl:call-template name="index.html"/>
-        </redirect:write>
-
-        <!-- create the stylesheet.css -->
-        <redirect:write file="{$output.dir}/stylesheet.css">
-            <xsl:call-template name="stylesheet.css"/>
-        </redirect:write>
-
-        <!-- create the overview-summary.html at the root -->
-        <redirect:write file="{$output.dir}/overview-frame.html">
-            <xsl:apply-templates select="." mode="overview"/>
-        </redirect:write>
-
-        <!-- create the all-classes.html at the root -->
-        <redirect:write file="{$output.dir}/allclasses-frame.html">
-            <xsl:apply-templates select="." mode="all.classes"/>
-        </redirect:write>
-
-        <!-- process all files -->
-        <xsl:apply-templates select="$allFilesWithError"/>
-    </xsl:template>
-
-    <xsl:template name="index.html">
-        <html>
-            <head>
-                <title>CheckStyle Audit</title>
-            </head>
-            <frameset cols="20%,80%">
-                <frame src="allclasses-frame.html" name="fileListFrame"/>
-                <frame src="overview-frame.html" name="fileFrame"/>
-            </frameset>
-            <noframes>
-                <h2>Frame Alert</h2>
-                <p>
-                    This document is designed to be viewed using the frames feature. If you see this message, you are using a non-frame-capable web client.
-                </p>
-            </noframes>
-        </html>
-    </xsl:template>
-
-    <xsl:template name="pageHeader">
-        <table border="0" cellpadding="0" cellspacing="0" width="100%">
-            <tr>
-                <td class="text-align:right"><h2>CheckStyle Audit</h2></td>
-            </tr>
-            <tr>
-                <td class="text-align:right">Designed for use with <a href='http://checkstyle.sourceforge.net/'>CheckStyle</a> and <a href='http://jakarta.apache.org'>Ant</a>.</td>
-            </tr>
-        </table>
-        <hr size="1"/>
-    </xsl:template>
-
-    <xsl:template match="checkstyle" mode="overview">
-        <html>
-            <head>
-                <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
-            </head>
-            <body>
-                <!-- page header -->
-                <xsl:call-template name="pageHeader"/>
-
-                <!-- Summary part -->
-                <xsl:apply-templates select="." mode="summary"/>
-                <hr size="1" width="100%" align="left"/>
-
-                <!-- File list part -->
-                <xsl:apply-templates select="." mode="filelist"/>
-            </body>
-        </html>
-    </xsl:template>
-
-    <xsl:template name="stylesheet.css">
-        .bannercell {
-        border: 0px;
-        padding: 0px;
-        }
-        body {
-        margin-left: 10;
-        margin-right: 10;
-        font:normal 80% arial,helvetica,sanserif;
-        background-color:#FFFFFF;
-        color:#000000;
-        }
-        .a td {
-        background: #efefef;
-        }
-        .b td {
-        background: #fff;
-        }
-        th, td {
-        text-align: left;
-        vertical-align: top;
-        }
-        th {
-        font-weight:bold;
-        background: #ccc;
-        color: black;
-        }
-        table, th, td {
-        font-size:100%;
-        border: none
-        }
-        table.log tr td, tr th {
-
-        }
-        h2 {
-        font-weight:bold;
-        font-size:140%;
-        margin-bottom: 5;
-        }
-        h3 {
-        font-size:100%;
-        font-weight:bold;
-        background: #525D76;
-        color: white;
-        text-decoration: none;
-        padding: 5px;
-        margin-right: 2px;
-        margin-left: 2px;
-        margin-bottom: 0;
-        }
-    </xsl:template>
-
-    <!--
-    Replace DOS characters in a path.
-    Replace '\' with '/', ':' with '_'.
-    -->
-    <xsl:template name="from-dos">
-        <xsl:param name="path"/>
-        <xsl:value-of select="translate($path, '\:', '/_')"/>
-    </xsl:template>
-
-    <!--
-    Creates an all-classes.html file that contains a link to all files.
-    -->
-    <xsl:template match="checkstyle" mode="all.classes">
-        <html>
-            <head>
-                <link rel="stylesheet" type="text/css" href="stylesheet.css"/>
-            </head>
-            <body>
-                <h2>Files</h2>
-                <p><a href="overview-frame.html" target="fileFrame">Summary</a></p>
-                <p>
-                    <table width="100%">
-                        <!-- For each file create its part -->
-                        <xsl:apply-templates select="$allFilesWithError" mode="all.classes">
-                            <xsl:sort select="@name"/>
-                        </xsl:apply-templates>
-                    </table>
-                </p>
-            </body>
-        </html>
-    </xsl:template>
-
-    <xsl:template match="checkstyle" mode="filelist">
-        <h3>Files</h3>
-        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
-            <tr>
-                <th>Name</th>
-                <th>Errors</th>
-            </tr>
-            <xsl:apply-templates select="$allFilesWithError" mode="filelist">
-                <xsl:sort select="@name"/>
-            </xsl:apply-templates>
-        </table>
-    </xsl:template>
-
-    <xsl:template match="file" mode="filelist">
-        <xsl:variable name="name" select="@name" />
-
-        <!--<xsl:if test="$first = 'true'">-->
-            <xsl:variable name="new-name">
-                <xsl:call-template name="from-dos">
-                    <xsl:with-param name="path" select="@name"/>
-                </xsl:call-template>
-            </xsl:variable>
-            <tr>
-                <xsl:call-template name="alternated-row" />
-                <td nowrap="nowrap">
-                    <a>
-                        <xsl:attribute name="href">
-                            <xsl:text>files/</xsl:text><xsl:value-of select="$new-name"/><xsl:text>.html</xsl:text>
-                        </xsl:attribute>
-                        <xsl:value-of select="@name"/>
-                    </a>
-                </td>
-                <td><xsl:value-of select="count(../file[@name = $name]/error)"/></td>
-            </tr>
-        <!--</xsl:if>-->
-    </xsl:template>
-
-    <xsl:template match="file" mode="all.classes">
-
-        <xsl:variable name="new-name">
-            <xsl:call-template name="from-dos">
-                <xsl:with-param name="path" select="@name"/>
-            </xsl:call-template>
-        </xsl:variable>
-        <tr>
-            <td nowrap="nowrap">
-                <a target="fileFrame">
-                    <xsl:attribute name="href">
-                        <xsl:text>files/</xsl:text>
-                        <xsl:value-of select="$new-name"/>
-                        <xsl:text>.html</xsl:text>
-                    </xsl:attribute>
-                    <xsl:value-of select="@name"/>
-                </a>
-            </td>
-        </tr>
-    </xsl:template>
-
-    <!--
-    transform string like a/b/c to ../../../
-    @param path the path to transform into a descending directory path
-    -->
-    <xsl:template name="path">
-        <xsl:param name="path"/>
-        <xsl:if test="contains($path,'/')">
-            <xsl:text>../</xsl:text>
-            <xsl:call-template name="path">
-                <xsl:with-param name="path"><xsl:value-of select="substring-after($path,'/')"/></xsl:with-param>
-            </xsl:call-template>
-        </xsl:if>
-        <xsl:if test="not(contains($path,'/')) and not($path = '')">
-            <xsl:text>../</xsl:text>
-        </xsl:if>
-    </xsl:template>
-
-    <xsl:template match="file">
-        <xsl:variable name="name" select="@name"/>
-
-        <xsl:variable name="new-name">
-            <xsl:call-template name="from-dos">
-                <xsl:with-param name="path" select="@name"/>
-            </xsl:call-template>
-        </xsl:variable>
-        <redirect:write file="{$output.dir}/files/{$new-name}.html">
-            <html>
-                <head>
-                    <link rel="stylesheet" type="text/css">
-                        <xsl:attribute name="href">
-                            <xsl:call-template name="path">
-                                <xsl:with-param name="path" select="$new-name"/>
-                            </xsl:call-template>
-                            <xsl:text>stylesheet.css</xsl:text>
-                        </xsl:attribute>
-                    </link>
-                </head>
-                <body>
-                    <xsl:call-template name="pageHeader"/>
-                    <h3>File <xsl:value-of select="@name"/> </h3>
-                    <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
-                        <tr>
-                            <th>Error Description</th>
-                            <th>Line</th>
-                        </tr>
-                        <xsl:for-each select="../file[@name = $name]/error">
-                            <tr>
-                                <xsl:call-template name="alternated-row"/>
-                                <td>
-                                    <xsl:value-of select="@message"/>
-                                </td>
-                                <td>
-                                    <xsl:value-of select="@line"/>
-                                </td>
-                            </tr>
-                        </xsl:for-each>
-                    </table>
-                </body>
-            </html>
-        </redirect:write>
-    </xsl:template>
-
-    <xsl:template match="checkstyle" mode="summary">
-        <h3>Summary</h3>
-        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
-            <tr>
-                <th>Files</th>
-                <th>Files with Errors</th>
-                <th>Errors</th>
-            </tr>
-            <tr>
-                <xsl:call-template name="alternated-row"/>
-                <td><xsl:value-of select="count($allFiles)"/></td>
-                <td><xsl:value-of select="count($allFilesWithError)"/></td>
-                <td><xsl:value-of select="count(file/error)"/></td>
-            </tr>
-        </table>
-        <table class="log" border="0" cellpadding="5" cellspacing="2" width="100%">
-            <tr>
-                <th>Check</th>
-                <th>Number of Violations</th>
-            </tr>
-            <xsl:for-each select="file/error[@source and generate-id(.) = generate-id(key('violations', @source))]">
-                <xsl:sort select="@source"/>
-                <xsl:variable name="source" select="@source"/>
-                <tr>
-                    <xsl:call-template name="alternated-row"/>
-                    <td>
-                        <xsl:value-of select="$source"/>
-                    </td>
-                    <td>
-                        <xsl:value-of select="count(/checkstyle/file/error[@source=$source])"/>
-                    </td>
-                </tr>
-            </xsl:for-each>
-        </table>
-    </xsl:template>
-
-    <xsl:template name="alternated-row">
-        <xsl:attribute name="class">
-            <xsl:if test="position() mod 2 = 1">a</xsl:if>
-            <xsl:if test="position() mod 2 = 0">b</xsl:if>
-        </xsl:attribute>
-    </xsl:template>
-
-</xsl:stylesheet>
-
diff --git a/config/checkstyle/checkstyle-report.groovy b/config/checkstyle/checkstyle-report.groovy
new file mode 100644
index 0000000..1c3dcac
--- /dev/null
+++ b/config/checkstyle/checkstyle-report.groovy
@@ -0,0 +1,154 @@
+/**
+ * A template which generates an HTML report from the checkstyle XML report
+ */
+yieldUnescaped '<!DOCTYPE html>'
+
+def severityMapping = [
+        error  : 'danger',
+        warning: 'warning',
+        info   : 'info',
+        ignore : 'success'
+]
+
+def github = { path, line=null ->
+    def localPath = (path - project.rootDir).replaceAll('\\\\','/')
+    def link = """https://github.com/groovy/groovy-core/blob/master$localPath${line?"#L$line":""}"""
+
+    if (line) {
+        "<a href='$link'>$line</a>"
+    } else {
+        "<i class='fa fa-github'></i> <a href='$link'>$link</a>"
+    }
+}
+
+html {
+    head {
+        meta 'charset': "utf-8"
+        meta 'http-equiv': "content-type", content: "text/html; charset=utf-8"
+        meta 'http-equiv': "X-UA-Compatible", content: "IE=edge"
+        meta name: "viewport", content: "width=device-width, initial-scale=1"
+
+        title "Checkstyle report for ${project.name}"
+        link href: "http://maxcdn.bootstrapcdn.com/font-awesome/4.1.0/css/font-awesome.min.css", rel: "stylesheet"
+        link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css", rel: "stylesheet"
+        link href: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap-theme.min.css", rel: "stylesheet"
+    }
+
+    body {
+        div(class:'navbar navbar-inverse navbar-fixed-top', role:'navigation') {
+            div(class:'container') {
+                div(class:'navbar-header') {
+                    button(type:'button', class:'navbar-toggle', 'data-toggle':'collapse', 'data-target':'navbar-collaspe') {
+                        span(class:'sr-only', 'Toggle navigation')
+                        span(class:'icon-bar'){}
+                        span(class:'icon-bar'){}
+                        span(class:'icon-bar'){}
+                    }
+                    a(class:'navbar-brand',href:'#', 'Checkstyle report')
+                }
+                div(class:'navbar-collapse collapse') {
+                    ul(class:"nav navbar-nav") {
+                        li(class: 'dropdown') {
+                            a(id: 'severityDropdown', href: '#', class: 'dropdown-toggle', 'data-toggle': 'dropdown', 'Severity <span class="caret"></span>')
+                            ul(class: "dropdown-menu dropdown-severity", role: "menu") {
+                                li(role: 'presentation', class: 'active') {
+                                    a(role: 'menuitem', tabindex: '-1', href: '#', 'All levels')
+                                }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Error') }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Warning') }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Info') }
+                                li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', 'Ignore') }
+                            }
+                        }
+
+                        Set rules = files.collect { it.errors.collect { it.source } }.flatten()
+
+                        li(class: 'dropdown') {
+                            a(id: 'rulesDropdown', href: '#', class: 'dropdown-toggle', 'data-toggle': 'dropdown', 'Rules <span class="caret"></span>')
+                            ul(class: "dropdown-menu dropdown-rule", role: "menu") {
+                                li(role: 'presentation', class: 'active') {
+                                    a(role: 'menuitem', tabindex: '-1', href: '#', 'All rules')
+                                }
+                                rules.each { rule ->
+                                    li(role: 'presentation') { a(role: 'menuitem', tabindex: '-1', href: '#', rule) }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+
+
+        div(class: 'container') {
+            div(class:'page-header') {
+                h1("Checkstyle report for project ${project.name}")
+            }
+            files.each { file ->
+                def errors = file.errors
+                Set severities = errors.collect { "severity-${it.severity}" }
+                Set panelRules = errors.collect { "rule-${it.source.toLowerCase()}" }
+                div(class: "panel panel-default ${severities.join(' ')} ${panelRules.join(' ')}") {
+                    div(class: "panel-heading") {
+                        h3(class: 'panel-title', github(file.name))
+                    }
+                    div(class: 'panel-body') {
+                        table(class: "table table-striped table-bordered") {
+                            tbody {
+                                errors.each { err ->
+                                    tr(class:"checkstyle-error severity-${err.severity} rule-${err.source.toLowerCase()}") {
+                                        td {
+                                            h4 {
+                                                span(class: "label label-${severityMapping[err.severity]}", err.severity.capitalize())
+                                            }
+                                        }
+                                        td { span "At line ${github(file.name, err.line)}, $err.message" }
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+
+            script(src: "http://code.jquery.com/jquery-1.11.0.min.js") {}
+            script(src: "http://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/js/bootstrap.min.js") {}
+            script {
+                yieldUnescaped '''$(document).ready(function () {
+        var severity = null;
+        var rule = null;
+        doFilter();
+        function doFilter() {
+          var severityClass = "severity-" + severity;
+          var ruleClass = "rule-" + rule;
+          $('.panel').hide();
+          $('.checkstyle-error').hide();
+          $('.checkstyle-error').filter(function () {
+              return (severity==null || $(this).hasClass(severityClass)) && (rule==null || $(this).hasClass(ruleClass));
+          }).show();
+          $('.panel').filter(function () {
+              return (severity==null || $(this).hasClass(severityClass)) && (rule==null || $(this).hasClass(ruleClass));
+          }).show();
+        }
+        $(".dropdown-severity li a").click(function() {
+          rule = null;
+          severity = $(this).text().toLowerCase();
+          if (severity==="all levels") {
+            severity = null;
+          }
+          doFilter();
+        });
+        $(".dropdown-rule li a").click(function() {
+          severity = null;
+          rule = $(this).text().toLowerCase();
+          if (rule==="all rules") {
+            rule = null;
+          }
+          doFilter();
+        });
+
+});'''
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/config/checkstyle/checkstyle.xml b/config/checkstyle/checkstyle.xml
index 6661d52..19d7367 100644
--- a/config/checkstyle/checkstyle.xml
+++ b/config/checkstyle/checkstyle.xml
@@ -105,16 +105,20 @@
         <module name="DefaultComesLast"/>
         <!-- very liberal values for metrics, perhaps tighten some later -->
         <module name="JavaNCSS">
+            <property name="severity" value="warning"/>
             <property name="methodMaximum" value="80"/>
             <property name="classMaximum" value="300"/>
         </module>
         <module name="ClassFanOutComplexity">
+            <property name="severity" value="warning"/>
             <property name="max" value="22"/>
         </module>
         <module name="ClassDataAbstractionCoupling">
+            <property name="severity" value="warning"/>
             <property name="max" value="14"/>
         </module>
         <module name="CyclomaticComplexity">
+            <property name="severity" value="warning"/>
             <property name="max" value="14"/>
         </module>
         <!-- TODO: turn this back on? -->
@@ -142,6 +146,8 @@
         <!--</module>-->
         <!-- add below in eventually for consistency -->
         <!--<module name="ArrayTypeStyle"/>-->
+
+        <module name="FileContentsHolder" />
     </module>
     <!-- Item 6 - Avoid finalizers -->
     <!-- this will not find violations that contain linebreaks -->
@@ -153,8 +159,15 @@
         <property name="headerFile" value="${rootProject.projectDir}/config/checkstyle/codeHeader.txt"/>
     </module>
     <module name="JavadocPackage">
+        <property name="severity" value="info"/>
         <property name="allowLegacy" value="true"/>
     </module>
+
+    <module name="SuppressionCommentFilter">
+        <property name="offCommentFormat" value="CHECKSTYLE.OFF\: ([\w\|]+)"/>
+        <property name="onCommentFormat" value="CHECKSTYLE.ON\: ([\w\|]+)"/>
+        <property name="checkFormat" value="$1"/>
+    </module>
 <!--
     <module name="au.com.redhillconsulting.simian.SimianCheck">
         <property name="threshold" value="8"/>
diff --git a/gradle.properties b/gradle.properties
index 50ed390..826fd4b 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -1,9 +1,9 @@
 groovycMain_mx=384m
 groovyJUnit_permSize=64m
-groovyBundleVersion=2.3.5
+groovyBundleVersion=2.4.3
 javacMain_mx=384m
-groovyVersion=2.3.5
-org.gradle.jvmargs=-Xmx640m -XX:MaxPermSize=196m -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
+groovyVersion=2.4.3
+org.gradle.jvmargs=-Xmx1G -XX:MaxPermSize=384m -XX:+CMSClassUnloadingEnabled -XX:+CMSPermGenSweepingEnabled
 groovyJUnit_mx=512m
 groovycTest_mx=640m
 groovycExamples_mx=384m
diff --git a/gradle.properties.gz b/gradle.properties.gz
deleted file mode 100644
index cbe0304..0000000
Binary files a/gradle.properties.gz and /dev/null differ
diff --git a/gradle/LICENSE.txt b/gradle/LICENSE.txt
new file mode 100644
index 0000000..d79ff3c
--- /dev/null
+++ b/gradle/LICENSE.txt
@@ -0,0 +1,13 @@
+Copyright 2003-${year} the original author or authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+    http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
\ No newline at end of file
diff --git a/gradle/asciidoctor.gradle b/gradle/asciidoctor.gradle
index 80053e0..fb0e7a2 100644
--- a/gradle/asciidoctor.gradle
+++ b/gradle/asciidoctor.gradle
@@ -20,65 +20,127 @@ asciidoctor {
     def (full, major, minor, patch, flavor) = (groovyVersion =~ /(\d+)\.(\d++)\.(\d+)(?:-(.+))?/)[0]
     logDocuments = true
     sourceDir = project.file('src/spec/doc')
-    options = [
-            attributes: [
-                    'source-highlighter': 'prettify',
-                    groovyversion: groovyVersion,
-                    'groovy-major-version': major,
-                    'groovy-minor-version': minor,
-                    'groovy-patch-version': patch,
-                    'groovy-full-version': groovyVersion,
-                    'groovy-short-version': "${major}.${minor}",
-                    doctype: 'book',
-                    revnumber: groovyVersion,
-                    icons: 'font',
-                    toc2: '',
-                    subprojroot: 'subprojects/groovy-',
-                    specfolder: 'src/spec/doc',
-                    linkcss: '',
-                    stylesheet: "assets/css/style.css",
-                    encoding: 'utf-8',
-                    toclevels: 10,
-                    numbered: ''
-            ]
-    ]
+
+    attributes([
+            'rootProjectDir': rootProject.projectDir,
+            'source-highlighter': 'prettify',
+            groovyversion: groovyVersion,
+            'groovy-major-version': major,
+            'groovy-minor-version': minor,
+            'groovy-patch-version': patch,
+            'groovy-full-version': groovyVersion,
+            'groovy-short-version': "${major}.${minor}",
+            doctype: 'book',
+            revnumber: groovyVersion,
+            icons: 'font',
+            toc2: '',
+            specfolder: 'src/spec/doc',
+            linkcss: '',
+            stylesheet: "assets/css/style.css",
+            encoding: 'utf-8',
+            toclevels: 10,
+            numbered: '',
+            sectanchors: ''
+    ])
+
+    extensions {
+
+        def baseUrls = [
+                jdk: "http://docs.oracle.com/javase/8/docs/api/index.html",
+                gjdk: "http://docs.groovy-lang.org/${version}/html/groovy-jdk/index.html",
+                gapi: "http://docs.groovy-lang.org/${version}/html/gapi/index.html",
+        ]
+
+        baseUrls.each { macroName, baseURL ->
+            inlinemacro(name: macroName) {
+                parent, target, attributes ->
+                    def (className, anchor) = target.split('#') as List
+                    options = [
+                            "type"  : ":link",
+                            "target": calculateDocUrl(baseURL, className, anchor)
+                    ]
+
+                    createInline(parent, "anchor", attributes.text?:target, attributes, options).render()
+            }
+        }
+    }
 }
 
 // skip the asciidoctor task if there's no directory with asciidoc files
 asciidoctor.onlyIf { project.file('src/spec/doc').exists() }
 
 task asciidoctorAssets(type:Copy) {
-    from rootProject.file('src/spec/assets')
-    into "${asciidoctor.outputDir}/assets"
+    from project.fileTree('src/spec/assets')
+    into "${asciidoctor.outputDir}/html5/assets"
+    into "${rootProject.asciidoctor.outputDir}/html5/assets"
 }
 asciidoctor.finalizedBy asciidoctorAssets
 
-asciidoctor.doLast {
+def adocSanityCheck = { file, text, errors ->
+    Set localErrors = []
+    text.eachLine(1) { line,i ->
+        if (line =~ /tag:[a-zA-Z0-9]/) {
+            localErrors << "line $i misses semicolon. Should be tag::\n $line"
+        }
+        if (line =~ /end:[a-zA-Z0-9]/) {
+            localErrors << "line $i misses semicolon. Should be end::\n $line"
+        }
+        if (line =~ /(tag|end)::[^\[\]]$/) {
+            localErrors << "line $i contains incorrect tag definition (misses []):\n $line"
+        }
+    }
+    localErrors.collect(errors) { "    $file, $it" }
+}
 
-    def scripts = '''<link rel="stylesheet" href="assets/css/view-example.css">
-<script src='assets/js/jquery-2.1.1.min.js'></script>
-<script src='assets/js/view-example.js'></script>'''
+def htmlOutputSanityCheck = { file, text, errors ->
+    Set localErrors = []
+    text.eachLine(1) { line,i ->
+        if (line =~ /^={1,5} /) {
+            localErrors << "line $i starting with asciidoctor raw markup:\n$line"
+        }
+        if (line =~ /<code class=".+?"><\/code>/) {
+            localErrors << "contains empty code block, probably incorrect import of a tag."
+        }
+        if (line =~ /(gapi|jdk|gjdk):(.+?)/) {
+            localErrors << "line $i starting with asciidoctor raw markup:\n$line"
+        }
+    }
+    localErrors.collect(errors) { "    $file, $it" }
+}
 
-    def baseUrls = [
-            jdk: "http://docs.oracle.com/javase/8/docs/api/index.html",
-            gjdk: "http://docs.groovy-lang.org/${version}/html/groovy-jdk/index.html",
-            gapi: "http://docs.groovy-lang.org/${version}/html/gapi/index.html",
-    ]
-
-    // gapi macro expansion
-    outputDir.eachFileMatch(~'.*html') { File file ->
-        def text = file.getText('UTF-8')
-        text = text.replaceAll(/(gapi|gjdk|jdk)::([a-zA-Z0-9$.#]+)(?:\[([^\]]*)\])?/) { m ->
-            def (className, anchor) = m[2].split('#') as List
-            def label = m[3] ?: '<code>' + className + '</code>'
-            "<a href='${calculateDocUrl(baseUrls[m[1]], className, anchor)}' target='_blank'>$label</a>"
+asciidoctor {
+    def errors = new LinkedHashSet<String>()
+    doFirst {
+        def specTestDir = file('src/spec/test')
+        if (specTestDir.exists()) {
+            specTestDir.eachFileRecurse { file ->
+                if (file.isFile()) {
+                    adocSanityCheck(file, file.getText('utf-8'), errors)
+                }
+            }
+        }
+        if (errors) {
+            throw new GradleException("Incorrect Asciidoctor input:\n${errors.join('\n')}")
         }
+    }
 
-        text = text.replaceAll('</head>', "$scripts</head>")
+    doLast {
 
-        file.write(text, 'UTF-8')
-    }
+        def scripts = '''<link rel="stylesheet" href="assets/css/view-example.css">
+<script src='assets/js/jquery-min-2.1.1.js'></script>
+<script src='assets/js/view-example.js'></script>'''
 
+        // gapi macro expansion
+        outputDir.eachFileMatch(~'.*html') { File file ->
+            def text = file.getText('UTF-8')
+            text = text.replaceAll('</head>', "$scripts</head>")
+            htmlOutputSanityCheck(file, text, errors)
+            file.write(text, 'UTF-8')
+        }
+        if (errors) {
+            throw new GradleException("Incorrect Asciidoctor output:\n${errors.join('\n')}")
+        }
+    }
 }
 
 String calculateDocUrl(String baseUrl, String className, String anchor) {
diff --git a/gradle/assemble.gradle b/gradle/assemble.gradle
index 1c8d537..49f7311 100644
--- a/gradle/assemble.gradle
+++ b/gradle/assemble.gradle
@@ -30,6 +30,8 @@ ext.srcSpec = copySpec {
                 'cobertura.ser',
                 'junitvmwatcher*.properties',
                 'out',
+                'bintray.properties', // generated by the CI server
+                'gradle.properties.gz', // generated by the CI server
                 '**/*.iml',         // used by Intellij IDEA
                 '**/*.ipr',         // used by Intellij IDEA
                 '**/*.iws',         // used by Intellij IDEA
@@ -50,7 +52,7 @@ ext.docSpec = copySpec {
         from groovydocAll.destinationDir
     }
     into('html/documentation') {
-        from "$buildDir/asciidoc"
+        from "$buildDir/asciidoc/html5"
     }
     into('html/groovy-jdk') {
         from docGDK.destinationDir
@@ -136,7 +138,7 @@ allprojects {
         def targetTmp = new File("${archivePath}.tmp.1.tmp")
 
         doFirst {
-            from zipTree(targetTmp)
+            from zipTree(target)
 
             def keepUntouched = [
                     'org/codehaus/groovy/cli/GroovyPosixParser*.class',
@@ -192,13 +194,47 @@ allprojects {
 
         }
         doLast {
-            // for some obscure reason, this produces a Gradle warning
             target.delete()
             ant.delete(file: targetTmp, quiet: true, deleteonexit: true)
         }
     }
-}
 
+    if (project.name in ['groovy', 'groovy-test']) {
+        task grooidjar(type: Jar) {
+            onlyIf {
+                !rootProject.useIndy()
+            }
+            destinationDir = jar.destinationDir
+            baseName = jar.baseName
+            appendix = jar.appendix
+            classifier = jar.classifier ? "${jar.classifier}grooid" : 'grooid'
+            includeEmptyDirs = false
+            def target = new File("${archivePath}.tmp")
+            boolean isRootProject = project==rootProject
+
+            doFirst {
+                from zipTree(target)
+                ant {
+                    taskdef name: 'jarjar', classname: 'com.tonicsystems.jarjar.JarJarTask', classpath: rootProject.configurations.tools.asPath
+                    jarjar(jarfile: target) {
+                        zipfileset(src: jarjar.archivePath)
+                        if (isRootProject) {
+                            zipfileset(src: rootProject.configurations.runtime.files.find { it.name.startsWith('openbeans') })
+                        }
+                        rule pattern: 'com.googlecode.openbeans.**', result: 'groovyjarjaropenbeans. at 1'
+                        rule pattern: 'org.apache.harmony.beans.**', result: 'groovyjarjarharmonybeans. at 1'
+                        rule pattern: 'java.beans.**', result: 'groovyjarjaropenbeans. at 1'
+                    }
+                }
+
+            }
+            doLast {
+                target.delete()
+            }
+        }
+        jarjar.finalizedBy(grooidjar)
+    }
+}
 
 subprojects {
     jar {
@@ -259,6 +295,10 @@ task replaceJarWithJarJar(dependsOn: allprojects.jarjar ) {
     outputs.files(allprojects.jar.archivePath)
 }
 
+allprojects {
+    rootProject.replaceJarWithJarJar.mustRunAfter(test)
+}
+
 task jarAll(type: Jar, dependsOn: replaceJarWithJarJar) {
 
     inputs.files(allprojects.jar.archivePath)
@@ -341,6 +381,13 @@ task jarAllAll(dependsOn: [jarAll, jarAllWithIndy]) {
     }
 }
 
+allprojects {
+    tasks.withType(Test) { task ->
+        jarAll.mustRunAfter(task)
+        jarAllWithIndy.mustRunAfter(task)
+    }
+}
+
 task sourceAllJar(type: Jar, dependsOn: { modules()*.sourceJar + rootProject.sourceJar }) {
     with sourceJar.rootSpec
     modules()*.sourceJar.each {
diff --git a/gradle/backports.gradle b/gradle/backports.gradle
index 9c927fc..a4df680 100644
--- a/gradle/backports.gradle
+++ b/gradle/backports.gradle
@@ -41,6 +41,24 @@ backports.each { pkg, classList ->
         include classList
         baseName = "groovy-backports-$pkg"
     }
-    backportJars.dependsOn backportJar
+
+    // the following two jars are empty. No wonder, Maven Central *requires* a javadoc and sources classifier
+    // it's stupid in our case, because we don't have such, but we have no choice
+    def javadocJar = task "backport${pkg}JavadocJar"(type:Jar) {
+        group = 'Backports'
+        dependsOn jarAll
+
+        baseName = "groovy-backports-$pkg"
+        classifier = 'javadoc'
+    }
+    def sourcesJar = task "backport${pkg}SourcesJar"(type:Jar) {
+        group = 'Backports'
+        dependsOn jarAll
+
+        baseName = "groovy-backports-$pkg"
+        classifier = 'sources'
+    }
+    backportJars.dependsOn([backportJar, javadocJar, sourcesJar])
+
 }
 
diff --git a/gradle/binarycompatibility.gradle b/gradle/binarycompatibility.gradle
new file mode 100644
index 0000000..c2abe9f
--- /dev/null
+++ b/gradle/binarycompatibility.gradle
@@ -0,0 +1,204 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import groovy.text.markup.MarkupTemplateEngine
+import groovy.text.markup.TemplateConfiguration
+
+import java.lang.reflect.Modifier
+
+buildscript {
+    // this block should not be necessary, but for some reason it fails without!
+    repositories {
+        jcenter()
+    }
+
+    dependencies {
+        classpath 'me.champeau.gradle:japicmp-gradle-plugin:0.1.1'
+    }
+}
+
+task checkBinaryCompatibility {
+    description = 'Generates binary compatibility reports'
+}
+check.dependsOn(checkBinaryCompatibility)
+
+if (JavaVersion.current().isJava7Compatible()) {
+    allprojects {
+        apply plugin: 'me.champeau.gradle.japicmp'
+    }
+
+    def referenceMinorVersion = '2.4.2'
+
+    def prettyPrint = { classOrMethod ->
+        "${Modifier.toString(classOrMethod.get()?.modifiers)} ${classOrMethod.get()?.longName}"
+    }
+
+    def reportGenerator = { model ->
+        outputProcessor {
+
+            def skipClass = { c ->
+                c.fullyQualifiedName =~ /\$[0-9]+$/ || // skip AIC
+                c.fullyQualifiedName.startsWith('org.codehaus.groovy.runtime.dgm$') ||
+                        c.fullyQualifiedName.contains('_closure')
+            }
+            def skipMethod = { c, m -> skipClass(c) || m.name =~ /access\$[0-9]+/ }
+            def violations = [:].withDefault {
+                // key = class name
+                // value = map of violations
+                [:].withDefault { [] }
+            }
+            removedConstructor { c, m ->
+                if (!skipMethod(c, m)) {
+                    def level = Modifier.isPrivate(m.oldConstructor.get()?.modifiers) ? 'info' : 'error'
+                    violations[c.fullyQualifiedName][level] << "Constructor ${prettyPrint(m.oldConstructor)} has been removed"
+                }
+            }
+            removedMethod { c, m ->
+                if (!skipMethod(c, m)) {
+                    def level = m.name.startsWith('super$') ? 'warning' : 'error'
+                    violations[c.fullyQualifiedName][level] << "Method ${m.name} has been removed"
+                }
+            }
+            removedClass { c ->
+                if (!skipClass(c)) {
+                    violations[c.fullyQualifiedName].error << "Class has been removed"
+                }
+            }
+
+            modifiedMethod { c, m ->
+                if (!skipMethod(c, m)) {
+                    violations[c.fullyQualifiedName].warning << """<p>Method ${m.name} has been modified</p>
+<p>From <pre>${prettyPrint(m.oldMethod)}</pre> to <pre>${prettyPrint(m.newMethod)}</pre></p>"""
+                }
+            }
+
+            modifiedConstructor { c, m ->
+                if (!skipMethod(c, m)) {
+                    violations[c.fullyQualifiedName].warning << """<p>Constructor ${m.name} has been modified</p>
+<p>From <pre>${prettyPrint(m.oldConstructor)}</pre> to <pre>${prettyPrint(m.newConstructor)}</pre></p>"""
+                }
+            }
+
+            modifiedClass { c ->
+                if (!skipClass(c)) {
+                    def level = c.binaryCompatible?'info':'error'
+                    def message = "Class ${c.fullyQualifiedName} has been modified"
+                    violations[c.fullyQualifiedName][level] << message
+                }
+            }
+
+            newClass { c ->
+                if (!skipClass(c)) {
+                    violations[c.fullyQualifiedName].info << "Class has been added"
+                }
+            }
+            newMethod { c, m ->
+                if (!skipMethod(c, m)) {
+                    violations[c.fullyQualifiedName].info << """<p>Method ${m.name} has been added</p>
+<p>Signature: <pre>${prettyPrint(m.newMethod)}</pre></p>"""
+                }
+            }
+
+            after {
+                model.violations = violations
+            }
+        }
+    }
+
+// using a global engine for all tasks in order to increase performance
+    def configDir = file("$rootProject.projectDir/config/binarycompatibility")
+    def templateFile = 'binarycompat-report.groovy'
+    def templateConfiguration = new TemplateConfiguration()
+    templateConfiguration.with {
+        autoIndent = true
+        autoNewLine = true
+    }
+    def engine = new MarkupTemplateEngine(this.class.classLoader, configDir, templateConfiguration)
+
+    task japicmpAll(type: me.champeau.gradle.ArtifactJapicmpTask) {
+        dependsOn jarAll
+        baseline = "org.codehaus.groovy:groovy-all:${referenceMinorVersion}@jar"
+        to = jarAll.archivePath
+        accessModifier = 'protected'
+        onlyModified = true
+        failOnModification = false
+        txtOutputFile = file("$buildDir/reports/japi.txt")
+
+        doFirst {
+            classpath = allprojects.configurations.japicmp.files.flatten()
+        }
+
+        def htmlReportFile = file("${buildDir}/reports/binary-compat-${project.name}-all.html")
+        inputs.file file("$configDir/$templateFile")
+        inputs.file templateFile
+        outputs.file htmlReportFile
+
+        def model = [title   : "Binary compatibility report for ${project.name}",
+                     project : project,
+                     baseline: baseline,
+                     archive : to.name]
+        outputProcessor(reportGenerator.curry(model))
+
+        doLast {
+            htmlReportFile.withWriter('utf-8') { wrt ->
+                engine.createTemplateByPath(templateFile).make(model).writeTo(wrt)
+            }
+        }
+    }
+
+    allprojects {
+
+        dependencies  {
+            japicmp files(rootProject.jar.archivePath)
+        }
+
+        task japicmp(type: me.champeau.gradle.ArtifactJapicmpTask) {
+            dependsOn replaceJarWithJarJar
+            baseline = "org.codehaus.groovy:${project.name}:${referenceMinorVersion}@jar"
+            to = jar.archivePath
+            accessModifier = 'protected'
+            onlyModified = true
+            failOnModification = false
+            txtOutputFile = file("$buildDir/reports/japi.txt")
+
+            def htmlReportFile = file("${buildDir}/reports/binary-compat-${project.name}.html")
+            inputs.file file("$configDir/$templateFile")
+            inputs.file templateFile
+            outputs.file htmlReportFile
+
+            def model = [title   : "Binary compatibility report for ${project.name}",
+                         project : project,
+                         baseline: baseline,
+                         archive : to.name]
+            outputProcessor(reportGenerator.curry(model))
+
+            doLast {
+                htmlReportFile.withWriter('utf-8') { wrt ->
+                    engine.createTemplateByPath(templateFile).make(model).writeTo(wrt)
+                }
+            }
+
+        }
+    }
+
+
+    allprojects {
+        tasks.withType(me.champeau.gradle.ArtifactJapicmpTask) { task ->
+            checkBinaryCompatibility.dependsOn(task)
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/gradle/bintray.gradle b/gradle/bintray.gradle
index 14a8f1d..bbd3154 100644
--- a/gradle/bintray.gradle
+++ b/gradle/bintray.gradle
@@ -59,12 +59,20 @@ artifactoryPublish {
                         curDate, file("$projectDir/target/poms/pom-binary.xml")), 'artifacts', "org/codehaus/groovy/groovy-binary/${version}/groovy-binary-${version}.pom"),
 
         ]
-        tasks.withType(Jar).matching { name.startsWith('backport') }.all {
+        tasks.withType(Jar).matching { it.name.startsWith('backport') }.all {
             additionalFiles << gradleDeployDetails(
-                    new DefaultPublishArtifact(baseName, "jar", "jar", null, curDate, archivePath),
+                    new DefaultPublishArtifact(baseName, "jar", "jar", classifier, curDate, archivePath),
                     'artifacts',
                     "org/codehaus/groovy/${baseName}/${version}/${archiveName}")
+            if (!classifier) {
+                additionalFiles << gradleDeployDetails(
+                        new DefaultPublishArtifact(baseName, "pom", "pom", null, curDate, file("$projectDir/target/poms/pom-${baseName - 'groovy-'}.xml")),
+                        'artifacts',
+                        "org/codehaus/groovy/${baseName}/${version}/${baseName}-${version}.pom")
+            }
         }
         additionalFiles.each { deployDetails.add(it) }
     }
 }
+
+artifactoryPublish.dependsOn('backportJars')
\ No newline at end of file
diff --git a/gradle/docs.gradle b/gradle/docs.gradle
index 0c45ac9..d8d8b06 100644
--- a/gradle/docs.gradle
+++ b/gradle/docs.gradle
@@ -1,13 +1,20 @@
-task doc(dependsOn: ['asciidocAll', 'assembleAsciidoc', 'javadocAll', 'groovydocAll', 'docGDK']) {
+task doc(dependsOn: ['javadocAll', 'groovydocAll', 'docGDK']) {
+    if (JavaVersion.current().java7Compatible) {
+        dependsOn 'asciidocAll', 'assembleAsciidoc'
+    }
     ext.footer = 'Copyright &copy; 2003-2014 The Codehaus. All rights reserved.'
     ext.title = "Groovy ${groovyVersion}"
 }
 
-task assembleAsciidoc(type: Copy, dependsOn: 'asciidocAll') {
-    subprojects {
-        from project.asciidoctor
+if (JavaVersion.current().java7Compatible) {
+    task assembleAsciidoc(type: Copy, dependsOn: 'asciidocAll') {
+        subprojects {
+            from project.asciidoctor
+        }
+        into "$buildDir/asciidoc"
     }
-    into "$buildDir/asciidoc"
+
+    task asciidocAll(dependsOn: 'asciidoctor')
 }
 
 def javadocSpec = {
@@ -21,9 +28,9 @@ def javadocSpec = {
         overview = rootProject.file('src/main/overviewj.html')
         footer = doc.footer
         source = rootProject.useIndy()?'1.7':'1.6'
-        links('http://docs.oracle.com/javase/7/docs/api/', 'http://evgeny-goldin.org/javadoc/ant/api/',
-                'http://commons.apache.org/proper/commons-cli/javadocs/api-release', 'http://junit.org/javadoc/latest/',
-                'http://docs.oracle.com/javaee/6/api/', 'http://www.antlr2.org/javadoc')
+        links('http://docs.oracle.com/javase/8/docs/api/', 'http://docs.oracle.com/javaee/7/api/',
+                'http://commons.apache.org/proper/commons-cli/javadocs/api-release/', 'http://junit.org/apidocs/',
+                'http://docs.oracle.com/javaee/6/api/', 'http://www.antlr2.org/javadoc/')
     }
 }
 
@@ -37,19 +44,17 @@ def groovydocSpec = {
     footer = doc.footer
     overview = rootProject.file('src/main/overview.html')
     includePrivate = false
-    link 'http://docs.oracle.com/javaee/6/api/', 'javax.servlet.', 'javax.management.'
-    link 'http://docs.oracle.com/javase/7/docs/api/', 'java.', 'org.xml.', 'javax.', 'org.w3c.'
-    link 'http://evgeny-goldin.org/javadoc/ant/api/', 'org.apache.ant.', 'org.apache.tools.ant.'
-    link 'http://junit.org/javadoc/latest/', 'org.junit.', 'junit.'
-    link 'http://www.antlr2.org/javadoc', 'antlr.'
-    link 'http://commons.apache.org/proper/commons-cli/javadocs/api-release', 'org.apache.commons.cli.'
+    link 'http://docs.oracle.com/javaee/7/api/', 'javax.servlet.', 'javax.management.'
+    link 'http://docs.oracle.com/javase/8/docs/api/', 'java.', 'org.xml.', 'javax.', 'org.w3c.'
+    link 'http://docs.groovy-lang.org/docs/ant/api/', 'org.apache.ant.', 'org.apache.tools.ant.'
+    link 'http://junit.org/apidocs/', 'org.junit.', 'junit.'
+    link 'http://www.antlr2.org/javadoc/', 'antlr.'
+    link 'http://commons.apache.org/proper/commons-cli/javadocs/api-release/', 'org.apache.commons.cli.'
 }
 
 allprojects {
     javadoc javadocSpec
     groovydoc groovydocSpec
-
-    task asciidocAll(dependsOn: 'asciidoctor')
 }
 
 // Root project has an extra 'all' javadoc task
diff --git a/gradle/indy.gradle b/gradle/indy.gradle
index c288583..cc6b5ee 100644
--- a/gradle/indy.gradle
+++ b/gradle/indy.gradle
@@ -28,8 +28,6 @@ rootProject.ext.indyCapable = {
     capable && !rootProject.hasProperty('skipIndy')
 }
 
-def INDY_SYSTEM_PROP = 'groovy.target.indy'
-
 rootProject.ext.useIndy = {
     boolean indy = false
 
@@ -40,14 +38,45 @@ rootProject.ext.useIndy = {
     // which is the case if the build is started with -Pindy=true or during install/dist tasks
     indy |= rootProject.hasProperty('indy') && (Boolean.valueOf(rootProject.indy))
 
-    // set the groovy runtime system property to ensure forked junit test will get the indy flag properly
-    if (indy) {
-        System.setProperty(INDY_SYSTEM_PROP, 'true')
-    } else {
-        if (System.properties[INDY_SYSTEM_PROP]) {
-            System.properties.remove(INDY_SYSTEM_PROP)
-        }
+    indy && rootProject.indyCapable()
+}
+rootProject.ext.indyBanner = {
+    if (project==rootProject && useIndy()) {
+        logger.lifecycle '''
+
+         DM .N$?
+          $I?7OM.
+        .7+?II77MZ       ,:~~
+        +I$7O$8?  .M..DMMNNMMNZ.
+         ONDOMI.     7MMMMMMOO$I.
+         DOM87=      ZMNM8NMI77$.
+    .MNDO?$8$?       8MMNMMMN7II.
+   MMMO. O$7Z.   OI8?MDNNM$$$$7OM
+    M8  ZZ7$.    MMMMMDD7I77I777MMMM.
+       ZZ$7$     DMM$N$ZNMZDMODNDM. DD
+     .Z$$I$$       .ZI777777II778     ?D.
+    8$$7I$I+         .$I7?I7II7D.       ?Z
+   .O$$7I$78         N77O+??I?$.          Z
+   =7$7777$7 .    .=7NZ?I$7I+$.             O
+  ~:7$$7$7D+$~:=Z:=~++77Z$?IIZ~.             N
+  $Z$7O8D8=Z8I7==I~I:+~OZ887$MOI$O           .7
+  :O$I+~=?:O8?I$=++=:===Z$77ZN++$+~.          Z.
+   :7$78ZZZZZ=ZZ$~?==~+DD$8O$OO$7+?:.         $
+    .=~=+Z7I7?7I$+~=:~+~O~???77?~+??~         O
+        +=IZ7$7OI$=Z:~:~=8I?I?+$Z8++:        N.
+          =$+8ZO$$==+=~=?=8$IIIIID$ZZ.      Z
+
+                   INDY ENABLED !
+'''
+
     }
+}
 
-    indy && rootProject.indyCapable()
+if (useIndy()) {
+    gradle.taskGraph.whenReady { graph ->
+        graph.allTasks.findAll { it instanceof org.gradle.process.JavaForkOptions }.unique().each { task ->
+            logger.debug "Adding indy target to project ${task.project.name} task ${task.name}"
+            task.systemProperties 'groovy.target.indy': true
+        }
+    }
 }
diff --git a/gradle/jacoco/jacoco.gradle b/gradle/jacoco/jacoco.gradle
new file mode 100644
index 0000000..3de031d
--- /dev/null
+++ b/gradle/jacoco/jacoco.gradle
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+if (rootProject.hasProperty('coverage') && Boolean.valueOf(rootProject.getProperty('coverage'))) {
+    // we only apply the jacoco configuration if a system property is set, in order to avoid instrumentation if we
+    // are not specifically asking for code coverage
+
+    allprojects {
+        apply plugin: 'jacoco'
+
+        project.afterEvaluate {
+            tasks.withType(JacocoReport) {
+                if (name!='jacocoAllReport') {
+                    sourceDirectories += files(project.sourceSets.main.allGroovy.srcDirs)
+                    classDirectories += files(project.sourceSets.main.output)
+                }
+            }
+        }
+
+    }
+
+    task jacocoMerge(type:JacocoMerge) {
+        destinationFile = file("$buildDir/jacoco/jacoco-all.exec")
+        allprojects {
+            project.plugins.withType(JavaPlugin) {
+                project.tasks.withType(Test) { task ->
+                    if (sourceSets.test.allSource.srcDirs.any { it.exists() }) {
+                        executionData(task)
+                    }
+                }
+            }
+        }
+    }
+
+    task jacocoAllReport(type:JacocoReport, dependsOn: 'jacocoMerge') {
+        executionData jacocoMerge.destinationFile
+        allprojects {
+            project.plugins.withType(JavaPlugin) {
+                def sd = sourceDirectories?:files()
+                def cd = classDirectories?:files()
+                sourceDirectories = sd + files(project.sourceSets.main.allGroovy.srcDirs, project.sourceSets.main.allJava.srcDirs)
+                classDirectories = cd + files(project.sourceSets.main.output)
+            }
+        }
+    }
+
+    check.dependsOn jacocoAllReport
+}
\ No newline at end of file
diff --git a/gradle/jacoco/jacocofix.gradle b/gradle/jacoco/jacocofix.gradle
new file mode 100644
index 0000000..37dcf25
--- /dev/null
+++ b/gradle/jacoco/jacocofix.gradle
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// workaround for configuration of Jacoco task being executed before all information is available
+gradle.taskGraph.whenReady {
+    tasks.withType(JacocoReport) {
+        sourceDirectories = files(sourceSets.main.allGroovy.srcDirs + sourceSets.main.allJava.srcDirs)
+        classDirectories = files(sourceSets.main.output)
+    }
+}
diff --git a/gradle/pomconfigurer.gradle b/gradle/pomconfigurer.gradle
index beb30c1..3d6db64 100644
--- a/gradle/pomconfigurer.gradle
+++ b/gradle/pomconfigurer.gradle
@@ -7,7 +7,6 @@ project.ext.optional = { project.ext.optionalDeps << it }
 project.ext.provided = { project.ext.providedDeps << it }
 
 project.ext.pomConfigureClosureWithoutTweaks = {
-    scopeMappings.addMapping(10, configurations.groovy, 'compile')
     project {
         name 'Groovy'
         description 'Groovy: A powerful, dynamic language for the JVM'
@@ -517,9 +516,7 @@ project.ext.pomConfigureClosure = {
 
         if (project == rootProject) {
             // make dependencies optional
-            def groovyConfDeps =
-                project.configurations.groovy.dependencies.collect { dep -> dep.name } - project.configurations.compile.dependencies.collect { dep -> dep.name }
-            pom.dependencies.each { dep ->  if (!groovyConfDeps.contains(dep.artifactId)) { dep.optional = true }}
+            pom.dependencies.each { dep ->  dep.optional = true }
         }
 
         // add 'packaging' node
diff --git a/gradle/quality.gradle b/gradle/quality.gradle
index 4a15d70..312eee1 100644
--- a/gradle/quality.gradle
+++ b/gradle/quality.gradle
@@ -1,3 +1,6 @@
+import groovy.text.markup.MarkupTemplateEngine
+import groovy.text.markup.TemplateConfiguration
+
 /*
  * Copyright 2003-2014 the original author or authors.
  *
@@ -15,31 +18,98 @@
  */
 
 allprojects {
-    apply plugin: 'cobertura'
+    //apply plugin: "com.github.hierynomus.license"
     apply plugin: 'checkstyle'
     apply plugin: 'codenarc'
-    cobertura {
-        coverageFormats = ['xml', 'html']
-        coverageReportDir = file("$buildDir/reports/cobertura")
-    }
+
+//    license {
+//        header rootProject.file('gradle/LICENSE.txt')
+//        include "**/*.groovy"
+//        include "**/*.java"
+//        include "**/*.properties"
+//        include "**/*.js"
+//        include "**/*.css"
+//        include "**/*.html"
+//        exclude "org/codehaus/groovy/antlr/**"
+//        exclude 'reloading/**' // test resources for documentation of reloading
+//        exclude 'includes/**'
+//        dryRun = true
+//        ignoreFailures = true
+//        skipExistingHeaders = true
+//        ext.year = Calendar.instance.get(Calendar.YEAR)
+//    }
 
     // don't fail build on CodeNarc tasks
     tasks.withType(CodeNarc) {
         ignoreFailures = true
         configFile = file("$rootProject.projectDir/config/codenarc/codenarc.groovy")
+        codenarcClasspath = rootProject.sourceSets.main.output +
+                project(':groovy-templates').sourceSets.main.output +
+                project(':groovy-xml').sourceSets.main.output +
+                configurations.compile +
+                files(configurations.codenarc.findAll { !(it.name =~ /groovy|junit/)})
     }
+
     tasks.withType(Checkstyle) {
+        showViolations = false
         ignoreFailures = true
         configFile = file("$rootProject.projectDir/config/checkstyle/checkstyle.xml")
         configProperties = ['rootProject.projectDir': rootProject.projectDir]
+        def reportFile = file("${buildDir}/reports/checkstyle/${name}.xml")
+        reports {
+            include ( '**/*.java')
+            xml {
+                destination reportFile
+            }
+        }
+        task("${name}Report") {
+            def configDir = file("$rootProject.projectDir/config/checkstyle")
+            def templateFile = 'checkstyle-report.groovy'
+            def htmlReportFile = file("${buildDir}/reports/checkstyle/${name}.html")
+            inputs.file file("$configDir/$templateFile")
+            inputs.file reportFile
+            outputs.file htmlReportFile
+
+            doLast {
+                if (reportFile.exists()) {
+                    def templateConfiguration = new TemplateConfiguration()
+                    templateConfiguration.with {
+                        autoIndent = true
+                        autoNewLine = true
+                    }
+                    def engine = new MarkupTemplateEngine(this.class.classLoader, configDir, templateConfiguration)
+                    def xml = new XmlSlurper().parse(reportFile.newReader('utf-8'))
+                    def files = []
+                    xml.file.each { f ->
+                        if (f.error.size()) {
+                            files << [
+                                    name: f. at name.toString(),
+                                    errors: f.error.collect { e ->
+                                        def rule = e. at source.toString()
+                                        rule = rule.substring(rule.lastIndexOf('.')+1)
+                                        [line: e. at line.toString(),
+                                         column: e. at column.toString(),
+                                         message: e. at message.toString(),
+                                         source: rule,
+                                         severity: e. at severity.toString()]
+                                    }]
+                        }
+                    }
+                    def model = [
+                            project: project,
+                            files: files
+                    ]
+                    htmlReportFile.withWriter('utf-8') { wrt ->
+                        engine.createTemplateByPath('checkstyle-report.groovy').make(model).writeTo(wrt)
+                    }
+                }
+            }
+        }
+        finalizedBy "${name}Report"
     }
 
 }
 
-// suppress CheckStyle/CodeNarc
-task checkstyleExamples(overwrite: true) << {}
-task checkstyleMain(overwrite: true) << {}
-task checkstyleTest(overwrite: true) << {}
-task checkstyleTools(overwrite: true) << {}
-task codenarcExamples(overwrite: true) << {}
-
+apply from: 'gradle/jacoco/jacoco.gradle'
+// Temporarily disabled because of conflict
+//apply from: 'gradle/binarycompatibility.gradle'
diff --git a/gradle/test.gradle b/gradle/test.gradle
index 8e2d2e5..3ab0010 100644
--- a/gradle/test.gradle
+++ b/gradle/test.gradle
@@ -11,10 +11,7 @@ allprojects {
         if (headless == 'true') {
             systemProperties 'java.awt.headless': 'true'
         }
-        if (rootProject.useIndy()) {
-            logger.debug 'Adding indy target'
-            systemProperties 'groovy.target.indy': true
-        }
+
         forkEvery = 50
         maxParallelForks = isRunningOnCI() ? 1 : Runtime.runtime.availableProcessors()
         scanForTestClasses = true
diff --git a/gradle/upload.gradle b/gradle/upload.gradle
index a214136..15c8952 100644
--- a/gradle/upload.gradle
+++ b/gradle/upload.gradle
@@ -79,6 +79,10 @@ allprojects {
             if (indyJar.exists()) {
                 project.artifacts.add('archives', indyJar)
             }
+            def grooidJar = new File(archive.parent, archive.name[0..archive.name.lastIndexOf('.')-1]+'-grooid.jar')
+            if (grooidJar.exists()) {
+                project.artifacts.add('archives', grooidJar)
+            }
         }
     }
 }
@@ -104,6 +108,10 @@ allprojects {
         if (indyJar.exists()) {
             project.artifacts.add('archives', indyJar)
         }
+        def grooidJar = new File(archive.parent, archive.name[0..archive.name.lastIndexOf('.')-1]+'-grooid.jar')
+        if (grooidJar.exists()) {
+            project.artifacts.add('archives', grooidJar)
+        }
     }
 }
 ext.pomAll = {
diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..0569213
Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index af4380b..598a03d 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
 distributionPath=wrapper/dists
 zipStoreBase=GRADLE_USER_HOME
 zipStorePath=wrapper/dists
-distributionUrl=http\://services.gradle.org/distributions/gradle-1.12-all.zip
+distributionUrl=http\://services.gradle.org/distributions/gradle-2.2.1-bin.zip
diff --git a/lib/openbeans-1.0.jar b/lib/openbeans-1.0.jar
new file mode 100644
index 0000000..7e61907
Binary files /dev/null and b/lib/openbeans-1.0.jar differ
diff --git a/security/GroovyJarTest.jar b/security/GroovyJarTest.jar
new file mode 100644
index 0000000..eb59c7d
Binary files /dev/null and b/security/GroovyJarTest.jar differ
diff --git a/src/examples/astbuilder/Main.groovy b/src/examples/astbuilder/Main.groovy
index b5c209e..200e8e3 100644
--- a/src/examples/astbuilder/Main.groovy
+++ b/src/examples/astbuilder/Main.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package examples.astbuilder
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass
diff --git a/src/examples/astbuilder/MainExample.groovy b/src/examples/astbuilder/MainExample.groovy
index 109381e..9a40da6 100644
--- a/src/examples/astbuilder/MainExample.groovy
+++ b/src/examples/astbuilder/MainExample.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package examples.astbuilder
 
 /**
diff --git a/src/examples/astbuilder/MainIntegrationTest.groovy b/src/examples/astbuilder/MainIntegrationTest.groovy
index 5db870f..5a98527 100644
--- a/src/examples/astbuilder/MainIntegrationTest.groovy
+++ b/src/examples/astbuilder/MainIntegrationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package examples.astbuilder
 
 import org.codehaus.groovy.tools.ast.TransformTestHelper
diff --git a/src/examples/astbuilder/MainTransformation.groovy b/src/examples/astbuilder/MainTransformation.groovy
index 97a239d..117d8b8 100644
--- a/src/examples/astbuilder/MainTransformation.groovy
+++ b/src/examples/astbuilder/MainTransformation.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package examples.astbuilder
 
 import org.codehaus.groovy.ast.*
diff --git a/src/examples/commandLineTools/AntMap.groovy b/src/examples/commandLineTools/AntMap.groovy
index c8e92fd..70a25ce 100644
--- a/src/examples/commandLineTools/AntMap.groovy
+++ b/src/examples/commandLineTools/AntMap.groovy
@@ -1,5 +1,20 @@
 #!/bin/env groovy
-// 
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
 // convert an ant build file into a format suitable for http://sf.net/projects/freemind
 //
 // by Jeremy Rayner - 2 Dec 2004
diff --git a/src/examples/commandLineTools/BigTests.groovy b/src/examples/commandLineTools/BigTests.groovy
index 3189ed8..e71358f 100644
--- a/src/examples/commandLineTools/BigTests.groovy
+++ b/src/examples/commandLineTools/BigTests.groovy
@@ -1,5 +1,20 @@
 #!/bin/env groovy
-// 
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+//
 // output tests in a junit xml report that took greater than specified time
 //
 // by Jeremy Rayner - 15 Dec 2004
diff --git a/src/examples/commandLineTools/Reflections.groovy b/src/examples/commandLineTools/Reflections.groovy
index fdeeef9..d10b55c 100644
--- a/src/examples/commandLineTools/Reflections.groovy
+++ b/src/examples/commandLineTools/Reflections.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Echoes back whatever is thrown at it (with a <br> at end for browsers) ...
  * @author <a href="mailto:jeremy.rayner at gmail.com">Jeremy Rayner</a>
diff --git a/src/examples/commandLineTools/SimpleWebServer.groovy b/src/examples/commandLineTools/SimpleWebServer.groovy
index 0815108..156b6a6 100644
--- a/src/examples/commandLineTools/SimpleWebServer.groovy
+++ b/src/examples/commandLineTools/SimpleWebServer.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Simple web server
  * @author <a href="mailto:jeremy.rayner at gmail.com">Jeremy Rayner</a>
diff --git a/src/examples/console/MortgageCalculator.groovy b/src/examples/console/MortgageCalculator.groovy
index e0c69c6..7d70b78 100644
--- a/src/examples/console/MortgageCalculator.groovy
+++ b/src/examples/console/MortgageCalculator.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /** 
  * Mortgage Calculator
  * @author: Jeremy Rayner
diff --git a/src/examples/console/knowYourTables.groovy b/src/examples/console/knowYourTables.groovy
index fbba15b..8afbcec 100644
--- a/src/examples/console/knowYourTables.groovy
+++ b/src/examples/console/knowYourTables.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /** 
  * Simple mathematics quiz
  * @author: Jeremy Rayner
diff --git a/src/examples/console/thinkOfANumber.groovy b/src/examples/console/thinkOfANumber.groovy
index d62c9ec..e7aab7a 100644
--- a/src/examples/console/thinkOfANumber.groovy
+++ b/src/examples/console/thinkOfANumber.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /** 
  * Simple game
  * @author: Jeremy Rayner
diff --git a/src/examples/groovy/j2ee/CreateData.groovy b/src/examples/groovy/j2ee/CreateData.groovy
index a09f7a2..6a7c825 100644
--- a/src/examples/groovy/j2ee/CreateData.groovy
+++ b/src/examples/groovy/j2ee/CreateData.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 println("Called with context: " + context)
 
 db = context.lookup("/client/tools/DatabaseHome").create()
diff --git a/src/examples/groovy/swing/MyTableModel.java b/src/examples/groovy/swing/MyTableModel.java
index 0ae65d7..9360185 100644
--- a/src/examples/groovy/swing/MyTableModel.java
+++ b/src/examples/groovy/swing/MyTableModel.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing;
 
 import java.util.logging.Level;
diff --git a/src/examples/groovy/swing/SwingDemo.groovy b/src/examples/groovy/swing/SwingDemo.groovy
index 87b8b67..79ae803 100644
--- a/src/examples/groovy/swing/SwingDemo.groovy
+++ b/src/examples/groovy/swing/SwingDemo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing
 
 import java.awt.BorderLayout
diff --git a/src/examples/groovy/swing/TableDemo.groovy b/src/examples/groovy/swing/TableDemo.groovy
index 258bdc7..17920f4 100644
--- a/src/examples/groovy/swing/TableDemo.groovy
+++ b/src/examples/groovy/swing/TableDemo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing
 
 import java.awt.BorderLayout
diff --git a/src/examples/groovy/swing/TableLayoutDemo.groovy b/src/examples/groovy/swing/TableLayoutDemo.groovy
index b29c7db..012588d 100644
--- a/src/examples/groovy/swing/TableLayoutDemo.groovy
+++ b/src/examples/groovy/swing/TableLayoutDemo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing
 
 import java.awt.BorderLayout
diff --git a/src/examples/groovy2d/paintingByNumbers.groovy b/src/examples/groovy2d/paintingByNumbers.groovy
index a112ef5..ce3c49a 100644
--- a/src/examples/groovy2d/paintingByNumbers.groovy
+++ b/src/examples/groovy2d/paintingByNumbers.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /** 
  * Simple patchwork graphics demo
  * @author: Jeremy Rayner, changes by Dierk Koenig
diff --git a/src/examples/groovyShell/ArithmeticShell.groovy b/src/examples/groovyShell/ArithmeticShell.groovy
index 1f54d2a..d634ba6 100644
--- a/src/examples/groovyShell/ArithmeticShell.groovy
+++ b/src/examples/groovyShell/ArithmeticShell.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.ImportCustomizer
diff --git a/src/examples/groovyShell/ArithmeticShellTest.groovy b/src/examples/groovyShell/ArithmeticShellTest.groovy
index b960e20..e1d7a60 100644
--- a/src/examples/groovyShell/ArithmeticShellTest.groovy
+++ b/src/examples/groovyShell/ArithmeticShellTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 /**
 * Unit test for ArithmeticShell.
diff --git a/src/examples/groovyShell/BlacklistingShell.groovy b/src/examples/groovyShell/BlacklistingShell.groovy
index d2961dc..a332782 100644
--- a/src/examples/groovyShell/BlacklistingShell.groovy
+++ b/src/examples/groovyShell/BlacklistingShell.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.control.CompilerConfiguration
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.control.customizers.SecureASTCustomizer
diff --git a/src/examples/groovyShell/BlacklistingShellTest.groovy b/src/examples/groovyShell/BlacklistingShellTest.groovy
index 0a0b59f..ae91304 100644
--- a/src/examples/groovyShell/BlacklistingShellTest.groovy
+++ b/src/examples/groovyShell/BlacklistingShellTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
 * Unit test for BlacklistingShell.
 * Requires JUnit to be in path, just like any other GroovyTestCase. 
diff --git a/src/examples/org/codehaus/groovy/grails/compiler/injection/DomainClass.java b/src/examples/org/codehaus/groovy/grails/compiler/injection/DomainClass.java
index bd2e61f..b48b0d4 100644
--- a/src/examples/org/codehaus/groovy/grails/compiler/injection/DomainClass.java
+++ b/src/examples/org/codehaus/groovy/grails/compiler/injection/DomainClass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.grails.compiler.injection;
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
diff --git a/src/examples/osgi/build.properties b/src/examples/osgi/build.properties
index f5c37bb..869c07b 100644
--- a/src/examples/osgi/build.properties
+++ b/src/examples/osgi/build.properties
@@ -1,3 +1,19 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 # groovy bin dir is required to locate the groovy jar 
 # in case it's not on the classpath
 groovy.bin.dir=../../../target/dist
diff --git a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/Activator.groovy b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/Activator.groovy
index e8670df..e5b4255 100644
--- a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/Activator.groovy
+++ b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/Activator.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.osgi
 
 import org.osgi.framework.BundleActivator
diff --git a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeter.groovy b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeter.groovy
index 243e175..b407dcc 100644
--- a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeter.groovy
+++ b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeter.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.osgi
 
 /**
diff --git a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeterImpl.groovy b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeterImpl.groovy
index 6b40085..87cc3bf 100644
--- a/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeterImpl.groovy
+++ b/src/examples/osgi/hello-groovy-bundle/org/codehaus/groovy/osgi/GroovyGreeterImpl.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.osgi
 
 /**
diff --git a/src/examples/searchEngine/Indexer.groovy b/src/examples/searchEngine/Indexer.groovy
index 185f782..e51fbcf 100644
--- a/src/examples/searchEngine/Indexer.groovy
+++ b/src/examples/searchEngine/Indexer.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.apache.lucene.analysis.standard.StandardAnalyzer
 import org.apache.lucene.document.Document
 import org.apache.lucene.document.Field
diff --git a/src/examples/searchEngine/Searcher.groovy b/src/examples/searchEngine/Searcher.groovy
index 86d8ade..9d70ed4 100644
--- a/src/examples/searchEngine/Searcher.groovy
+++ b/src/examples/searchEngine/Searcher.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.apache.lucene.analysis.standard.StandardAnalyzer
 import org.apache.lucene.queryparser.classic.QueryParser
 import org.apache.lucene.search.IndexSearcher
diff --git a/src/examples/swing/BloglinesClient.groovy b/src/examples/swing/BloglinesClient.groovy
index 3d5b6a9..a617906 100644
--- a/src/examples/swing/BloglinesClient.groovy
+++ b/src/examples/swing/BloglinesClient.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
  * BloglinesClient.groovy - an example of the Bloglines Web Services
  *
  * Written by Marc Hedlund <marc at precipice.org>, September 2004.
diff --git a/src/examples/swing/ModelNodeExample.groovy b/src/examples/swing/ModelNodeExample.groovy
index 2ab4d6c..7cf5ea0 100644
--- a/src/examples/swing/ModelNodeExample.groovy
+++ b/src/examples/swing/ModelNodeExample.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.swing.SwingBuilder
 import static javax.swing.WindowConstants.*
 import static java.awt.GridBagConstraints.*
diff --git a/src/examples/swing/RegexCoach.groovy b/src/examples/swing/RegexCoach.groovy
index d362948..3c6bdfe 100644
--- a/src/examples/swing/RegexCoach.groovy
+++ b/src/examples/swing/RegexCoach.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Groovy Regex Coach - Copyright 2007 Jeremy Rayner
 // inspired by http://weitz.de/regex-coach/
 
diff --git a/src/examples/swing/RegexCoachController.groovy b/src/examples/swing/RegexCoachController.groovy
index aa628ef..946afaa 100644
--- a/src/examples/swing/RegexCoachController.groovy
+++ b/src/examples/swing/RegexCoachController.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Groovy Regex Coach - Copyright 2007 Jeremy Rayner
 
 import groovy.swing.SwingBuilder
diff --git a/src/examples/swing/RegexCoachView.groovy b/src/examples/swing/RegexCoachView.groovy
index fad61b8..5fe3067 100644
--- a/src/examples/swing/RegexCoachView.groovy
+++ b/src/examples/swing/RegexCoachView.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import static java.awt.BorderLayout.*
 import static javax.swing.JSplitPane.VERTICAL_SPLIT
 import static javax.swing.WindowConstants.EXIT_ON_CLOSE
diff --git a/src/examples/swing/Widgets.groovy b/src/examples/swing/Widgets.groovy
index 40944f4..4a0e1fd 100644
--- a/src/examples/swing/Widgets.groovy
+++ b/src/examples/swing/Widgets.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing
 
 import java.awt.Color
diff --git a/src/examples/swing/binding/caricature/Caricature.groovy b/src/examples/swing/binding/caricature/Caricature.groovy
index 9448ad3..1f87e37 100644
--- a/src/examples/swing/binding/caricature/Caricature.groovy
+++ b/src/examples/swing/binding/caricature/Caricature.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing.binding.caricature
 
 import groovy.swing.SwingBuilder
diff --git a/src/examples/swing/binding/caricature/JCaricature.java b/src/examples/swing/binding/caricature/JCaricature.java
index 2e448ed..0e26cfc 100644
--- a/src/examples/swing/binding/caricature/JCaricature.java
+++ b/src/examples/swing/binding/caricature/JCaricature.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /*
  * Caricature.java
  *
diff --git a/src/examples/swing/greet/Greet.groovy b/src/examples/swing/greet/Greet.groovy
index 15b10ca..0e9875f 100644
--- a/src/examples/swing/greet/Greet.groovy
+++ b/src/examples/swing/greet/Greet.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
  * Created by IntelliJ IDEA.
  * User: Danno.Ferrin
  * Date: Apr 26, 2008
diff --git a/src/examples/swing/greet/TwitterAPI.groovy b/src/examples/swing/greet/TwitterAPI.groovy
index b907afb..5b7eeb7 100644
--- a/src/examples/swing/greet/TwitterAPI.groovy
+++ b/src/examples/swing/greet/TwitterAPI.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Created by IntelliJ IDEA.
  * User: Danno.Ferrin
diff --git a/src/examples/swing/greet/View.groovy b/src/examples/swing/greet/View.groovy
index 345d138..6866b64 100644
--- a/src/examples/swing/greet/View.groovy
+++ b/src/examples/swing/greet/View.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Created by IntelliJ IDEA.
  * User: Danno.Ferrin
diff --git a/src/examples/swing/timelog/TimeLogMain.groovy b/src/examples/swing/timelog/TimeLogMain.groovy
index 767aaa6..dc916c2 100644
--- a/src/examples/swing/timelog/TimeLogMain.groovy
+++ b/src/examples/swing/timelog/TimeLogMain.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing.timelog
 
 import groovy.swing.SwingBuilder
diff --git a/src/examples/swing/timelog/TimeLogModel.groovy b/src/examples/swing/timelog/TimeLogModel.groovy
index 5f2a6e7..42fa06c 100644
--- a/src/examples/swing/timelog/TimeLogModel.groovy
+++ b/src/examples/swing/timelog/TimeLogModel.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing.timelog
 
 import groovy.beans.Bindable
diff --git a/src/examples/swing/timelog/TimeLogView.groovy b/src/examples/swing/timelog/TimeLogView.groovy
index 9d1c729..5555281 100644
--- a/src/examples/swing/timelog/TimeLogView.groovy
+++ b/src/examples/swing/timelog/TimeLogView.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing.timelog
 
 import java.text.SimpleDateFormat
diff --git a/src/examples/transforms/global/CompiledAtASTTransformation.groovy b/src/examples/transforms/global/CompiledAtASTTransformation.groovy
index ae8cc09..6fc212c 100755
--- a/src/examples/transforms/global/CompiledAtASTTransformation.groovy
+++ b/src/examples/transforms/global/CompiledAtASTTransformation.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.global
 
 import org.codehaus.groovy.ast.*
diff --git a/src/examples/transforms/global/CompiledAtExample.groovy b/src/examples/transforms/global/CompiledAtExample.groovy
index 654b518..58a30a4 100755
--- a/src/examples/transforms/global/CompiledAtExample.groovy
+++ b/src/examples/transforms/global/CompiledAtExample.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.global
 
 /**
diff --git a/src/examples/transforms/global/CompiledAtIntegrationTest.groovy b/src/examples/transforms/global/CompiledAtIntegrationTest.groovy
index 1eab350..9fbeff4 100644
--- a/src/examples/transforms/global/CompiledAtIntegrationTest.groovy
+++ b/src/examples/transforms/global/CompiledAtIntegrationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import transforms.global.CompiledAtASTTransformation 
 import org.codehaus.groovy.ast.*
 import org.codehaus.groovy.transform.*
diff --git a/src/examples/transforms/global/LoggingASTTransformation.groovy b/src/examples/transforms/global/LoggingASTTransformation.groovy
index bd9b84a..2f965c9 100644
--- a/src/examples/transforms/global/LoggingASTTransformation.groovy
+++ b/src/examples/transforms/global/LoggingASTTransformation.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.global
 
 import org.codehaus.groovy.transform.ASTTransformation
diff --git a/src/examples/transforms/global/LoggingExample.groovy b/src/examples/transforms/global/LoggingExample.groovy
index a6dcddb..5fb35c2 100644
--- a/src/examples/transforms/global/LoggingExample.groovy
+++ b/src/examples/transforms/global/LoggingExample.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.global
 
 /**
diff --git a/src/examples/transforms/local/LoggingASTTransformation.groovy b/src/examples/transforms/local/LoggingASTTransformation.groovy
index dc6885b..fd9c0c9 100644
--- a/src/examples/transforms/local/LoggingASTTransformation.groovy
+++ b/src/examples/transforms/local/LoggingASTTransformation.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.local
 
 import org.codehaus.groovy.transform.ASTTransformation
diff --git a/src/examples/transforms/local/LoggingExample.groovy b/src/examples/transforms/local/LoggingExample.groovy
index f3e1015..3053fed 100644
--- a/src/examples/transforms/local/LoggingExample.groovy
+++ b/src/examples/transforms/local/LoggingExample.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.local
 
 /**
diff --git a/src/examples/transforms/local/WithLogging.groovy b/src/examples/transforms/local/WithLogging.groovy
index 35b2f18..ed3e862 100644
--- a/src/examples/transforms/local/WithLogging.groovy
+++ b/src/examples/transforms/local/WithLogging.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package transforms.local
 import java.lang.annotation.Retention
 import java.lang.annotation.Target
diff --git a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy
index 3cdaa17..f27477c 100644
--- a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy
+++ b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/Animal.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 interface Animal {
 
   String saySomething(String something);
diff --git a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy
index 494d5a8..e8e5442 100644
--- a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy
+++ b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/Fish.groovy
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package zoo
 
 abstract class Fish implements Animal {
 
   String saySomething(String something) {
-    return "Blubb�: " + something + "..."
+    return "Blubb�: " + something + "..."
   }
 
 }
diff --git a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy
index afdf10c..4864580 100644
--- a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy
+++ b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Shark.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package zoo.fish
 
 import zoo.Fish
@@ -5,7 +20,7 @@ import zoo.Fish
 class Shark extends Fish {
 
   String saySomething(String something) {
-    return "Shark bites " + something + "...ROOOAR�!"
+    return "Shark bites " + something + "...ROOOAR�!"
   }
 
 }
diff --git a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy
index faa8f03..58f4aee 100644
--- a/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy
+++ b/src/examples/webapps/groovlet-examples/WEB-INF/groovy/zoo/fish/Trout.groovy
@@ -1,9 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package zoo.fish
 
 class Trout extends zoo.Fish {
 
   String saySomething(String something) {
-    return "Trout says " + something + "...blubb�!"
+    return "Trout says " + something + "...blubb�!"
   }
 
 }
diff --git a/src/examples/webapps/groovlet-examples/codehaus-style.css b/src/examples/webapps/groovlet-examples/codehaus-style.css
index a5cf0dd..2417a45 100644
--- a/src/examples/webapps/groovlet-examples/codehaus-style.css
+++ b/src/examples/webapps/groovlet-examples/codehaus-style.css
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 body {
   font-family: Verdana, Helvetica, Arial, sans-serif;
diff --git a/src/examples/webapps/groovlet-examples/hello/hello.groovy b/src/examples/webapps/groovlet-examples/hello/hello.groovy
index 74e97cd..a01229d 100644
--- a/src/examples/webapps/groovlet-examples/hello/hello.groovy
+++ b/src/examples/webapps/groovlet-examples/hello/hello.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 println """
 <html>
     <head>
diff --git a/src/examples/webapps/groovlet-examples/index.groovy b/src/examples/webapps/groovlet-examples/index.groovy
index 534201b..d91b56e 100644
--- a/src/examples/webapps/groovlet-examples/index.groovy
+++ b/src/examples/webapps/groovlet-examples/index.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 println """
 
 <!-- Groovy Groovlet Examples. -->
diff --git a/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy b/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy
index 760e55f..7d76455 100644
--- a/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy
+++ b/src/examples/webapps/groovlet-examples/zoo/HommingbergerGepardenforelle.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package zoo
 
 class HommingbergerGepardenforelle extends zoo.fish.Trout {
diff --git a/src/examples/webapps/groovlet-examples/zoo/visit.groovy b/src/examples/webapps/groovlet-examples/zoo/visit.groovy
index 21abe87..9c7caf1 100644
--- a/src/examples/webapps/groovlet-examples/zoo/visit.groovy
+++ b/src/examples/webapps/groovlet-examples/zoo/visit.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 Animal shark = new zoo.fish.Shark()
 Animal trout = new zoo.fish.Trout()
 Animal forelle = new zoo.HommingbergerGepardenforelle()
diff --git a/src/examples/webapps/groovlet-examples/zoo/zoo.groovy b/src/examples/webapps/groovlet-examples/zoo/zoo.groovy
index 27118db..768514f 100644
--- a/src/examples/webapps/groovlet-examples/zoo/zoo.groovy
+++ b/src/examples/webapps/groovlet-examples/zoo/zoo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 println """
 <html>
     <head>
diff --git a/src/examples/webapps/template-examples/3.times.HelloWorld.html b/src/examples/webapps/template-examples/3.times.HelloWorld.html
index 39eec70..68bbc16 100644
--- a/src/examples/webapps/template-examples/3.times.HelloWorld.html
+++ b/src/examples/webapps/template-examples/3.times.HelloWorld.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <body>
 
diff --git a/src/main/META-INF/groovy-release-info.properties b/src/main/META-INF/groovy-release-info.properties
index b7c588c..54926bb 100644
--- a/src/main/META-INF/groovy-release-info.properties
+++ b/src/main/META-INF/groovy-release-info.properties
@@ -1,3 +1,19 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 ImplementationVersion=#ImplementationVersion#
 BundleVersion=#BundleVersion#
 BuildDate=#BuildDate#
diff --git a/src/main/groovy/beans/BindableASTTransformation.java b/src/main/groovy/beans/BindableASTTransformation.java
index 2b25c91..802a5f2 100644
--- a/src/main/groovy/beans/BindableASTTransformation.java
+++ b/src/main/groovy/beans/BindableASTTransformation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2013 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -341,7 +341,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "addPropertyChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(pclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -354,7 +354,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "addPropertyChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(pclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -367,7 +367,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "removePropertyChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(pclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -377,7 +377,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "removePropertyChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(pclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -390,7 +390,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "firePropertyChange",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(ClassHelper.OBJECT_TYPE, "oldValue"), param(ClassHelper.OBJECT_TYPE, "newValue")),
                         ClassNode.EMPTY_ARRAY,
@@ -403,7 +403,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "getPropertyChangeListeners",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         pclClassNode.makeArray(),
                         Parameter.EMPTY_ARRAY,
                         ClassNode.EMPTY_ARRAY,
@@ -416,7 +416,7 @@ public class BindableASTTransformation implements ASTTransformation, Opcodes {
         declaringClass.addMethod(
                 new MethodNode(
                         "getPropertyChangeListeners",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         pclClassNode.makeArray(),
                         params(param(ClassHelper.STRING_TYPE, "name")),
                         ClassNode.EMPTY_ARRAY,
diff --git a/src/main/groovy/beans/VetoableASTTransformation.java b/src/main/groovy/beans/VetoableASTTransformation.java
index 81592be..d3d3507 100644
--- a/src/main/groovy/beans/VetoableASTTransformation.java
+++ b/src/main/groovy/beans/VetoableASTTransformation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2013 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -354,7 +354,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "addVetoableChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(vclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -367,7 +367,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "addVetoableChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(vclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -380,7 +380,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "removeVetoableChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(vclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -390,7 +390,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "removeVetoableChangeListener",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(vclClassNode, "listener")),
                         ClassNode.EMPTY_ARRAY,
@@ -405,7 +405,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "fireVetoableChange",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         ClassHelper.VOID_TYPE,
                         params(param(ClassHelper.STRING_TYPE, "name"), param(ClassHelper.OBJECT_TYPE, "oldValue"), param(ClassHelper.OBJECT_TYPE, "newValue")),
                         new ClassNode[] {ClassHelper.make(PropertyVetoException.class)},
@@ -418,7 +418,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "getVetoableChangeListeners",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         vclClassNode.makeArray(),
                         Parameter.EMPTY_ARRAY,
                         ClassNode.EMPTY_ARRAY,
@@ -431,7 +431,7 @@ public class VetoableASTTransformation extends BindableASTTransformation {
         declaringClass.addMethod(
                 new MethodNode(
                         "getVetoableChangeListeners",
-                        ACC_PUBLIC | ACC_SYNTHETIC,
+                        ACC_PUBLIC,
                         vclClassNode.makeArray(),
                         params(param(ClassHelper.STRING_TYPE, "name")),
                         ClassNode.EMPTY_ARRAY,
diff --git a/src/main/groovy/grape/GrabAnnotationTransformation.java b/src/main/groovy/grape/GrabAnnotationTransformation.java
index 1e28508..a5d448b 100644
--- a/src/main/groovy/grape/GrabAnnotationTransformation.java
+++ b/src/main/groovy/grape/GrabAnnotationTransformation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -57,6 +57,8 @@ import java.util.*;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
+import static org.codehaus.groovy.transform.AbstractASTTransformation.getMemberStringValue;
+
 /**
  * Transformation for declarative dependency management.
  */
@@ -222,19 +224,12 @@ public class GrabAnnotationTransformation extends ClassCodeVisitorSupport implem
                 grabResolverAnnotationLoop:
                 for (AnnotationNode node : grabResolverAnnotations) {
                     Map<String, Object> grabResolverMap = new HashMap<String, Object>();
-                    Expression value = node.getMember("value");
-                    ConstantExpression ce = null;
-                    if (value != null && value instanceof ConstantExpression) {
-                        ce = (ConstantExpression) value;
-                    }
-                    String sval = null;
-                    if (ce != null && ce.getValue() instanceof String) {
-                        sval = (String) ce.getValue();
-                    }
+                    String sval = getMemberStringValue(node, "value");
                     if (sval != null && sval.length() > 0) {
                         for (String s : GRABRESOLVER_REQUIRED) {
-                            Expression member = node.getMember(s);
-                            if (member != null) {
+                            String mval = getMemberStringValue(node, s);
+                            if (mval != null && mval.isEmpty()) mval = null;
+                            if (mval != null) {
                                 addError("The attribute \"" + s + "\" conflicts with attribute 'value' in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                 continue grabResolverAnnotationLoop;
                             }
@@ -243,15 +238,17 @@ public class GrabAnnotationTransformation extends ClassCodeVisitorSupport implem
                         grabResolverMap.put("root", sval);
                     } else {
                         for (String s : GRABRESOLVER_REQUIRED) {
+                            String mval = getMemberStringValue(node, s);
+                            if (mval != null && mval.isEmpty()) mval = null;
                             Expression member = node.getMember(s);
-                            if (member == null) {
+                            if (member == null || mval == null) {
                                 addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                 continue grabResolverAnnotationLoop;
-                            } else if (member != null && !(member instanceof ConstantExpression)) {
-                                addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
+                            } else if (mval == null) {
+                                addError("Attribute \"" + s + "\" has value " + member.getText() + " but should be an inline constant String in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                                 continue grabResolverAnnotationLoop;
                             }
-                            grabResolverMap.put(s, ((ConstantExpression) member).getValue());
+                            grabResolverMap.put(s, mval);
                         }
                     }
 
@@ -324,6 +321,8 @@ public class GrabAnnotationTransformation extends ClassCodeVisitorSupport implem
                     checkForConvenienceForm(node, false);
                     for (String s : GRAB_ALL) {
                         Expression member = node.getMember(s);
+                        String mval = getMemberStringValue(node, s);
+                        if (mval != null && mval.isEmpty()) member = null;
                         if (member == null && !GRAB_OPTIONAL.contains(s)) {
                             addError("The missing attribute \"" + s + "\" is required in @" + node.getClassNode().getNameWithoutPackage() + " annotations", node);
                             continue grabAnnotationLoop;
@@ -336,8 +335,7 @@ public class GrabAnnotationTransformation extends ClassCodeVisitorSupport implem
                         }
                     }
                     grabMaps.add(grabMap);
-                    if ((node.getMember("initClass") == null)
-                            || (node.getMember("initClass") == ConstantExpression.TRUE)) {
+                    if ((node.getMember("initClass") == null) || (node.getMember("initClass") == ConstantExpression.TRUE)) {
                         grabMapsInit.add(grabMap);
                     }
                 }
diff --git a/src/main/groovy/grape/GrapeIvy.groovy b/src/main/groovy/grape/GrapeIvy.groovy
index 9536f40..1d84e15 100644
--- a/src/main/groovy/grape/GrapeIvy.groovy
+++ b/src/main/groovy/grape/GrapeIvy.groovy
@@ -15,6 +15,8 @@
  */
 package groovy.grape
 
+import org.codehaus.groovy.reflection.ReflectionCache
+
 import java.util.regex.Pattern
 import org.apache.ivy.Ivy
 import org.apache.ivy.core.cache.ResolutionCacheManager
@@ -290,17 +292,12 @@ class GrapeIvy implements GrapeEngine {
                         metaMethods.each { CachedClass c, List<MetaMethod> methods ->
                             // GROOVY-5543: if a module was loaded using grab, there are chances that subclasses
                             // have their own ClassInfo, and we must change them as well!
-                            def classesToBeUpdated = ClassInfo.allClassInfo.findAll {
-                                boolean found = false
-                                CachedClass current = it.cachedClass
-                                while (!found && current != null) {
-                                    if (current == c || current.interfaces.contains(c)) {
-                                        found = true
-                                    }
-                                    current = current.cachedSuperClass
+                            Set<CachedClass> classesToBeUpdated = [c]
+                            ClassInfo.onAllClassInfo { ClassInfo info ->
+                                if (c.theClass.isAssignableFrom(info.cachedClass.theClass)) {
+                                    classesToBeUpdated << info.cachedClass
                                 }
-                                found
-                            }.collect { it.cachedClass }
+                            }
                             classesToBeUpdated*.addNewMopMethods(methods)
                         }
                     }
diff --git a/src/main/groovy/lang/BenchmarkInterceptor.java b/src/main/groovy/lang/BenchmarkInterceptor.java
index c4118a3..450aba4 100644
--- a/src/main/groovy/lang/BenchmarkInterceptor.java
+++ b/src/main/groovy/lang/BenchmarkInterceptor.java
@@ -57,19 +57,37 @@ public class BenchmarkInterceptor implements Interceptor {
     public void reset() {
         calls = new HashMap();
     }
-
+    /**
+     * This code is executed before the method is called.
+     * @param object        receiver object for the method call
+     * @param methodName    name of the method to call
+     * @param arguments     arguments to the method call
+     * @return null
+     * relays this result.
+     */
     public Object beforeInvoke(Object object, String methodName, Object[] arguments) {
         if (!calls.containsKey(methodName)) calls.put(methodName, new LinkedList());
         ((List) calls.get(methodName)).add(new Long(System.currentTimeMillis()));
 
         return null;
     }
-
+    /**
+     * This code is executed after the method is called.
+     * @param object        receiver object for the called method
+     * @param methodName    name of the called method
+     * @param arguments     arguments to the called method
+     * @param result        result of the executed method call or result of beforeInvoke if method was not called
+     * @return result
+     */
     public Object afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
         ((List) calls.get(methodName)).add(new Long(System.currentTimeMillis()));
         return result;
     }
 
+    /**
+     *The call should be invoked seperately
+     *@return true
+     */
     public boolean doInvoke() {
         return true;
     }
diff --git a/src/main/groovy/lang/DelegatesTo.java b/src/main/groovy/lang/DelegatesTo.java
index 2352281..c0d149f 100644
--- a/src/main/groovy/lang/DelegatesTo.java
+++ b/src/main/groovy/lang/DelegatesTo.java
@@ -50,6 +50,18 @@ public @interface DelegatesTo {
 
     String target() default "";
 
+    /**
+     * The type member should be used when the type of the delagate cannot
+     * be represented with {@link #value()}, {@link #genericTypeIndex()} or
+     * {@link #target()}. In this case, it is possible to use a String to represent
+     * the type, at the cost of potential uncatched errors at compile time if the
+     * type is invalid and increased compile time.
+     *
+     * @return a String representation of a type
+     * @since 2.4.0
+     */
+    String type() default "";
+
     @Retention(RetentionPolicy.RUNTIME)
     @java.lang.annotation.Target({ElementType.PARAMETER})
     public static @interface Target {
diff --git a/src/main/groovy/lang/ExpandoMetaClass.java b/src/main/groovy/lang/ExpandoMetaClass.java
index 951dbe6..69e651e 100644
--- a/src/main/groovy/lang/ExpandoMetaClass.java
+++ b/src/main/groovy/lang/ExpandoMetaClass.java
@@ -52,6 +52,7 @@ import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod;
 import org.codehaus.groovy.runtime.metaclass.OwnedMetaClass;
 import org.codehaus.groovy.runtime.metaclass.ThreadManagedMetaBeanProperty;
 import org.codehaus.groovy.util.FastArray;
+import org.objectweb.asm.Opcodes;
 
 /**
  * ExpandoMetaClass is a MetaClass that behaves like an Expando, allowing the addition or replacement
@@ -253,6 +254,7 @@ import org.codehaus.groovy.util.FastArray;
  */
 public class ExpandoMetaClass extends MetaClassImpl implements GroovyObject {
 
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
     private static final String META_CLASS = "metaClass";
     private static final String CLASS = "class";
     private static final String META_METHODS = "metaMethods";
@@ -280,16 +282,16 @@ public class ExpandoMetaClass extends MetaClassImpl implements GroovyObject {
     public boolean inRegistry;
     
     private final Set<MetaMethod> inheritedMetaMethods = new HashSet<MetaMethod>();
-    private final Map<String, MetaProperty> beanPropertyCache = new ConcurrentHashMap<String, MetaProperty>();
-    private final Map<String, MetaProperty> staticBeanPropertyCache = new ConcurrentHashMap<String, MetaProperty>();
-    private final Map<MethodKey, MetaMethod> expandoMethods = new ConcurrentHashMap<MethodKey, MetaMethod>();
+    private final Map<String, MetaProperty> beanPropertyCache = new ConcurrentHashMap<String, MetaProperty>(16, 0.75f, 1);
+    private final Map<String, MetaProperty> staticBeanPropertyCache = new ConcurrentHashMap<String, MetaProperty>(16, 0.75f, 1);
+    private final Map<MethodKey, MetaMethod> expandoMethods = new ConcurrentHashMap<MethodKey, MetaMethod>(16, 0.75f, 1);
 
     public Collection getExpandoSubclassMethods() {
         return expandoSubclassMethods.values();
     }
 
-    private final ConcurrentHashMap expandoSubclassMethods = new ConcurrentHashMap();
-    private final Map<String, MetaProperty> expandoProperties = new ConcurrentHashMap<String, MetaProperty>();
+    private final ConcurrentHashMap expandoSubclassMethods = new ConcurrentHashMap(16, 0.75f, 1);
+    private final Map<String, MetaProperty> expandoProperties = new ConcurrentHashMap<String, MetaProperty>(16, 0.75f, 1);
     private ClosureStaticMetaMethod invokeStaticMethodMethod;
     private final Set<MixinInMetaClass> mixinClasses = new LinkedHashSet<MixinInMetaClass>();
 
@@ -365,11 +367,11 @@ public class ExpandoMetaClass extends MetaClassImpl implements GroovyObject {
                 MetaMethod method = new MixinInstanceMetaMethod(metaMethod, mixin);
 
                 if (method.getParameterTypes().length == 1 && !method.getParameterTypes()[0].isPrimitive) {
-                    MetaMethod noParam = pickMethod(methodName, new Class[0]);
+                    MetaMethod noParam = pickMethod(methodName, EMPTY_CLASS_ARRAY);
                     // if the current call itself is with empty arg class array, no need to recurse with 'new Class[0]'
                     if (noParam == null && arguments.length != 0) {
                         try {
-                            findMixinMethod(methodName, new Class[0]);
+                            findMixinMethod(methodName, EMPTY_CLASS_ARRAY);
                         } catch (MethodSelectionException msex) {
                             /*
                              * Here we just additionally tried to find another no-arg mixin method of the same name and register that as well, if found.
@@ -950,6 +952,15 @@ public class ExpandoMetaClass extends MetaClassImpl implements GroovyObject {
     private void registerBeanPropertyForMethod(MetaMethod metaMethod, String propertyName, boolean getter, boolean isStatic) {
         Map<String, MetaProperty> propertyCache = isStatic ? staticBeanPropertyCache : beanPropertyCache;
         MetaBeanProperty beanProperty = (MetaBeanProperty) propertyCache.get(propertyName);
+        if (beanProperty==null) {
+            MetaProperty metaProperty = super.getMetaProperty(propertyName);
+            if (metaProperty instanceof MetaBeanProperty) {
+                boolean staticProp = Modifier.isStatic(metaProperty.getModifiers());
+                if (isStatic==staticProp) {
+                    beanProperty = (MetaBeanProperty) metaProperty;
+                }
+            }
+        }
         if (beanProperty == null) {
             if (getter)
                 beanProperty = new MetaBeanProperty(propertyName, Object.class, metaMethod, null);
diff --git a/src/main/groovy/lang/GString.java b/src/main/groovy/lang/GString.java
index ea78a7d..de5420d 100644
--- a/src/main/groovy/lang/GString.java
+++ b/src/main/groovy/lang/GString.java
@@ -15,6 +15,7 @@
  */
 package groovy.lang;
 
+import org.codehaus.groovy.runtime.GStringImpl;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.runtime.StringGroovyMethods;
 
@@ -110,11 +111,7 @@ public abstract class GString extends GroovyObjectSupport implements Comparable,
         stringList.toArray(newStrings);
         Object[] newValues = valueList.toArray();
 
-        return new GString(newValues) {
-            public String[] getStrings() {
-                return newStrings;
-            }
-        };
+        return new GStringImpl(newValues, newStrings);
     }
 
     public GString plus(String that) {
@@ -139,13 +136,7 @@ public abstract class GString extends GroovyObjectSupport implements Comparable,
             newStrings[lastIndex] = that;
         }
 
-        final String[] finalStrings = newStrings;
-        return new GString(newValues) {
-
-            public String[] getStrings() {
-                return finalStrings;
-            }
-        };
+        return new GStringImpl(newValues, newStrings);
     }
 
     public int getValueCount() {
diff --git a/src/main/groovy/lang/Grab.java b/src/main/groovy/lang/Grab.java
index e5e45ab..3443667 100644
--- a/src/main/groovy/lang/Grab.java
+++ b/src/main/groovy/lang/Grab.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -55,19 +55,19 @@ import java.lang.annotation.ElementType;
         ElementType.TYPE})
 public @interface Grab {
     /**
-     * The organisation or group, e.g.: "org.apache.ant"
+     * The organisation or group, e.g.: "org.apache.ant". A non-empty value is required unless value() is used.
      */
     String group() default "";
 
     /**
-     * The module or artifact, e.g.: "ant-junit"
+     * The module or artifact, e.g.: "ant-junit". A non-empty value is required unless value() is used.
      */
-    String module();
+    String module() default "";
 
     /**
-     * The revision or version, e.g.: "1.7.1"
+     * The revision or version, e.g.: "1.7.1". A non-empty value is required unless value() is used.
      */
-    String version();
+    String version() default "";
 
     /**
      * The classifier if in use, e.g.: "jdk14"
@@ -118,6 +118,7 @@ public @interface Grab {
 
     /**
      * Allows a more compact convenience form in one of two formats with optional appended attributes.
+     * Must not be used if group(), module() or version() are used.
      * <p>
      * You can choose either format but not mix-n-match:<br>
      * {@code group:module:version:classifier at ext} (where only group and module are required)<br>
diff --git a/src/main/groovy/lang/GrabExclude.java b/src/main/groovy/lang/GrabExclude.java
index 7aeeb20..ed83e8c 100644
--- a/src/main/groovy/lang/GrabExclude.java
+++ b/src/main/groovy/lang/GrabExclude.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,7 +51,7 @@ public @interface GrabExclude {
     String module() default "";
 
     /**
-     * Allows to specify the group (organisation) and the module (artifact) in a two compact convenience formats,
+     * Allows you to specify the group (organisation) and the module (artifact) in one of two compact convenience formats,
      * e.g.: <code>@GrabExclude('org.apache.ant:ant-junit')</code> or <code>@GrabExclude('org.apache.ant#ant-junit')</code>
      */
     String value() default "";
diff --git a/src/main/groovy/lang/GrabResolver.java b/src/main/groovy/lang/GrabResolver.java
index f6e596f..c53d77d 100644
--- a/src/main/groovy/lang/GrabResolver.java
+++ b/src/main/groovy/lang/GrabResolver.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -51,9 +51,27 @@ import java.lang.annotation.ElementType;
         ElementType.PARAMETER,
         ElementType.TYPE})
 public @interface GrabResolver {
+    /**
+     * Allows a shorthand form which sets the name and root to this value.
+     * Must not be used if name() or root() is non-empty.
+     */
     String value() default "";
-    String name();
-    String root();
+
+    /**
+     * A meaningful name for a repo containing the grape/artifact.
+     * A non-empty value is required unless value() is used.
+     */
+    String name() default "";
+
+    /**
+     * The URL for a repo containing the grape/artifact.
+     * A non-empty value is required unless value() is used.
+     */
+    String root() default "";
+
+    /**
+     * Defaults to Maven2 compatibility. Set false for Ivy only compatibility.
+     */
     boolean m2Compatible() default true;
 
     /**
diff --git a/src/main/groovy/lang/GroovyClassLoader.java b/src/main/groovy/lang/GroovyClassLoader.java
index d053293..fd00e1b 100644
--- a/src/main/groovy/lang/GroovyClassLoader.java
+++ b/src/main/groovy/lang/GroovyClassLoader.java
@@ -23,13 +23,19 @@
  */
 package groovy.lang;
 
+import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.ModuleNode;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.control.*;
 import org.codehaus.groovy.runtime.IOGroovyMethods;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Opcodes;
 
 import java.io.*;
 import java.net.*;
@@ -55,6 +61,8 @@ import java.util.regex.Pattern;
  */
 public class GroovyClassLoader extends URLClassLoader {
 
+    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
+
     /**
      * this cache contains the loaded classes or PARSING, if the class is currently parsed
      */
@@ -119,7 +127,7 @@ public class GroovyClassLoader extends URLClassLoader {
      * @param useConfigurationClasspath determines if the configurations classpath should be added
      */
     public GroovyClassLoader(ClassLoader parent, CompilerConfiguration config, boolean useConfigurationClasspath) {
-        super(new URL[0], parent);
+        super(EMPTY_URL_ARRAY, parent);
         if (config == null) config = CompilerConfiguration.DEFAULT;
         this.config = config;
         if (useConfigurationClasspath) {
@@ -266,6 +274,9 @@ public class GroovyClassLoader extends URLClassLoader {
         validate(codeSource);
         Class answer;  // Was neither already loaded nor compiling, so compile and add to cache.
         CompilationUnit unit = createCompilationUnit(config, codeSource.getCodeSource());
+        if (recompile!=null && recompile || recompile==null && config.getRecompileGroovySource()) {
+            unit.addFirstPhaseOperation(TimestampAdder.INSTANCE, CompilePhase.CLASS_GENERATION.getPhaseNumber());
+        }
         SourceUnit su = null;
         File file = codeSource.getFile();
         if (file != null) {
@@ -335,22 +346,27 @@ public class GroovyClassLoader extends URLClassLoader {
     protected PermissionCollection getPermissions(CodeSource codeSource) {
         PermissionCollection perms;
         try {
-            perms = super.getPermissions(codeSource);
-        } catch (SecurityException e) {
-            // We lied about our CodeSource and that makes URLClassLoader unhappy.
-            perms = new Permissions();
-        }
-
-        ProtectionDomain myDomain = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
-            public ProtectionDomain run() {
-                return getClass().getProtectionDomain();
+            try {
+                perms = super.getPermissions(codeSource);
+            } catch (SecurityException e) {
+                // We lied about our CodeSource and that makes URLClassLoader unhappy.
+                perms = new Permissions();
             }
-        });
-        PermissionCollection myPerms = myDomain.getPermissions();
-        if (myPerms != null) {
-            for (Enumeration<Permission> elements = myPerms.elements(); elements.hasMoreElements();) {
-                perms.add(elements.nextElement());
+
+            ProtectionDomain myDomain = AccessController.doPrivileged(new PrivilegedAction<ProtectionDomain>() {
+                public ProtectionDomain run() {
+                    return getClass().getProtectionDomain();
+                }
+            });
+            PermissionCollection myPerms = myDomain.getPermissions();
+            if (myPerms != null) {
+                for (Enumeration<Permission> elements = myPerms.elements(); elements.hasMoreElements();) {
+                    perms.add(elements.nextElement());
+                }
             }
+        } catch (Throwable e) {
+            // We lied about our CodeSource and that makes URLClassLoader unhappy.
+            perms = new Permissions();
         }
         perms.setReadOnly();
         return perms;
@@ -474,8 +490,13 @@ public class GroovyClassLoader extends URLClassLoader {
         }
 
         protected Class createClass(byte[] code, ClassNode classNode) {
+            BytecodeProcessor bytecodePostprocessor = unit.getConfiguration().getBytecodePostprocessor();
+            byte[] fcode = code;
+            if (bytecodePostprocessor!=null) {
+                fcode = bytecodePostprocessor.processBytecode(classNode.getName(), fcode);
+            }
             GroovyClassLoader cl = getDefiningClassLoader();
-            Class theClass = cl.defineClass(classNode.getName(), code, 0, code.length, unit.getAST().getCodeSource());
+            Class theClass = cl.defineClass(classNode.getName(), fcode, 0, fcode.length, unit.getAST().getCodeSource());
             this.loadedClasses.add(theClass);
 
             if (generatedClass == null) {
@@ -952,4 +973,47 @@ public class GroovyClassLoader extends URLClassLoader {
             sourceCache.clear();
         }
     }
+
+    private static class TimestampAdder extends CompilationUnit.PrimaryClassNodeOperation implements Opcodes {
+        private final static TimestampAdder INSTANCE = new TimestampAdder();
+
+        private TimestampAdder() {}
+
+        protected void addTimeStamp(ClassNode node) {
+            if (node.getDeclaredField(Verifier.__TIMESTAMP) == null) { // in case if verifier visited the call already
+                FieldNode timeTagField = new FieldNode(
+                        Verifier.__TIMESTAMP,
+                        ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC,
+                        ClassHelper.long_TYPE,
+                        //"",
+                        node,
+                        new ConstantExpression(System.currentTimeMillis()));
+                // alternatively, FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
+                timeTagField.setSynthetic(true);
+                node.addField(timeTagField);
+
+                timeTagField = new FieldNode(
+                        Verifier.__TIMESTAMP__ + String.valueOf(System.currentTimeMillis()),
+                        ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC,
+                        ClassHelper.long_TYPE,
+                        //"",
+                        node,
+                        new ConstantExpression((long) 0));
+                // alternatively, FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
+                timeTagField.setSynthetic(true);
+                node.addField(timeTagField);
+            }
+        }
+
+        @Override
+        public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+            if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0) {
+                // does not apply on interfaces
+                return;
+            }
+            if (!(classNode instanceof InnerClassNode)) {
+                addTimeStamp(classNode);
+            }
+        }
+    }
 }
diff --git a/src/main/groovy/lang/GroovyShell.java b/src/main/groovy/lang/GroovyShell.java
index e4ed08a..7917741 100644
--- a/src/main/groovy/lang/GroovyShell.java
+++ b/src/main/groovy/lang/GroovyShell.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -64,6 +64,10 @@ public class GroovyShell extends GroovyObjectSupport {
         this(null, binding);
     }
 
+    public GroovyShell(ClassLoader parent, CompilerConfiguration config) {
+        this(parent, new Binding(), config);
+    }
+
     public GroovyShell(CompilerConfiguration config) {
         this(new Binding(), config);
     }
@@ -239,23 +243,39 @@ public class GroovyShell extends GroovyObjectSupport {
      * }
      */
     private Object runScriptOrMainOrTestOrRunnable(Class scriptClass, String[] args) {
+        // Always set the "args" property, regardless of what path we take in the code.
+        // Bad enough to have side effects but worse if their behavior is wonky.
+        context.setProperty("args", args);
+
         if (scriptClass == null) {
             return null;
         }
+
+        //TODO: This logic mostly duplicates InvokerHelper.createScript.  They should probably be unified.
+
         if (Script.class.isAssignableFrom(scriptClass)) {
             // treat it just like a script if it is one
-            Script script  = null;
             try {
-                script = (Script) scriptClass.newInstance();
+                Constructor constructor = scriptClass.getConstructor(Binding.class);
+                Script script = (Script) constructor.newInstance(context);
+                return script.run();
             } catch (InstantiationException e) {
                 // ignore instantiation errors,, try to do main
             } catch (IllegalAccessException e) {
                // ignore instantiation errors, try to do main
-            }
-            if (script != null) {
-                script.setBinding(context);
-                script.setProperty("args", args);
-                return script.run();
+            } catch (NoSuchMethodException e) {
+                try {
+                    // Fallback for non-standard "Scripts" that don't have contextual constructor.
+                    Script script = (Script) scriptClass.newInstance();
+                    script.setBinding(context);
+                    return script.run();
+                } catch (InstantiationException e1) {
+                    // ignore instantiation errors, try to do main
+                } catch (IllegalAccessException e1) {
+                    // ignore instantiation errors, try to do main
+                }
+            } catch (InvocationTargetException e) {
+                // ignore instantiation errors, try to do main
             }
         }
         try {
@@ -530,7 +550,7 @@ public class GroovyShell extends GroovyObjectSupport {
      * @param list     the command line arguments to pass in
      */
     public Object run(final Reader in, final String fileName, List list) throws CompilationFailedException {
-        return run(in, fileName, new String[list.size()]);
+        return run(in, fileName, (String[]) list.toArray(new String[list.size()]));
     }
 
     /**
@@ -566,7 +586,6 @@ public class GroovyShell extends GroovyObjectSupport {
      */
     public Object evaluate(GroovyCodeSource codeSource) throws CompilationFailedException {
         Script script = parse(codeSource);
-        script.setBinding(context);
         return script.run();
     }
 
@@ -645,7 +664,6 @@ public class GroovyShell extends GroovyObjectSupport {
         Script script = null;
         try {
             script = parse(in, fileName);
-            script.setBinding(context);
             return script.run();
         } finally {
             if (script != null) {
diff --git a/src/main/groovy/lang/MetaClassImpl.java b/src/main/groovy/lang/MetaClassImpl.java
index 55fa3c9..1772888 100644
--- a/src/main/groovy/lang/MetaClassImpl.java
+++ b/src/main/groovy/lang/MetaClassImpl.java
@@ -16,7 +16,6 @@
 package groovy.lang;
 
 import org.codehaus.groovy.GroovyBugError;
-import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.control.CompilationUnit;
@@ -32,6 +31,7 @@ import org.codehaus.groovy.reflection.ReflectionCache;
 import org.codehaus.groovy.runtime.ConvertedClosure;
 import org.codehaus.groovy.runtime.CurriedClosure;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.runtime.ExceptionUtils;
 import org.codehaus.groovy.runtime.GeneratedClosure;
 import org.codehaus.groovy.runtime.GroovyCategorySupport;
 import org.codehaus.groovy.runtime.InvokerHelper;
@@ -58,6 +58,7 @@ import org.codehaus.groovy.runtime.metaclass.MissingMethodExceptionNoStack;
 import org.codehaus.groovy.runtime.metaclass.MissingMethodExecutionFailed;
 import org.codehaus.groovy.runtime.metaclass.MissingPropertyExceptionNoStack;
 import org.codehaus.groovy.runtime.metaclass.MixinInstanceMetaMethod;
+import org.codehaus.groovy.runtime.metaclass.MultipleSetterProperty;
 import org.codehaus.groovy.runtime.metaclass.NewInstanceMetaMethod;
 import org.codehaus.groovy.runtime.metaclass.NewMetaMethod;
 import org.codehaus.groovy.runtime.metaclass.NewStaticMetaMethod;
@@ -68,6 +69,7 @@ import org.codehaus.groovy.runtime.wrappers.Wrapper;
 import org.codehaus.groovy.util.ComplexKeyHashMap;
 import org.codehaus.groovy.util.FastArray;
 import org.codehaus.groovy.util.SingleKeyHashMap;
+import org.codehaus.groovy.reflection.android.AndroidSupport;
 import org.objectweb.asm.ClassVisitor;
 
 import java.beans.BeanInfo;
@@ -238,11 +240,10 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     public List respondsTo(Object obj, String name, Object[] argTypes) {
         Class[] classes = MetaClassHelper.castArgumentsToClassArray(argTypes);
         MetaMethod m = getMetaMethod(name, classes);
-        List<MetaMethod> methods = new ArrayList<MetaMethod>();
-        if (m != null) {
-            methods.add(m);
+        if (m!=null) {
+            return Collections.singletonList(m);
         }
-        return methods;
+        return Collections.emptyList();
     }
 
     /**
@@ -331,7 +332,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
      */
     private void fillMethodIndex() {
         mainClassMethodHeader = metaMethodIndex.getHeader(theClass);
-        LinkedList superClasses = getSuperClasses();
+        LinkedList<CachedClass> superClasses = getSuperClasses();
         CachedClass firstGroovySuper = calcFirstGroovySuperClass(superClasses);
 
         Set<CachedClass> interfaces = theCachedClass.getInterfaces();
@@ -350,13 +351,13 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private void populateMethods(LinkedList superClasses, CachedClass firstGroovySuper) {
-        Iterator iter = superClasses.iterator();
+    private void populateMethods(LinkedList<CachedClass> superClasses, CachedClass firstGroovySuper) {
 
         MetaMethodIndex.Header header = metaMethodIndex.getHeader(firstGroovySuper.getTheClass());
         CachedClass c;
+        Iterator<CachedClass> iter = superClasses.iterator();
         for (; iter.hasNext();) {
-            c = (CachedClass) iter.next();
+            c = iter.next();
 
             CachedMethod[] cachedMethods = c.getMethods();
             for (CachedMethod metaMethod : cachedMethods) {
@@ -379,7 +380,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
 
         MetaMethodIndex.Header last = header;
         for (;iter.hasNext();) {
-            c = (CachedClass) iter.next();
+            c = iter.next();
             header = metaMethodIndex.getHeader(c.getTheClass());
 
             if (last != null) {
@@ -543,7 +544,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
                         // GROOVY-4922: Due to a numbering scheme change, we must find the super$X$method which exists
                         // with the highest number. If we don't, no method may be found, leading to a stack overflow
                         String[] decomposedMopName = decomposeMopName(mopName);
-                        int distance = Integer.valueOf(decomposedMopName[1]);
+                        int distance = Integer.parseInt(decomposedMopName[1]);
                         while (distance>0) {
                             String fixedMopName = decomposedMopName[0] + distance + decomposedMopName[2];
                             int index = Arrays.binarySearch(mopMethods, fixedMopName, CachedClass.CachedMethodComparatorWithString.INSTANCE);
@@ -631,11 +632,10 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private void connectMultimethods(List superClasses, CachedClass firstGroovyClass) {
+    private void connectMultimethods(List<CachedClass> superClasses, CachedClass firstGroovyClass) {
         superClasses = DefaultGroovyMethods.reverse(superClasses);
         MetaMethodIndex.Header last = null;
-        for (Iterator iter = superClasses.iterator(); iter.hasNext();) {
-            CachedClass c = (CachedClass) iter.next();
+        for (final CachedClass c : superClasses) {
             MetaMethodIndex.Header methodIndex = metaMethodIndex.getHeader(c.getTheClass());
             // We don't copy DGM methods to superclasses' indexes
             // The reason we can do that is particular set of DGM methods in use,
@@ -646,7 +646,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             last = methodIndex;
 
             if (c == firstGroovyClass)
-              break;
+                break;
         }
     }
 
@@ -1908,7 +1908,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         if (!useSuper && !isStatic && GroovyCategorySupport.hasCategoryInCurrentThread()) {
             String getterName = GroovyCategorySupport.getPropertyCategoryGetterName(name);
             if (getterName != null) {
-                MetaMethod categoryMethod = getCategoryMethodGetter(sender, getterName, false);
+                MetaMethod categoryMethod = getCategoryMethodGetter(theClass, getterName, false);
                 if (categoryMethod != null)
                     method = categoryMethod;
             }
@@ -2076,6 +2076,11 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     public List<MetaProperty> getProperties() {
         checkInitalised();
         SingleKeyHashMap propertyMap = classPropertyIndex.getNullable(theCachedClass);
+        if (propertyMap==null) {
+            // GROOVY-6903: May happen in some special environment, like under Android, due
+            // to classloading issues
+            propertyMap = new SingleKeyHashMap();
+        }
         // simply return the values of the metaproperty map as a List
         List ret = new ArrayList(propertyMap.size());
         for (ComplexKeyHashMap.EntryIterator iter = propertyMap.getEntrySetIterator(); iter.hasNext();) {
@@ -2106,47 +2111,56 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         return ret;
     }
 
-    private MetaMethod findPropertyMethod(Object methodOrList, boolean isGetter, boolean booleanGetter) {
-        if (methodOrList == null)
-          return null;
-
+    /**
+     * return null if nothing valid has been found, a MetaMethod (for getter always the case if not null) or
+     * a LinkedList<MetaMethod> if there are multiple setter
+     */
+    private Object filterPropertyMethod(Object methodOrList, boolean isGetter, boolean booleanGetter) {
+        // Method has been optimized to reach a target of 325 bytecode size, making it JIT'able
         Object ret = null;
+
         if (methodOrList instanceof MetaMethod) {
             MetaMethod element = (MetaMethod)methodOrList;
+            int parameterCount = element.getParameterTypes().length;
             if (!isGetter &&
                     //(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) &&
-                    element.getParameterTypes().length == 1) {
-                ret = addElementToList(ret, element);
+                    parameterCount == 1) {
+                ret = element;
             }
+            Class returnType = element.getReturnType();
             if (isGetter &&
-                    !(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) &&
-                    (!booleanGetter || element.getReturnType() == Boolean.class || element.getReturnType() == Boolean.TYPE) &&
-                    element.getParameterTypes().length == 0) {
-                ret = addElementToList(ret, element);
+                    !(returnType == Void.class || returnType == Void.TYPE) &&
+                    (!booleanGetter || returnType == Boolean.class || returnType == Boolean.TYPE) &&
+                    parameterCount == 0) {
+                ret = element;
             }
-
         }
-        else {
+        if (methodOrList instanceof FastArray) {
             FastArray methods = (FastArray) methodOrList;
             final int len = methods.size();
             final Object[] data = methods.getArray();
             for (int i = 0; i != len; ++i) {
                 MetaMethod element = (MetaMethod) data[i];
+                int parameterCount = element.getParameterTypes().length;
                 if (!isGetter &&
                         //(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) &&
-                        element.getParameterTypes().length == 1) {
+                        parameterCount == 1) {
                     ret = addElementToList(ret, element);
                 }
+                Class returnType = element.getReturnType();
                 if (isGetter &&
-                        !(element.getReturnType() == Void.class || element.getReturnType() == Void.TYPE) &&
-                        element.getParameterTypes().length == 0) {
+                        !(returnType == Void.class || returnType == Void.TYPE) &&
+                        parameterCount == 0) {
                     ret = addElementToList(ret, element);
                 }
             }
         }
 
-        if (ret == null) return null;
-        if (ret instanceof MetaMethod) return (MetaMethod) ret;
+        if (ret == null
+                || (ret instanceof MetaMethod)
+                || !isGetter) {
+            return ret;
+        }
 
         // we found multiple matching methods
         // this is a problem, because we can use only one
@@ -2155,15 +2169,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         // we use the type of the first parameter
         MetaMethod method = null;
         int distance = -1;
-        for (Iterator iter = ((List) ret).iterator(); iter.hasNext();) {
-            MetaMethod element = (MetaMethod) iter.next();
-            Class c;
-            if (isGetter) {
-                c = element.getReturnType();
-            } else {
-                c = element.getParameterTypes()[0].getTheClass();
-            }
-            int localDistance = distanceToObject(c);
+        for (final Object o : ((List) ret)) {
+            MetaMethod element = (MetaMethod) o;
+            int localDistance = distanceToObject(element.getReturnType());
             //TODO: maybe implement the case localDistance==distance
             if (distance == -1 || distance > localDistance) {
                 distance = localDistance;
@@ -2272,6 +2280,9 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
                 else {
                     mp = result;
                 }
+            } else if (mp instanceof MultipleSetterProperty) {
+                MultipleSetterProperty msp = (MultipleSetterProperty) mp;
+                mp = msp.createStaticVersion();
             } else {
                 continue; // ignore all other types
             }
@@ -2391,11 +2402,18 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
                 boolean isSetter = methodName.startsWith("set");
                 if (!isGetter && !isSetter) continue;
 
-                MetaMethod propertyMethod = findPropertyMethod(isThis ? e.methods : e.methodsForSuper, isGetter, isBooleanGetter);
-                if (propertyMethod == null) continue;
+                Object propertyMethods = filterPropertyMethod(isThis ? e.methods : e.methodsForSuper, isGetter, isBooleanGetter);
+                if (propertyMethods == null) continue;
 
                 String propName = getPropName(methodName);
-                createMetaBeanProperty(propertyIndex, propName, isGetter, propertyMethod);
+                if (propertyMethods instanceof MetaMethod) {
+                    createMetaBeanProperty(propertyIndex, propName, isGetter, (MetaMethod) propertyMethods);
+                } else {
+                    LinkedList<MetaMethod> methods = (LinkedList<MetaMethod>) propertyMethods;
+                    for (MetaMethod m: methods) {
+                        createMetaBeanProperty(propertyIndex, propName, isGetter, m);
+                    }
+                }
             }
         }
     }
@@ -2416,44 +2434,61 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
     }
 
-    private void createMetaBeanProperty(SingleKeyHashMap propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod) {
-        // is this property already accounted for?
-        MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
+    private MetaProperty makeReplacementMetaProperty(MetaProperty mp, String propName, boolean isGetter, MetaMethod propertyMethod) {
         if (mp == null) {
             if (isGetter) {
-                mp = new MetaBeanProperty(propName,
+                return new MetaBeanProperty(propName,
                         propertyMethod.getReturnType(),
                         propertyMethod, null);
             } else {
                 //isSetter
-                mp = new MetaBeanProperty(propName,
+                return new MetaBeanProperty(propName,
                         propertyMethod.getParameterTypes()[0].getTheClass(),
                         null, propertyMethod);
             }
-        } else {
-            MetaBeanProperty mbp;
-            CachedField mfp;
-            if (mp instanceof MetaBeanProperty) {
-                mbp = (MetaBeanProperty) mp;
-                mfp = mbp.getField();
-            } else if (mp instanceof CachedField) {
-                mfp = (CachedField) mp;
-                mbp = new MetaBeanProperty(propName,
-                        mfp.getType(),
-                        null, null);
-            } else {
-                throw new GroovyBugError("unknown MetaProperty class used. Class is " + mp.getClass());
+        }
+
+        if (mp instanceof CachedField) {
+            CachedField mfp = (CachedField) mp;
+            MetaBeanProperty mbp = new MetaBeanProperty(propName, mfp.getType(),
+                                            isGetter? propertyMethod: null,
+                                            isGetter? null: propertyMethod);
+            mbp.setField(mfp);
+            return mbp;
+        } else if (mp instanceof MultipleSetterProperty) {
+            MultipleSetterProperty msp = (MultipleSetterProperty) mp;
+            if (isGetter) {
+                msp.setGetter(propertyMethod);
             }
-            // we may have already found one for this name
-            if (isGetter && mbp.getGetter() == null) {
+            return msp;
+        } else if (mp instanceof MetaBeanProperty) {
+            MetaBeanProperty mbp = (MetaBeanProperty) mp;
+            if (isGetter) {
                 mbp.setGetter(propertyMethod);
-            } else if (!isGetter && mbp.getSetter() == null) {
+                return mbp;
+            } else if (mbp.getSetter()==null || mbp.getSetter()==propertyMethod) {
                 mbp.setSetter(propertyMethod);
+                return mbp;
+            } else {
+                MultipleSetterProperty msp = new MultipleSetterProperty(propName);
+                msp.setField(mbp.getField());
+                msp.setGetter(mbp.getGetter());
+                return msp;
             }
-            mbp.setField(mfp);
-            mp = mbp;
+        } else {
+            throw new GroovyBugError("unknown MetaProperty class used. Class is " + mp.getClass());
+        }
+
+
+    }
+
+    private void createMetaBeanProperty(SingleKeyHashMap propertyIndex, String propName, boolean isGetter, MetaMethod propertyMethod) {
+        // is this property already accounted for?
+        MetaProperty mp = (MetaProperty) propertyIndex.get(propName);
+        MetaProperty newMp = makeReplacementMetaProperty(mp, propName, isGetter, propertyMethod);
+        if (newMp!=mp) {
+            propertyIndex.put(propName, newMp);
         }
-        propertyIndex.put(propName, mp);
     }
 
     protected void applyPropertyDescriptors(PropertyDescriptor[] propertyDescriptors) {
@@ -2512,6 +2547,8 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
             if (old != null) {
                 if (old instanceof MetaBeanProperty) {
                     field = ((MetaBeanProperty) old).getField();
+                } else if (old instanceof MultipleSetterProperty) {
+                    field = ((MultipleSetterProperty)old).getField();
                 } else {
                     field = (CachedField) old;
                 }
@@ -3165,8 +3202,7 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
 
         long matchesDistance = -1;
         LinkedList matches = new LinkedList();
-        for (Iterator iter = matchingMethods.iterator(); iter.hasNext();) {
-            Object method = iter.next();
+        for (Object method : matchingMethods) {
             ParameterTypes paramTypes = (ParameterTypes) method;
             long dist = MetaClassHelper.calculateParameterDistance(arguments, paramTypes);
             if (dist == 0) return method;
@@ -3190,16 +3226,16 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
         }
 
         //more than one matching method found --> ambiguous!
-        String msg = "Ambiguous method overloading for method ";
-        msg += theClass.getName() + "#" + name;
-        msg += ".\nCannot resolve which method to invoke for ";
-        msg += InvokerHelper.toString(arguments);
-        msg += " due to overlapping prototypes between:";
-        for (Iterator iter = matches.iterator(); iter.hasNext();) {
-            Class[] types = ((ParameterTypes) iter.next()).getNativeParameterTypes();
-            msg += "\n\t" + InvokerHelper.toString(types);
+        StringBuilder msg = new StringBuilder("Ambiguous method overloading for method ");
+        msg.append(theClass.getName()).append("#").append(name)
+           .append(".\nCannot resolve which method to invoke for ")
+           .append(InvokerHelper.toString(arguments))
+           .append(" due to overlapping prototypes between:");
+        for (final Object matche : matches) {
+            Class[] types = ((ParameterTypes) matche).getNativeParameterTypes();
+            msg.append("\n\t").append(InvokerHelper.toString(types));
         }
-        throw new GroovyRuntimeException(msg);
+        throw new GroovyRuntimeException(msg.toString());
     }
 
     private boolean isGenericGetMethod(MetaMethod method) {
@@ -3223,7 +3259,15 @@ public class MetaClassImpl implements MetaClass, MutableMetaClass {
     public synchronized void initialize() {
         if (!isInitialized()) {
             fillMethodIndex();
-            addProperties();
+            try {
+                addProperties();
+            } catch (Throwable e) {
+                if (!AndroidSupport.isRunningAndroid()) {
+                    ExceptionUtils.sneakyThrow(e);
+                }
+                // Introspection failure...
+                // May happen in Android
+            }
             initialized = true;
         }
     }
diff --git a/src/main/groovy/lang/ObjectRange.java b/src/main/groovy/lang/ObjectRange.java
index 8a7881c..f3290f7 100644
--- a/src/main/groovy/lang/ObjectRange.java
+++ b/src/main/groovy/lang/ObjectRange.java
@@ -275,8 +275,8 @@ public class ObjectRange extends AbstractList implements Range {
             } else if (from instanceof BigDecimal || to instanceof BigDecimal ||
                        from instanceof BigInteger || to instanceof BigInteger) {
                 // let's fast calculate the size
-                BigDecimal fromNum = new BigDecimal("" + from);
-                BigDecimal toNum = new BigDecimal("" + to);
+                BigDecimal fromNum = new BigDecimal(from.toString());
+                BigDecimal toNum = new BigDecimal(to.toString());
                 BigInteger sizeNum = toNum.subtract(fromNum).add(new BigDecimal(1.0)).toBigInteger();
                 size = sizeNum.intValue();
             } else {
diff --git a/src/main/groovy/lang/Tuple.java b/src/main/groovy/lang/Tuple.java
index de55e32..3e8bb8d 100644
--- a/src/main/groovy/lang/Tuple.java
+++ b/src/main/groovy/lang/Tuple.java
@@ -27,11 +27,11 @@ import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
  * @version $Revision$
  */
 public class Tuple extends AbstractList {
-
-    private Object[] contents;
+    private final Object[] contents;
     private int hashCode;
 
     public Tuple(Object[] contents) {
+        if (contents == null) throw new NullPointerException();
         this.contents = contents;
     }
 
@@ -43,26 +43,22 @@ public class Tuple extends AbstractList {
         return contents.length;
     }
 
-    public boolean equals(Object that) {
-        if (that instanceof Tuple) {
-            return equals((Tuple) that);
-        }
-        return false;
-    }
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || !(o instanceof Tuple)) return false;
 
-    public boolean equals(Tuple that) {
-        if (contents.length == that.contents.length) {
-            for (int i = 0; i < contents.length; i++) {
-                if (! DefaultTypeTransformation.compareEqual(this.contents[i], that.contents[i])) {
-                    return false;
-                }
+        Tuple that = (Tuple) o;
+        if (size() != that.size()) return false;
+        for (int i = 0; i < contents.length; i++) {
+            if (!DefaultTypeTransformation.compareEqual(contents[i], that.contents[i])) {
+                return false;
             }
-            return true;
         }
-        return false;
+        return true;
     }
 
-
+    @Override
     public int hashCode() {
         if (hashCode == 0) {
             for (int i = 0; i < contents.length; i++ ) {
@@ -77,6 +73,7 @@ public class Tuple extends AbstractList {
         return hashCode;
     }
 
+    @Override
     public List subList(int fromIndex, int toIndex) {
         int size = toIndex - fromIndex;
         Object[] newContent = new Object[size];
diff --git a/src/main/groovy/lang/Tuple2.java b/src/main/groovy/lang/Tuple2.java
new file mode 100644
index 0000000..cefa363
--- /dev/null
+++ b/src/main/groovy/lang/Tuple2.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.lang;
+
+/**
+ * Represents a list of 2 typed Objects.
+ */
+public class Tuple2<T1, T2> extends Tuple {
+    public Tuple2(T1 first, T2 second) {
+        super(new Object[]{first, second});
+    }
+
+    @SuppressWarnings("unchecked")
+    public T1 getFirst() {
+        return (T1) get(0);
+    }
+
+    @SuppressWarnings("unchecked")
+    public T2 getSecond() {
+        return (T2) get(1);
+    }
+}
diff --git a/src/main/groovy/transform/AutoClone.java b/src/main/groovy/transform/AutoClone.java
index e6fcde0..931a0cb 100644
--- a/src/main/groovy/transform/AutoClone.java
+++ b/src/main/groovy/transform/AutoClone.java
@@ -49,7 +49,7 @@ import java.lang.annotation.Target;
  *   ...
  *   public Person clone() throws CloneNotSupportedException {
  *     Person result = (Person) super.clone()
- *     result.favItems = favItems instanceof Cloneable ? (List) favItems.clone()
+ *     result.favItems = favItems instanceof Cloneable ? (List) favItems.clone() : favItems
  *     result.since = (Date) since.clone()
  *     return result
  *   }
@@ -135,7 +135,9 @@ import java.lang.annotation.Target;
  * If you use this style on a child class, the parent class must
  * also have a copy constructor (created using this annotation or by hand).
  * This approach can be slightly slower than the traditional cloning approach
- * but the {@code Cloneable} fields of your class can be final.
+ * but the {@code Cloneable} fields of your class can be final. When using the copy constructor style,
+ * you can provide your own custom constructor by hand if you wish. If you do so, it is up to you to
+ * correctly copy, clone or deep clone the properties of your class.
  * <p>
  * As a variation of the last two styles, if you set {@code style=SIMPLE}
  * then the no-arg constructor will be called followed by setting the
diff --git a/src/main/groovy/transform/CompileStatic.java b/src/main/groovy/transform/CompileStatic.java
index 82ff2d6..dfda91f 100644
--- a/src/main/groovy/transform/CompileStatic.java
+++ b/src/main/groovy/transform/CompileStatic.java
@@ -22,9 +22,21 @@ import java.lang.annotation.*;
 /**
  * This will let the Groovy compiler use compile time checks in the style of Java
  * then perform static compilation, thus bypassing the Groovy meta object protocol.
+ * <p>
+ * When a class is annotated, all methods, properties, files, inner classes, etc.
+ * of the annotated class will be type checked. When a method is annotated, static
+ * compilation applies only to items (closures and anonymous inner clsses) within
+ * the method.
+ * <p>
+ * By using {@link TypeCheckingMode#SKIP}, static compilation can be skipped on an
+ * element within a class or method otherwise marked with CompileStatic. For example
+ * a class can be annotated with CompileStatic, and a method within can be marked
+ * to skip static checking to use dynamic language features.
  *
  * @author <a href="mailto:blackdrag at gmx.org">Jochen "blackdrag" Theodorou</a>
  * @author Cedric Champeau
+ *
+ * @see CompileDynamic
  */
 @Documented
 @Retention(RetentionPolicy.SOURCE)
diff --git a/src/main/groovy/transform/InheritConstructors.java b/src/main/groovy/transform/InheritConstructors.java
index 03d5032..11fda8f 100644
--- a/src/main/groovy/transform/InheritConstructors.java
+++ b/src/main/groovy/transform/InheritConstructors.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2013 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -110,4 +110,19 @@ import java.lang.annotation.Target;
 @Target({ElementType.TYPE})
 @GroovyASTTransformationClass("org.codehaus.groovy.transform.InheritConstructorsASTTransformation")
 public @interface InheritConstructors {
+    /**
+     * Whether to carry over annotations on the copied constructors.
+     * Currently Closure annotation members are not supported.
+     *
+     * @return true if copied constructor should keep constructor annotations
+     */
+    boolean constructorAnnotations() default false;
+
+    /**
+     * Whether to carry over parameter annotations on the copied constructors.
+     * Currently Closure annotation members are not supported.
+     *
+     * @return true if copied constructor should keep parameter annotations
+     */
+    boolean parameterAnnotations() default false;
 }
diff --git a/src/main/groovy/transform/PackageScope.java b/src/main/groovy/transform/PackageScope.java
index 6ee5508..87ed599 100644
--- a/src/main/groovy/transform/PackageScope.java
+++ b/src/main/groovy/transform/PackageScope.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2010 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,13 +24,13 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 
 /**
- * Class, method or field annotation used for turning off Groovy's auto
- * visibility conventions. By default, Groovy automatically turns package
- * protected fields into properties and makes package protected methods
- * and classes public. This annotation allows this feature to be turned
+ * Annotation used for turning off Groovy's auto visibility conventions.
+ * By default, Groovy automatically turns package protected fields into properties
+ * and makes package protected methods, constructors and classes public.
+ * This annotation allows this feature to be turned
  * off and revert back to Java behavior if needed.
  *
- * Place it on classes, fields or methods of interest as follows:
+ * Place it on classes, fields, constructors or methods of interest as follows:
  * <pre>
  * {@code @}PackageScope class Bar {      // package protected
  *     {@code @}PackageScope int field    // package protected; not a property
@@ -54,15 +54,15 @@ import java.lang.annotation.Target;
  * }
  * </pre>
  *
- * This transformation is typically only used in conjunction with a third-party
- * library or framework which relies upon package scoping.
+ * This transformation is not frequently needed but can be useful in certain testing scenarios
+ * or when using a third-party library or framework which relies upon package scoping.
  *
  * @author Paul King
  * @since 1.8.0
  */
 @java.lang.annotation.Documented
 @Retention(RetentionPolicy.SOURCE)
- at Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD})
+ at Target({ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.FIELD})
 @GroovyASTTransformationClass("org.codehaus.groovy.transform.PackageScopeASTTransformation")
 public @interface PackageScope {
     groovy.transform.PackageScopeTarget[] value() default {PackageScopeTarget.CLASS};
diff --git a/src/main/groovy/transform/PackageScopeTarget.java b/src/main/groovy/transform/PackageScopeTarget.java
index 1ab6444..bb86712 100644
--- a/src/main/groovy/transform/PackageScopeTarget.java
+++ b/src/main/groovy/transform/PackageScopeTarget.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2010 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,5 +35,10 @@ public enum PackageScopeTarget {
     /**
      * Make the Class fields have package protected visibility.
      */
-    FIELDS
+    FIELDS,
+
+    /**
+     * Make the Class constructors have package protected visibility.
+     */
+    CONSTRUCTORS
 }
diff --git a/src/main/groovy/transform/SelfType.java b/src/main/groovy/transform/SelfType.java
new file mode 100644
index 0000000..c2b7f7f
--- /dev/null
+++ b/src/main/groovy/transform/SelfType.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.transform;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+/**
+ * This annotation can be added on a trait to declare the list of types that a class
+ * implementing that trait is supposed to extend. This is useful when you want to be
+ * able to call methods from the class implementing the trait without having to declare
+ * all of them as members of the trait.
+ *
+ * Self types are particularily useful in combination with {@link groovy.transform.CompileStatic},
+ * if you know that a trait can only be applied to a specific type but that the trait cannot extend
+ * that type itself. For example, imagine the following code:
+ * <pre><code>
+ *     class Component { void methodInComponent() }
+ *     trait ComponentDecorator {
+ *         void logAndCall() {
+ *             println "Calling method in component"
+ *             methodInComponent()
+ *         }
+ *         // other useful methods
+ *     }
+ *     class DecoratedComponent extends Component implements ComponentDecorator {}
+ * </code></pre>
+ *
+ * This will work because the trait uses the dynamic backend, so there is no check at
+ * compile time that the <i>methodInComponent</i> call in <i>logAndCall</i> is actually
+ * defined. If you annotate the trait with {@link groovy.transform.CompileStatic}, compilation
+ * will fail because the trait does not define the method. To declare that the trait can be
+ * applied on something that will extend <i>Component</i>, you need to add the <i>SelfType</i>
+ * annotation like this:
+ * <pre><code>
+ *     class Component { void methodInComponent() }
+ *
+ *     {@literal @}CompileStatic
+ *     {@literal @}SelfType(Component)
+ *     trait ComponentDecorator {
+ *         void logAndCall() {
+ *             println "Calling method in component"
+ *             methodInComponent()
+ *         }
+ *         // other useful methods
+ *     }
+ *     class DecoratedComponent extends Component implements ComponentDecorator {}
+ * </code></pre>
+ *
+ * This pattern can therefore be used to avoid explicit casts everywhere you need to call a method
+ * that you know is defined in the class that will implement the trait but normally don't have access
+ * to, which is often the case where a trait needs to be applied on a class provided by a third-party
+ * library.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+ at Documented
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target({ElementType.TYPE})
+public @interface SelfType {
+    Class[] value();
+}
diff --git a/src/main/groovy/transform/ToString.java b/src/main/groovy/transform/ToString.java
index 5c330a0..3ffee92 100644
--- a/src/main/groovy/transform/ToString.java
+++ b/src/main/groovy/transform/ToString.java
@@ -136,17 +136,23 @@ public @interface ToString {
     String[] includes() default {};
 
     /**
-     * Whether to include super in generated toString.
+     * Whether to include the toString() of super in the generated toString.
      */
     boolean includeSuper() default false;
 
     /**
-     * Whether to include names of properties/fields in generated toString.
+     * Whether to include super properties in the generated toString.
+     * @since 2.4.0
+     */
+    boolean includeSuperProperties() default false;
+
+    /**
+     * Whether to include names of properties/fields in the generated toString.
      */
     boolean includeNames() default false;
 
     /**
-     * Include fields as well as properties in generated toString.
+     * Include fields as well as properties in the generated toString.
      */
     boolean includeFields() default false;
 
diff --git a/src/main/groovy/transform/Undefined.java b/src/main/groovy/transform/Undefined.java
new file mode 100644
index 0000000..c2f3e70
--- /dev/null
+++ b/src/main/groovy/transform/Undefined.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.transform;
+
+import org.codehaus.groovy.ast.ClassNode;
+
+/**
+ * Java doesn't allow you to have null as an attribute value. It wants you to indicate what you really
+ * mean by null, so that is what we do here - as ugly as it is.
+ */
+public final class Undefined {
+    private Undefined() {}
+    public static final String STRING = "<DummyUndefinedMarkerString-DoNotUse>";
+    public static final class CLASS {}
+    public static boolean isUndefined(String other) { return STRING.equals(other); }
+    public static boolean isUndefined(ClassNode other) { return CLASS.class.getName().equals(other.getName()); }
+}
diff --git a/src/main/groovy/transform/builder/Builder.java b/src/main/groovy/transform/builder/Builder.java
index 588fd86..17fac33 100644
--- a/src/main/groovy/transform/builder/Builder.java
+++ b/src/main/groovy/transform/builder/Builder.java
@@ -21,6 +21,7 @@ import java.lang.annotation.RetentionPolicy;
 import java.lang.annotation.Target;
 import java.lang.annotation.Documented;
 
+import groovy.transform.Undefined;
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
 
 import static org.codehaus.groovy.transform.BuilderASTTransformation.BuilderStrategy;
@@ -70,9 +71,10 @@ import static org.codehaus.groovy.transform.BuilderASTTransformation.BuilderStra
 public @interface Builder {
 
     /**
-     * A class for which builder methods should be created
+     * A class for which builder methods should be created. It will be an error to leave
+     * this attribute with its default value for some strategies.
      */
-    Class forClass();
+    Class forClass() default Undefined.CLASS.class;
 
     /**
      * A class capturing the builder strategy
@@ -84,20 +86,20 @@ public @interface Builder {
      * Default is determined by the strategy which might use "" or "set" but you can choose your own, e.g. "with".
      * If non-empty the first letter of the property will be capitalized before being appended to the prefix.
      */
-    String prefix();
+    String prefix() default Undefined.STRING;
 
     /**
      * For strategies which create a builder helper class, the class name to use for the helper class.
      * Not used if using {@code forClass} since in such cases the builder class is explicitly supplied.
      * Default is determined by the strategy, e.g. <em>TargetClass</em> + "Builder" or <em>TargetClass</em> + "Initializer".
      */
-    String builderClassName();
+    String builderClassName() default Undefined.STRING;
 
     /**
      * For strategies which create a builder helper class that creates the instance, the method name to call to create the instance.
      * Default is determined by the strategy, e.g. <em>build</em> or <em>create</em>.
      */
-    String buildMethodName();
+    String buildMethodName() default Undefined.STRING;
 
     /**
      * The method name to use for a builder factory method in the source class for easy access of the
@@ -105,7 +107,7 @@ public @interface Builder {
      * Must not be used if using {@code forClass}.
      * Default is determined by the strategy, e.g. <em>builder</em> or <em>createInitializer</em>.
      */
-    String builderMethodName();
+    String builderMethodName() default Undefined.STRING;
 
     /**
      * List of field and/or property names to exclude from generated builder methods.
diff --git a/src/main/groovy/transform/builder/DefaultStrategy.java b/src/main/groovy/transform/builder/DefaultStrategy.java
index d3754e5..6b9a53d 100644
--- a/src/main/groovy/transform/builder/DefaultStrategy.java
+++ b/src/main/groovy/transform/builder/DefaultStrategy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2014 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,7 +18,6 @@ package groovy.transform.builder;
 
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
-import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
@@ -27,12 +26,13 @@ import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
-import org.codehaus.groovy.transform.AbstractASTTransformation;
 import org.codehaus.groovy.transform.BuilderASTTransformation;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
@@ -47,13 +47,17 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.newClass;
+import static org.codehaus.groovy.transform.AbstractASTTransformation.getMemberStringValue;
+import static org.codehaus.groovy.transform.AbstractASTTransformation.shouldSkip;
 import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;
 import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_PARAMS;
 import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
 import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
 import static org.objectweb.asm.Opcodes.ACC_STATIC;
-import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
 
 /**
  * This strategy is used with the {@link Builder} AST transform to create a builder helper class
@@ -158,8 +162,10 @@ import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
  */
 public class DefaultStrategy extends BuilderASTTransformation.AbstractBuilderStrategy {
     private static final Expression DEFAULT_INITIAL_VALUE = null;
+    private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
 
     public void build(BuilderASTTransformation transform, AnnotatedNode annotatedNode, AnnotationNode anno) {
+        if (unsupportedAttribute(transform, anno, "forClass")) return;
         if (annotatedNode instanceof ClassNode) {
             buildClass(transform, (ClassNode) annotatedNode, anno);
         } else if (annotatedNode instanceof MethodNode) {
@@ -172,45 +178,59 @@ public class DefaultStrategy extends BuilderASTTransformation.AbstractBuilderStr
             transform.addError("Error during " + BuilderASTTransformation.MY_TYPE_NAME +
                     " processing: includes/excludes only allowed on classes", anno);
         }
-        String prefix = transform.getMemberStringValue(anno, "prefix", "");
-        if (unsupportedAttribute(transform, anno, "forClass")) return;
-        final int visibility = ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC;
         ClassNode buildee = mNode.getDeclaringClass();
-        String builderClassName = transform.getMemberStringValue(anno, "builderClassName", buildee.getName() + "Builder");
-        final String fullName = buildee.getName() + "$" + builderClassName;
-        ClassNode builder = new InnerClassNode(buildee, fullName, visibility, ClassHelper.OBJECT_TYPE);
-        buildee.getModule().addClass(builder);
-        buildee.addMethod(createBuilderMethod(transform, anno, builder));
+        ClassNode builder = createBuilder(anno, buildee);
+        createBuilderFactoryMethod(anno, buildee, builder);
         for (Parameter parameter : mNode.getParameters()) {
             builder.addField(createFieldCopy(buildee, parameter));
-            builder.addMethod(createBuilderMethodForProp(builder, new PropertyInfo(parameter.getName(), parameter.getType()), prefix));
+            builder.addMethod(createBuilderMethodForProp(builder, new PropertyInfo(parameter.getName(), parameter.getType()), getPrefix(anno)));
         }
-        builder.addMethod(createBuildMethodForMethod(transform, anno, buildee, mNode, mNode.getParameters()));
+        builder.addMethod(createBuildMethodForMethod(anno, buildee, mNode, mNode.getParameters()));
     }
 
     public void buildClass(BuilderASTTransformation transform, ClassNode buildee, AnnotationNode anno) {
         List<String> excludes = new ArrayList<String>();
         List<String> includes = new ArrayList<String>();
         if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) return;
-        String prefix = transform.getMemberStringValue(anno, "prefix", "");
-        if (unsupportedAttribute(transform, anno, "forClass")) return;
-        final int visibility = ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC;
-        String builderClassName = transform.getMemberStringValue(anno, "builderClassName", buildee.getName() + "Builder");
-        final String fullName = buildee.getName() + "$" + builderClassName;
-        ClassNode builder = new InnerClassNode(buildee, fullName, visibility, ClassHelper.OBJECT_TYPE);
-        buildee.getModule().addClass(builder);
-        buildee.addMethod(createBuilderMethod(transform, anno, builder));
+        ClassNode builder = createBuilder(anno, buildee);
+        createBuilderFactoryMethod(anno, buildee, builder);
         List<FieldNode> fields = getInstancePropertyFields(buildee);
         List<FieldNode> filteredFields = selectFieldsFromExistingClass(fields, includes, excludes);
         for (FieldNode fieldNode : filteredFields) {
-            builder.addField(createFieldCopy(buildee, fieldNode));
-            builder.addMethod(createBuilderMethodForProp(builder, new PropertyInfo(fieldNode.getName(), fieldNode.getType()), prefix));
+            ClassNode correctedType = getCorrectedType(buildee, fieldNode);
+            String fieldName = fieldNode.getName();
+            builder.addField(createFieldCopy(buildee, fieldName, correctedType));
+            builder.addMethod(createBuilderMethodForProp(builder, new PropertyInfo(fieldName, correctedType), getPrefix(anno)));
         }
-        builder.addMethod(createBuildMethod(transform, anno, buildee, filteredFields));
+        builder.addMethod(createBuildMethod(anno, buildee, filteredFields));
+    }
+
+    private ClassNode getCorrectedType(ClassNode buildee, FieldNode fieldNode) {
+        Map<String,ClassNode> genericsSpec = createGenericsSpec(fieldNode.getDeclaringClass());
+        extractSuperClassGenerics(fieldNode.getType(), buildee, genericsSpec);
+        return correctToGenericsSpecRecurse(genericsSpec, fieldNode.getType());
+    }
+
+    private void createBuilderFactoryMethod(AnnotationNode anno, ClassNode buildee, ClassNode builder) {
+        buildee.getModule().addClass(builder);
+        buildee.addMethod(createBuilderMethod(anno, builder));
+    }
+
+    private ClassNode createBuilder(AnnotationNode anno, ClassNode buildee) {
+        return new InnerClassNode(buildee, getFullName(anno, buildee), PUBLIC_STATIC, OBJECT_TYPE);
+    }
+
+    private String getFullName(AnnotationNode anno, ClassNode buildee) {
+        String builderClassName = getMemberStringValue(anno, "builderClassName", buildee.getName() + "Builder");
+        return buildee.getName() + "$" + builderClassName;
+    }
+
+    private String getPrefix(AnnotationNode anno) {
+        return getMemberStringValue(anno, "prefix", "");
     }
 
-    private MethodNode createBuildMethodForMethod(BuilderASTTransformation transform, AnnotationNode anno, ClassNode buildee, MethodNode mNode, Parameter[] params) {
-        String buildMethodName = transform.getMemberStringValue(anno, "buildMethodName", "build");
+    private MethodNode createBuildMethodForMethod(AnnotationNode anno, ClassNode buildee, MethodNode mNode, Parameter[] params) {
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", "build");
         final BlockStatement body = new BlockStatement();
         ClassNode returnType;
         if (mNode instanceof ConstructorNode) {
@@ -223,42 +243,45 @@ public class DefaultStrategy extends BuilderASTTransformation.AbstractBuilderStr
         return new MethodNode(buildMethodName, ACC_PUBLIC, returnType, NO_PARAMS, NO_EXCEPTIONS, body);
     }
 
-    private static MethodNode createBuilderMethod(BuilderASTTransformation transform, AnnotationNode anno, ClassNode builder) {
-        String builderMethodName = transform.getMemberStringValue(anno, "builderMethodName", "builder");
+    private static MethodNode createBuilderMethod(AnnotationNode anno, ClassNode builder) {
+        String builderMethodName = getMemberStringValue(anno, "builderMethodName", "builder");
         final BlockStatement body = new BlockStatement();
         body.addStatement(returnS(ctorX(builder)));
-        final int visibility = ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC;
-        return new MethodNode(builderMethodName, visibility, builder, NO_PARAMS, NO_EXCEPTIONS, body);
+        return new MethodNode(builderMethodName, PUBLIC_STATIC, builder, NO_PARAMS, NO_EXCEPTIONS, body);
     }
 
-    private static MethodNode createBuildMethod(BuilderASTTransformation transform, AnnotationNode anno, ClassNode buildee, List<FieldNode> fields) {
-        String buildMethodName = transform.getMemberStringValue(anno, "buildMethodName", "build");
+    private static MethodNode createBuildMethod(AnnotationNode anno, ClassNode buildee, List<FieldNode> fields) {
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", "build");
         final BlockStatement body = new BlockStatement();
         body.addStatement(returnS(initializeInstance(buildee, fields, body)));
         return new MethodNode(buildMethodName, ACC_PUBLIC, newClass(buildee), NO_PARAMS, NO_EXCEPTIONS, body);
     }
 
     private MethodNode createBuilderMethodForProp(ClassNode builder, PropertyInfo pinfo, String prefix) {
+        ClassNode fieldType = pinfo.getType();
         String fieldName = pinfo.getName();
         String setterName = getSetterName(prefix, fieldName);
-        return new MethodNode(setterName, ACC_PUBLIC, newClass(builder), params(param(pinfo.getType(), fieldName)), NO_EXCEPTIONS, block(
-                stmt(assignX(propX(varX("this"), constX(fieldName)), varX(fieldName))),
+        return new MethodNode(setterName, ACC_PUBLIC, newClass(builder), params(param(fieldType, fieldName)), NO_EXCEPTIONS, block(
+                stmt(assignX(propX(varX("this"), constX(fieldName)), varX(fieldName, fieldType))),
                 returnS(varX("this", builder))
         ));
     }
 
     private static FieldNode createFieldCopy(ClassNode buildee, Parameter param) {
-        return new FieldNode(param.getName(), ACC_PRIVATE, ClassHelper.make(param.getType().getName()), buildee, param.getInitialExpression());
+        Map<String,ClassNode> genericsSpec = createGenericsSpec(buildee);
+        extractSuperClassGenerics(param.getType(), buildee, genericsSpec);
+        ClassNode correctedParamType = correctToGenericsSpecRecurse(genericsSpec, param.getType());
+        return new FieldNode(param.getName(), ACC_PRIVATE, correctedParamType, buildee, param.getInitialExpression());
     }
 
-    private static FieldNode createFieldCopy(ClassNode buildee, FieldNode fNode) {
-        return new FieldNode(fNode.getName(), ACC_PRIVATE, ClassHelper.make(fNode.getType().getName()), buildee, DEFAULT_INITIAL_VALUE);
+    private static FieldNode createFieldCopy(ClassNode buildee, String fieldName, ClassNode fieldType) {
+        return new FieldNode(fieldName, ACC_PRIVATE, fieldType, buildee, DEFAULT_INITIAL_VALUE);
     }
 
     private static List<FieldNode> selectFieldsFromExistingClass(List<FieldNode> fieldNodes, List<String> includes, List<String> excludes) {
         List<FieldNode> fields = new ArrayList<FieldNode>();
         for (FieldNode fNode : fieldNodes) {
-            if (AbstractASTTransformation.shouldSkip(fNode.getName(), excludes, includes)) continue;
+            if (shouldSkip(fNode.getName(), excludes, includes)) continue;
             fields.add(fNode);
         }
         return fields;
diff --git a/src/main/groovy/transform/builder/InitializerStrategy.java b/src/main/groovy/transform/builder/InitializerStrategy.java
index a5897f4..81d65b7 100644
--- a/src/main/groovy/transform/builder/InitializerStrategy.java
+++ b/src/main/groovy/transform/builder/InitializerStrategy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2014 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -20,12 +20,12 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.transform.AbstractASTTransformation;
@@ -34,7 +34,9 @@ import org.codehaus.groovy.transform.ImmutableASTTransformation;
 
 import java.util.ArrayList;
 import java.util.List;
+import java.util.Map;
 
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.args;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.assignX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.block;
@@ -50,8 +52,11 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.makeClassSafeWithGenerics;
-import static org.codehaus.groovy.ast.tools.GenericsUtils.newClass;
+import static org.codehaus.groovy.transform.AbstractASTTransformation.getMemberStringValue;
 import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_EXCEPTIONS;
 import static org.codehaus.groovy.transform.BuilderASTTransformation.NO_PARAMS;
 import static org.objectweb.asm.Opcodes.ACC_PRIVATE;
@@ -99,7 +104,13 @@ import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
  * </pre>
  * The message is a little cryptic, but it is basically the static compiler telling us that the third parameter, {@code age} in our case, is unset.
  *
+ * You can also add this annotation to your predefined constructors. These will be made private and an initializer will be set up
+ * to call your constructor. Any parameters to your constructor become the properties expected by the initializer.
+ * If you use such a builder on a constructor as well as on the class or on more than one constructor, then it is up to you
+ * to define unique values for 'builderClassName' and 'builderMethodName' for each annotation.
+ *
  * @author Paul King
+ * @author Marcin Grzejszczak
  */
 public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilderStrategy {
 
@@ -115,42 +126,97 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
     public abstract static class UNSET {
     }
 
+    private static final int PUBLIC_STATIC = ACC_PUBLIC | ACC_STATIC;
     private static final Expression DEFAULT_INITIAL_VALUE = null;
 
     public void build(BuilderASTTransformation transform, AnnotatedNode annotatedNode, AnnotationNode anno) {
-        if (!(annotatedNode instanceof ClassNode)) {
-            transform.addError("Error during " + BuilderASTTransformation.MY_TYPE_NAME + " processing: building for " +
-                    annotatedNode.getClass().getSimpleName() + " not supported by " + getClass().getSimpleName(), annotatedNode);
-            return;
+        if (unsupportedAttribute(transform, anno, "forClass")) return;
+        if (annotatedNode instanceof ClassNode) {
+            createBuilderForAnnotatedClass(transform, (ClassNode) annotatedNode, anno);
+        } else if (annotatedNode instanceof MethodNode) {
+            createBuilderForAnnotatedMethod(transform, (MethodNode) annotatedNode, anno);
         }
-        ClassNode buildee = (ClassNode) annotatedNode;
+    }
+
+    private void createBuilderForAnnotatedClass(BuilderASTTransformation transform, ClassNode buildee, AnnotationNode anno) {
         List<String> excludes = new ArrayList<String>();
         List<String> includes = new ArrayList<String>();
         if (!getIncludeExclude(transform, anno, buildee, excludes, includes)) return;
-        String prefix = transform.getMemberStringValue(anno, "prefix", "");
-        if (unsupportedAttribute(transform, anno, "forClass")) return;
-        String builderClassName = transform.getMemberStringValue(anno, "builderClassName", buildee.getName() + "Initializer");
-        String buildMethodName = transform.getMemberStringValue(anno, "buildMethodName", "create");
         List<FieldNode> fields = getInstancePropertyFields(buildee);
-        List<FieldNode> filteredFields = selectFieldsFromExistingClass(fields, includes, excludes);
-        int numFields = filteredFields.size();
-        ClassNode builder = createInnerHelperClass(buildee, builderClassName, filteredFields);
-        createBuilderConstructors(builder, filteredFields);
-        createBuildeeConstructors(transform, buildee, builder, filteredFields);
+        List<FieldNode> filteredFields = filterFields(fields, includes, excludes);
+        ClassNode builder = createInnerHelperClass(buildee, getBuilderClassName(buildee, anno), filteredFields.size());
+        addFields(buildee, filteredFields, builder);
+
+        buildCommon(buildee, anno, filteredFields, builder);
+        createBuildeeConstructors(transform, buildee, builder, filteredFields, true);
+    }
+
+    private void createBuilderForAnnotatedMethod(BuilderASTTransformation transform, MethodNode mNode, AnnotationNode anno) {
+        if (transform.getMemberValue(anno, "includes") != null || transform.getMemberValue(anno, "includes") != null) {
+            transform.addError("Error during " + BuilderASTTransformation.MY_TYPE_NAME +
+                    " processing: includes/excludes only allowed on classes", anno);
+        }
+        if (mNode instanceof ConstructorNode) {
+            mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC);
+        } else {
+            if ((mNode.getModifiers() & ACC_STATIC) == 0) {
+                transform.addError("Error during " + BuilderASTTransformation.MY_TYPE_NAME +
+                        " processing: method builders only allowed on static methods", anno);
+            }
+            mNode.setModifiers(ACC_PRIVATE | ACC_SYNTHETIC | ACC_STATIC);
+        }
+        ClassNode buildee = mNode.getDeclaringClass();
+        Parameter[] parameters = mNode.getParameters();
+        ClassNode builder = createInnerHelperClass(buildee, getBuilderClassName(buildee, anno), parameters.length);
+        List<FieldNode> convertedFields = convertParamsToFields(builder, parameters);
+
+        buildCommon(buildee, anno, convertedFields, builder);
+        if (mNode instanceof ConstructorNode) {
+            createBuildeeConstructors(transform, buildee, builder, convertedFields, false);
+        } else {
+            createBuildeeMethods(buildee, mNode, builder, convertedFields);
+        }
+    }
+
+    private String getBuilderClassName(ClassNode buildee, AnnotationNode anno) {
+        return getMemberStringValue(anno, "builderClassName", buildee.getName() + "Initializer");
+    }
+
+    private void addFields(ClassNode buildee, List<FieldNode> filteredFields, ClassNode builder) {
+        for (FieldNode filteredField : filteredFields) {
+            builder.addField(createFieldCopy(buildee, filteredField));
+        }
+    }
+
+    private void buildCommon(ClassNode buildee, AnnotationNode anno, List<FieldNode> fieldNodes, ClassNode builder) {
+        String prefix = getMemberStringValue(anno, "prefix", "");
+        String buildMethodName = getMemberStringValue(anno, "buildMethodName", "create");
+        createBuilderConstructors(builder, buildee, fieldNodes);
         buildee.getModule().addClass(builder);
-        buildee.addMethod(createBuilderMethod(transform, anno, buildMethodName, builder, numFields));
-        for (int i = 0; i < numFields; i++) {
-            builder.addField(createFieldCopy(buildee, filteredFields.get(i)));
-            builder.addMethod(createBuilderMethodForField(builder, filteredFields, prefix, i));
+        String builderMethodName = getMemberStringValue(anno, "builderMethodName", "createInitializer");
+        buildee.addMethod(createBuilderMethod(buildMethodName, builder, fieldNodes.size(), builderMethodName));
+        for (int i = 0; i < fieldNodes.size(); i++) {
+            builder.addMethod(createBuilderMethodForField(builder, fieldNodes, prefix, i));
         }
-        builder.addMethod(createBuildMethod(builder, buildMethodName, filteredFields));
+        builder.addMethod(createBuildMethod(builder, buildMethodName, fieldNodes));
     }
 
-    private ClassNode createInnerHelperClass(ClassNode buildee, String builderClassName, List<FieldNode> fields) {
+    private List<FieldNode> convertParamsToFields(ClassNode builder, Parameter[] parameters) {
+        List<FieldNode> fieldNodes = new ArrayList<FieldNode>();
+        for(Parameter parameter: parameters) {
+            Map<String,ClassNode> genericsSpec = createGenericsSpec(builder);
+            ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, parameter.getType());
+            FieldNode fieldNode = new FieldNode(parameter.getName(), parameter.getModifiers(), correctedType, builder, DEFAULT_INITIAL_VALUE);
+            fieldNodes.add(fieldNode);
+            builder.addField(fieldNode);
+        }
+        return fieldNodes;
+    }
+
+    private ClassNode createInnerHelperClass(ClassNode buildee, String builderClassName, int fieldsSize) {
         final String fullName = buildee.getName() + "$" + builderClassName;
-        final int visibility = ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC;
-        ClassNode builder = new InnerClassNode(buildee, fullName, visibility, ClassHelper.OBJECT_TYPE);
-        GenericsType[] gtypes = new GenericsType[fields.size()];
+        ClassNode builder = new InnerClassNode(buildee, fullName, PUBLIC_STATIC, OBJECT_TYPE);
+        GenericsType[] gtypes = new GenericsType[fieldsSize];
         for (int i = 0; i < gtypes.length; i++) {
             gtypes[i] = makePlaceholder(i);
         }
@@ -158,13 +224,11 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
         return builder;
     }
 
-    private static MethodNode createBuilderMethod(BuilderASTTransformation transform, AnnotationNode anno, String buildMethodName, ClassNode builder, int numFields) {
-        String builderMethodName = transform.getMemberStringValue(anno, "builderMethodName", "createInitializer");
+    private static MethodNode createBuilderMethod(String buildMethodName, ClassNode builder, int numFields, String builderMethodName) {
         final BlockStatement body = new BlockStatement();
         body.addStatement(returnS(callX(builder, buildMethodName)));
-        final int visibility = ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC;
         ClassNode returnType = makeClassSafeWithGenerics(builder, unsetGenTypes(numFields));
-        return new MethodNode(builderMethodName, visibility, returnType, NO_PARAMS, NO_EXCEPTIONS, body);
+        return new MethodNode(builderMethodName, PUBLIC_STATIC, returnType, NO_PARAMS, NO_EXCEPTIONS, body);
     }
 
     private static GenericsType[] unsetGenTypes(int numFields) {
@@ -183,41 +247,70 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
         return gtypes;
     }
 
-    private static void createBuilderConstructors(ClassNode builder, List<FieldNode> fields) {
+    private static void createBuilderConstructors(ClassNode builder, ClassNode buildee, List<FieldNode> fields) {
         builder.addConstructor(ACC_PRIVATE, NO_PARAMS, NO_EXCEPTIONS, block(ctorSuperS()));
         final BlockStatement body = new BlockStatement();
         body.addStatement(ctorSuperS());
         initializeFields(fields, body);
-        builder.addConstructor(ACC_PRIVATE, getParams(fields), NO_EXCEPTIONS, body);
+        builder.addConstructor(ACC_PRIVATE, getParams(fields, buildee), NO_EXCEPTIONS, body);
     }
 
-    private static void createBuildeeConstructors(BuilderASTTransformation transform, ClassNode buildee, ClassNode builder, List<FieldNode> fields) {
-        ClassNode paramType = makeClassSafeWithGenerics(builder, setGenTypes(fields.size()));
-        List<Expression> argsList = new ArrayList<Expression>();
-        for (FieldNode fieldNode : fields) {
-            argsList.add(propX(varX("initializer"), fieldNode.getName()));
-        }
-        Expression args = new ArgumentListExpression(argsList);
-        buildee.addConstructor(ACC_PUBLIC | ACC_SYNTHETIC, params(param(paramType, "initializer")), NO_EXCEPTIONS, block(ctorThisS(args)));
-        if (!transform.hasAnnotation(buildee, ImmutableASTTransformation.MY_TYPE)) {
+    private static void createBuildeeConstructors(BuilderASTTransformation transform, ClassNode buildee, ClassNode builder, List<FieldNode> fields, boolean needsConstructor) {
+        ConstructorNode initializer = createInitializerConstructor(buildee, builder, fields);
+        if (transform.hasAnnotation(buildee, ImmutableASTTransformation.MY_TYPE)) {
+            initializer.putNodeMetaData(ImmutableASTTransformation.IMMUTABLE_SAFE_FLAG, Boolean.TRUE);
+        } else if (needsConstructor) {
             final BlockStatement body = new BlockStatement();
             body.addStatement(ctorSuperS());
             initializeFields(fields, body);
-            buildee.addConstructor(ACC_PRIVATE | ACC_SYNTHETIC, getParams(fields), NO_EXCEPTIONS, body);
+            buildee.addConstructor(ACC_PRIVATE | ACC_SYNTHETIC, getParams(fields, buildee), NO_EXCEPTIONS, body);
+        }
+    }
+
+    private static void createBuildeeMethods(ClassNode buildee, MethodNode mNode, ClassNode builder, List<FieldNode> fields) {
+        ClassNode paramType = makeClassSafeWithGenerics(builder, setGenTypes(fields.size()));
+        List<Expression> argsList = new ArrayList<Expression>();
+        Parameter initParam = param(paramType, "initializer");
+        for (FieldNode fieldNode : fields) {
+            argsList.add(propX(varX(initParam), fieldNode.getName()));
         }
+        String newName = "$" + mNode.getName(); // can't have private and public methods of the same name, so rename original
+        buildee.addMethod(mNode.getName(), PUBLIC_STATIC, mNode.getReturnType(), params(param(paramType, "initializer")), NO_EXCEPTIONS,
+                block(stmt(callX(buildee, newName, args(argsList)))));
+        renameMethod(buildee, mNode, newName);
     }
 
-    private static Parameter[] getParams(List<FieldNode> fields) {
+    // no rename so delete and add
+    private static void renameMethod(ClassNode buildee, MethodNode mNode, String newName) {
+        buildee.addMethod(newName, mNode.getModifiers(), mNode.getReturnType(), mNode.getParameters(), mNode.getExceptions(), mNode.getCode());
+        buildee.removeMethod(mNode);
+    }
+
+    private static Parameter[] getParams(List<FieldNode> fields, ClassNode cNode) {
         Parameter[] parameters = new Parameter[fields.size()];
         for (int i = 0; i < parameters.length; i++) {
-            parameters[i] = new Parameter(newClass(fields.get(i).getType()), fields.get(i).getName());
+            FieldNode fNode = fields.get(i);
+            Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass());
+            extractSuperClassGenerics(fNode.getType(), cNode, genericsSpec);
+            ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType());
+            parameters[i] = new Parameter(correctedType, fNode.getName());
         }
         return parameters;
     }
 
+    private static ConstructorNode createInitializerConstructor(ClassNode buildee, ClassNode builder, List<FieldNode> fields) {
+        ClassNode paramType = makeClassSafeWithGenerics(builder, setGenTypes(fields.size()));
+        List<Expression> argsList = new ArrayList<Expression>();
+        Parameter initParam = param(paramType, "initializer");
+        for (FieldNode fieldNode : fields) {
+            argsList.add(propX(varX(initParam), fieldNode.getName()));
+        }
+        return buildee.addConstructor(ACC_PUBLIC, params(param(paramType, "initializer")), NO_EXCEPTIONS, block(ctorThisS(args(argsList))));
+    }
+
     private static MethodNode createBuildMethod(ClassNode builder, String buildMethodName, List<FieldNode> fields) {
         ClassNode returnType = makeClassSafeWithGenerics(builder, unsetGenTypes(fields.size()));
-        return new MethodNode(buildMethodName, ACC_PUBLIC | ACC_STATIC, returnType, NO_PARAMS, NO_EXCEPTIONS, block(returnS(ctorX(returnType))));
+        return new MethodNode(buildMethodName, PUBLIC_STATIC, returnType, NO_PARAMS, NO_EXCEPTIONS, block(returnS(ctorX(returnType))));
     }
 
     private MethodNode createBuilderMethodForField(ClassNode builder, List<FieldNode> fields, String prefix, int fieldPos) {
@@ -230,24 +323,31 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
             argList.add(i == fieldPos ? propX(varX("this"), constX(fieldName)) : varX(fields.get(i).getName()));
         }
         ClassNode returnType = makeClassSafeWithGenerics(builder, gtypes);
-        return new MethodNode(setterName, ACC_PUBLIC, returnType, params(param(fields.get(fieldPos).getType(), fieldName)), NO_EXCEPTIONS, block(
-                stmt(assignX(propX(varX("this"), constX(fieldName)), varX(fieldName))),
+        FieldNode fNode = fields.get(fieldPos);
+        Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass());
+        extractSuperClassGenerics(fNode.getType(), builder, genericsSpec);
+        ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType());
+        return new MethodNode(setterName, ACC_PUBLIC, returnType, params(param(correctedType, fieldName)), NO_EXCEPTIONS, block(
+                stmt(assignX(propX(varX("this"), constX(fieldName)), varX(fieldName, correctedType))),
                 returnS(ctorX(returnType, args(argList)))
         ));
     }
 
     private GenericsType makePlaceholder(int i) {
         ClassNode type = ClassHelper.makeWithoutCaching("T" + i);
-        type.setRedirect(ClassHelper.OBJECT_TYPE);
+        type.setRedirect(OBJECT_TYPE);
         type.setGenericsPlaceHolder(true);
         return new GenericsType(type);
     }
 
     private static FieldNode createFieldCopy(ClassNode buildee, FieldNode fNode) {
-        return new FieldNode(fNode.getName(), fNode.getModifiers(), ClassHelper.make(fNode.getType().getName()), buildee, DEFAULT_INITIAL_VALUE);
+        Map<String,ClassNode> genericsSpec = createGenericsSpec(fNode.getDeclaringClass());
+        extractSuperClassGenerics(fNode.getType(), buildee, genericsSpec);
+        ClassNode correctedType = correctToGenericsSpecRecurse(genericsSpec, fNode.getType());
+        return new FieldNode(fNode.getName(), fNode.getModifiers(), correctedType, buildee, DEFAULT_INITIAL_VALUE);
     }
 
-    private static List<FieldNode> selectFieldsFromExistingClass(List<FieldNode> fieldNodes, List<String> includes, List<String> excludes) {
+    private static List<FieldNode> filterFields(List<FieldNode> fieldNodes, List<String> includes, List<String> excludes) {
         List<FieldNode> fields = new ArrayList<FieldNode>();
         for (FieldNode fNode : fieldNodes) {
             if (AbstractASTTransformation.shouldSkip(fNode.getName(), excludes, includes)) continue;
@@ -258,7 +358,7 @@ public class InitializerStrategy extends BuilderASTTransformation.AbstractBuilde
 
     private static void initializeFields(List<FieldNode> fields, BlockStatement body) {
         for (FieldNode field : fields) {
-            body.addStatement(stmt(assignX(propX(varX("this"), field.getName()), varX(field))));
+            body.addStatement(stmt(assignX(propX(varX("this"), field.getName()), varX(param(field.getType(), field.getName())))));
         }
     }
 }
diff --git a/src/main/groovy/transform/stc/FromString.java b/src/main/groovy/transform/stc/FromString.java
index 3c07daa..d5fecb2 100644
--- a/src/main/groovy/transform/stc/FromString.java
+++ b/src/main/groovy/transform/stc/FromString.java
@@ -15,29 +15,15 @@
  */
 package groovy.transform.stc;
 
-import antlr.RecognitionException;
-import antlr.TokenStreamException;
-import org.codehaus.groovy.antlr.AntlrParserPlugin;
-import org.codehaus.groovy.antlr.parser.GroovyLexer;
-import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
 import org.codehaus.groovy.ast.ASTNode;
-import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
-import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
-import org.codehaus.groovy.ast.ModuleNode;
-import org.codehaus.groovy.ast.Parameter;
-import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.control.CompilationUnit;
-import org.codehaus.groovy.control.ResolveVisitor;
 import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.syntax.ParserException;
-import org.codehaus.groovy.syntax.Reduction;
 
-import java.io.StringReader;
 import java.util.ArrayList;
 import java.util.List;
-import java.util.concurrent.atomic.AtomicReference;
 
 
 /**
@@ -84,64 +70,8 @@ public class FromString extends ClosureSignatureHint {
      * @param usage
      * @return a class node if it could be parsed and resolved, null otherwise
      */
-    private ClassNode[] parseOption(final String option, final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage) {
-        GroovyLexer lexer = new GroovyLexer(new StringReader("DummyNode<"+option+">"));
-        final GroovyRecognizer rn = GroovyRecognizer.make(lexer);
-        try {
-            rn.classOrInterfaceType(true);
-            final AtomicReference<ClassNode> ref = new AtomicReference<ClassNode>();
-            AntlrParserPlugin plugin = new AntlrParserPlugin() {
-                @Override
-                public ModuleNode buildAST(final SourceUnit sourceUnit, final ClassLoader classLoader, final Reduction cst) throws ParserException {
-                    ref.set(makeTypeWithArguments(rn.getAST()));
-                    return null;
-                }
-            };
-            plugin.buildAST(null, null, null);
-            ClassNode parsedNode = ref.get();
-            // the returned node is DummyNode<Param1, Param2, Param3, ...)
-            GenericsType[] parsedNodeGenericsTypes = parsedNode.getGenericsTypes();
-            if (parsedNodeGenericsTypes==null) {
-                return null;
-            }
-            ClassNode[] signature = new ClassNode[parsedNodeGenericsTypes.length];
-            for (int i = 0; i < parsedNodeGenericsTypes.length; i++) {
-                final GenericsType genericsType = parsedNodeGenericsTypes[i];
-                signature[i] = resolveClassNode(sourceUnit, compilationUnit, mn, usage, genericsType.getType());
-            }
-            return signature;
-        } catch (RecognitionException e) {
-            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
-        } catch (TokenStreamException e) {
-            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
-        } catch (ParserException e) {
-            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
-        }
-        return null;
-    }
-
-    private ClassNode resolveClassNode(final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage, final ClassNode parsedNode) {
-        ClassNode dummyClass = new ClassNode("dummy",0, ClassHelper.OBJECT_TYPE);
-        dummyClass.setModule(new ModuleNode(sourceUnit));
-        dummyClass.setGenericsTypes(mn.getDeclaringClass().getGenericsTypes());
-        MethodNode dummyMN = new MethodNode(
-                "dummy",
-                0,
-                parsedNode,
-                Parameter.EMPTY_ARRAY,
-                ClassNode.EMPTY_ARRAY,
-                EmptyStatement.INSTANCE
-        );
-        dummyMN.setGenericsTypes(mn.getGenericsTypes());
-        dummyClass.addMethod(dummyMN);
-        ResolveVisitor visitor = new ResolveVisitor(compilationUnit) {
-            @Override
-            protected void addError(final String msg, final ASTNode expr) {
-                sourceUnit.addError(new IncorrectTypeHintException(mn, msg, usage.getLineNumber(), usage.getColumnNumber()));
-            }
-        };
-        visitor.startResolving(dummyClass, sourceUnit);
-        return dummyMN.getReturnType();
+    private static ClassNode[] parseOption(final String option, final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage) {
+        return GenericsUtils.parseClassNodesFromString(option, sourceUnit, compilationUnit, mn, usage);
     }
 
 }
diff --git a/src/main/groovy/transform/stc/MapEntryOrKeyValue.java b/src/main/groovy/transform/stc/MapEntryOrKeyValue.java
index 296f0c1..1ecd6c5 100644
--- a/src/main/groovy/transform/stc/MapEntryOrKeyValue.java
+++ b/src/main/groovy/transform/stc/MapEntryOrKeyValue.java
@@ -47,7 +47,7 @@ import java.util.Map;
  *     <li><i>index=true or false</i>, by default false. If true, then an additional "int" parameter is added,
  *     for "withIndex" variants</li>
  * </ul>
- * <code>void doSomething(String str, Map<K,>V map, @ClosureParams(value=MapEntryOrKeyValue.class,options="1") Closure c) { ... }</code>
+ * <code>void doSomething(String str, Map<K,>V map, @ClosureParams(value=MapEntryOrKeyValue.class,options="argNum=1") Closure c) { ... }</code>
  */
 public class MapEntryOrKeyValue extends ClosureSignatureHint {
     private static final ClassNode MAPENTRY_TYPE = ClassHelper.make(Map.Entry.class);
@@ -101,7 +101,7 @@ public class MapEntryOrKeyValue extends ClosureSignatureHint {
                     String key = keyValue[0];
                     String value = keyValue[1];
                     if ("argNum".equals(key)) {
-                        pIndex = Integer.valueOf(value);
+                        pIndex = Integer.parseInt(value);
                     } else if ("index".equals(key)) {
                         generateIndex = Boolean.valueOf(value);
                     } else {
diff --git a/src/main/groovy/util/ConfigObject.java b/src/main/groovy/util/ConfigObject.java
index 4446b53..fb322dd 100644
--- a/src/main/groovy/util/ConfigObject.java
+++ b/src/main/groovy/util/ConfigObject.java
@@ -16,6 +16,7 @@
 package groovy.util;
 
 import groovy.lang.GroovyObjectSupport;
+import groovy.lang.GroovyRuntimeException;
 import groovy.lang.Writable;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.runtime.InvokerHelper;
@@ -24,6 +25,7 @@ import org.codehaus.groovy.syntax.Types;
 
 import java.io.BufferedWriter;
 import java.io.IOException;
+import java.io.StringWriter;
 import java.io.Writer;
 import java.net.URL;
 import java.util.*;
@@ -142,7 +144,7 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
     public Properties toProperties() {
         Properties props = new Properties();
         flatten(props);
-        
+
         props = convertValuesToString(props);
 
         return props;
@@ -364,7 +366,7 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
             throw new AssertionError();
         }
     }
-    
+
     /**
      * Checks if a config option is set. Example usage:
      * <pre>
@@ -372,7 +374,7 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
      * assert config.foo.isSet('password')
      * assert config.foo.isSet('username') == false
      * </pre>
-     * 
+     *
      * The check works <b>only</v> for options <b>one</b> block below the current block.
      * E.g. <code>config.isSet('foo.password')</code> will always return false.
      *
@@ -384,9 +386,32 @@ public class ConfigObject extends GroovyObjectSupport implements Writable, Map,
         if (delegateMap.containsKey(option)) {
             Object entry = delegateMap.get(option);
             if (!(entry instanceof ConfigObject) || !((ConfigObject) entry).isEmpty()) {
-                return Boolean.TRUE; 
-            } 
+                return Boolean.TRUE;
+            }
+        }
+        return Boolean.FALSE;
+    }
+
+    public String prettyPrint() {
+        StringWriter sw = new StringWriter();
+        try {
+            writeTo(sw);
+        } catch (IOException e) {
+            throw new GroovyRuntimeException(e);
         }
-        return Boolean.FALSE; 
+
+        return sw.toString();
+    }
+
+    @Override
+    public String toString() {
+        StringWriter sw = new StringWriter();
+        try {
+            InvokerHelper.write(sw, this);
+        } catch (IOException e) {
+            throw new GroovyRuntimeException(e);
+        }
+
+        return sw.toString();
     }
 }
diff --git a/src/main/groovy/util/DelegatingScript.java b/src/main/groovy/util/DelegatingScript.java
index de0606f..bba196f 100644
--- a/src/main/groovy/util/DelegatingScript.java
+++ b/src/main/groovy/util/DelegatingScript.java
@@ -36,7 +36,7 @@ import org.codehaus.groovy.runtime.InvokerHelper;
  * }
  *
  * CompilerConfiguration cc = new CompilerConfiguration();
- * cc.setScriptBaseClass(DelegatingScript.class);
+ * cc.setScriptBaseClass(DelegatingScript.class.getName());
  * GroovyShell sh = new GroovyShell(cl,new Binding(),cc);
  * DelegatingScript script = (DelegatingScript)sh.parse(new File("my.dsl"))
  * script.setDelegate(new MyDSL());
diff --git a/src/main/groovy/util/FileTreeBuilder.groovy b/src/main/groovy/util/FileTreeBuilder.groovy
new file mode 100644
index 0000000..7f4cb1a
--- /dev/null
+++ b/src/main/groovy/util/FileTreeBuilder.groovy
@@ -0,0 +1,181 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.util
+
+import groovy.transform.CompileStatic
+
+/**
+ * A builder dedicated at generating a file directory structure from a
+ * specification. For example, imagine that you want to create the following tree:
+ * <pre>
+ * src/
+ *  |--- main
+ *  |     |--- groovy
+ *  |            |--- Foo.groovy
+ *  |--- test
+ *        |--- groovy
+ *               |--- FooTest.groovy
+ *
+ * </pre>
+ *
+ * <p>Then you can create the structure using:</p>
+ * <pre><code>
+ *     def tree = new FileTreeBuilder()
+ *     tree.dir('src') {
+ *        dir('main') {
+ *           dir('groovy') {
+ *              file('Foo.groovy', 'println "Hello"')
+ *           }
+ *        }
+ *        dir('test') {
+ *           dir('groovy') {
+ *              file('FooTest.groovy', 'class FooTest extends GroovyTestCase {}')
+ *           }
+ *        }
+ *     }
+ * </code></pre>
+ *
+ * <p>or with this shorthand syntax:</p>
+ * <pre><code>
+ *     def tree = new FileTreeBuilder()
+ *     tree.src {
+ *        main {
+ *           groovy {
+ *              'Foo.groovy'('println "Hello"')
+ *           }
+ *        }
+ *        test {
+ *           groovy {
+ *              'FooTest.groovy'('class FooTest extends GroovyTestCase {}')
+ *           }
+ *        }
+ *     }
+ * </code></pre>
+ *
+ * @since 2.4.2
+ */
+ at CompileStatic
+class FileTreeBuilder {
+
+    File baseDir
+
+    FileTreeBuilder(File baseDir = new File('.')) {
+        this.baseDir = baseDir
+    }
+
+    /**
+     * Creates a file with the specified name and the text contents using the system default encoding.
+     * @param name name of the file to be created
+     * @param contents the contents of the file, written using the system default encoding
+     * @return the file being created
+     */
+    File file(String name, CharSequence contents) {
+        new File(baseDir, name) << contents
+    }
+
+    /**
+     * Creates a file with the specified name and the specified binary contents
+     * @param name name of the file to be created
+     * @param contents the contents of the file
+     * @return the file being created
+     */
+    File file(String name, byte[] contents) {
+        new File(baseDir, name) << contents
+    }
+
+    /**
+     * Creates a file with the specified name and the contents from the source file (copy).
+     * @param name name of the file to be created
+     * @param contents the contents of the file
+     * @return the file being created
+     */
+    File file(String name, File source) {
+        // TODO: Avoid using bytes and prefer streaming copy
+        file(name, source.bytes)
+    }
+
+    /**
+     * Creates a new file in the current directory, whose contents is going to be generated in the
+     * closure. The delegate of the closure is the file being created.
+     * @param name name of the file to create
+     * @param spec closure for generating the file contents
+     * @return the created file
+     */
+    File file(String name, @DelegatesTo(value = File, strategy = Closure.DELEGATE_FIRST) Closure spec) {
+        def file = new File(baseDir, name)
+        def clone = (Closure) spec.clone()
+        clone.delegate = file
+        clone.resolveStrategy = Closure.DELEGATE_FIRST
+        clone(file)
+        file
+    }
+
+    /**
+     * Creates a new empty directory
+     * @param name the name of the directory to create
+     * @return the created directory
+     */
+    File dir(String name) {
+        def f = new File(baseDir, name)
+        f.mkdirs()
+        f
+    }
+
+    /**
+     * Creates a new directory and allows to specify a subdirectory structure using the closure as a specification
+     * @param name name of the directory to be created
+     * @param cl specification of the subdirectory structure
+     * @return the created directory
+     */
+    File dir(String name, @DelegatesTo(value = FileTreeBuilder, strategy = Closure.DELEGATE_FIRST) Closure cl) {
+        def oldBase = baseDir
+        def newBase = dir(name)
+        try {
+            baseDir = newBase
+            cl.delegate = this
+            cl.resolveStrategy = Closure.DELEGATE_FIRST
+            cl()
+        } finally {
+            baseDir = oldBase
+        }
+        newBase
+    }
+
+    File call(@DelegatesTo(value = FileTreeBuilder, strategy = Closure.DELEGATE_FIRST) Closure spec) {
+        def clone = (Closure) spec.clone()
+        clone.delegate = this
+        clone.resolveStrategy = Closure.DELEGATE_FIRST
+        clone.call()
+        baseDir
+    }
+
+
+    def methodMissing(String name, args) {
+        if (args instanceof Object[] && ((Object[]) args).length == 1) {
+            def arg = ((Object[]) args)[0]
+            if (arg instanceof Closure) {
+                dir(name, arg)
+            } else if (arg instanceof CharSequence) {
+                file(name, arg.toString())
+            } else if (arg instanceof byte[]) {
+                file(name, arg)
+            } else if (arg instanceof File) {
+                file(name, arg)
+            }
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/main/groovy/util/GroovyScriptEngine.java b/src/main/groovy/util/GroovyScriptEngine.java
index ed2067a..7f7a9a0 100644
--- a/src/main/groovy/util/GroovyScriptEngine.java
+++ b/src/main/groovy/util/GroovyScriptEngine.java
@@ -70,13 +70,16 @@ public class GroovyScriptEngine implements ResourceConnector {
 
     private static final ClassLoader CL_STUB = new ClassLoader() {
     };
+    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
 
     private static class LocalData {
         CompilationUnit cu;
         StringSetMap dependencyCache = new StringSetMap();
-        Map<String,String> precompiledEntries = new HashMap<String,String>();
+        Map<String, String> precompiledEntries = new HashMap<String, String>();
     }
+
     private static WeakReference<ThreadLocal<LocalData>> localData = new WeakReference<ThreadLocal<LocalData>>(null);
+
     private static synchronized ThreadLocal<LocalData> getLocalData() {
         ThreadLocal<LocalData> local = localData.get();
         if (local != null) return local;
@@ -113,6 +116,7 @@ public class GroovyScriptEngine implements ResourceConnector {
             this.dependencies = depend;
             this.sourceNewer = sourceNewer;
         }
+
         public ScriptCacheEntry(ScriptCacheEntry old, long lastCheck, boolean sourceNewer) {
             this(old.scriptClass, old.lastModified, lastCheck, old.dependencies, sourceNewer);
         }
@@ -155,7 +159,7 @@ public class GroovyScriptEngine implements ResourceConnector {
             LocalData local = getLocalData().get();
             local.cu = cu;
             final StringSetMap cache = local.dependencyCache;
-            final Map<String,String> precompiledEntries = local.precompiledEntries;
+            final Map<String, String> precompiledEntries = local.precompiledEntries;
 
             // "." is used to transfer compilation dependencies, which will be
             // recollected later during compilation
@@ -170,7 +174,7 @@ public class GroovyScriptEngine implements ResourceConnector {
 
             // remove all old entries including the "." entry
             cache.clear();
-            
+
             cu.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
                 @Override
                 public void call(final SourceUnit source, GeneratorContext context, ClassNode classNode)
@@ -190,7 +194,7 @@ public class GroovyScriptEngine implements ResourceConnector {
                     String name = origName.replace('.', '/');
                     for (String ext : cc.getScriptExtensions()) {
                         try {
-                            String finalName = name+"."+ext;
+                            String finalName = name + "." + ext;
                             URLConnection conn = rc.getResourceConnection(finalName);
                             URL url = conn.getURL();
                             String path = url.toExternalForm();
@@ -207,7 +211,7 @@ public class GroovyScriptEngine implements ResourceConnector {
                             } else {
                                 precompiledEntries.put(origName, path);
                             }
-                            if (clazz!=null) {
+                            if (clazz != null) {
                                 ClassNode cn = new ClassNode(clazz);
                                 return new LookupResult(null, cn);
                             }
@@ -220,7 +224,7 @@ public class GroovyScriptEngine implements ResourceConnector {
             });
 
             final List<CompilationCustomizer> customizers = config.getCompilationCustomizers();
-            if (customizers!=null) {
+            if (customizers != null) {
                 // GROOVY-4813 : apply configuration customizers
                 for (CompilationCustomizer customizer : customizers) {
                     cu.addPhaseOperation(customizer, customizer.getPhase().getPhaseNumber());
@@ -243,7 +247,7 @@ public class GroovyScriptEngine implements ResourceConnector {
             LocalData localData = new LocalData();
             localTh.set(localData);
             StringSetMap cache = localData.dependencyCache;
-            
+
             // we put the old dependencies into local cache so createCompilationUnit
             // can pick it up. We put that entry under the name "."
             ScriptCacheEntry origEntry = scriptCache.get(codeSource.getName());
@@ -253,12 +257,12 @@ public class GroovyScriptEngine implements ResourceConnector {
                 Set<String> newDep = new HashSet<String>(origDep.size());
                 for (String depName : origDep) {
                     ScriptCacheEntry dep = scriptCache.get(depName);
-                    try{
-                        if (origEntry==dep || GroovyScriptEngine.this.isSourceNewer(dep)) {
+                    try {
+                        if (origEntry == dep || GroovyScriptEngine.this.isSourceNewer(dep)) {
                             newDep.add(depName);
                         }
                     } catch (ResourceException re) {
-                        
+
                     }
                 }
                 cache.put(".", newDep);
@@ -291,21 +295,22 @@ public class GroovyScriptEngine implements ResourceConnector {
             localTh.set(null);
             return answer;
         }
-        private String getPath(Class clazz, Map<String,String> precompiledEntries) {
+
+        private String getPath(Class clazz, Map<String, String> precompiledEntries) {
             CompilationUnit cu = getLocalData().get().cu;
             String name = clazz.getName();
             ClassNode classNode = cu.getClassNode(name);
             if (classNode == null) {
                 // this is a precompiled class!
                 String path = precompiledEntries.get(name);
-                if (path == null) throw new GroovyBugError("Precompiled class "+name+" should be available in precompiled entries map, but was not.");
+                if (path == null) throw new GroovyBugError("Precompiled class " + name + " should be available in precompiled entries map, but was not.");
                 return path;
             } else {
                 return classNode.getModule().getContext().getName();
             }
         }
 
-        private Set<String> convertToPaths(Set<String> orig, Map<String,String> precompiledEntries) {
+        private Set<String> convertToPaths(Set<String> orig, Map<String, String> precompiledEntries) {
             Set<String> ret = new HashSet<String>();
             for (String className : orig) {
                 Class clazz = getClassCacheEntry(className);
@@ -329,8 +334,9 @@ public class GroovyScriptEngine implements ResourceConnector {
         String line;
         while (true) {
             System.out.print("groovy> ");
-            if ((line = br.readLine()) == null || line.equals("quit"))
+            if ((line = br.readLine()) == null || line.equals("quit")) {
                 break;
+            }
             try {
                 System.out.println(gse.run(line, new Binding()));
             } catch (Exception e) {
@@ -374,14 +380,9 @@ public class GroovyScriptEngine implements ResourceConnector {
             URL scriptURL = null;
             try {
                 scriptURL = new URL(root, resourceName);
-                groovyScriptConn = scriptURL.openConnection();
-
-                // Make sure we can open it, if we can't it doesn't exist.
-                // Could be very slow if there are any non-file:// URLs in there
-                groovyScriptConn.getInputStream();
+                groovyScriptConn = openConnection(scriptURL);
 
                 break; // Now this is a bit unusual
-
             } catch (MalformedURLException e) {
                 String message = "Malformed URL: " + root + ", " + resourceName;
                 if (se == null) {
@@ -390,7 +391,6 @@ public class GroovyScriptEngine implements ResourceConnector {
                     se = new ResourceException(message, se);
                 }
             } catch (IOException e1) {
-                groovyScriptConn = null;
                 String message = "Cannot open URL: " + root + resourceName;
                 groovyScriptConn = null;
                 if (se == null) {
@@ -408,6 +408,13 @@ public class GroovyScriptEngine implements ResourceConnector {
         return groovyScriptConn;
     }
 
+    private static URLConnection openConnection(URL scriptURL) throws IOException {
+        URLConnection urlConnection = scriptURL.openConnection();
+        verifyInputStream(urlConnection);
+
+        return scriptURL.openConnection();
+    }
+
     /**
      * This method closes a {@link URLConnection} by getting its {@link InputStream} and calling the
      * {@link InputStream#close()} method on it. The {@link URLConnection} doesn't have a close() method
@@ -419,24 +426,29 @@ public class GroovyScriptEngine implements ResourceConnector {
      *
      * @param urlConnection the {@link URLConnection} to be "closed" to close the underlying file descriptors.
      */
-    private void forceClose(URLConnection urlConnection) {
+    private static void forceClose(URLConnection urlConnection) {
         if (urlConnection != null) {
             // We need to get the input stream and close it to force the open
             // file descriptor to be released. Otherwise, we will reach the limit
             // for number of files open at one time.
 
-            InputStream in = null;
             try {
-                in = urlConnection.getInputStream();
+                verifyInputStream(urlConnection);
             } catch (Exception e) {
                 // Do nothing: We were not going to use it anyway.
-            } finally {
-                if (in != null) {
-                    try {
-                        in.close();
-                    } catch (IOException e) {
-                        // Do nothing: Just want to make sure it is closed.
-                    }
+            }
+        }
+    }
+
+    private static void verifyInputStream(URLConnection urlConnection) throws IOException {
+        InputStream in = null;
+        try {
+            in = urlConnection.getInputStream();
+        } finally {
+            if (in != null) {
+                try {
+                    in.close();
+                } catch (IOException ignore) {
                 }
             }
         }
@@ -451,7 +463,7 @@ public class GroovyScriptEngine implements ResourceConnector {
      *              be laid out using their package structure like Java classes
      */
     private GroovyScriptEngine(URL[] roots, ClassLoader parent, ResourceConnector rc) {
-        if (roots == null) roots = new URL[0];
+        if (roots == null) roots = EMPTY_URL_ARRAY;
         this.roots = roots;
         if (rc == null) rc = this;
         this.rc = rc;
@@ -589,7 +601,7 @@ public class GroovyScriptEngine implements ResourceConnector {
     public Script createScript(String scriptName, Binding binding) throws ResourceException, ScriptException {
         return InvokerHelper.createScript(loadScriptByName(scriptName), binding);
     }
-    
+
     private long getLastModified(String scriptName) throws ResourceException {
         URLConnection conn = rc.getResourceConnection(scriptName);
         long lastMod = 0;
@@ -614,12 +626,12 @@ public class GroovyScriptEngine implements ResourceConnector {
             if (depEntry.sourceNewer) return true;
 
             // check if maybe dependency was recompiled, but this one here not
-            if (mainEntryLastCheck<depEntry.lastModified) {
+            if (mainEntryLastCheck < depEntry.lastModified) {
                 returnValue = true;
                 continue;
             }
 
-            if (now==0) now = getCurrentTime();
+            if (now == 0) now = getCurrentTime();
             long nextSourceCheck = depEntry.lastCheck + config.getMinimumRecompilationInterval();
             if (nextSourceCheck > now) continue;
 
diff --git a/src/main/groovy/util/ObservableMap.java b/src/main/groovy/util/ObservableMap.java
index 8edd85c..a676992 100644
--- a/src/main/groovy/util/ObservableMap.java
+++ b/src/main/groovy/util/ObservableMap.java
@@ -377,7 +377,9 @@ public class ObservableMap implements Map {
 
     public static class MultiPropertyEvent extends PropertyEvent {
         public static final String MULTI_PROPERTY = "groovy_util_ObservableMap_MultiPropertyEvent_MULTI";
-        private PropertyEvent[] events = new PropertyEvent[0];
+        private static final PropertyEvent[] EMPTY_PROPERTY_EVENTS = new PropertyEvent[0];
+
+        private PropertyEvent[] events = EMPTY_PROPERTY_EVENTS;
 
         public MultiPropertyEvent(Object source, PropertyEvent[] events) {
             super(source, MULTI_PROPERTY, ChangeType.oldValue, ChangeType.newValue, ChangeType.MULTI);
diff --git a/src/main/groovy/util/OrderBy.java b/src/main/groovy/util/OrderBy.java
index 3a79dea..82c808d 100644
--- a/src/main/groovy/util/OrderBy.java
+++ b/src/main/groovy/util/OrderBy.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2010 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -26,9 +26,8 @@ import java.util.List;
 /**
  * A helper class for sorting objects via a closure to return the field
  * or operation on which to sort.
- * 
+ *
  * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
- * @version $Revision$
  */
 public class OrderBy<T> implements Comparator<T> {
 
@@ -37,15 +36,28 @@ public class OrderBy<T> implements Comparator<T> {
     private final NumberAwareComparator<Object> numberAwareComparator = new NumberAwareComparator<Object>();
 
     public OrderBy() {
-        this.closures = new ArrayList<Closure>();
+        this(new ArrayList<Closure>(), false);
+    }
+
+    public OrderBy(boolean equalityCheck) {
+        this(new ArrayList<Closure>(), equalityCheck);
     }
 
     public OrderBy(Closure closure) {
-        this();
+        this(closure, false);
+    }
+
+    public OrderBy(Closure closure, boolean equalityCheck) {
+        this(new ArrayList<Closure>(), equalityCheck);
         closures.add(closure);
     }
 
     public OrderBy(List<Closure> closures) {
+        this(closures, false);
+    }
+
+    public OrderBy(List<Closure> closures, boolean equalityCheck) {
+        this.equalityCheck = equalityCheck;
         this.closures = closures;
     }
 
diff --git a/src/main/groovy/util/PermutationGenerator.java b/src/main/groovy/util/PermutationGenerator.java
index e1c5ede..9f1d97d 100644
--- a/src/main/groovy/util/PermutationGenerator.java
+++ b/src/main/groovy/util/PermutationGenerator.java
@@ -15,6 +15,8 @@
  */
 package groovy.util;
 
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+
 import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Collection;
@@ -54,6 +56,10 @@ public class PermutationGenerator<E> implements Iterator<List<E>> {
         reset();
     }
 
+    public PermutationGenerator(Iterable<E> items) {
+        this(DefaultGroovyMethods.asCollection(items));
+    }
+
     public void reset() {
         for (int i = 0; i < a.length; i++) {
             a[i] = i;
diff --git a/src/main/groovy/util/ProxyGenerator.java b/src/main/groovy/util/ProxyGenerator.java
index 8cefe48..d94cb77 100644
--- a/src/main/groovy/util/ProxyGenerator.java
+++ b/src/main/groovy/util/ProxyGenerator.java
@@ -19,6 +19,7 @@ import groovy.lang.*;
 import org.codehaus.groovy.runtime.*;
 import org.codehaus.groovy.runtime.memoize.LRUCache;
 import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
+import org.codehaus.groovy.transform.trait.Traits;
 
 import java.lang.ref.WeakReference;
 import java.lang.reflect.Modifier;
@@ -235,8 +236,12 @@ public class ProxyGenerator {
     }
     
     private static final class CacheKey {
-        private static final Comparator<Class> CLASSNAME_COMPARATOR = new Comparator<Class>() {
+        private static final Comparator<Class> INTERFACE_COMPARATOR = new Comparator<Class>() {
             public int compare(final Class o1, final Class o2) {
+                // Traits order *must* be preserved
+                // See GROOVY-7285
+                if (Traits.isTrait(o1)) return -1;
+                if (Traits.isTrait(o2)) return 1;
                 return o1.getName().compareTo(o2.getName());
             }
         };
@@ -254,9 +259,11 @@ public class ProxyGenerator {
             this.emptyMethods = emptyMethods;
             this.interfaces = interfaces == null ? null : new ClassReference[interfaces.length];
             if (interfaces != null) {
-                Arrays.sort(interfaces, CLASSNAME_COMPARATOR);
-                for (int i = 0; i < interfaces.length; i++) {
-                    Class anInterface = interfaces[i];
+                Class[] interfacesCopy = new Class[interfaces.length];
+                System.arraycopy(interfaces, 0, interfacesCopy, 0, interfaces.length);
+                Arrays.sort(interfacesCopy, INTERFACE_COMPARATOR);
+                for (int i = 0; i < interfacesCopy.length; i++) {
+                    Class anInterface = interfacesCopy[i];
                     this.interfaces[i] = new ClassReference(anInterface);
                 }
             }
diff --git a/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java b/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
index a8268ce..0e02c02 100644
--- a/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
+++ b/src/main/org/codehaus/groovy/antlr/AntlrParserPlugin.java
@@ -1441,8 +1441,7 @@ public class AntlrParserPlugin extends ASTHelper implements ParserPlugin, Groovy
         AST node = labelNode.getFirstChild();
         String label = identifier(node);
         Statement statement = statement(node.getNextSibling());
-        if (statement.getStatementLabel() == null) // if statement has multiple labels, retain the last one
-            statement.setStatementLabel(label);
+        statement.addStatementLabel(label);
         return statement;
     }
 
diff --git a/src/main/org/codehaus/groovy/antlr/groovy.g b/src/main/org/codehaus/groovy/antlr/groovy.g
index 47b4b8e..7527359 100644
--- a/src/main/org/codehaus/groovy/antlr/groovy.g
+++ b/src/main/org/codehaus/groovy/antlr/groovy.g
@@ -3961,9 +3961,16 @@ options {
         (
             DOLLAR_REGEXP_SYMBOL
             tt=DOLLAR_REGEXP_CTOR_END[true]
-        | {!atValidDollarEscape()}? '$'
+        | {!atValidDollarEscape() && !atDollarSlashEscape() && !atDollarDollarEscape()}? '$'
             tt=DOLLAR_REGEXP_CTOR_END[true]
-        | '$'!
+        |
+            ('$' '/') => ESCAPED_SLASH
+            tt=DOLLAR_REGEXP_CTOR_END[true]
+        |
+            ('$' '$') => ESCAPED_DOLLAR
+            tt=DOLLAR_REGEXP_CTOR_END[true]
+        |
+            '$'!
             {
                 // Yes, it's a regexp constructor, and we've got a value part.
                 tt = STRING_CTOR_START;
diff --git a/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java b/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
index f86ca51..7011658 100644
--- a/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
+++ b/src/main/org/codehaus/groovy/antlr/java/Java2GroovyMain.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,33 +15,11 @@
  */
 package org.codehaus.groovy.antlr.java;
 
-import antlr.collections.AST;
 import org.apache.commons.cli.CommandLine;
 import org.apache.commons.cli.CommandLineParser;
 import org.apache.commons.cli.GroovyInternalPosixParser;
 import org.apache.commons.cli.Options;
-import org.codehaus.groovy.antlr.AntlrASTProcessor;
-import org.codehaus.groovy.antlr.SourceBuffer;
-import org.codehaus.groovy.antlr.UnicodeEscapingReader;
-import org.codehaus.groovy.antlr.parser.GroovyLexer;
-import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
-import org.codehaus.groovy.antlr.treewalker.MindMapPrinter;
-import org.codehaus.groovy.antlr.treewalker.NodePrinter;
-import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal;
-import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal;
-import org.codehaus.groovy.antlr.treewalker.SourcePrinter;
-import org.codehaus.groovy.antlr.treewalker.Visitor;
-import org.codehaus.groovy.runtime.ResourceGroovyMethods;
-
-import java.io.ByteArrayOutputStream;
-import java.io.File;
-import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
-import java.io.PrintStream;
-import java.io.StringReader;
 import java.util.Arrays;
-import java.util.Iterator;
-import java.util.List;
 
 public class Java2GroovyMain {
 
@@ -54,148 +32,9 @@ public class Java2GroovyMain {
             if (filenames.length == 0) {
                 System.err.println("Needs at least one filename");
             }
-            List filenameList = Arrays.asList(filenames);
-            Iterator i = filenameList.iterator();
-            while (i.hasNext()) {
-                String filename = (String) i.next();
-                File f = new File(filename);
-                String text = ResourceGroovyMethods.getText(f);
-                System.out.println(convert(filename, text, true, true));
-            }
+            Java2GroovyProcessor.processFiles(Arrays.asList(filenames));
         } catch (Throwable t) {
             t.printStackTrace();
         }
     }
-
-    public static String convert(String filename, String input) throws Exception {
-        return convert(filename, input, false, false);
-    }
-
-    public static String convert(String filename, String input, boolean withHeader, boolean withNewLines) throws Exception {
-        JavaRecognizer parser = getJavaParser(input);
-        String[] tokenNames = parser.getTokenNames();
-        parser.compilationUnit();
-        AST ast = parser.getAST();
-
-        // output AST in format suitable for opening in http://freemind.sourceforge.net
-        // which is a really nice way of seeing the AST, folding nodes etc
-        if ("mindmap".equals(System.getProperty("ANTLR.AST".toLowerCase()))) { // uppercase to hide from jarjar
-            try {
-                PrintStream out = new PrintStream(new FileOutputStream(filename + ".mm"));
-                Visitor visitor = new MindMapPrinter(out, tokenNames);
-                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
-                treewalker.process(ast);
-            } catch (FileNotFoundException e) {
-                System.out.println("Cannot create " + filename + ".mm");
-            }
-        }
-
-        // modify the Java AST into a Groovy AST
-        modifyJavaASTintoGroovyAST(tokenNames, ast);
-        String[] groovyTokenNames = getGroovyTokenNames(input);
-        // groovify the fat Java-Like Groovy AST
-        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
-
-        // now output
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        Visitor visitor = new SourcePrinter(new PrintStream(baos), groovyTokenNames, withNewLines);
-        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
-
-        traverser.process(ast);
-
-        String header = "";
-        if (withHeader) {
-            header = "/*\n" +
-                    "  Automatically Converted from Java Source \n" +
-                    "  \n" +
-                    "  by java2groovy v0.0.1   Copyright Jeremy Rayner 2007\n" +
-                    "  \n" +
-                    "  !! NOT FIT FOR ANY PURPOSE !! \n" +
-                    "  'java2groovy' cannot be used to convert one working program into another" +
-                    "  */\n\n";
-        }
-        return header + new String(baos.toByteArray());
-    }
-
-    private static void groovifyFatJavaLikeGroovyAST(AST ast, String[] groovyTokenNames) {
-        Visitor groovifier = new Groovifier(groovyTokenNames);
-        AntlrASTProcessor groovifierTraverser = new PreOrderTraversal(groovifier);
-        groovifierTraverser.process(ast);
-    }
-
-    private static void modifyJavaASTintoGroovyAST(String[] tokenNames, AST ast) {
-        // mutate the tree when in Javaland
-        Visitor preJava2groovyConverter = new PreJava2GroovyConverter(tokenNames);
-        AntlrASTProcessor preJava2groovyTraverser = new PreOrderTraversal(preJava2groovyConverter);
-        preJava2groovyTraverser.process(ast);
-
-        // map the nodes to Groovy types
-        Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames);
-        AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter);
-        java2groovyTraverser.process(ast);
-    }
-
-    private static JavaRecognizer getJavaParser(String input) {
-        JavaRecognizer parser = null;
-        SourceBuffer sourceBuffer = new SourceBuffer();
-        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input), sourceBuffer);
-        JavaLexer lexer = new JavaLexer(unicodeReader);
-        unicodeReader.setLexer(lexer);
-        parser = JavaRecognizer.make(lexer);
-        parser.setSourceBuffer(sourceBuffer);
-        return parser;
-    }
-
-    public static String mindmap(String input) throws Exception {
-        JavaRecognizer parser = getJavaParser(input);
-        String[] tokenNames = parser.getTokenNames();
-        parser.compilationUnit();
-        AST ast = parser.getAST();
-        // modify the Java AST into a Groovy AST
-        modifyJavaASTintoGroovyAST(tokenNames, ast);
-        String[] groovyTokenNames = getGroovyTokenNames(input);
-        // groovify the fat Java-Like Groovy AST
-        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
-
-        // now output
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        Visitor visitor = new MindMapPrinter(new PrintStream(baos), groovyTokenNames);
-        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
-
-        traverser.process(ast);
-
-        return new String(baos.toByteArray());
-    }
-
-    public static String nodePrinter(String input) throws Exception {
-        JavaRecognizer parser = getJavaParser(input);
-        String[] tokenNames = parser.getTokenNames();
-        parser.compilationUnit();
-        AST ast = parser.getAST();
-        // modify the Java AST into a Groovy AST
-        modifyJavaASTintoGroovyAST(tokenNames, ast);
-        String[] groovyTokenNames = getGroovyTokenNames(input);
-        // groovify the fat Java-Like Groovy AST
-        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
-
-        // now output
-        ByteArrayOutputStream baos = new ByteArrayOutputStream();
-        Visitor visitor = new NodePrinter(new PrintStream(baos), groovyTokenNames);
-        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
-
-        traverser.process(ast);
-
-        return new String(baos.toByteArray());
-    }
-
-    private static String[] getGroovyTokenNames(String input) {
-        GroovyRecognizer groovyParser = null;
-        SourceBuffer groovySourceBuffer = new SourceBuffer();
-        UnicodeEscapingReader groovyUnicodeReader = new UnicodeEscapingReader(new StringReader(input), groovySourceBuffer);
-        GroovyLexer groovyLexer = new GroovyLexer(groovyUnicodeReader);
-        groovyUnicodeReader.setLexer(groovyLexer);
-        groovyParser = GroovyRecognizer.make(groovyLexer);
-        return groovyParser.getTokenNames();
-    }
-
 }
diff --git a/src/main/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java b/src/main/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java
new file mode 100644
index 0000000..1441fc3
--- /dev/null
+++ b/src/main/org/codehaus/groovy/antlr/java/Java2GroovyProcessor.java
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.antlr.java;
+
+import antlr.collections.AST;
+import org.codehaus.groovy.antlr.AntlrASTProcessor;
+import org.codehaus.groovy.antlr.SourceBuffer;
+import org.codehaus.groovy.antlr.UnicodeEscapingReader;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.antlr.treewalker.MindMapPrinter;
+import org.codehaus.groovy.antlr.treewalker.NodePrinter;
+import org.codehaus.groovy.antlr.treewalker.PreOrderTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourceCodeTraversal;
+import org.codehaus.groovy.antlr.treewalker.SourcePrinter;
+import org.codehaus.groovy.antlr.treewalker.Visitor;
+import org.codehaus.groovy.runtime.ResourceGroovyMethods;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.PrintStream;
+import java.io.StringReader;
+import java.util.Iterator;
+import java.util.List;
+
+public class Java2GroovyProcessor {
+
+    public static void processFiles(List<String> fileNames) throws Exception {
+        Iterator i = fileNames.iterator();
+        while (i.hasNext()) {
+            String filename = (String) i.next();
+            File f = new File(filename);
+            String text = ResourceGroovyMethods.getText(f);
+            System.out.println(convert(filename, text, true, true));
+        }
+    }
+
+    public static String convert(String filename, String input) throws Exception {
+        return convert(filename, input, false, false);
+    }
+
+    public static String convert(String filename, String input, boolean withHeader, boolean withNewLines) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+
+        // output AST in format suitable for opening in http://freemind.sourceforge.net
+        // which is a really nice way of seeing the AST, folding nodes etc
+        if ("mindmap".equals(System.getProperty("ANTLR.AST".toLowerCase()))) { // uppercase to hide from jarjar
+            try {
+                PrintStream out = new PrintStream(new FileOutputStream(filename + ".mm"));
+                Visitor visitor = new MindMapPrinter(out, tokenNames);
+                AntlrASTProcessor treewalker = new PreOrderTraversal(visitor);
+                treewalker.process(ast);
+            } catch (FileNotFoundException e) {
+                System.out.println("Cannot create " + filename + ".mm");
+            }
+        }
+
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new SourcePrinter(new PrintStream(baos), groovyTokenNames, withNewLines);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        String header = "";
+        if (withHeader) {
+            header = "/*\n" +
+                    "  Automatically Converted from Java Source \n" +
+                    "  \n" +
+                    "  by java2groovy v0.0.1   Copyright Jeremy Rayner 2007\n" +
+                    "  \n" +
+                    "  !! NOT FIT FOR ANY PURPOSE !! \n" +
+                    "  'java2groovy' cannot be used to convert one working program into another" +
+                    "  */\n\n";
+        }
+        return header + new String(baos.toByteArray());
+    }
+
+    private static void groovifyFatJavaLikeGroovyAST(AST ast, String[] groovyTokenNames) {
+        Visitor groovifier = new Groovifier(groovyTokenNames);
+        AntlrASTProcessor groovifierTraverser = new PreOrderTraversal(groovifier);
+        groovifierTraverser.process(ast);
+    }
+
+    private static void modifyJavaASTintoGroovyAST(String[] tokenNames, AST ast) {
+        // mutate the tree when in Javaland
+        Visitor preJava2groovyConverter = new PreJava2GroovyConverter(tokenNames);
+        AntlrASTProcessor preJava2groovyTraverser = new PreOrderTraversal(preJava2groovyConverter);
+        preJava2groovyTraverser.process(ast);
+
+        // map the nodes to Groovy types
+        Visitor java2groovyConverter = new Java2GroovyConverter(tokenNames);
+        AntlrASTProcessor java2groovyTraverser = new PreOrderTraversal(java2groovyConverter);
+        java2groovyTraverser.process(ast);
+    }
+
+    private static JavaRecognizer getJavaParser(String input) {
+        JavaRecognizer parser = null;
+        SourceBuffer sourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader unicodeReader = new UnicodeEscapingReader(new StringReader(input), sourceBuffer);
+        JavaLexer lexer = new JavaLexer(unicodeReader);
+        unicodeReader.setLexer(lexer);
+        parser = JavaRecognizer.make(lexer);
+        parser.setSourceBuffer(sourceBuffer);
+        return parser;
+    }
+
+    public static String mindmap(String input) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new MindMapPrinter(new PrintStream(baos), groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        return new String(baos.toByteArray());
+    }
+
+    public static String nodePrinter(String input) throws Exception {
+        JavaRecognizer parser = getJavaParser(input);
+        String[] tokenNames = parser.getTokenNames();
+        parser.compilationUnit();
+        AST ast = parser.getAST();
+        // modify the Java AST into a Groovy AST
+        modifyJavaASTintoGroovyAST(tokenNames, ast);
+        String[] groovyTokenNames = getGroovyTokenNames(input);
+        // groovify the fat Java-Like Groovy AST
+        groovifyFatJavaLikeGroovyAST(ast, groovyTokenNames);
+
+        // now output
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        Visitor visitor = new NodePrinter(new PrintStream(baos), groovyTokenNames);
+        AntlrASTProcessor traverser = new SourceCodeTraversal(visitor);
+
+        traverser.process(ast);
+
+        return new String(baos.toByteArray());
+    }
+
+    private static String[] getGroovyTokenNames(String input) {
+        GroovyRecognizer groovyParser = null;
+        SourceBuffer groovySourceBuffer = new SourceBuffer();
+        UnicodeEscapingReader groovyUnicodeReader = new UnicodeEscapingReader(new StringReader(input), groovySourceBuffer);
+        GroovyLexer groovyLexer = new GroovyLexer(groovyUnicodeReader);
+        groovyUnicodeReader.setLexer(groovyLexer);
+        groovyParser = GroovyRecognizer.make(groovyLexer);
+        return groovyParser.getTokenNames();
+    }
+
+}
diff --git a/src/main/org/codehaus/groovy/ast/ASTNode.java b/src/main/org/codehaus/groovy/ast/ASTNode.java
index 05a0159..a6627fc 100644
--- a/src/main/org/codehaus/groovy/ast/ASTNode.java
+++ b/src/main/org/codehaus/groovy/ast/ASTNode.java
@@ -18,6 +18,10 @@ package org.codehaus.groovy.ast;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.util.ListHashMap;
 
+import java.util.Collections;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
 /**
  * Base class for any AST node. This class supports basic information used in all nodes of the AST:
  * <ul>
@@ -176,4 +180,15 @@ public class ASTNode {
         }
         metaDataMap.remove(key);
     }
+
+    /**
+     * Returns an unmodifiable view of the current node metadata.
+     * @return the node metadata. Always not null.
+     */
+    public Map<?,?> getNodeMetaData() {
+        if (metaDataMap==null) {
+            return Collections.emptyMap();
+        }
+        return Collections.unmodifiableMap(metaDataMap);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/ast/ClassHelper.java b/src/main/org/codehaus/groovy/ast/ClassHelper.java
index ebe191c..c91b1b4 100644
--- a/src/main/org/codehaus/groovy/ast/ClassHelper.java
+++ b/src/main/org/codehaus/groovy/ast/ClassHelper.java
@@ -69,7 +69,8 @@ public class ClassHelper {
         MAP_TYPE = makeWithoutCaching(Map.class), RANGE_TYPE = makeCached(Range.class),
         PATTERN_TYPE = makeCached(Pattern.class), STRING_TYPE = makeCached(String.class),
         SCRIPT_TYPE = makeCached(Script.class),   REFERENCE_TYPE = makeWithoutCaching(Reference.class),
-        
+        BINDING_TYPE = makeCached(Binding.class),
+
         boolean_TYPE = makeCached(boolean.class),     char_TYPE = makeCached(char.class),
         byte_TYPE = makeCached(byte.class),           int_TYPE = makeCached(int.class),
         long_TYPE = makeCached(long.class),           short_TYPE = makeCached(short.class),
diff --git a/src/main/org/codehaus/groovy/ast/ClassNode.java b/src/main/org/codehaus/groovy/ast/ClassNode.java
index 0714911..12b2d7e 100644
--- a/src/main/org/codehaus/groovy/ast/ClassNode.java
+++ b/src/main/org/codehaus/groovy/ast/ClassNode.java
@@ -31,6 +31,7 @@ import org.codehaus.groovy.vmplugin.VMPluginFactory;
 import org.objectweb.asm.Opcodes;
 
 import java.lang.reflect.Array;
+import java.lang.reflect.Constructor;
 import java.util.*;
 
 /**
@@ -399,6 +400,7 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
         } else {
             return result;
         }
+
     }
 
     public List<MethodNode> getAllDeclaredMethods() {
@@ -485,6 +487,24 @@ public class ClassNode extends AnnotatedNode implements Opcodes {
         return r.constructors;
     }
 
+    /**
+     * Finds a constructor matching the given parameters in this class.
+     *
+     * @return the constructor matching the given parameters or null
+     */
+    public ConstructorNode getDeclaredConstructor(Parameter[] parameters) {
+        for (ConstructorNode method : getDeclaredConstructors()) {
+            if (parametersEqual(method.getParameters(), parameters)) {
+                return method;
+            }
+        }
+        return null;
+    }
+
+    public void removeConstructor(ConstructorNode node) {
+        redirect().constructors.remove(node);
+    }
+
     public ModuleNode getModule() {
         return redirect().module;
     }
diff --git a/src/main/org/codehaus/groovy/ast/GenericsType.java b/src/main/org/codehaus/groovy/ast/GenericsType.java
index 575caa0..bbccb74 100644
--- a/src/main/org/codehaus/groovy/ast/GenericsType.java
+++ b/src/main/org/codehaus/groovy/ast/GenericsType.java
@@ -33,6 +33,8 @@ import java.util.Set;
  * @see ClassNode
  */
 public class GenericsType extends ASTNode {
+    public static final GenericsType[] EMPTY_ARRAY = new GenericsType[0];
+    
     private final ClassNode[] upperBounds;
     private final ClassNode lowerBound;
     private ClassNode type;
diff --git a/src/main/org/codehaus/groovy/ast/MixinASTTransformation.java b/src/main/org/codehaus/groovy/ast/MixinASTTransformation.java
index 24c3aa7..ab15e1b 100644
--- a/src/main/org/codehaus/groovy/ast/MixinASTTransformation.java
+++ b/src/main/org/codehaus/groovy/ast/MixinASTTransformation.java
@@ -70,7 +70,7 @@ public class MixinASTTransformation extends AbstractASTTransformation {
         if (parent instanceof ClassNode) {
             ClassNode annotatedClass = (ClassNode) parent;
 
-            final Parameter[] noparams = new Parameter[0];
+            final Parameter[] noparams = Parameter.EMPTY_ARRAY;
             MethodNode clinit = annotatedClass.getDeclaredMethod("<clinit>", noparams);
             if (clinit == null) {
                 clinit = annotatedClass.addMethod("<clinit>", ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC, ClassHelper.VOID_TYPE, noparams, null, new BlockStatement());
diff --git a/src/main/org/codehaus/groovy/ast/ModuleNode.java b/src/main/org/codehaus/groovy/ast/ModuleNode.java
index 4fbaa6b..533d54d 100644
--- a/src/main/org/codehaus/groovy/ast/ModuleNode.java
+++ b/src/main/org/codehaus/groovy/ast/ModuleNode.java
@@ -18,11 +18,13 @@ package org.codehaus.groovy.ast;
 import groovy.lang.Binding;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstructorCallExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.transform.BaseScriptASTTransformation;
@@ -65,6 +67,7 @@ public class ModuleNode extends ASTNode implements Opcodes {
     private boolean importsResolved = false;
     private ClassNode scriptDummy;
     private String mainClassName = null;
+    private final Parameter[] SCRIPT_CONTEXT_CTOR = {new Parameter(ClassHelper.BINDING_TYPE, "context")};
 
     public ModuleNode (SourceUnit context ) {
         this.context = context;
@@ -240,7 +243,7 @@ public class ModuleNode extends ASTNode implements Opcodes {
         if (getDescription() == null) {
             throw new RuntimeException("Cannot generate main(String[]) class for statements when we have no file description");
         }
-        name += extractClassFromFileDescription();
+        name += GeneratorContext.encodeAsValidClassName(extractClassFromFileDescription());
 
         ClassNode classNode;
         if (isPackageInfo()) {
@@ -301,12 +304,25 @@ public class ModuleNode extends ASTNode implements Opcodes {
         classNode.addMethod(methodNode);
 
         classNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, new BlockStatement());
-        Statement stmt = new ExpressionStatement(
-                        new MethodCallExpression(
+
+        Statement stmt;
+        // A script's contextual constructor should call it's super class' contextual constructor, if it has one.
+        // In practice this will always be true because currently this visitor is run before the AST transformations
+        // (like @BaseScript) that could change this.  But this is cautious and anticipates possible compiler changes.
+        if (classNode.getSuperClass().getDeclaredConstructor(SCRIPT_CONTEXT_CTOR) != null) {
+            stmt = new ExpressionStatement(
+                    new ConstructorCallExpression(ClassNode.SUPER,
+                            new ArgumentListExpression(
+                                    new VariableExpression("context"))));
+        } else {
+            // Fallback for non-standard base "script" classes with no context (Binding) constructor.
+            stmt = new ExpressionStatement(
+                    new MethodCallExpression(
                             new VariableExpression("super"),
                             "setBinding",
                             new ArgumentListExpression(
-                                        new VariableExpression("context"))));
+                                    new VariableExpression("context"))));
+        }
 
         classNode.addConstructor(
             ACC_PUBLIC,
diff --git a/src/main/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java b/src/main/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
index e385cb5..d2092b9 100644
--- a/src/main/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
+++ b/src/main/org/codehaus/groovy/ast/builder/AstBuilderTransformation.java
@@ -19,6 +19,7 @@ import groovy.lang.MissingPropertyException;
 import org.codehaus.groovy.ast.*;
 import org.codehaus.groovy.ast.expr.*;
 import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.ClosureUtils;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.io.ReaderSource;
@@ -285,37 +286,12 @@ public class AstBuilderTransformation implements ASTTransformation {
          * @return the source the closure was created from
          */
         private String convertClosureToSource(ClosureExpression expression) {
-            if (expression == null) throw new IllegalArgumentException("Null: expression");
-
-            StringBuilder result = new StringBuilder();
-            for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
-                String line = source.getLine(x, null);
-                if (line == null) {
-                    addError(
-                            "Error calculating source code for expression. Trying to read line " + x + " from " + source.getClass(),
-                            expression
-                    );
-                }
-                if (x == expression.getLastLineNumber()) {
-                    line = line.substring(0, expression.getLastColumnNumber() - 1);
-                }
-                if (x == expression.getLineNumber()) {
-                    line = line.substring(expression.getColumnNumber() - 1);
-                }
-                //restoring line breaks is important b/c of lack of semicolons
-                result.append(line).append('\n');
-            }
-
-
-            String source = result.toString().trim();
-            if (!source.startsWith("{")) {
-                addError(
-                        "Error converting ClosureExpression into source code. Closures must start with {. Found: " + source,
-                        expression
-                );
+            try {
+                return ClosureUtils.convertClosureToSource(source, expression);
+            } catch(Exception e) {
+                addError(e.getMessage(), expression);
             }
-
-            return source;
+            return null;
         }
     }
 }
diff --git a/src/main/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy b/src/main/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
index 34cc9b0..8eb0e80 100644
--- a/src/main/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
+++ b/src/main/org/codehaus/groovy/ast/builder/AstSpecificationCompiler.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2010 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -106,17 +106,14 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     /**
      * Creates the DSL compiler.
      */
-
     AstSpecificationCompiler(@DelegatesTo(AstSpecificationCompiler) Closure spec) {
         spec.delegate = this
         spec()
     }
 
-
     /**
      * Gets the current generated expression.
      */
-
     List<ASTNode> getExpression() {
         return expression
     }
@@ -187,13 +184,10 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     */ 
     private void makeNode(Class target, String typeAlias, List<Class<? super ASTNode>> ctorArgs, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode(target.class.simpleName, argBlock) {
-            target.newInstance(
-                    * enforceConstraints(typeAlias, ctorArgs)
-            )
+            target.newInstance(*enforceConstraints(typeAlias, ctorArgs))
         }
     }
 
-
     /**
     * Helper method to convert a DSL invocation with a list of parameters specified 
     * in a Closure into an ASTNode instance. 
@@ -210,7 +204,6 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
     * Helper method to convert a DSL invocation with a String parameter into a List of ASTNode instances. 
     * 
@@ -225,7 +218,6 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
     * Helper method to convert a DSL invocation with a String parameter into an Array of ASTNode instances. 
     * 
@@ -239,7 +231,6 @@ class AstSpecificationCompiler implements GroovyInterceptable {
             expression.toArray(target)
         }
     }
-
     
     /**
     * Helper method to convert a DSL invocation into an ASTNode instance when a Class parameter is specified. 
@@ -258,107 +249,83 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     private void makeNodeWithClassParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, Class type) {
         captureAndCreateNode(target.class.simpleName, argBlock) {
             expression.add(0, ClassHelper.make(type))
-            target.newInstance(
-                    * enforceConstraints(alias, spec)
-            )
+            target.newInstance(*enforceConstraints(alias, spec))
         }
     }
 
     private void makeNodeWithStringParameter(Class target, String alias, List<Class> spec, @DelegatesTo(AstSpecificationCompiler) Closure argBlock, String text) {
         captureAndCreateNode(target.class.simpleName, argBlock) {
             expression.add(0, text)
-            target.newInstance(
-                    * enforceConstraints(alias, spec)
-            )
+            target.newInstance(*enforceConstraints(alias, spec))
         }
     }
 
-
     /**
      * Creates a CastExpression.
      */
-
     void cast(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeWithClassParameter(CastExpression, 'cast', [ClassNode, Expression], argBlock, type)
     }
 
-
     /**
      * Creates an ConstructorCallExpression.
      */
-
     void constructorCall(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeWithClassParameter(ConstructorCallExpression, 'constructorCall', [ClassNode, Expression], argBlock, type)
     }
 
-
     /**
      * Creates a MethodCallExpression.
      */
-
     void methodCall(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(MethodCallExpression, 'methodCall', [Expression, Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates an AnnotationConstantExpression.
      */
-
     void annotationConstant(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(AnnotationConstantExpression, 'annotationConstant', [AnnotationNode], argBlock)
     }
 
-
     /**
      * Creates a PostfixExpression.
      */
-
     void postfix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(PostfixExpression, 'postfix', [Expression, Token], argBlock)
     }
 
-
     /**
      * Creates a FieldExpression.
      */
-
     void field(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(FieldExpression, 'field', [FieldNode], argBlock)
     }
 
-
     /**
      * Creates a MapExpression.
      */
-
     void map(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeFromList(MapExpression, argBlock)
     }
 
-
     /**
      * Creates a TupleExpression.
      */
-
     void tuple(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeFromList(TupleExpression, argBlock)
     }
 
-
     /**
      * Creates a MapEntryExpression.
      */
-
     void mapEntry(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(MapEntryExpression, 'mapEntry', [Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates a gString.
      */
-
     void gString(String verbatimText, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeWithStringParameter(GStringExpression, 'gString', [String, List, List], argBlock, verbatimText)
     }
@@ -372,88 +339,69 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         makeNode(MethodPointerExpression, 'methodPointer', [Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates a property.
      */
-
     void property(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(PropertyExpression, 'property', [Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates a RangeExpression.
      */
-
     void range(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(RangeExpression, 'range', [Expression, Expression, Boolean], argBlock)
     }
 
-
     /**
      * Creates EmptyStatement.
      */
-
     void empty() {
         expression << EmptyStatement.INSTANCE
     }
 
-
     /**
      * Creates a label.
      */
-
     void label(String label) {
         expression << label
     }
 
-
     /**
      * Creates an ImportNode.
      */
-
     void importNode(Class target, String alias = null) {
         expression << new ImportNode(ClassHelper.make(target), alias)
     }
 
-
     /**
      * Creates a CatchStatement.
      */
-
     void catchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(CatchStatement, 'catchStatement', [Parameter, Statement], argBlock)
     }
 
-
     /**
      * Creates a ThrowStatement.
      */
-
     void throwStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ThrowStatement, 'throwStatement', [Expression], argBlock)
     }
 
-
     /**
      * Creates a SynchronizedStatement.
      */
-
     void synchronizedStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(SynchronizedStatement, 'synchronizedStatement', [Expression, Statement], argBlock)
     }
 
-
     /**
      * Creates a ReturnStatement.
      */
-
     void returnStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ReturnStatement, 'returnStatement', [Expression], argBlock)
     }
 
-
     /**
      * Creates a TernaryExpression.
      */
@@ -466,16 +414,13 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     /**
      * Creates an ElvisOperatorExpression.
      */
-
     void elvisOperator(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ElvisOperatorExpression, 'elvisOperator', [Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates a BreakStatement.
      */
-
     void breakStatement(String label = null) {
         if (label) {
             expression << new BreakStatement(label)
@@ -484,11 +429,9 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates a ContinueStatement.
      */
-
     void continueStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
         if (!argBlock) {
             expression << new ContinueStatement()
@@ -497,69 +440,84 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Create a CaseStatement.
      */
-
     void caseStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(CaseStatement, 'caseStatement', [Expression, Statement], argBlock)
     }
 
-
     /**
      * Creates a BlockStatement.
      */
-
     void defaultCase(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         block(argBlock) // same as arg block
     }
 
-
     /**
      * Creates a PrefixExpression.
      */
-
     void prefix(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(PrefixExpression, 'prefix', [Token, Expression], argBlock)
     }
 
-
     /**
      * Creates a NotExpression.
      */
-
     void not(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(NotExpression, 'not', [Expression], argBlock)
     }
 
-
     /**
      * Creates a DynamicVariable.
      */
-
     void dynamicVariable(String variable, boolean isStatic = false) {
         expression << new DynamicVariable(variable, isStatic)
     }
 
-
     /**
      * Creates a ClassNode[].
      */
-
     void exceptions(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeArrayOfNodes([] as ClassNode[], argBlock)
     }
 
-
     /**
      * Designates a list of AnnotationNodes.
      */
-
     void annotations(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeListOfNodes(argBlock, "List<AnnotationNode>")
     }
 
+
+    /**
+     * Designates a list of MethodNodes.
+     */
+    void methods(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<MethodNode>")
+    }
+
+    /**
+     * Designates a list of ConstructorNodes.
+     */
+    void constructors(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<ConstructorNode>")
+    }
+
+    /**
+     * Designates a list of {@code PropertyNode}s.
+     */
+    void properties(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<PropertyNode>")
+    }
+
+    /**
+     * Designates a list of {@code FieldNode}s.
+     */
+    void fields(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
+        makeListOfNodes(argBlock, "List<FieldNode>")
+    }
+
     /**
      * Designates a list of ConstantExpressions.
      */
@@ -576,247 +534,193 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         makeListOfNodes(argBlock, "List<Expression>")
     }
 
-
     /**
      * Creates a boolean value.
      */
-
     void inclusive(boolean value) {
         expression << value
     }
 
-
     /**
      * Creates a ConstantExpression.
      */
-
     void constant(Object value) {
         expression << new ConstantExpression(value)
     }
 
-
     /**
      * Creates an IfStatement.
      */
-
     void ifStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(IfStatement, 'ifStatement', [BooleanExpression, Statement, Statement], argBlock)
     }
 
-
     /**
      * Creates a SpreadExpression.
      */
-
     void spread(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(SpreadExpression, 'spread', [Expression], argBlock)
     }
 
-
     /**
      * Creates a SpreadMapExpression.
      */
-
     void spreadMap(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(SpreadMapExpression, 'spreadMap', [Expression], argBlock)
     }
 
-
     /**
      * Creates a WhileStatement.
      */
-
     void whileStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(WhileStatement, 'whileStatement', [BooleanExpression, Statement], argBlock)
     }
 
-
     /**
      * Create a ForStatement.
      */
-
     void forStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ForStatement, 'forStatement', [Parameter, Expression, Statement], argBlock)
     }
 
-
     /**
      * Creates a ClosureListExpression.
      */
-
     void closureList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeFromList(ClosureListExpression, argBlock)
     }
 
-
     /**
      * Creates a DeclarationExpression.
      */
-
     void declaration(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(DeclarationExpression, 'declaration', [Expression, Token, Expression], argBlock)
     }
 
-
     /**
      * Creates a ListExpression.
      */
-
     void list(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeFromList(ListExpression, argBlock)
     }
 
-
     /**
      * Creates a BitwiseNegationExpression.
      */
-
     void bitwiseNegation(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(BitwiseNegationExpression, 'bitwiseNegation', [Expression], argBlock)
     }
 
-
     /**
      * Creates a ClosureExpression.
      */
-
     void closure(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ClosureExpression, 'closure', [Parameter[], Statement], argBlock)
     }
 
-
     /**
      * Creates a BooleanExpression.
      */
-
     void booleanExpression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(BooleanExpression, 'booleanExpression', [Expression], argBlock)
     }
 
-
     /**
      * Creates a BinaryExpression.
      */
-
     void binary(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(BinaryExpression, 'binary', [Expression, Token, Expression], argBlock)
     }
 
-
     /**
      * Creates a UnaryPlusExpression.
      */
-
     void unaryPlus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(UnaryPlusExpression, 'unaryPlus', [Expression], argBlock)
     }
 
-
     /**
      * Creates a ClassExpression.
      */
-
     void classExpression(Class type) {
         expression << new ClassExpression(ClassHelper.make(type))
     }
 
-
     /**
      * Creates a UnaryMinusExpression
      */
-
     void unaryMinus(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(UnaryMinusExpression, 'unaryMinus', [Expression], argBlock)
     }
 
-
     /**
      * Creates an AttributeExpression.
      */
-
     void attribute(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(AttributeExpression, 'attribute', [Expression, Expression], argBlock)
     }
 
-
     /**
      * Creates an ExpressionStatement.
      */
-
     void expression(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNode(ExpressionStatement, 'expression', [Expression], argBlock)
     }
 
-
     /**
      * Creates a NamedArgumentListExpression.
      */
-
     void namedArgumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeNodeFromList(NamedArgumentListExpression, argBlock)
     }
 
-
     /**
      * Creates a ClassNode[].
      */
-
     void interfaces(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeListOfNodes(argBlock, "List<ClassNode>")
     }
 
-
     /**
      * Creates a MixinNode[].
      */
-
     void mixins(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeListOfNodes(argBlock, "List<MixinNode>")
     }
 
-
     /**
      * Creates a GenericsTypes[].
      */
-
     void genericsTypes(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeListOfNodes(argBlock, "List<GenericsTypes>")
     }
 
-
     /**
      * Creates a ClassNode.
      */
-
     void classNode(Class target) {
         expression << ClassHelper.make(target, false)
     }
 
-
     /**
      * Creates a Parameter[].
      */
-
     void parameters(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeArrayOfNodes([] as Parameter[], argBlock)
     }
 
-
     /**
      * Creates a BlockStatement.
      */
-
     void block(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("BlockStatement", argBlock) {
             return new BlockStatement(new ArrayList(expression), new VariableScope())
         }
     }
 
-
     /**
      * Creates a Parameter.
      */
-
     void parameter(Map<String, Class> args, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
         if (!args) throw new IllegalArgumentException()
         if (args.size() > 1) throw new IllegalArgumentException()
@@ -835,23 +739,18 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates an ArrayExpression.
      */
-
     void array(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("ArrayExpression", argBlock) {
             new ArrayExpression(ClassHelper.make(type), new ArrayList(expression))
         }
     }
 
-
-
     /**
      * Creates a GenericsType.
      */
-
     void genericsType(Class type, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
         if (argBlock) {
             captureAndCreateNode("GenericsType", argBlock) {
@@ -863,14 +762,14 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     }
 
     /**
-     * Creates a list of ClassNodes.
+     * Creates a list of upperBound ClassNodes.
      */
     void upperBound(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         makeListOfNodes(argBlock, 'List<ClassNode>')
     }
 
     /**
-     * Creates a list of ClassNodes. 
+     * Create lowerBound ClassNode.
      */
     void lowerBound(Class target) {
         expression << ClassHelper.make(target)
@@ -879,18 +778,15 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     /**
      * Creates a 2 element list of name and Annotation. Used with Annotation Members.
      */
-
     void member(String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("Annotation Member", argBlock) {
             [name, expression[0]]
         }
     }
 
-
     /**
      * Creates an ArgumentListExpression.
      */
-
     void argumentList(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         if (!argBlock) {
             expression << new ArgumentListExpression()
@@ -899,11 +795,9 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates an AnnotationNode.
      */
-
     void annotation(Class target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock = null) {
         if (argBlock) {
             //todo: add better error handling
@@ -919,11 +813,9 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates a MixinNode.
      */
-
     void mixin(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("AttributeExpression", argBlock) {
             if (expression.size() > 1) {
@@ -934,12 +826,9 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
-
     /**
      * Creates a ClassNode
      */
-
     void classNode(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("ClassNode", argBlock) {
             def result = new ClassNode(name, modifiers,
@@ -947,37 +836,63 @@ class AstSpecificationCompiler implements GroovyInterceptable {
                     new ArrayList(expression[1]) as ClassNode[],
                     new ArrayList(expression[2]) as MixinNode[]
             )
-            if (expression[3]) {
-                result.setGenericsTypes(new ArrayList(expression[3]) as GenericsType[])
+            while (expression.size() > 3) {
+                if (!List.isAssignableFrom(expression[3].getClass())) {
+                    throw new IllegalArgumentException("Expecting to find list of additional items instead found: " + expression[3].getClass())
+                }
+                if (expression[3].size() > 0) {
+                    def clazz = expression[3][0].getClass()
+                    switch(clazz) {
+                        case GenericsType:
+                            result.setGenericsTypes(new ArrayList(expression[3]) as GenericsType[])
+                            break
+                        case MethodNode:
+                            expression[3].each{ result.addMethod(it) }
+                            break
+                        case ConstructorNode:
+                            expression[3].each{ result.addConstructor(it) }
+                            break
+                        case PropertyNode:
+                            expression[3].each{
+                                it.field.owner = result
+                                result.addProperty(it)
+                            }
+                            break
+                        case FieldNode:
+                            expression[3].each{
+                                it.owner = result
+                                result.addField(it)
+                            }
+                            break
+                        case AnnotationNode:
+                            result.addAnnotations(new ArrayList(expression[3]))
+                            break
+                        default:
+                            throw new IllegalArgumentException("Unexpected item found in ClassNode spec. Expecting [Field|Method|Property|Constructor|Annotation|GenericsType] but found: $clazz.name")
+                    }
+                }
+                expression.remove(3)
             }
             result
         }
     }
 
-
     /**
      * Creates an AssertStatement.
      */
-
     void assertStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("AssertStatement", argBlock) {
             if (expression.size() < 2) {
-                new AssertStatement(
-                        * enforceConstraints('assertStatement', [BooleanExpression])
-                )
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression]))
             } else {
-                new AssertStatement(
-                        * enforceConstraints('assertStatement', [BooleanExpression, Expression])
-                )
+                new AssertStatement(*enforceConstraints('assertStatement', [BooleanExpression, Expression]))
             }
         }
     }
 
-
     /**
      * Creates a TryCatchStatement.
      */
-
     void tryCatch(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("TryCatchStatement", argBlock) {
             def result = new TryCatchStatement(expression[0], expression[1])
@@ -987,39 +902,30 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates a VariableExpression.
      */
-
     void variable(String variable) {
         expression << new VariableExpression(variable)
     }
 
-
     /**
      * Creates a MethodNode.
      */
-
     void method(String name, int modifiers, Class returnType, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("MethodNode", argBlock) {
             //todo: enforce contract
-            def result = new MethodNode(
-                    name, modifiers, ClassHelper.make(returnType), expression[0], expression[1], expression[2]
-            )
+            def result = new MethodNode(name, modifiers, ClassHelper.make(returnType), expression[0], expression[1], expression[2])
             if (expression[3]) {
-                def annotations = expression[3]
-                result.addAnnotations(new ArrayList(annotations))
+                result.addAnnotations(new ArrayList(expression[3]))
             }
             result
         }
     }
 
-
     /**
      * Creates a token.
      */
-
     void token(String value) {
         if (value == null) throw new IllegalArgumentException("Null: value")
 
@@ -1032,24 +938,17 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         expression << new Token(tokenID, value, -1, -1)
     }
 
-
     /**
      * Creates a RangeExpression.
      */
-
     void range(Range range) {
         if (range == null) throw new IllegalArgumentException('Null: range')
-        expression << new RangeExpression(
-                new ConstantExpression(range.getFrom()),
-                new ConstantExpression(range.getTo()),
-                true)   //default is inclusive
+        expression << new RangeExpression(new ConstantExpression(range.getFrom()), new ConstantExpression(range.getTo()), true) //default is inclusive
     }
 
-
     /**
      * Creates a SwitchStatement.
      */
-
     void switchStatement(@DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("SwitchStatement", argBlock) {
             def switchExpression = expression.head()
@@ -1059,11 +958,9 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates a mapEntry.
      */
-
     void mapEntry(Map map) {
         map.entrySet().each {
             expression << new MapEntryExpression(
@@ -1076,28 +973,31 @@ class AstSpecificationCompiler implements GroovyInterceptable {
     // todo: these methods can still be reduced smaller
     //
 
-
     /**
      * Creates a FieldNode.
      */
-
     void fieldNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("FieldNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 1) {
+                annotations = expression[1]
+                expression.remove(1)
+            }
             expression.add(0, ClassHelper.make(owner))
             expression.add(0, ClassHelper.make(type))
             expression.add(0, modifiers)
             expression.add(0, name)
-            new FieldNode(
-                    * enforceConstraints('fieldNode', [String, Integer, ClassNode, ClassNode, Expression]))
+            def result = new FieldNode(*enforceConstraints('fieldNode', [String, Integer, ClassNode, ClassNode, Expression]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
         }
     }
 
-
-
     /**
-     * Creates a property.
+     * Creates an inner class.
      */
-
     void innerClass(String name, int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("InnerClassNode", argBlock) {
             //todo: enforce contract
@@ -1111,63 +1011,67 @@ class AstSpecificationCompiler implements GroovyInterceptable {
         }
     }
 
-
     /**
      * Creates a PropertyNode.
      */
-
     void propertyNode(String name, int modifiers, Class type, Class owner, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         //todo: improve error handling?
         captureAndCreateNode("PropertyNode", argBlock) {
-            new PropertyNode(name, modifiers, ClassHelper.make(type), ClassHelper.make(owner),
-                    expression[0],  // initial value
-                    expression[1],  // getter block
-                    expression[2])  // setter block
+            def annotations = null
+            // check if the last expression looks like annotations
+            if (List.isAssignableFrom(expression[-1].getClass())) {
+                annotations = expression[-1]
+                expression.remove(expression.size() - 1)
+            }
+            def result = new PropertyNode(name, modifiers, ClassHelper.make(type), ClassHelper.make(owner),
+                    expression[0],  // initial value (possibly null)
+                    expression[1],  // getter block (possibly null)
+                    expression[2])  // setter block (possibly null)
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
         }
     }
 
-
-
     /**
      * Creates a StaticMethodCallExpression.
      */
-
     void staticMethodCall(Class target, String name, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("StaticMethodCallExpression", argBlock) {
             expression.add(0, name)
             expression.add(0, ClassHelper.make(target))
-            new StaticMethodCallExpression(
-                    * enforceConstraints('staticMethodCall', [ClassNode, String, Expression])
-            )
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
         }
     }
 
-
     /**
      * Creates a StaticMethodCallExpression.
      */
-
     void staticMethodCall(MethodClosure target, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("StaticMethodCallExpression", argBlock) {
             expression.add(0, target.method)
             expression.add(0, ClassHelper.makeWithoutCaching(target.owner.class, false))
-            new StaticMethodCallExpression(
-                    * enforceConstraints('staticMethodCall', [ClassNode, String, Expression])
-            )
+            new StaticMethodCallExpression(*enforceConstraints('staticMethodCall', [ClassNode, String, Expression]))
         }
     }
 
-
     /**
      * Creates a ConstructorNode.
      */
-
     void constructor(int modifiers, @DelegatesTo(AstSpecificationCompiler) Closure argBlock) {
         captureAndCreateNode("ConstructorNode", argBlock) {
+            def annotations = null
+            if (expression.size() > 3) {
+                annotations = expression[3]
+                expression.remove(3)
+            }
             expression.add(0, modifiers)
-            new ConstructorNode(
-                    * enforceConstraints('constructor', [Integer, Parameter[], ClassNode[], Statement])
-            )
+            def result = new ConstructorNode(*enforceConstraints('constructor', [Integer, Parameter[], ClassNode[], Statement]))
+            if (annotations) {
+                result.addAnnotations(new ArrayList(annotations))
+            }
+            result
         }
     }
 }
diff --git a/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java b/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java
index 380a98a..82f0a2e 100644
--- a/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java
+++ b/src/main/org/codehaus/groovy/ast/expr/ConstantExpression.java
@@ -61,6 +61,8 @@ public class ConstantExpression extends Expression {
                     setType(ClassHelper.double_TYPE);
                 } else if (value instanceof Float) {
                     setType(ClassHelper.float_TYPE);
+                } else if (value instanceof Character) {
+                    setType(ClassHelper.char_TYPE);
                 } else {
                     setType(ClassHelper.make(value.getClass()));
                 }
diff --git a/src/main/org/codehaus/groovy/ast/stmt/Statement.java b/src/main/org/codehaus/groovy/ast/stmt/Statement.java
index 87d7abd..28cf9e6 100644
--- a/src/main/org/codehaus/groovy/ast/stmt/Statement.java
+++ b/src/main/org/codehaus/groovy/ast/stmt/Statement.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2007 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,30 +17,45 @@ package org.codehaus.groovy.ast.stmt;
 
 import org.codehaus.groovy.ast.ASTNode;
 
+import java.util.LinkedList;
+import java.util.List;
+
 /**
  * Base class for any statement
- * 
+ *
  * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
- * @version $Revision$
  */
 public class Statement extends ASTNode {
 
-    private String statementLabel;
+    private List<String> statementLabels;
 
     public Statement() {
-        statementLabel = null;
+        statementLabels = null;
+    }
+
+    public List<String> getStatementLabels() {
+        return statementLabels;
     }
 
+    // TODO @Deprecated
     public String getStatementLabel() {
-        return statementLabel;
+        // last label by default which is added first by APP
+        return statementLabels == null ? null : statementLabels.get(0);
     }
 
-    public void setStatementLabel( String label ) {
-        statementLabel = label;
+    // TODO @Deprecated
+    public void setStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new LinkedList<String>();
+        statementLabels.add(label);
+    }
+
+    public void addStatementLabel(String label) {
+        if (statementLabels == null) statementLabels = new LinkedList<String>();
+        statementLabels.add(label);
     }
 
     public boolean isEmpty() {
         return false;
     }
-    
+
 }
diff --git a/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java b/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
new file mode 100644
index 0000000..c57c950
--- /dev/null
+++ b/src/main/org/codehaus/groovy/ast/tools/ClosureUtils.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.ast.tools;
+
+import org.codehaus.groovy.ast.expr.ClosureExpression;
+import org.codehaus.groovy.control.io.ReaderSource;
+/**
+ * Handy methods when working with the Closure expressions.
+ *
+ * @author Hamlet D'Arcy
+ * @author Sergei Egorov
+ */
+
+public class ClosureUtils {
+
+    /**
+     * Converts a ClosureExpression into the String source.
+     *
+     * @param readerSource a source
+     * @param expression a closure. Can't be null
+     * @return the source the closure was created from
+     * @throws java.lang.IllegalArgumentException when expression is null
+     * @throws java.lang.Exception when closure can't be read from source
+     */
+    public static String convertClosureToSource(ReaderSource readerSource, ClosureExpression expression) throws Exception {
+        if (expression == null) throw new IllegalArgumentException("Null: expression");
+
+        StringBuilder result = new StringBuilder();
+        for (int x = expression.getLineNumber(); x <= expression.getLastLineNumber(); x++) {
+            String line = readerSource.getLine(x, null);
+            if (line == null) {
+                throw new Exception(
+                        "Error calculating source code for expression. Trying to read line " + x + " from " + readerSource.getClass()
+                );
+            }
+            if (x == expression.getLastLineNumber()) {
+                line = line.substring(0, expression.getLastColumnNumber() - 1);
+            }
+            if (x == expression.getLineNumber()) {
+                line = line.substring(expression.getColumnNumber() - 1);
+            }
+            //restoring line breaks is important b/c of lack of semicolons
+            result.append(line).append('\n');
+        }
+
+
+        String source = result.toString().trim();
+        if (!source.startsWith("{")) {
+            throw new Exception("Error converting ClosureExpression into source code. Closures must start with {. Found: " + source);
+        }
+
+        return source;
+    }
+}
diff --git a/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java b/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
index 72d734a..974d485 100644
--- a/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
+++ b/src/main/org/codehaus/groovy/ast/tools/GenericsUtils.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2014 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,17 +15,35 @@
  */
 package org.codehaus.groovy.ast.tools;
 
+import antlr.RecognitionException;
+import antlr.TokenStreamException;
+import groovy.transform.stc.IncorrectTypeHintException;
 import org.codehaus.groovy.GroovyBugError;
+import org.codehaus.groovy.antlr.AntlrParserPlugin;
+import org.codehaus.groovy.antlr.parser.GroovyLexer;
+import org.codehaus.groovy.antlr.parser.GroovyRecognizer;
+import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.ast.Parameter;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.control.CompilationUnit;
+import org.codehaus.groovy.control.ResolveVisitor;
+import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.ParserException;
+import org.codehaus.groovy.syntax.Reduction;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 
+import java.io.StringReader;
+import java.util.ArrayList;
 import java.util.Collections;
 import java.util.HashMap;
+import java.util.List;
 import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
 
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.extractSuperClassGenerics;
@@ -188,8 +206,11 @@ public class GenericsUtils {
      * @return a parameterized interface class node
      */
     public static ClassNode parameterizeType(final ClassNode hint, final ClassNode target) {
-        if (hint.isArray() && target.isArray()) {
-            return parameterizeType(hint.getComponentType(), target.getComponentType()).makeArray();
+        if (hint.isArray()) {
+            if (target.isArray()) {
+                return parameterizeType(hint.getComponentType(), target.getComponentType()).makeArray();
+            }
+            return target;
         }
         if (!target.equals(hint) && StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(target, hint)) {
             ClassNode nextSuperClass = ClassHelper.getNextSuperClass(target, hint);
@@ -269,10 +290,29 @@ public class GenericsUtils {
     }
 
     public static ClassNode correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode type) {
+        return correctToGenericsSpecRecurse(genericsSpec, type, new ArrayList<String>());
+    }
+
+    /**
+     * @since 2.4.1
+     */
+    public static ClassNode[] correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode[] types) {
+        if (types==null || types.length==1) return types;
+        ClassNode[] newTypes = new ClassNode[types.length];
+        boolean modified = false;
+        for (int i=0; i<types.length; i++) {
+            newTypes[i] = correctToGenericsSpecRecurse(genericsSpec, types[i], new ArrayList<String>());
+            modified = modified || (types[i]!=newTypes[i]);
+        }
+        if (!modified) return types;
+        return newTypes;
+    }
+
+    public static ClassNode correctToGenericsSpecRecurse(Map<String,ClassNode> genericsSpec, ClassNode type, List<String> exclusions) {
         if (type.isArray()) {
-            return correctToGenericsSpecRecurse(genericsSpec, type.getComponentType()).makeArray();
+            return correctToGenericsSpecRecurse(genericsSpec, type.getComponentType(), exclusions).makeArray();
         }
-        if (type.isGenericsPlaceHolder()) {
+        if (type.isGenericsPlaceHolder() && !exclusions.contains(type.getUnresolvedName())) {
             String name = type.getGenericsTypes()[0].getName();
             type = genericsSpec.get(name);
             if (type != null && type.isGenericsPlaceHolder() && type.getGenericsTypes() == null) {
@@ -283,7 +323,7 @@ public class GenericsUtils {
         }
         if (type == null) type = ClassHelper.OBJECT_TYPE;
         GenericsType[] oldgTypes = type.getGenericsTypes();
-        GenericsType[] newgTypes = new GenericsType[0];
+        GenericsType[] newgTypes = GenericsType.EMPTY_ARRAY;
         if (oldgTypes != null) {
             newgTypes = new GenericsType[oldgTypes.length];
             for (int i = 0; i < newgTypes.length; i++) {
@@ -296,20 +336,21 @@ public class GenericsUtils {
                     }
                 } else if (oldgType.isWildcard()) {
                     ClassNode oldLower = oldgType.getLowerBound();
-                    ClassNode lower = oldLower!=null?correctToGenericsSpecRecurse(genericsSpec, oldLower):null;
+                    ClassNode lower = oldLower!=null?correctToGenericsSpecRecurse(genericsSpec, oldLower, exclusions):null;
                     ClassNode[] oldUpper = oldgType.getUpperBounds();
                     ClassNode[] upper = null;
                     if (oldUpper!=null) {
                         upper = new ClassNode[oldUpper.length];
                         for (int j = 0; j < oldUpper.length; j++) {
-                            upper[j] = correctToGenericsSpecRecurse(genericsSpec,oldUpper[j]);
+                            upper[j] = correctToGenericsSpecRecurse(genericsSpec,oldUpper[j], exclusions);
                         }
                     }
                     GenericsType fixed = new GenericsType(oldgType.getType(), upper, lower);
+                    fixed.setName(oldgType.getName());
                     fixed.setWildcard(true);
                     newgTypes[i] = fixed;
                 } else {
-                    newgTypes[i] = new GenericsType(correctToGenericsSpecRecurse(genericsSpec,correctToGenericsSpec(genericsSpec, oldgType)));
+                    newgTypes[i] = new GenericsType(correctToGenericsSpecRecurse(genericsSpec,correctToGenericsSpec(genericsSpec, oldgType), exclusions));
                 }
             }
         }
@@ -371,6 +412,18 @@ public class GenericsUtils {
         return ret;
     }
 
+    public static Map<String,ClassNode> addMethodGenerics(MethodNode current, Map<String,ClassNode> oldSpec) {
+        Map<String,ClassNode> ret = new HashMap<String,ClassNode>(oldSpec);
+        // ret starts with the original type specs, now add gts for the current method if any
+        GenericsType[] sgts = current.getGenericsTypes();
+        if (sgts != null) {
+            for (GenericsType sgt : sgts) {
+                ret.put(sgt.getName(), sgt.getType());
+            }
+        }
+        return ret;
+    }
+
     public static void extractSuperClassGenerics(ClassNode type, ClassNode target, Map<String,ClassNode> spec) {
         // TODO: this method is very similar to StaticTypesCheckingSupport#extractGenericsConnections,
         // but operates on ClassNodes instead of GenericsType
@@ -442,4 +495,117 @@ public class GenericsUtils {
             }
         }
     }
+
+    public static ClassNode[] parseClassNodesFromString(
+            final String option,
+            final SourceUnit sourceUnit,
+            final CompilationUnit compilationUnit,
+            final MethodNode mn,
+            final ASTNode usage) {
+        GroovyLexer lexer = new GroovyLexer(new StringReader("DummyNode<" + option + ">"));
+        final GroovyRecognizer rn = GroovyRecognizer.make(lexer);
+        try {
+            rn.classOrInterfaceType(true);
+            final AtomicReference<ClassNode> ref = new AtomicReference<ClassNode>();
+            AntlrParserPlugin plugin = new AntlrParserPlugin() {
+                @Override
+                public ModuleNode buildAST(final SourceUnit sourceUnit, final ClassLoader classLoader, final Reduction cst) throws ParserException {
+                    ref.set(makeTypeWithArguments(rn.getAST()));
+                    return null;
+                }
+            };
+            plugin.buildAST(null, null, null);
+            ClassNode parsedNode = ref.get();
+            // the returned node is DummyNode<Param1, Param2, Param3, ...)
+            GenericsType[] parsedNodeGenericsTypes = parsedNode.getGenericsTypes();
+            if (parsedNodeGenericsTypes == null) {
+                return null;
+            }
+            ClassNode[] signature = new ClassNode[parsedNodeGenericsTypes.length];
+            for (int i = 0; i < parsedNodeGenericsTypes.length; i++) {
+                final GenericsType genericsType = parsedNodeGenericsTypes[i];
+                signature[i] = resolveClassNode(sourceUnit, compilationUnit, mn, usage, genericsType.getType());
+            }
+            return signature;
+        } catch (RecognitionException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        } catch (TokenStreamException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        } catch (ParserException e) {
+            sourceUnit.addError(new IncorrectTypeHintException(mn, e, usage.getLineNumber(), usage.getColumnNumber()));
+        }
+        return null;
+    }
+
+    private static ClassNode resolveClassNode(final SourceUnit sourceUnit, final CompilationUnit compilationUnit, final MethodNode mn, final ASTNode usage, final ClassNode parsedNode) {
+        ClassNode dummyClass = new ClassNode("dummy",0, ClassHelper.OBJECT_TYPE);
+        dummyClass.setModule(new ModuleNode(sourceUnit));
+        dummyClass.setGenericsTypes(mn.getDeclaringClass().getGenericsTypes());
+        MethodNode dummyMN = new MethodNode(
+                "dummy",
+                0,
+                parsedNode,
+                Parameter.EMPTY_ARRAY,
+                ClassNode.EMPTY_ARRAY,
+                EmptyStatement.INSTANCE
+        );
+        dummyMN.setGenericsTypes(mn.getGenericsTypes());
+        dummyClass.addMethod(dummyMN);
+        ResolveVisitor visitor = new ResolveVisitor(compilationUnit) {
+            @Override
+            protected void addError(final String msg, final ASTNode expr) {
+                sourceUnit.addError(new IncorrectTypeHintException(mn, msg, usage.getLineNumber(), usage.getColumnNumber()));
+            }
+        };
+        visitor.startResolving(dummyClass, sourceUnit);
+        return dummyMN.getReturnType();
+    }
+
+    /**
+     * transforms generics types from an old context to a new context using the given spec. This method assumes
+     * all generics types will be placeholders. WARNING: The resulting generics types may or may not be placeholders
+     * after the transformation.
+     * @param genericsSpec the generics context information spec
+     * @param oldPlaceHolders the old placeholders
+     * @return the new generics types
+     */
+    public static GenericsType[] applyGenericsContextToPlaceHolders(Map<String, ClassNode> genericsSpec, GenericsType[] oldPlaceHolders) {
+        if (oldPlaceHolders==null || oldPlaceHolders.length==0) return oldPlaceHolders;
+        if (genericsSpec.isEmpty()) return oldPlaceHolders;
+        GenericsType[] newTypes = new GenericsType[oldPlaceHolders.length];
+        for (int i=0; i<oldPlaceHolders.length; i++) {
+            GenericsType old = oldPlaceHolders[i];
+            if (!old.isPlaceholder()) throw new GroovyBugError("Given generics type "+old+" must be a placeholder!");
+            ClassNode fromSpec = genericsSpec.get(old.getName());
+            if (fromSpec!=null) {
+                if (fromSpec.isGenericsPlaceHolder()) {
+                    ClassNode[] upper = new ClassNode[]{fromSpec.redirect()};
+                    newTypes[i] = new GenericsType(fromSpec, upper, null);
+                } else {
+                    newTypes[i] = new GenericsType(fromSpec);
+                }
+            } else {
+                ClassNode[] upper = old.getUpperBounds();
+                ClassNode[] newUpper = upper;
+                if (upper!=null && upper.length>0) {
+                    ClassNode[] upperCorrected = new ClassNode[upper.length];
+                    for (int j=0;j<upper.length;j++) {
+                        upperCorrected[i] = correctToGenericsSpecRecurse(genericsSpec,upper[j]);
+                    }
+                    upper = upperCorrected;
+                }
+                ClassNode lower = old.getLowerBound();
+                ClassNode newLower = correctToGenericsSpecRecurse(genericsSpec,lower);
+                if (lower==newLower && upper==newUpper) {
+                    newTypes[i] = oldPlaceHolders[i];
+                } else {
+                    ClassNode newPlaceHolder = ClassHelper.make(old.getName());
+                    GenericsType gt = new GenericsType(newPlaceHolder, newUpper, newLower);
+                    gt.setPlaceholder(true);
+                    newTypes[i] = gt;
+                }
+            }
+        }
+        return newTypes;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/ast/tools/WideningCategories.java b/src/main/org/codehaus/groovy/ast/tools/WideningCategories.java
index 1481c62..8f775dd 100644
--- a/src/main/org/codehaus/groovy/ast/tools/WideningCategories.java
+++ b/src/main/org/codehaus/groovy/ast/tools/WideningCategories.java
@@ -298,6 +298,9 @@ public class WideningCategories {
             // compare two class nodes if one of them is null
             return null;
         }
+        if (a.isArray() && b.isArray()) {
+            return lowestUpperBound(a.getComponentType(), b.getComponentType(), interfacesImplementedByA, interfacesImplementedByB).makeArray();
+        }
         if (a.equals(OBJECT_TYPE) || b.equals(OBJECT_TYPE)) {
             // one of the objects is at the top of the hierarchy
             GenericsType[] gta = a.getGenericsTypes();
diff --git a/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java b/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
index 62f4cf2..5675edb 100644
--- a/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
+++ b/src/main/org/codehaus/groovy/classgen/AsmClassGenerator.java
@@ -52,6 +52,7 @@ import org.codehaus.groovy.ast.stmt.SynchronizedStatement;
 import org.codehaus.groovy.ast.stmt.ThrowStatement;
 import org.codehaus.groovy.ast.stmt.TryCatchStatement;
 import org.codehaus.groovy.ast.stmt.WhileStatement;
+import org.codehaus.groovy.ast.tools.WideningCategories;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.classgen.asm.BytecodeVariable;
 import org.codehaus.groovy.classgen.asm.MethodCaller;
@@ -229,7 +230,11 @@ public class AsmClassGenerator extends ClassGenerator {
                 createInterfaceSyntheticStaticFields();
             } else {
                 super.visitClass(classNode);
-                MopWriter mopWriter = new MopWriter(controller);
+                MopWriter.Factory mopWriterFactory = classNode.getNodeMetaData(MopWriter.Factory.class);
+                if (mopWriterFactory==null) {
+                    mopWriterFactory = MopWriter.FACTORY;
+                }
+                MopWriter mopWriter = mopWriterFactory.create(controller);
                 mopWriter.createMopMethods();
                 controller.getCallSiteWriter().generateCallSiteArray();
                 createSyntheticStaticFields();
@@ -272,6 +277,10 @@ public class AsmClassGenerator extends ClassGenerator {
         int mods = adjustedClassModifiersForInnerClassTable(cn);
 
 
+        if (Modifier.isPrivate(mods)) {
+            mods = mods ^ Modifier.PRIVATE;
+            innerClass.setModifiers(mods);
+        }
         cv.visitInnerClass(
                 innerClassInternalName,
                 outerClassName,
@@ -654,7 +663,7 @@ public class AsmClassGenerator extends ClassGenerator {
         if (isInnerClass()) {
             visitFieldExpression(new FieldExpression(controller.getClassNode().getDeclaredField("owner")));
         } else {
-            loadThis();
+            loadThis(null);
         }
     }
 
@@ -715,13 +724,20 @@ public class AsmClassGenerator extends ClassGenerator {
         ClassNode type = castExpression.getType();
         Expression subExpression = castExpression.getExpression();
         subExpression.visit(this);
+        if (ClassHelper.OBJECT_TYPE.equals(type)) return;
         if (castExpression.isCoerce()) {
             controller.getOperandStack().doAsType(type);
         } else {
             if (isNullConstant(subExpression) && !ClassHelper.isPrimitiveType(type)) {
                 controller.getOperandStack().replace(type);
             } else {
-                controller.getOperandStack().doGroovyCast(type);
+                ClassNode subExprType = controller.getTypeChooser().resolveType(subExpression, controller.getClassNode());
+                if (!ClassHelper.isPrimitiveType(type) && WideningCategories.implementsInterfaceOrSubclassOf(subExprType, type)) {
+                    BytecodeHelper.doCast(controller.getMethodVisitor(), type);
+                    controller.getOperandStack().replace(type);
+                } else {
+                    controller.getOperandStack().doGroovyCast(type);
+                }
             }
         }
     }
@@ -891,7 +907,7 @@ public class AsmClassGenerator extends ClassGenerator {
             if (isSuperExpression(objectExpression)) {
                 String prefix;
                 if (controller.getCompileStack().isLHS()) {
-                    prefix = "set";
+                    throw new GroovyBugError("Unexpected super property set for:"+expression.getText());
                 } else {
                     prefix = "get";
                 }
@@ -1162,7 +1178,7 @@ public class AsmClassGenerator extends ClassGenerator {
                 if (controller.isInClosure()) classNode = controller.getOutermostClass();
                 visitClassExpression(new ClassExpression(classNode));
             } else {
-                loadThis();
+                loadThis(expression);
             }
             return;
         }
@@ -1172,7 +1188,7 @@ public class AsmClassGenerator extends ClassGenerator {
             if (controller.isStaticMethod()) {
                 visitClassExpression(new ClassExpression(classNode.getSuperClass()));
             } else {
-                loadThis();
+                loadThis(expression);
             }
             return;
         }
@@ -1186,13 +1202,18 @@ public class AsmClassGenerator extends ClassGenerator {
         if (!controller.getCompileStack().isLHS()) controller.getAssertionWriter().record(expression);
     }
 
-    private void loadThis() {
+    private void loadThis(VariableExpression thisExpression) {
         MethodVisitor mv = controller.getMethodVisitor();
         mv.visitVarInsn(ALOAD, 0);
         if (controller.isInClosure() && !controller.getCompileStack().isImplicitThis()) {
             mv.visitMethodInsn(INVOKEVIRTUAL, "groovy/lang/Closure", "getThisObject", "()Ljava/lang/Object;", false);
-            controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
-//            controller.getOperandStack().push(controller.getClassNode().getOuterClass());
+            ClassNode expectedType = thisExpression!=null?controller.getTypeChooser().resolveType(thisExpression, controller.getOutermostClass()):null;
+            if (!ClassHelper.OBJECT_TYPE.equals(expectedType) && !ClassHelper.isPrimitiveType(expectedType)) {
+                BytecodeHelper.doCast(mv, expectedType);
+                controller.getOperandStack().push(expectedType);
+            } else {
+                controller.getOperandStack().push(ClassHelper.OBJECT_TYPE);
+            }
         } else {
             controller.getOperandStack().push(controller.getClassNode());
         }
@@ -1211,7 +1232,7 @@ public class AsmClassGenerator extends ClassGenerator {
 
             mv.visitMethodInsn(INVOKESPECIAL, "org/codehaus/groovy/runtime/ScriptReference", "<init>", "(Lgroovy/lang/Script;Ljava/lang/String;)V", false);
         } else {
-            PropertyExpression pexp = new PropertyExpression(VariableExpression.THIS_EXPRESSION, name);
+            PropertyExpression pexp = new PropertyExpression(new VariableExpression("this"), name);
             pexp.setImplicitThis(true);
             visitPropertyExpression(pexp);
         }
@@ -1239,6 +1260,9 @@ public class AsmClassGenerator extends ClassGenerator {
     }
 
     protected void createSyntheticStaticFields() {
+        if (referencedClasses.isEmpty()) {
+            return;
+        }
         MethodVisitor mv;
         for (String staticFieldName : referencedClasses.keySet()) {
             // generate a field node
@@ -1721,10 +1745,8 @@ public class AsmClassGenerator extends ClassGenerator {
                 List<String> methods = new ArrayList();
                 MethodVisitor oldMv = mv;
                 int index = 0;
-                int methodIndex = 0;
                 while (index<size) {
-                    methodIndex++;
-                    String methodName = "$createListEntry_" + methodIndex;
+                    String methodName = "$createListEntry_" + controller.getNextHelperMethodIndex();
                     methods.add(methodName);
                     mv = controller.getClassVisitor().visitMethod(
                             ACC_PRIVATE+ACC_STATIC+ACC_SYNTHETIC,
diff --git a/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java b/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
index 756e58e..04f9cf9 100644
--- a/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
+++ b/src/main/org/codehaus/groovy/classgen/ClassCompletionVerifier.java
@@ -11,7 +11,10 @@
  ******************************************************************************/
 package org.codehaus.groovy.classgen;
 
+import java.util.HashMap;
+import java.util.LinkedHashSet;
 import java.util.List;
+import java.util.Map;
 
 import org.codehaus.groovy.ast.*;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
@@ -25,9 +28,11 @@ import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.CatchStatement;
+import org.codehaus.groovy.ast.tools.GeneralUtils;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.MetaClassHelper;
 import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.trait.Traits;
 
 import static java.lang.reflect.Modifier.*;
 import static org.objectweb.asm.Opcodes.*;
@@ -61,13 +66,49 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
             checkMethodsForWeakerAccess(node);
             checkMethodsForOverridingFinal(node);
             checkNoAbstractMethodsNonabstractClass(node);
+            checkClassExtendsAllSelfTypes(node);
+            checkNoStaticMethodWithSameSignatureAsNonStatic(node);
             checkGenericsUsage(node, node.getUnresolvedInterfaces());
             checkGenericsUsage(node, node.getUnresolvedSuperClass());
         }
         super.visitClass(node);
         currentClass = oldClass;
     }
-    
+
+    private void checkNoStaticMethodWithSameSignatureAsNonStatic(final ClassNode node) {
+        Map<String, MethodNode> result = new HashMap<String, MethodNode>();
+        // add in unimplemented abstract methods from the interfaces
+        for (ClassNode iface : node.getInterfaces()) {
+            Map<String, MethodNode> ifaceMethodsMap = iface.getDeclaredMethodsMap();
+            for (String methSig : ifaceMethodsMap.keySet()) {
+                if (!result.containsKey(methSig)) {
+                    MethodNode methNode = ifaceMethodsMap.get(methSig);
+                    result.put(methSig, methNode);
+                }
+            }
+        }
+        for (MethodNode methodNode : node.getMethods()) {
+            MethodNode mn = result.get(methodNode.getTypeDescriptor());
+            if (mn!=null && methodNode.isStatic() && !methodNode.isStaticConstructor()) {
+                ClassNode declaringClass = mn.getDeclaringClass();
+                ClassNode cn = declaringClass.getOuterClass();
+                if (cn==null && declaringClass.isResolved()) {
+                    // in case of a precompiled class, the outerclass is unknown
+                    Class typeClass = declaringClass.getTypeClass();
+                    typeClass = typeClass.getEnclosingClass();
+                    if (typeClass!=null) {
+                        cn = ClassHelper.make(typeClass);
+                    }
+                }
+                if (cn==null || !Traits.isTrait(cn)) {
+                    addError("Method '" + mn.getName() + "' is already defined in " + getDescription(node) + ". You cannot have " +
+                            "both a static and a non static method with the same signature", methodNode);
+                }
+            }
+            result.put(methodNode.getTypeDescriptor(), methodNode);
+        }
+    }
+
     private void checkInterfaceMethodVisibility(ClassNode node) {
         if (!node.isInterface()) return;
         for (MethodNode method : node.getMethods()) {
@@ -84,9 +125,42 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
         List<MethodNode> abstractMethods = node.getAbstractMethods();
         if (abstractMethods == null) return;
         for (MethodNode method : abstractMethods) {
-            addError("Can't have an abstract method in a non-abstract class." +
-                    " The " + getDescription(node) + " must be declared abstract or" +
-                    " the " + getDescription(method) + " must be implemented.", node);
+            MethodNode sameArgsMethod = node.getMethod(method.getName(), method.getParameters());
+            if (sameArgsMethod==null) {
+                addError("Can't have an abstract method in a non-abstract class." +
+                        " The " + getDescription(node) + " must be declared abstract or" +
+                        " the " + getDescription(method) + " must be implemented.", node);
+            } else {
+                addError("Abstract "+getDescription(method)+" is not implemented but a " +
+                                "method of the same name but different return type is defined: "+
+                                (sameArgsMethod.isStatic()?"static ":"")+
+                                getDescription(sameArgsMethod), method
+                );
+            }
+        }
+    }
+
+    private void checkClassExtendsAllSelfTypes(ClassNode node) {
+        int modifiers = node.getModifiers();
+        if (!isInterface(modifiers)) {
+            for (ClassNode anInterface : GeneralUtils.getInterfacesAndSuperInterfaces(node)) {
+                if (Traits.isTrait(anInterface)) {
+                    LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
+                    for (ClassNode type : Traits.collectSelfTypes(anInterface, selfTypes, true, false)) {
+                        if (type.isInterface() && !node.implementsInterface(type)) {
+                            addError(getDescription(node)
+                                    + " implements " + getDescription(anInterface)
+                                    + " but does not implement self type " + getDescription(type),
+                                    anInterface);
+                        } else if (!type.isInterface() && !node.isDerivedFrom(type)) {
+                            addError(getDescription(node)
+                                            + " implements " + getDescription(anInterface)
+                                            + " but does not extend self type " + getDescription(type),
+                                    anInterface);
+                        }
+                    }
+                }
+            }
         }
     }
 
@@ -127,7 +201,7 @@ public class ClassCompletionVerifier extends ClassCodeVisitorSupport {
     }
 
     private String getDescription(ClassNode node) {
-        return (node.isInterface() ? "interface" : "class") + " '" + node.getName() + "'";
+        return (node.isInterface() ? (Traits.isTrait(node)?"trait":"interface") : "class") + " '" + node.getName() + "'";
     }
 
     private String getDescription(MethodNode node) {
diff --git a/src/main/org/codehaus/groovy/classgen/EnumVisitor.java b/src/main/org/codehaus/groovy/classgen/EnumVisitor.java
index 7b6069b..63aa953 100644
--- a/src/main/org/codehaus/groovy/classgen/EnumVisitor.java
+++ b/src/main/org/codehaus/groovy/classgen/EnumVisitor.java
@@ -113,7 +113,7 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
 
         {
             // create values() method
-            MethodNode valuesMethod = new MethodNode("values", PUBLIC_FS, enumRef.makeArray(), new Parameter[0], ClassNode.EMPTY_ARRAY, null);
+            MethodNode valuesMethod = new MethodNode("values", PUBLIC_FS, enumRef.makeArray(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
             valuesMethod.setSynthetic(true);
             BlockStatement code = new BlockStatement();
             MethodCallExpression cloneCall = new MethodCallExpression(new FieldExpression(values), "clone", MethodCallExpression.NO_ARGUMENTS);
@@ -132,7 +132,7 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
             //     }
             Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
             Token ge = Token.newSymbol(Types.COMPARE_GREATER_THAN_EQUAL, -1, -1);
-            MethodNode nextMethod = new MethodNode("next", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, new Parameter[0], ClassNode.EMPTY_ARRAY, null);
+            MethodNode nextMethod = new MethodNode("next", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
             nextMethod.setSynthetic(true);
             BlockStatement code = new BlockStatement();
             BlockStatement ifStatement = new BlockStatement();
@@ -191,7 +191,7 @@ public class EnumVisitor extends ClassCodeVisitorSupport {
             //    }
             Token assign = Token.newSymbol(Types.ASSIGN, -1, -1);
             Token lt = Token.newSymbol(Types.COMPARE_LESS_THAN, -1, -1);
-            MethodNode nextMethod = new MethodNode("previous", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, new Parameter[0], ClassNode.EMPTY_ARRAY, null);
+            MethodNode nextMethod = new MethodNode("previous", Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, enumRef, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, null);
             nextMethod.setSynthetic(true);
             BlockStatement code = new BlockStatement();
             BlockStatement ifStatement = new BlockStatement();
diff --git a/src/main/org/codehaus/groovy/classgen/GeneratorContext.java b/src/main/org/codehaus/groovy/classgen/GeneratorContext.java
index db587ed..a41087d 100644
--- a/src/main/org/codehaus/groovy/classgen/GeneratorContext.java
+++ b/src/main/org/codehaus/groovy/classgen/GeneratorContext.java
@@ -15,6 +15,7 @@
  */
 package org.codehaus.groovy.classgen;
 
+import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.CompileUnit;
@@ -51,34 +52,60 @@ public class GeneratorContext {
     }
 
     public String getNextClosureInnerName(ClassNode owner, ClassNode enclosingClass, MethodNode enclosingMethod) {
-        String ownerShortName = owner.getNameWithoutPackage();
-        String classShortName = enclosingClass.getNameWithoutPackage();
-        if (classShortName.equals(ownerShortName)) {
-            classShortName = "";
-        }
-        else {
-            classShortName += "_";
-        }
-        // remove $
-        int dp = classShortName.lastIndexOf("$");
-        if (dp >= 0) {
-            classShortName = classShortName.substring(++dp);
-        }
-        // remove leading _
-        if (classShortName.startsWith("_")) {
-            classShortName = classShortName.substring(1);
-        }
         String methodName = "";
         if (enclosingMethod != null) {
-            methodName = enclosingMethod.getName() + "_";
+            methodName = enclosingMethod.getName();
 
             if (enclosingClass.isDerivedFrom(ClassHelper.CLOSURE_TYPE)) {
                 methodName = "";
+            } else {
+                methodName = "_"+encodeAsValidClassName(methodName);
+            }
+        }
+        return methodName + "_closure" + closureClassIdx++;
+    }
+
+
+    private static final int MIN_ENCODING = ' ';
+    private static final int MAX_ENCODING = ']';
+    private static final boolean[] CHARACTERS_TO_ENCODE = new boolean[MAX_ENCODING-MIN_ENCODING+1];
+    static {
+        CHARACTERS_TO_ENCODE[' '-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['!'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['/'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['.'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[';'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['$'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['<'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['>'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['['-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[']'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE[':'-MIN_ENCODING] = true;
+        CHARACTERS_TO_ENCODE['\\'-MIN_ENCODING] = true;
+    }
+
+    public static String encodeAsValidClassName(String name) {
+        final int l = name.length();
+        StringBuilder b = null;
+        int lastEscape = -1;
+        for(int i = 0; i < l; ++i) {
+            final int encodeIndex = name.charAt(i) - MIN_ENCODING;
+            if (encodeIndex >= 0 && encodeIndex < CHARACTERS_TO_ENCODE.length) {
+                if (CHARACTERS_TO_ENCODE[encodeIndex]) {
+                    if(b == null) {
+                        b = new StringBuilder(name.length() + 3);
+                        b.append(name, 0, i);
+                    } else {
+                        b.append(name, lastEscape + 1, i);
+                    }
+                    b.append('_');
+                    lastEscape = i;
+                }
             }
-            methodName = methodName.replace('<', '_');
-            methodName = methodName.replace('>', '_');
-            methodName = methodName.replaceAll(" ", "_");
         }
-        return "_" + classShortName + methodName + "closure" + closureClassIdx++;
+        if(b == null) return name.toString();
+        if (lastEscape == -1) throw new GroovyBugError("unexpected escape char control flow in "+name);
+        b.append(name, lastEscape + 1, l);
+        return b.toString();
     }
-}
+}
\ No newline at end of file
diff --git a/src/main/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java b/src/main/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
index 3ad864a..a147300 100644
--- a/src/main/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
+++ b/src/main/org/codehaus/groovy/classgen/InnerClassCompletionVisitor.java
@@ -69,11 +69,12 @@ public class InnerClassCompletionVisitor extends InnerClassVisitorHelper impleme
             thisField = innerClass.getField("this$0");
             if (innerClass.getVariableScope() == null && innerClass.getDeclaredConstructors().isEmpty()) {
                 // add dummy constructor
-                innerClass.addConstructor(ACC_PUBLIC, new Parameter[0], null, null);
+                innerClass.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, null, null);
             }
         }
         if (node.isEnum() || node.isInterface()) return;
-        addDispatcherMethods(node);
+        // use Iterator.hasNext() to check for available inner classes
+        if (node.getInnerClasses().hasNext()) addDispatcherMethods(node);
         if (innerClass == null) return;
         super.visitClass(node);
         addDefaultMethods(innerClass);
diff --git a/src/main/org/codehaus/groovy/classgen/ReturnAdder.java b/src/main/org/codehaus/groovy/classgen/ReturnAdder.java
index 40ccb46..a10a991 100644
--- a/src/main/org/codehaus/groovy/classgen/ReturnAdder.java
+++ b/src/main/org/codehaus/groovy/classgen/ReturnAdder.java
@@ -148,6 +148,20 @@ public class ReturnAdder {
 
         if (statement instanceof TryCatchStatement) {
             TryCatchStatement trys = (TryCatchStatement) statement;
+            final boolean[] missesReturn = new boolean[1];
+            new ReturnAdder(new ReturnStatementListener() {
+                @Override
+                public void returnStatementAdded(ReturnStatement returnStatement) {
+                    missesReturn[0] = true;
+                }
+            }).addReturnsIfNeeded(trys.getFinallyStatement(), scope);
+            boolean hasFinally = !(trys.getFinallyStatement() instanceof EmptyStatement);
+
+            // if there is no missing return in the finally block and the block exists
+            // there is nothing to do
+            if (hasFinally && !missesReturn[0]) return trys;
+
+            // add returns to try and catch blocks
             final Statement tryStatement = addReturnsIfNeeded(trys.getTryStatement(), scope);
             if (doAdd) trys.setTryStatement(tryStatement);
             final int len = trys.getCatchStatements().size();
diff --git a/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java b/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java
index 44de114..6c8b572 100644
--- a/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java
+++ b/src/main/org/codehaus/groovy/classgen/VariableScopeVisitor.java
@@ -164,7 +164,7 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
         for (MethodNode mn : cn.getMethods()) {
             String pName = getPropertyName(mn);
             if (pName != null && pName.equals(name))
-                return new PropertyNode(pName, mn.getModifiers(), getPropertyType(mn), cn, null, null, null);
+                return new PropertyNode(pName, mn.getModifiers(), ClassHelper.OBJECT_TYPE, cn, null, null, null);
         }
 
         for (PropertyNode pn : cn.getProperties()) {
@@ -176,13 +176,6 @@ public class VariableScopeVisitor extends ClassCodeVisitorSupport {
         return findClassMember(cn.getOuterClass(), name);
     }
 
-    private ClassNode getPropertyType(MethodNode m) {
-        if (m.getReturnType() != ClassHelper.VOID_TYPE) {
-            return m.getReturnType();
-        }
-        return m.getParameters()[0].getType();
-    }
-
     private String getPropertyName(MethodNode m) {
         String name = m.getName();
         if (!(name.startsWith("set") || name.startsWith("get"))) return null;
diff --git a/src/main/org/codehaus/groovy/classgen/Verifier.java b/src/main/org/codehaus/groovy/classgen/Verifier.java
index 1b461e0..4d09c1b 100644
--- a/src/main/org/codehaus/groovy/classgen/Verifier.java
+++ b/src/main/org/codehaus/groovy/classgen/Verifier.java
@@ -34,6 +34,7 @@ import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
+import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.classgen.asm.MopWriter;
 import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.ClassNodeSkip;
@@ -43,6 +44,7 @@ import org.codehaus.groovy.syntax.RuntimeParserException;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.reflection.ClassInfo;
+import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Opcodes;
@@ -77,6 +79,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     public static final String SWAP_INIT = "__$swapInit";
     public static final String INITIAL_EXPRESSION = "INITIAL_EXPRESSION";
 
+    // NOTE: timeStamp constants shouldn't belong to Verifier but kept here
+    // for binary compatibility
     public static final String __TIMESTAMP = "__timeStamp";
     public static final String __TIMESTAMP__ = "__timeStamp__239_neverHappen";
     private static final Parameter[] INVOKE_METHOD_PARAMS = new Parameter[]{
@@ -101,6 +105,10 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         return classNode;
     }
 
+    protected void setClassNode(ClassNode classNode) {
+        this.classNode = classNode;
+    }
+
     public MethodNode getMethodNode() {
         return methodNode;
     }
@@ -150,7 +158,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     public void visitClass(final ClassNode node) {
         this.classNode = node;
 
-        if ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0) {
+        if (Traits.isTrait(node) // maybe possible to have this true in joint compilation mode
+                || ((classNode.getModifiers() & Opcodes.ACC_INTERFACE) > 0)) {
             //interfaces have no constructors, but this code expects one,
             //so create a dummy and don't add it to the class node
             ConstructorNode dummy = new ConstructorNode(0, null);
@@ -188,9 +197,6 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
 
         addDefaultConstructor(node);
 
-        // add a static timestamp field to the class
-        if (!(node instanceof InnerClassNode)) addTimeStamp(node);
-
         addInitialization(node);
         checkReturnInObjectInitializer(node.getObjectInitializerStatements());
         node.getObjectInitializerStatements().clear();
@@ -487,30 +493,8 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         }
     }
 
+    @Deprecated
     protected void addTimeStamp(ClassNode node) {
-        if (node.getDeclaredField(Verifier.__TIMESTAMP) == null) { // in case if verifier visited the call already
-            FieldNode timeTagField = new FieldNode(
-                    Verifier.__TIMESTAMP,
-                    ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC,
-                    ClassHelper.long_TYPE,
-                    //"",
-                    node,
-                    new ConstantExpression(System.currentTimeMillis()));
-            // alternatively, FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
-            timeTagField.setSynthetic(true);
-            node.addField(timeTagField);
-
-            timeTagField = new FieldNode(
-                    Verifier.__TIMESTAMP__ + String.valueOf(System.currentTimeMillis()),
-                    ACC_PUBLIC | ACC_STATIC | ACC_SYNTHETIC,
-                    ClassHelper.long_TYPE,
-                    //"",
-                    node,
-                    new ConstantExpression((long) 0));
-            // alternatively, FieldNode timeTagField = SourceUnit.createFieldNode("public static final long __timeStamp = " + System.currentTimeMillis() + "L");
-            timeTagField.setSynthetic(true);
-            node.addField(timeTagField);
-        }
     }
 
     private void checkReturnInObjectInitializer(List init) {
@@ -942,9 +926,11 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
             }
         }
 
-        for (FieldNode fn : node.getFields()) {
-            addFieldInitialization(statements, staticStatements, fn, isEnum,
-                    initStmtsAfterEnumValuesInit, explicitStaticPropsInEnum);
+        if (!Traits.isTrait(node)) {
+            for (FieldNode fn : node.getFields()) {
+                addFieldInitialization(statements, staticStatements, fn, isEnum,
+                        initStmtsAfterEnumValuesInit, explicitStaticPropsInEnum);
+            }
         }
 
         statements.addAll(node.getObjectInitializerStatements());
@@ -1256,12 +1242,16 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
         // method name
         if (!oldMethod.getName().equals(overridingMethod.getName())) return null;
         if ((overridingMethod.getModifiers() & ACC_BRIDGE) != 0) return null;
+        if (oldMethod.isPrivate()) return null;
 
         // parameters
         boolean normalEqualParameters = equalParametersNormal(overridingMethod, oldMethod);
         boolean genericEqualParameters = equalParametersWithGenerics(overridingMethod, oldMethod, genericsSpec);
         if (!normalEqualParameters && !genericEqualParameters) return null;
 
+        //correct to method level generics for the overriding method
+        genericsSpec = GenericsUtils.addMethodGenerics(overridingMethod, genericsSpec);
+
         // return type
         ClassNode mr = overridingMethod.getReturnType();
         ClassNode omr = oldMethod.getReturnType();
@@ -1422,22 +1412,21 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
     }
 
     private boolean moveOptimizedConstantsInitialization(final ClassNode node) {
-        if (node.isInterface()) return false;
+        if (node.isInterface() && !Traits.isTrait(node)) return false;
 
         final int mods = Opcodes.ACC_STATIC|Opcodes.ACC_SYNTHETIC| Opcodes.ACC_PUBLIC;
         String name = SWAP_INIT;
         BlockStatement methodCode = new BlockStatement();
-        node.addSyntheticMethod(
-                name, mods, ClassHelper.VOID_TYPE,
-                Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, methodCode);
 
         methodCode.addStatement(new SwapInitStatement());
+        boolean swapInitRequired = false;
         for (FieldNode fn : node.getFields()) {
             if (!fn.isStatic() || !fn.isSynthetic() || !fn.getName().startsWith("$const$")) continue;
             if (fn.getInitialExpression()==null) continue;
             final FieldExpression fe = new FieldExpression(fn);
             if (fn.getType().equals(ClassHelper.REFERENCE_TYPE)) fe.setUseReferenceDirectly(true);
             ConstantExpression init = (ConstantExpression) fn.getInitialExpression();
+            init = new ConstantExpression(init.getValue(), true);
             ExpressionStatement statement =
                     new ExpressionStatement(
                             new BinaryExpression(
@@ -1445,11 +1434,17 @@ public class Verifier implements GroovyClassVisitor, Opcodes {
                                     Token.newSymbol(Types.EQUAL, fn.getLineNumber(), fn.getColumnNumber()),
                                     init));
             fn.setInitialValueExpression(null);
-            init.setConstantName(null);
             methodCode.addStatement(statement);
+            swapInitRequired = true;
         }
 
-        return true;
+        if (swapInitRequired) {
+            node.addSyntheticMethod(
+                    name, mods, ClassHelper.VOID_TYPE,
+                    Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, methodCode);
+        }
+
+        return swapInitRequired;
     }
 
     /**
diff --git a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
index 8192236..ffdb33f 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/BinaryExpressionHelper.java
@@ -250,7 +250,7 @@ public class BinaryExpressionHelper {
         case COMPARE_IDENTICAL:
         case COMPARE_NOT_IDENTICAL:
             Token op = expression.getOperation();
-            Throwable cause = new SyntaxException("Operator " + op + " not supported", op.getStartLine(), op.getStartColumn());
+            Throwable cause = new SyntaxException("Operator " + op + " not supported", op.getStartLine(), op.getStartColumn(), op.getStartLine(), op.getStartColumn()+3);
             throw new GroovyRuntimeException(cause);
 
         default:
diff --git a/src/main/org/codehaus/groovy/classgen/asm/BytecodeDumper.java b/src/main/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
new file mode 100644
index 0000000..40599d8
--- /dev/null
+++ b/src/main/org/codehaus/groovy/classgen/asm/BytecodeDumper.java
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.classgen.asm;
+
+import org.codehaus.groovy.control.BytecodeProcessor;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.util.TraceClassVisitor;
+
+import java.io.PrintWriter;
+import java.io.Writer;
+
+/**
+ * An utility class which can be used in test cases to dump generated bytecode.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class BytecodeDumper implements BytecodeProcessor {
+    public static final BytecodeDumper STANDARD_ERR = new BytecodeDumper(new PrintWriter(System.err));
+
+    private final Writer out;
+
+    public BytecodeDumper(final Writer out) {
+        this.out = out;
+    }
+
+    @Override
+    public byte[] processBytecode(final String name, final byte[] original) {
+        PrintWriter pw = out instanceof PrintWriter ? (PrintWriter) out : new PrintWriter(out);
+        TraceClassVisitor visitor = new TraceClassVisitor(pw);
+        ClassReader reader = new ClassReader(original);
+        reader.accept(visitor, 0);
+        return original;
+    }
+
+}
diff --git a/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java b/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
index 6bba60c..6d7fc16 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/BytecodeHelper.java
@@ -147,7 +147,8 @@ public class BytecodeHelper implements Opcodes {
         StringBuilder buf = new StringBuilder();
         ClassNode d = c;
         while (true) {
-            if (ClassHelper.isPrimitiveType(d)) {
+            if (ClassHelper.isPrimitiveType(d.redirect())) {
+                d = d.redirect();
                 char car;
                 if (d == ClassHelper.int_TYPE) {
                     car = 'I';
@@ -442,7 +443,7 @@ public class BytecodeHelper implements Opcodes {
 
     private static void writeGenericsBoundType(StringBuilder ret, ClassNode printType, boolean writeInterfaceMarker) {
         if (writeInterfaceMarker && printType.isInterface()) ret.append(":");
-        if (printType.equals(ClassHelper.OBJECT_TYPE) && printType.getGenericsTypes() != null) {
+        if (printType.isGenericsPlaceHolder() && printType.getGenericsTypes()!=null) {
             ret.append("T");
             ret.append(printType.getGenericsTypes()[0].getName());
             ret.append(";");
diff --git a/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
index 1f01a15..4f5422c 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/CallSiteWriter.java
@@ -81,9 +81,9 @@ public class CallSiteWriter {
     public static final String CONSTRUCTOR = "<$constructor$>";
     
     private final List callSites = new ArrayList(32);
-    private int callSiteArrayVarIndex;
+    private int callSiteArrayVarIndex = -1;
     private WriterController controller;
-    
+
     public CallSiteWriter(WriterController wc) {
         this.controller = wc;
         ClassNode node = controller.getClassNode();
@@ -360,4 +360,8 @@ public class CallSiteWriter {
         mv.visitInsn(ACONST_NULL);
         mv.visitFieldInsn(PUTSTATIC, classInternalName, "$callSiteArray", "Ljava/lang/ref/SoftReference;");
     }
+
+    public boolean hasCallSiteUse() {
+        return callSiteArrayVarIndex>=0;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/ClosureWriter.java b/src/main/org/codehaus/groovy/classgen/asm/ClosureWriter.java
index 4b8caf3..bee7b48 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/ClosureWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/ClosureWriter.java
@@ -167,7 +167,7 @@ public class ClosureWriter {
         ClassNode classNode = controller.getClassNode();
         ClassNode outerClass = controller.getOutermostClass();
         MethodNode methodNode = controller.getMethodNode();
-        String name = outerClass.getName() + "$"
+        String name = classNode.getName() + "$"
                 + controller.getContext().getNextClosureInnerName(outerClass, classNode, methodNode); // add a more informative name
         boolean staticMethodOrInStaticClass = controller.isStaticMethod() || classNode.isStaticClass();
 
@@ -211,7 +211,9 @@ public class ClosureWriter {
         if (parameters.length > 1
                 || (parameters.length == 1
                 && parameters[0].getType() != null
-                && parameters[0].getType() != ClassHelper.OBJECT_TYPE)) {
+                && parameters[0].getType() != ClassHelper.OBJECT_TYPE
+                && !ClassHelper.OBJECT_TYPE.equals(parameters[0].getType().getComponentType())))
+        {
 
             // let's add a typesafe call method
             MethodNode call = answer.addMethod(
diff --git a/src/main/org/codehaus/groovy/classgen/asm/CompileStack.java b/src/main/org/codehaus/groovy/classgen/asm/CompileStack.java
index 8b04dbd..c6243df 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/CompileStack.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/CompileStack.java
@@ -19,6 +19,7 @@ package org.codehaus.groovy.classgen.asm;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.VariableScope;
@@ -216,7 +217,12 @@ public class CompileStack implements Opcodes {
         final BytecodeVariable head = (BytecodeVariable) temporaryVariables.removeFirst();
         if (head.getIndex() != tempIndex) {
             temporaryVariables.addFirst(head);
+            MethodNode methodNode = controller.getMethodNode();
+            if (methodNode==null) {
+                methodNode = controller.getConstructorNode();
+            }
             throw new GroovyBugError(
+                    "In method "+ (methodNode!=null?methodNode.getText():"<unknown>") + ", " +
                     "CompileStack#removeVar: tried to remove a temporary " +
                     "variable with index "+ tempIndex + " in wrong order. " +
                     "Current temporary variables=" + temporaryVariables);
@@ -254,7 +260,7 @@ public class CompileStack implements Opcodes {
     }
 
     public BytecodeVariable getVariable(String variableName ) {
-        return getVariable(variableName,true);
+        return getVariable(variableName, true);
     }
 
     /**
@@ -442,33 +448,68 @@ public class CompileStack implements Opcodes {
      * Should be called when descending into a loop that defines
      * also a scope. Calls pushVariableScope and prepares labels
      * for a loop structure. Creates a element for the state stack
-     * so pop has to be called later
+     * so pop has to be called later, TODO: @Deprecate
      */
     public void pushLoop(VariableScope el, String labelName) {
         pushVariableScope(el);
-        initLoopLabels(labelName);
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelName != null) {
+            initLoopLabels(labelName);
+        }
     }
 
-    private void initLoopLabels(String labelName) {
+    /**
+     * Should be called when descending into a loop that defines
+     * also a scope. Calls pushVariableScope and prepares labels
+     * for a loop structure. Creates a element for the state stack
+     * so pop has to be called later
+     */
+    public void pushLoop(VariableScope el, List<String> labelNames) {
+        pushVariableScope(el);
         continueLabel = new Label();
         breakLabel = new Label();
-        if (labelName!=null) {
-            namedLoopBreakLabel.put(labelName,breakLabel);
-            namedLoopContinueLabel.put(labelName,continueLabel);
+        if (labelNames != null) {
+            for (String labelName : labelNames) {
+                initLoopLabels(labelName);
+            }
         }
     }
 
+    private void initLoopLabels(String labelName) {
+        namedLoopBreakLabel.put(labelName,breakLabel);
+        namedLoopContinueLabel.put(labelName,continueLabel);
+    }
+
     /**
      * Should be called when descending into a loop that does
      * not define a scope. Creates a element for the state stack
-     * so pop has to be called later
+     * so pop has to be called later, TODO: @Deprecate
      */
     public void pushLoop(String labelName) {
         pushState();
+        continueLabel = new Label();
+        breakLabel = new Label();
         initLoopLabels(labelName);
     }
 
     /**
+     * Should be called when descending into a loop that does
+     * not define a scope. Creates a element for the state stack
+     * so pop has to be called later
+     */
+    public void pushLoop(List<String> labelNames) {
+        pushState();
+        continueLabel = new Label();
+        breakLabel = new Label();
+        if (labelNames != null) {
+            for (String labelName : labelNames) {
+                initLoopLabels(labelName);
+            }
+        }
+    }
+
+    /**
      * Used for <code>break foo</code> inside a loop to end the
      * execution of the marked loop. This method will return the
      * break label of the loop if there is one found for the name.
diff --git a/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java b/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java
index c4ab5ac..1b7b9c9 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/InvocationWriter.java
@@ -30,8 +30,10 @@ import org.codehaus.groovy.ast.tools.WideningCategories;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.asm.OptimizingStatementWriter.StatementMeta;
 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
+import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
 import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
 import org.codehaus.groovy.syntax.SyntaxException;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 
@@ -45,6 +47,7 @@ public class InvocationWriter {
     public static final MethodCallerMultiAdapter invokeMethod = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeMethod", true, false);
     public static final MethodCallerMultiAdapter invokeStaticMethod = MethodCallerMultiAdapter.newStatic(ScriptBytecodeAdapter.class, "invokeStaticMethod", true, true);
     public static final MethodCaller invokeClosureMethod = MethodCaller.newStatic(ScriptBytecodeAdapter.class, "invokeClosure");
+    public static final MethodCaller castToVargsArray = MethodCaller.newStatic(DefaultTypeTransformation.class, "castToVargsArray");
     private static final MethodNode CLASS_FOR_NAME_STRING = ClassHelper.CLASS_Type.getDeclaredMethod("forName", new Parameter[]{new Parameter(ClassHelper.STRING_TYPE,"name")});
 
     // type conversions
@@ -146,25 +149,46 @@ public class InvocationWriter {
                 argumentsToRemove++;
             } else {
                 mv.visitIntInsn(ALOAD,0);
+                operandStack.push(classNode);
+                argumentsToRemove++;
             }
         }
 
         int stackSize = operandStack.getStackLength();
-        loadArguments(args.getExpressions(), target.getParameters());
-
 
         String owner = BytecodeHelper.getClassInternalName(declaringClass);
-        ClassNode receiverType = receiver!=null?controller.getTypeChooser().resolveType(receiver, classNode):target.getDeclaringClass();
-        if (opcode==INVOKEVIRTUAL
-                && target.isPublic()
-                && (!Modifier.isPublic(declaringClass.getModifiers())
-                && !receiverType.equals(declaringClass))
-                && receiverType.isDerivedFrom(declaringClass)
-                && !receiverType.getPackageName().equals(classNode.getPackageName())) {
-            // package private class, public method
-            // see GROOVY-6962
-            owner = BytecodeHelper.getClassInternalName(receiverType);
+        ClassNode receiverType = receiver!=null?controller.getTypeChooser().resolveType(receiver, classNode):declaringClass;
+        if (opcode == INVOKEVIRTUAL && ClassHelper.OBJECT_TYPE.equals(declaringClass)) {
+            // avoid using a narrowed type if the method is defined on object because it can interfere
+            // with delegate type inference in static compilation mode and trigger a ClassCastException
+            receiverType = declaringClass;
+        }
+        if (opcode == INVOKEVIRTUAL) {
+            if (!receiverType.equals(declaringClass)
+                    && !ClassHelper.OBJECT_TYPE.equals(declaringClass)
+                    && !receiverType.isArray()
+                    && !receiverType.isInterface()
+                    && !ClassHelper.isPrimitiveType(receiverType) // e.g int.getClass()
+                    && receiverType.isDerivedFrom(declaringClass)) {
+
+                owner = BytecodeHelper.getClassInternalName(receiverType);
+                ClassNode top = operandStack.getTopOperand();
+                if (!receiverType.equals(top)) {
+                    mv.visitTypeInsn(CHECKCAST, owner);
+                }
+            } else if (target.isPublic()
+                    && (!Modifier.isPublic(declaringClass.getModifiers())
+                    && !receiverType.equals(declaringClass))
+                    && receiverType.isDerivedFrom(declaringClass)
+                    && !receiverType.getPackageName().equals(classNode.getPackageName())) {
+                // package private class, public method
+                // see GROOVY-6962
+                owner = BytecodeHelper.getClassInternalName(receiverType);
+            }
         }
+
+        loadArguments(args.getExpressions(), target.getParameters());
+
         String desc = BytecodeHelper.getMethodDescriptor(target.getReturnType(), target.getParameters());
         mv.visitMethodInsn(opcode, owner, methodName, desc, opcode == INVOKEINTERFACE);
         ClassNode ret = target.getReturnType().redirect();
@@ -661,7 +685,6 @@ public class InvocationWriter {
     private void makeMOPBasedConstructorCall(List<ConstructorNode> constructors, ConstructorCallExpression call, ClassNode callNode) {
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
-
         call.getArguments().visit(controller.getAcg());
         // keep Object[] on stack
         mv.visitInsn(DUP);
@@ -732,23 +755,31 @@ public class InvocationWriter {
 
             ConstructorNode cn = constructorIt.next();
             String descriptor = BytecodeHelper.getMethodDescriptor(ClassHelper.VOID_TYPE, cn.getParameters());
+
             // unwrap the Object[] and make transformations if needed
             // that means, to duplicate the Object[], make a cast with possible
             // unboxing and then swap it with the Object[] for each parameter
+            // vargs need special attention and transformation though
             Parameter[] parameters = cn.getParameters();
-            for (int p = 0; p < parameters.length; p++) {
-                operandStack.push(ClassHelper.OBJECT_TYPE);
-                mv.visitInsn(DUP);
-                BytecodeHelper.pushConstant(mv, p);
-                mv.visitInsn(AALOAD);
-                operandStack.push(ClassHelper.OBJECT_TYPE);
-                ClassNode type = parameters[p].getType();
-                operandStack.doGroovyCast(type);
-                operandStack.swap();
-                operandStack.remove(2);
+            int lengthWithoutVargs = parameters.length;
+            if (parameters.length>0 && parameters[parameters.length-1].getType().isArray()) {
+                lengthWithoutVargs--;
+            }
+            for (int p = 0; p < lengthWithoutVargs; p++) {
+                loadAndCastElement(operandStack, mv, parameters, p);
+            }
+            if (parameters.length>lengthWithoutVargs) {
+                ClassNode type = parameters[lengthWithoutVargs].getType();
+                BytecodeHelper.pushConstant(mv, lengthWithoutVargs);
+                controller.getAcg().visitClassExpression(new ClassExpression(type));
+                operandStack.remove(1);
+                castToVargsArray.call(mv);
+                BytecodeHelper.doCast(mv, type);
+            } else {
+                // at the end we remove the Object[]
+                // the vargs case simply the last swap so no pop is needed
+                mv.visitInsn(POP);
             }
-            // at the end we remove the Object[]
-            mv.visitInsn(POP);
             // make the constructor call
             mv.visitMethodInsn(INVOKESPECIAL, BytecodeHelper.getClassInternalName(callNode), "<init>", descriptor, false);
             mv.visitJumpInsn(GOTO, afterSwitch);
@@ -778,6 +809,18 @@ public class InvocationWriter {
         mv.visitInsn(POP);
     }
 
+    private static void loadAndCastElement(OperandStack operandStack, MethodVisitor mv, Parameter[] parameters, int p) {
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        mv.visitInsn(DUP);
+        BytecodeHelper.pushConstant(mv, p);
+        mv.visitInsn(AALOAD);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        ClassNode type = parameters[p].getType();
+        operandStack.doGroovyCast(type);
+        operandStack.swap();
+        operandStack.remove(2);
+    }
+
     // we match only on the number of arguments, not anything else
     private static ConstructorNode getMatchingConstructor(List<ConstructorNode> constructors, List<Expression> argumentList) {
         ConstructorNode lastMatch = null;
diff --git a/src/main/org/codehaus/groovy/classgen/asm/MopWriter.java b/src/main/org/codehaus/groovy/classgen/asm/MopWriter.java
index ee101b9..a435634 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/MopWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/MopWriter.java
@@ -16,9 +16,12 @@
 package org.codehaus.groovy.classgen.asm;
 
 import java.lang.reflect.Modifier;
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Set;
 
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
@@ -29,7 +32,17 @@ import org.objectweb.asm.MethodVisitor;
 import static org.objectweb.asm.Opcodes.*;
 
 public class MopWriter {
-    
+    public static interface Factory {
+        MopWriter create(WriterController controller);
+    }
+
+    public static final Factory FACTORY = new Factory() {
+        @Override
+        public MopWriter create(final WriterController controller) {
+            return new MopWriter(controller);
+        }
+    };
+
     private static class MopKey {
         int hash = 0;
         String name;
@@ -62,8 +75,19 @@ public class MopWriter {
         if (classNode.declaresInterface(ClassHelper.GENERATED_CLOSURE_Type)) {
             return;
         }
-        visitMopMethodList(classNode.getMethods(), true);
-        visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false);
+        Set<MopKey> currentClassSignatures = buildCurrentClassSignatureSet(classNode.getMethods());
+        visitMopMethodList(classNode.getMethods(), true, Collections.EMPTY_SET);
+        visitMopMethodList(classNode.getSuperClass().getAllDeclaredMethods(), false, currentClassSignatures);
+    }
+
+    private Set<MopKey> buildCurrentClassSignatureSet(List<MethodNode> methods) {
+        if (methods.size()==0) return Collections.EMPTY_SET;
+        HashSet<MopKey> result = new HashSet<MopKey>(methods.size());
+        for (MethodNode mn : methods) {
+            MopKey key = new MopKey(mn.getName(), mn.getParameters());
+            result.add(key);
+        }
+        return result;
     }
     
     /**
@@ -77,11 +101,10 @@ public class MopWriter {
      * @param isThis  if true, then we are creating a MOP method on "this", "super" else
      * @see #generateMopCalls(LinkedList, boolean)
      */
-    private void visitMopMethodList(List methods, boolean isThis) {
+    private void visitMopMethodList(List<MethodNode> methods, boolean isThis, Set<MopKey> useOnlyIfDeclaredHereToo) {
         HashMap<MopKey, MethodNode> mops = new HashMap<MopKey, MethodNode>();
         LinkedList<MethodNode> mopCalls = new LinkedList<MethodNode>();
-        for (Object method : methods) {
-            MethodNode mn = (MethodNode) method;
+        for (MethodNode mn : methods) {
             // mop methods are helper for this and super calls and do direct calls
             // to the target methods. Such a method cannot be abstract or a bridge
             if ((mn.getModifiers() & (ACC_ABSTRACT | ACC_BRIDGE)) != 0) continue;
@@ -97,6 +120,7 @@ public class MopWriter {
                 continue;
             }
             if (methodName.startsWith("<")) continue;
+            if (!useOnlyIfDeclaredHereToo.contains(new MopKey(methodName, mn.getParameters()))) continue;
             String name = getMopMethodName(mn, isThis);
             MopKey key = new MopKey(name, mn.getParameters());
             if (mops.containsKey(key)) continue;
@@ -144,7 +168,7 @@ public class MopWriter {
      * @param mopCalls list of methods a mop call method should be generated for
      * @param useThis  true if "this" should be used for the naming
      */
-    private void generateMopCalls(LinkedList<MethodNode> mopCalls, boolean useThis) {
+    protected void generateMopCalls(LinkedList<MethodNode> mopCalls, boolean useThis) {
         for (MethodNode method : mopCalls) {
             String name = getMopMethodName(method, useThis);
             Parameter[] parameters = method.getParameters();
diff --git a/src/main/org/codehaus/groovy/classgen/asm/OperandStack.java b/src/main/org/codehaus/groovy/classgen/asm/OperandStack.java
index fdda319..72d9f4b 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/OperandStack.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/OperandStack.java
@@ -508,8 +508,9 @@ public class OperandStack {
         boolean isInt = ClassHelper.int_TYPE.equals(type);
         boolean isShort = ClassHelper.short_TYPE.equals(type);
         boolean isByte = ClassHelper.byte_TYPE.equals(type);
-        if (isInt || isShort || isByte) {
-            int val = isInt?(Integer)value:isShort?(Short)value:(Byte)value;
+        boolean isChar = ClassHelper.char_TYPE.equals(type);
+        if (isInt || isShort || isByte || isChar) {
+            int val = isInt?(Integer)value:isShort?(Short)value:isChar?(Character)value:(Byte)value;
             switch (val) {
                 case 0:
                     mv.visitInsn(ICONST_0);
diff --git a/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java b/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
index d072d2c..e63e3b1 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/OptimizingStatementWriter.java
@@ -624,19 +624,37 @@ public class OptimizingStatementWriter extends StatementWriter {
                     case Types.COMPARE_GREATER_THAN:
                     case Types.COMPARE_GREATER_THAN_EQUAL:
                     case Types.COMPARE_NOT_EQUAL:
+                        if (isIntCategory(leftType) && isIntCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else {
+                            opt.chainCanOptimize(true);
+                        }
+                        resultType = boolean_TYPE;
+                        break;
                     case Types.LOGICAL_AND: case Types.LOGICAL_AND_EQUAL:
                     case Types.LOGICAL_OR: case Types.LOGICAL_OR_EQUAL:
+                        if (boolean_TYPE.equals(leftType) && boolean_TYPE.equals(rightType)) {
+                            opt.chainShouldOptimize(true);
+                        } else {
+                            opt.chainCanOptimize(true);
+                        }
                         expression.setType(boolean_TYPE);
                         resultType = boolean_TYPE;
                         break;
                     case Types.DIVIDE: case Types.DIVIDE_EQUAL:
                         if (isLongCategory(leftType) && isLongCategory(rightType)) {
                             resultType = BigDecimal_TYPE;
+                            opt.chainShouldOptimize(true);
                         } else if (isBigDecCategory(leftType) && isBigDecCategory(rightType)) {
                             // no optimization for BigDecimal yet
                             //resultType = BigDecimal_TYPE;
                         } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
                             resultType = double_TYPE;
+                            opt.chainShouldOptimize(true);
                         }
                         break;
                     case Types.POWER: case Types.POWER_EQUAL:
@@ -649,13 +667,16 @@ public class OptimizingStatementWriter extends StatementWriter {
                     default:
                         if (isIntCategory(leftType) && isIntCategory(rightType)) {
                             resultType = int_TYPE;
+                            opt.chainShouldOptimize(true);
                         } else if (isLongCategory(leftType) && isLongCategory(rightType)) {
                             resultType = long_TYPE;
+                            opt.chainShouldOptimize(true);
                         } else if (isBigDecCategory(leftType) && isBigDecCategory(rightType)) {
                             // no optimization for BigDecimal yet
                             //resultType = BigDecimal_TYPE;
                         } else if (isDoubleCategory(leftType) && isDoubleCategory(rightType)) {
                             resultType = double_TYPE;
+                            opt.chainShouldOptimize(true);
                         }
                 }
             }
@@ -663,7 +684,6 @@ public class OptimizingStatementWriter extends StatementWriter {
             if (resultType!=null) {
                 StatementMeta meta = addMeta(expression);
                 meta.type = resultType;
-                opt.chainShouldOptimize(true);
                 opt.chainInvolvedType(resultType);
                 opt.chainInvolvedType(leftType);
                 opt.chainInvolvedType(rightType);
diff --git a/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java b/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java
index 05e8b09..cfac74f 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/StatementWriter.java
@@ -110,7 +110,7 @@ public class StatementWriter {
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
 
-        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabel());
+        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabels());
 
         // Declare the loop counter.
         BytecodeVariable variable = compileStack.defineVariable(loop.getVariable(), false);
@@ -150,7 +150,7 @@ public class StatementWriter {
         writeStatementLabel(loop);
 
         MethodVisitor mv = controller.getMethodVisitor();
-        controller.getCompileStack().pushLoop(loop.getVariableScope(), loop.getStatementLabel());
+        controller.getCompileStack().pushLoop(loop.getVariableScope(), loop.getStatementLabels());
 
         ClosureListExpression clExpr = (ClosureListExpression) loop.getCollectionExpression();
         controller.getCompileStack().pushVariableScope(clExpr.getVariableScope());
@@ -219,7 +219,7 @@ public class StatementWriter {
 
         MethodVisitor mv = controller.getMethodVisitor();
 
-        controller.getCompileStack().pushLoop(loop.getStatementLabel());
+        controller.getCompileStack().pushLoop(loop.getStatementLabels());
         Label continueLabel = controller.getCompileStack().getContinueLabel();
         Label breakLabel = controller.getCompileStack().getBreakLabel();
 
@@ -256,7 +256,7 @@ public class StatementWriter {
 
         MethodVisitor mv = controller.getMethodVisitor();
 
-        controller.getCompileStack().pushLoop(loop.getStatementLabel());
+        controller.getCompileStack().pushLoop(loop.getStatementLabels());
         Label breakLabel = controller.getCompileStack().getBreakLabel();
         Label continueLabel = controller.getCompileStack().getContinueLabel();
         mv.visitLabel(continueLabel);
diff --git a/src/main/org/codehaus/groovy/classgen/asm/WriterController.java b/src/main/org/codehaus/groovy/classgen/asm/WriterController.java
index daa02d0..4c2dea7 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/WriterController.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/WriterController.java
@@ -79,6 +79,7 @@ public class WriterController {
     private TypeChooser typeChooser;
     private int bytecodeVersion = Opcodes.V1_5;
     private int lineNumber = -1;
+    private int helperMethodIndex = 0;
 
     public void init(AsmClassGenerator asmClassGenerator, GeneratorContext gcon, ClassVisitor cv, ClassNode cn) {
         CompilerConfiguration config = cn.getCompileUnit().getConfig();
@@ -398,4 +399,8 @@ public class WriterController {
 	public void resetLineNumber() {
 		setLineNumber(-1);
 	}
+
+    public int getNextHelperMethodIndex() {
+        return helperMethodIndex++;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java
new file mode 100644
index 0000000..f0e8814
--- /dev/null
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticCompilationMopWriter.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.classgen.asm.MopWriter;
+import org.codehaus.groovy.classgen.asm.WriterController;
+import org.codehaus.groovy.transform.stc.StaticTypesMarker;
+
+import java.util.LinkedList;
+
+/**
+ * A MOP Writer that skips the generation of MOP methods. This writer is used
+ * when a class is *fully* statically compiled. In mixed mode, MOP methods are
+ * still generated.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class StaticCompilationMopWriter extends MopWriter {
+
+    public static final MopWriter.Factory FACTORY = new MopWriter.Factory() {
+        @Override
+        public MopWriter create(final WriterController controller) {
+            return new StaticCompilationMopWriter(controller);
+        }
+    };
+
+    private final StaticTypesWriterController controller;
+
+    public StaticCompilationMopWriter(final WriterController wc) {
+        super(wc);
+        this.controller = (StaticTypesWriterController) wc;
+    }
+
+
+    public void createMopMethods() {
+        ClassNode classNode = controller.getClassNode();
+        LinkedList<MethodNode> requiredMopMethods = classNode.getNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED);
+        if (requiredMopMethods!=null) {
+            generateMopCalls(requiredMopMethods, false);
+        }
+    }
+
+}
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
index 45439bd..cb6b4e2 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticInvocationWriter.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.*;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.ast.tools.WideningCategories;
 import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.classgen.asm.*;
@@ -46,6 +47,8 @@ import java.util.Map;
 import java.util.concurrent.atomic.AtomicInteger;
 
 import static org.codehaus.groovy.ast.ClassHelper.CLOSURE_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.OBJECT_TYPE;
+import static org.codehaus.groovy.ast.ClassHelper.getWrapper;
 import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.PRIVATE_BRIDGE_METHODS;
 import static org.objectweb.asm.Opcodes.*;
 
@@ -82,6 +85,22 @@ public class StaticInvocationWriter extends InvocationWriter {
     }
 
     @Override
+    protected boolean makeDirectCall(final Expression origin, final Expression receiver, final Expression message, final Expression arguments, final MethodCallerMultiAdapter adapter, final boolean implicitThis, final boolean containsSpreadExpression) {
+        if (origin instanceof MethodCallExpression &&
+                receiver instanceof VariableExpression &&
+                ((VariableExpression) receiver).isSuperExpression()) {
+            ClassNode superClass = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+            if (superClass!=null && !controller.getCompileStack().isLHS()) {
+                // GROOVY-7300
+                MethodCallExpression mce = (MethodCallExpression) origin;
+                MethodNode node = superClass.getDeclaredMethod(mce.getMethodAsString(), Parameter.EMPTY_ARRAY);
+                mce.setMethodTarget(node);
+            }
+        }
+        return super.makeDirectCall(origin, receiver, message, arguments, adapter, implicitThis, containsSpreadExpression);
+    }
+
+    @Override
     public void writeInvokeMethod(final MethodCallExpression call) {
         MethodCallExpression old = currentCall;
         currentCall = call;
@@ -152,7 +171,16 @@ public class StaticInvocationWriter extends InvocationWriter {
      * Attempts to make a direct method call on a bridge method, if it exists.
      */
     protected boolean tryBridgeMethod(MethodNode target, Expression receiver, boolean implicitThis, TupleExpression args) {
-        Map<MethodNode, MethodNode> bridges = target.getDeclaringClass().redirect().getNodeMetaData(PRIVATE_BRIDGE_METHODS);
+        ClassNode lookupClassNode;
+        if (target.isProtected()) {
+            lookupClassNode = controller.getClassNode();
+            if (controller.isInClosure()) {
+                lookupClassNode = lookupClassNode.getOuterClass();
+            }
+        } else {
+            lookupClassNode = target.getDeclaringClass().redirect();
+        }
+        Map<MethodNode, MethodNode> bridges = lookupClassNode.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
         MethodNode bridge = bridges==null?null:bridges.get(target);
         if (bridge != null) {
             Expression fixedReceiver = receiver;
@@ -217,7 +245,7 @@ public class StaticInvocationWriter extends InvocationWriter {
             ClassNode classNode = controller.getClassNode();
             if (classNode.isDerivedFrom(ClassHelper.CLOSURE_TYPE)
                     && controller.isInClosure()
-                    && !(target.isPublic() || target.isProtected())
+                    && !target.isPublic()
                     && target.getDeclaringClass() != classNode) {
                 if (!tryBridgeMethod(target, receiver, implicitThis, args)) {
                     // replace call with an invoker helper call
@@ -416,6 +444,7 @@ public class StaticInvocationWriter extends InvocationWriter {
                     cce
             );
             declr.visit(controller.getAcg());
+            operandStack.pop();
             // if (receiver != null)
             receiver.visit(controller.getAcg());
             Label ifnull = compileStack.createLocalLabel("ifnull_" + counter);
@@ -432,6 +461,7 @@ public class StaticInvocationWriter extends InvocationWriter {
                     origMCE.getMethodAsString(),
                     origMCE.getArguments()
             );
+            newMCE.setImplicitThis(false);
             newMCE.setMethodTarget(origMCE.getMethodTarget());
             newMCE.setSafe(true);
             MethodCallExpression add = new MethodCallExpression(
@@ -439,6 +469,7 @@ public class StaticInvocationWriter extends InvocationWriter {
                     "add",
                     newMCE
             );
+            add.setImplicitThis(false);
             add.setMethodTarget(StaticCompilationVisitor.ARRAYLIST_ADD_METHOD);
             // for (e in receiver) { result.add(e?.method(arguments) }
             ForStatement stmt = new ForStatement(
@@ -499,7 +530,7 @@ public class StaticInvocationWriter extends InvocationWriter {
                 if (pname!=null && callSiteWriter instanceof StaticTypesCallSiteWriter) {
                     StaticTypesCallSiteWriter stcsw = (StaticTypesCallSiteWriter) callSiteWriter;
                     TypeChooser typeChooser = controller.getTypeChooser();
-                    if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, false, true)) {
+                    if (stcsw.makeGetField(receiver, typeChooser.resolveType(receiver, controller.getClassNode()), pname, safe, false, true)) {
                         return;
                     }
                 }
@@ -569,6 +600,8 @@ public class StaticInvocationWriter extends InvocationWriter {
         private final Expression receiver;
         private final MethodNode target;
 
+        private ClassNode resolvedType;
+
         public CheckcastReceiverExpression(final Expression receiver, final MethodNode target) {
             this.receiver = receiver;
             this.target = target;
@@ -584,12 +617,7 @@ public class StaticInvocationWriter extends InvocationWriter {
             receiver.visit(visitor);
             if (visitor instanceof AsmClassGenerator) {
                 ClassNode topOperand = controller.getOperandStack().getTopOperand();
-                ClassNode type;
-                if (target instanceof ExtensionMethodNode) {
-                    type = ((ExtensionMethodNode) target).getExtensionMethodNode().getDeclaringClass();
-                } else {
-                    type = target.getDeclaringClass();
-                }
+                ClassNode type = getType();
                 if (ClassHelper.GSTRING_TYPE.equals(topOperand) && ClassHelper.STRING_TYPE.equals(type)) {
                     // perform regular type conversion
                     controller.getOperandStack().doGroovyCast(type);
@@ -610,11 +638,40 @@ public class StaticInvocationWriter extends InvocationWriter {
 
         @Override
         public ClassNode getType() {
-            return controller.getTypeChooser().resolveType(receiver, controller.getClassNode());
+            if (resolvedType!=null) {
+                return resolvedType;
+            }
+            ClassNode type;
+            if (target instanceof ExtensionMethodNode) {
+                type = ((ExtensionMethodNode) target).getExtensionMethodNode().getDeclaringClass();
+            } else {
+                type = getWrapper(controller.getTypeChooser().resolveType(receiver, controller.getClassNode()));
+                ClassNode declaringClass = target.getDeclaringClass();
+                if (type.getClass() != ClassNode.class && type.getClass() !=InnerClassNode.class) {
+                    type = declaringClass; // ex: LUB type
+                }
+                if (OBJECT_TYPE.equals(type) && !OBJECT_TYPE.equals(declaringClass)) {
+                    // can happen for compiler rewritten code, where type information is missing
+                    type = declaringClass;
+                }
+                if (OBJECT_TYPE.equals(declaringClass)) {
+                    // check cast not necessary because Object never evolves
+                    // and it prevents a potential ClassCastException if the delegate of a closure
+                    // is changed in a statically compiled closure
+                    type = OBJECT_TYPE;
+                }
+            }
+            resolvedType = type;
+            return type;
         }
     }
 
     public MethodCallExpression getCurrentCall() {
         return currentCall;
     }
+
+    @Override
+    protected boolean makeCachedCall(Expression origin, ClassExpression sender, Expression receiver, Expression message, Expression arguments, MethodCallerMultiAdapter adapter, boolean safe, boolean spreadSafe, boolean implicitThis, boolean containsSpreadExpression) {
+        return false;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
new file mode 100644
index 0000000..ecbcbff
--- /dev/null
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticPropertyAccessHelper.java
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.classgen.asm.sc;
+
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.transform.sc.ListOfExpressionsExpression;
+import org.codehaus.groovy.transform.sc.TemporaryVariableExpression;
+
+import java.util.Arrays;
+
+/**
+ * Contains helper methods aimed at facilitating the generation of statically compiled bytecode for property access.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public abstract class StaticPropertyAccessHelper {
+    public static Expression transformToSetterCall(
+            Expression receiver,
+            MethodNode setterMethod,
+            final Expression arguments,
+            boolean implicitThis,
+            boolean safe,
+            boolean spreadSafe,
+            boolean requiresReturnValue,
+            Expression location) {
+        if (requiresReturnValue) {
+            TemporaryVariableExpression tmp = new TemporaryVariableExpression(arguments);
+            PoppingMethodCallExpression call = new PoppingMethodCallExpression(receiver, setterMethod, tmp);
+            call.setImplicitThis(implicitThis);
+            call.setSafe(safe);
+            call.setSpreadSafe(spreadSafe);
+            call.setSourcePosition(location);
+            PoppingListOfExpressionsExpression result = new PoppingListOfExpressionsExpression(tmp, call);
+            result.setSourcePosition(location);
+            return result;
+        } else {
+            MethodCallExpression call = new MethodCallExpression(
+                    receiver,
+                    setterMethod.getName(),
+                    arguments
+            );
+            call.setImplicitThis(implicitThis);
+            call.setSafe(safe);
+            call.setSpreadSafe(spreadSafe);
+            call.setMethodTarget(setterMethod);
+            call.setSourcePosition(location);
+            return call;
+        }
+    }
+
+    private static class PoppingListOfExpressionsExpression extends ListOfExpressionsExpression {
+        private final TemporaryVariableExpression tmp;
+        private final PoppingMethodCallExpression call;
+
+        public PoppingListOfExpressionsExpression(final TemporaryVariableExpression tmp, final PoppingMethodCallExpression call) {
+            super(Arrays.asList(
+                    tmp,
+                    call
+            ));
+            this.tmp = tmp;
+            this.call = call;
+        }
+
+        @Override
+        public Expression transformExpression(final ExpressionTransformer transformer) {
+            PoppingMethodCallExpression tcall = (PoppingMethodCallExpression) call.transformExpression(transformer);
+            return new PoppingListOfExpressionsExpression(tcall.tmp, tcall);
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            super.visit(visitor);
+            if (visitor instanceof AsmClassGenerator) {
+                tmp.remove(((AsmClassGenerator) visitor).getController());
+            }
+        }
+    }
+
+    private static class PoppingMethodCallExpression extends MethodCallExpression {
+        private final Expression receiver;
+        private final MethodNode setter;
+        private final TemporaryVariableExpression tmp;
+
+        public PoppingMethodCallExpression(final Expression receiver, final MethodNode setterMethod, final TemporaryVariableExpression tmp) {
+            super(receiver, setterMethod.getName(), tmp);
+            this.receiver = receiver;
+            this.setter = setterMethod;
+            this.tmp = tmp;
+            setMethodTarget(setterMethod);
+        }
+
+        @Override
+        public Expression transformExpression(final ExpressionTransformer transformer) {
+            PoppingMethodCallExpression trn = new PoppingMethodCallExpression(receiver.transformExpression(transformer), setter, (TemporaryVariableExpression) tmp.transformExpression(transformer));
+            trn.copyNodeMetaData(this);
+            trn.setImplicitThis(isImplicitThis());
+            trn.setSafe(isSafe());
+            trn.setSpreadSafe(isSpreadSafe());
+            return trn;
+        }
+
+        @Override
+        public void visit(final GroovyCodeVisitor visitor) {
+            super.visit(visitor);
+            if (visitor instanceof AsmClassGenerator) {
+                // ignore the return of the call
+                ((AsmClassGenerator) visitor).getController().getOperandStack().pop();
+            }
+        }
+    }
+}
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
index b4f5df3..0e8280f 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesBinaryExpressionMultiTypeDispatcher.java
@@ -45,6 +45,7 @@ import static org.codehaus.groovy.transform.sc.StaticCompilationVisitor.*;
  * It is able to generate optimized bytecode for some operations using JVM instructions when available.
  *
  * @author Cedric Champeau
+ * @author Jochen Theodorou
  */
 public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpressionMultiTypeDispatcher implements Opcodes {
 
@@ -65,85 +66,9 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
         return 0;
     }
 
- /*   @Override
-    public void evaluatePrefixMethod(final PrefixExpression expression) {
-        final Expression src = expression.getExpression();
-        ListOfExpressionsExpression list = new ListOfExpressionsExpression();
-        list.addExpression(new BinaryExpression(
-                src,
-                Token.newSymbol(Types.EQUAL, -1, -1),
-                new BinaryExpression(
-                        src,
-                        Token.newSymbol(Types.MINUS, -1, -1),
-                        new ConstantExpression(1)
-                )
-        ));
-        list.addExpression(src);
-        list.setSourcePosition(expression);
-        list.visit(getController().getAcg());
-        if (true) return;
-        if (src instanceof VariableExpression) {
-            final WriterController controller = getController();
-            final ClassNode type = controller.getTypeChooser().resolveType(src, controller.getClassNode());
-            if (ClassHelper.isPrimitiveType(type) && ClassHelper.isNumberType(type)) {
-                BytecodeExpression bytecode = new BytecodeExpression() {
-                    @Override
-                    public void visit(final MethodVisitor mv) {
-                        BytecodeVariable variable = controller.getCompileStack().getVariable(((VariableExpression) src).getName(), true);
-                        if (WideningCategories.isIntCategory(type)) {
-                            mv.visitIincInsn(variable.getIndex(), incValue(expression.getOperation()));
-                            mv.visitIntInsn(ILOAD, variable.getIndex());
-                        } else if (WideningCategories.isLongCategory(type)) {
-                            mv.visitIntInsn(LLOAD, variable.getIndex());
-                            mv.visitInsn(LCONST_1);
-                            mv.visitInsn(incValue(expression.getOperation())<0?LSUB:LADD);
-                            mv.visitVarInsn(LSTORE, variable.getIndex());
-                            mv.visitVarInsn(LLOAD, variable.getIndex());
-                        }
-                    }
-                };
-                bytecode.setType(type);
-                bytecode.visit(controller.getAcg());
-                return;
-            }
-        }
-        super.evaluatePrefixMethod(expression);
-    }
-
-    @Override
-    public void evaluatePostfixMethod(final PostfixExpression expression) {
-        final Expression src = expression.getExpression();
-        if (src instanceof VariableExpression) {
-            final WriterController controller = getController();
-            final ClassNode type = controller.getTypeChooser().resolveType(src, controller.getClassNode());
-            if (ClassHelper.isPrimitiveType(type) && ClassHelper.isNumberType(type)) {
-                BytecodeExpression bytecode = new BytecodeExpression() {
-                    @Override
-                    public void visit(final MethodVisitor mv) {
-                        BytecodeVariable variable = controller.getCompileStack().getVariable(((VariableExpression) src).getName(), true);
-                        if (WideningCategories.isIntCategory(type)) {
-                            mv.visitIntInsn(ILOAD, variable.getIndex());
-                            mv.visitIincInsn(variable.getIndex(), incValue(expression.getOperation()));
-                        } else if (WideningCategories.isLongCategory(type)) {
-                            mv.visitIntInsn(LLOAD, variable.getIndex());
-                            mv.visitInsn(DUP2);
-                            mv.visitInsn(LCONST_1);
-                            mv.visitInsn(incValue(expression.getOperation())<0?LSUB:LADD);
-                            mv.visitVarInsn(LSTORE, variable.getIndex());
-                        }
-                    }
-                };
-                bytecode.setType(type);
-                bytecode.visit(controller.getAcg());
-                return;
-            }
-        }
-        super.evaluatePostfixMethod(expression);
-    }
-*/
     @Override
     protected void writePostOrPrefixMethod(int op, String method, Expression expression, Expression orig) {
-        MethodNode mn = (MethodNode) orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        MethodNode mn = orig.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
         WriterController controller = getController();
         OperandStack operandStack = controller.getOperandStack();
         if (mn!=null) {
@@ -357,15 +282,16 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
                 }
             }
             if (setterMethod != null) {
-                MethodCallExpression call = new MethodCallExpression(
+                Expression call = StaticPropertyAccessHelper.transformToSetterCall(
                         receiver,
-                        setter,
-                        arguments
+                        setterMethod,
+                        arguments,
+                        implicitThis,
+                        safe,
+                        spreadSafe,
+                        true, // to be replaced with a proper test whether a return value should be used or not
+                        message
                 );
-                call.setImplicitThis(implicitThis);
-                call.setSafe(safe);
-                call.setSpreadSafe(spreadSafe);
-                call.setMethodTarget(setterMethod);
                 call.visit(controller.getAcg());
                 return true;
             }
@@ -382,27 +308,12 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
         AsmClassGenerator acg = getController().getAcg();
 
         if (bew.arraySet(true) && arrayType.isArray()) {
-            OperandStack operandStack   =   getController().getOperandStack();
-
-            // load the array
-            receiver.visit(acg);
-            operandStack.doGroovyCast(arrayType);
-
-            // load index
-            index.visit(acg);
-            operandStack.doGroovyCast(int_TYPE);
-
-            // load rhs
-            rhsValueLoader.visit(acg);
-            operandStack.doGroovyCast(arrayComponentType);
-
-            // store value in array
-            bew.arraySet(false);
-
-            // load return value && correct operand stack stack
-            operandStack.remove(3);
-            rhsValueLoader.visit(acg);
+            super.assignToArray(parent, receiver, index, rhsValueLoader);
         } else {
+            /******
+            / This code path is needed because ACG creates array access expressions
+            *******/
+
             WriterController controller = getController();
             StaticTypeCheckingVisitor visitor = new StaticCompilationVisitor(controller.getSourceUnit(), controller.getClassNode());
             // let's replace this assignment to a subscript operator with a
@@ -424,7 +335,11 @@ public class StaticTypesBinaryExpressionMultiTypeDispatcher extends BinaryExpres
             );
             mce.setSourcePosition(parent);
             visitor.visitMethodCallExpression(mce);
+            OperandStack operandStack = controller.getOperandStack();
+            int height = operandStack.getStackLength();
             mce.visit(controller.getAcg());
+            operandStack.pop();
+            operandStack.remove(operandStack.getStackLength()-height);
             // return value of assignment
             rhsValueLoader.visit(controller.getAcg());
         }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
index 9841a75..f2e0914 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesCallSiteWriter.java
@@ -50,11 +50,13 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
     private static final MethodNode GROOVYOBJECT_GETPROPERTY_METHOD = GROOVY_OBJECT_TYPE.getMethod("getProperty", new Parameter[]{new Parameter(STRING_TYPE, "propertyName")});
     private static final MethodNode INVOKERHELPER_GETPROPERTY_METHOD = INVOKERHELPER_TYPE.getMethod("getProperty", new Parameter[]{new Parameter(OBJECT_TYPE, "object"), new Parameter(STRING_TYPE, "propertyName")});
     private static final MethodNode INVOKERHELPER_GETPROPERTYSAFE_METHOD = INVOKERHELPER_TYPE.getMethod("getPropertySafe", new Parameter[]{new Parameter(OBJECT_TYPE, "object"), new Parameter(STRING_TYPE, "propertyName")});
+    private static final MethodNode CLOSURE_GETTHISOBJECT_METHOD = CLOSURE_TYPE.getMethod("getThisObject", new Parameter[0]);
     private static final ClassNode COLLECTION_TYPE = make(Collection.class);
     private static final MethodNode COLLECTION_SIZE_METHOD = COLLECTION_TYPE.getMethod("size", Parameter.EMPTY_ARRAY);
     private static final MethodNode MAP_GET_METHOD = MAP_TYPE.getMethod("get", new Parameter[] { new Parameter(OBJECT_TYPE, "key")});
 
-    private WriterController controller;
+
+    private StaticTypesWriterController controller;
 
     public StaticTypesCallSiteWriter(final StaticTypesWriterController controller) {
         super(controller);
@@ -63,10 +65,9 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
 
     @Override
     public void generateCallSiteArray() {
-        if (controller instanceof StaticTypesWriterController) {
-            ((StaticTypesWriterController)controller).getRegularCallSiteWriter().generateCallSiteArray();
-        } else {
-            super.generateCallSiteArray();
+        CallSiteWriter regularCallSiteWriter = controller.getRegularCallSiteWriter();
+        if (regularCallSiteWriter.hasCallSiteUse()) {
+            regularCallSiteWriter.generateCallSiteArray();
         }
     }
 
@@ -78,21 +79,12 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
     public void makeGetPropertySite(Expression receiver, final String methodName, final boolean safe, final boolean implicitThis) {
         Object dynamic = receiver.getNodeMetaData(StaticCompilationMetadataKeys.RECEIVER_OF_DYNAMIC_PROPERTY);
         if (dynamic !=null) {
-            MethodNode target = safe?INVOKERHELPER_GETPROPERTYSAFE_METHOD:INVOKERHELPER_GETPROPERTY_METHOD;
-            MethodCallExpression mce = new MethodCallExpression(
-                    new ClassExpression(INVOKERHELPER_TYPE),
-                    target.getName(),
-                    new ArgumentListExpression(receiver, new ConstantExpression(methodName))
-            );
-            mce.setSafe(false);
-            mce.setImplicitThis(false);
-            mce.setMethodTarget(target);
-            mce.visit(controller.getAcg());
+            makeDynamicGetProperty(receiver, methodName, safe);
             return;
         }
         TypeChooser typeChooser = controller.getTypeChooser();
         ClassNode classNode = controller.getClassNode();
-        ClassNode receiverType = (ClassNode) receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
+        ClassNode receiverType = receiver.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
         if (receiverType==null) {
             receiverType = typeChooser.resolveType(receiver, classNode);
         }
@@ -113,6 +105,12 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
             isClassReceiver = true;
             receiverType = receiverType.getGenericsTypes()[0].getType();
         }
+
+        if (isPrimitiveType(receiverType)) {
+            // GROOVY-6590: wrap primitive types
+            receiverType = getWrapper(receiverType);
+        }
+
         MethodVisitor mv = controller.getMethodVisitor();
 
         if (receiverType.isArray() && methodName.equals("length")) {
@@ -137,21 +135,21 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
             return;
         }
         if (makeGetPropertyWithGetter(receiver, receiverType, methodName, safe, implicitThis)) return;
-        if (makeGetField(receiver, receiverType, methodName, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
+        if (makeGetField(receiver, receiverType, methodName, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
         if (receiverType.isEnum()) {
             mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(receiverType), methodName, BytecodeHelper.getTypeDescription(receiverType));
             controller.getOperandStack().push(receiverType);
             return;
         }
         if (receiver instanceof ClassExpression) {
-            if (makeGetField(receiver, receiver.getType(), methodName, implicitThis, samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
+            if (makeGetField(receiver, receiver.getType(), methodName, safe, implicitThis, samePackages(receiver.getType().getPackageName(), classNode.getPackageName()))) return;
             if (makeGetPropertyWithGetter(receiver, receiver.getType(), methodName, safe, implicitThis)) return;
             if (makeGetPrivateFieldWithBridgeMethod(receiver, receiver.getType(), methodName, safe, implicitThis)) return;
         }
         if (isClassReceiver) {
             // we are probably looking for a property of the class
             if (makeGetPropertyWithGetter(receiver, CLASS_Type, methodName, safe, implicitThis)) return;
-            if (makeGetField(receiver, CLASS_Type, methodName, false, true)) return;
+            if (makeGetField(receiver, CLASS_Type, methodName, safe, false, true)) return;
         }
         if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, methodName, safe, implicitThis)) return;
 
@@ -178,6 +176,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
                 call.setMethodTarget(getterMethod);
                 call.setImplicitThis(false);
                 call.setSourcePosition(receiver);
+                call.setSafe(safe);
                 call.visit(controller.getAcg());
                 return;
             }
@@ -197,6 +196,7 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
                 );
                 call.setMethodTarget(getter);
                 call.setImplicitThis(false);
+                call.setSafe(safe);
                 call.setSourcePosition(receiver);
                 call.visit(controller.getAcg());
                 return;
@@ -228,6 +228,19 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
         controller.getOperandStack().push(OBJECT_TYPE);
     }
 
+    private void makeDynamicGetProperty(final Expression receiver, final String methodName, final boolean safe) {
+        MethodNode target = safe?INVOKERHELPER_GETPROPERTYSAFE_METHOD:INVOKERHELPER_GETPROPERTY_METHOD;
+        MethodCallExpression mce = new MethodCallExpression(
+                new ClassExpression(INVOKERHELPER_TYPE),
+                target.getName(),
+                new ArgumentListExpression(receiver, new ConstantExpression(methodName))
+        );
+        mce.setSafe(false);
+        mce.setImplicitThis(false);
+        mce.setMethodTarget(target);
+        mce.visit(controller.getAcg());
+    }
+
     private void writeMapDotProperty(final Expression receiver, final String methodName, final MethodVisitor mv, final boolean safe) {
         receiver.visit(controller.getAcg()); // load receiver
 
@@ -339,6 +352,30 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
     @SuppressWarnings("unchecked")
     private boolean makeGetPrivateFieldWithBridgeMethod(final Expression receiver, final ClassNode receiverType, final String fieldName, final boolean safe, final boolean implicitThis) {
         FieldNode field = receiverType.getField(fieldName);
+        ClassNode outerClass = receiverType.getOuterClass();
+        if (field==null && implicitThis && outerClass !=null && !receiverType.isStaticClass()) {
+            Expression pexp;
+            if (controller.isInClosure()) {
+                MethodCallExpression mce = new MethodCallExpression(
+                        new VariableExpression("this"),
+                        "getThisObject",
+                        ArgumentListExpression.EMPTY_ARGUMENTS
+                );
+                mce.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, controller.getOutermostClass());
+                mce.setImplicitThis(true);
+                mce.setMethodTarget(CLOSURE_GETTHISOBJECT_METHOD);
+                pexp = new CastExpression(controller.getOutermostClass(),mce);
+            } else {
+                pexp = new PropertyExpression(
+                        new ClassExpression(outerClass),
+                        "this"
+                );
+                ((PropertyExpression)pexp).setImplicitThis(true);
+            }
+            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, outerClass);
+            pexp.setSourcePosition(receiver);
+            return makeGetPrivateFieldWithBridgeMethod(pexp, outerClass, fieldName, safe, true);
+        }
         ClassNode classNode = controller.getClassNode();
         if (field!=null && Modifier.isPrivate(field.getModifiers())
                 && (StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(receiverType, classNode) || StaticInvocationWriter.isPrivateBridgeMethodsCallAllowed(classNode,receiverType))
@@ -395,9 +432,9 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
             }
         }
 
-
         if (makeGetPropertyWithGetter(receiver, receiverType, property, safe, implicitThis)) return;
-        if (makeGetField(receiver, receiverType, property, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
+        if (makeGetPrivateFieldWithBridgeMethod(receiver, receiverType, property, safe, implicitThis)) return;
+        if (makeGetField(receiver, receiverType, property, safe, implicitThis, samePackages(receiverType.getPackageName(), classNode.getPackageName()))) return;
 
         MethodCallExpression call = new MethodCallExpression(
                 receiver,
@@ -468,15 +505,22 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
             }
         }
 
+        // check direct interfaces (GROOVY-7149)
+        for (ClassNode node : receiverType.getInterfaces()) {
+            if (makeGetPropertyWithGetter(receiver, node, methodName, safe, implicitThis)) {
+                return true;
+            }
+        }
         // go upper level
         ClassNode superClass = receiverType.getSuperClass();
         if (superClass !=null) {
             return makeGetPropertyWithGetter(receiver, superClass, methodName, safe, implicitThis);
         }
+
         return false;
     }
 
-    boolean makeGetField(final Expression receiver, final ClassNode receiverType, final String fieldName, final boolean implicitThis, final boolean samePackage) {
+    boolean makeGetField(final Expression receiver, final ClassNode receiverType, final String fieldName, final boolean safe, final boolean implicitThis, final boolean samePackage) {
         FieldNode field = receiverType.getField(fieldName);
         // direct access is allowed if we are in the same class as the declaring class
         // or we are in an inner class
@@ -484,26 +528,52 @@ public class StaticTypesCallSiteWriter extends CallSiteWriter implements Opcodes
                 && isDirectAccessAllowed(field, controller.getClassNode(), samePackage)) {
             CompileStack compileStack = controller.getCompileStack();
             MethodVisitor mv = controller.getMethodVisitor();
+            ClassNode replacementType = field.getOriginType();
+            OperandStack operandStack = controller.getOperandStack();
             if (field.isStatic()) {
-                mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(field.getOriginType()));
-                controller.getOperandStack().push(field.getOriginType());
+                mv.visitFieldInsn(GETSTATIC, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
+                operandStack.push(replacementType);
             } else {
                 if (implicitThis) {
                     compileStack.pushImplicitThis(implicitThis);
                 }
                 receiver.visit(controller.getAcg());
                 if (implicitThis) compileStack.popImplicitThis();
-                if (!controller.getOperandStack().getTopOperand().isDerivedFrom(field.getOwner())) {
+                Label exit = new Label();
+                if (safe) {
+                    mv.visitInsn(DUP);
+                    Label doGet = new Label();
+                    mv.visitJumpInsn(IFNONNULL, doGet);
+                    mv.visitJumpInsn(GOTO, exit);
+                    mv.visitLabel(doGet);
+                }
+                if (!operandStack.getTopOperand().isDerivedFrom(field.getOwner())) {
                     mv.visitTypeInsn(CHECKCAST, BytecodeHelper.getClassInternalName(field.getOwner()));
                 }
-                mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(field.getOriginType()));
+                mv.visitFieldInsn(GETFIELD, BytecodeHelper.getClassInternalName(field.getOwner()), fieldName, BytecodeHelper.getTypeDescription(replacementType));
+                if (safe) {
+                    if (ClassHelper.isPrimitiveType(replacementType)) {
+                        operandStack.replace(replacementType);
+                        operandStack.box();
+                        replacementType = operandStack.getTopOperand();
+                    }
+                    mv.visitLabel(exit);
+                }
             }
-            controller.getOperandStack().replace(field.getOriginType());
+            operandStack.replace(replacementType);
             return true;
         }
+
+        for (ClassNode intf : receiverType.getInterfaces()) {
+            // GROOVY-7039
+            if (intf!=receiverType && makeGetField(receiver, intf, fieldName, safe, implicitThis, false)) {
+                return true;
+            }
+        }
+
         ClassNode superClass = receiverType.getSuperClass();
         if (superClass !=null) {
-            return makeGetField(receiver, superClass, fieldName, implicitThis, false);
+            return makeGetField(receiver, superClass, fieldName, safe, implicitThis, false);
         }
         return false;
     }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java
index c85ad12..70a5a5f 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesClosureWriter.java
@@ -80,7 +80,7 @@ public class StaticTypesClosureWriter extends ClosureWriter {
         // call(Object)
         Parameter args = new Parameter(ClassHelper.OBJECT_TYPE, "args");
         MethodCallExpression doCall1arg = new MethodCallExpression(
-                new VariableExpression("this"),
+                new VariableExpression("this", closureClass),
                 "doCall",
                 new ArgumentListExpression(new VariableExpression(args))
         );
@@ -95,7 +95,7 @@ public class StaticTypesClosureWriter extends ClosureWriter {
                         new ReturnStatement(doCall1arg)));
 
         // call()
-        MethodCallExpression doCallNoArgs = new MethodCallExpression(new VariableExpression("this"), "doCall", new ArgumentListExpression(new ConstantExpression(null)));
+        MethodCallExpression doCallNoArgs = new MethodCallExpression(new VariableExpression("this", closureClass), "doCall", new ArgumentListExpression(new ConstantExpression(null)));
         doCallNoArgs.setImplicitThis(true);
         doCallNoArgs.setMethodTarget(doCallMethod);
         closureClass.addMethod(
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
index a48d310..e9db562 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesStatementWriter.java
@@ -23,10 +23,15 @@ import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
 import org.codehaus.groovy.classgen.asm.*;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 
+import java.util.Enumeration;
+import java.util.Iterator;
+
 import static org.objectweb.asm.Opcodes.*;
 
 /**
@@ -36,6 +41,10 @@ import static org.objectweb.asm.Opcodes.*;
 public class StaticTypesStatementWriter extends StatementWriter {
 
     private static final ClassNode ITERABLE_CLASSNODE = ClassHelper.make(Iterable.class);
+    private static final ClassNode ENUMERATION_CLASSNODE = ClassHelper.make(Enumeration.class);
+    private static final MethodCaller ENUMERATION_NEXT_METHOD = MethodCaller.newInterface(Enumeration.class, "nextElement");
+    private static final MethodCaller ENUMERATION_HASMORE_METHOD = MethodCaller.newInterface(Enumeration.class, "hasMoreElements");
+
     private StaticTypesWriterController controller;
 
     public StaticTypesStatementWriter(StaticTypesWriterController controller) {
@@ -59,17 +68,132 @@ public class StaticTypesStatementWriter extends StatementWriter {
         MethodVisitor mv = controller.getMethodVisitor();
         OperandStack operandStack = controller.getOperandStack();
 
-        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabel());
-
-        // Declare the loop counter.
-        BytecodeVariable variable = compileStack.defineVariable(loop.getVariable(), false);
+        compileStack.pushLoop(loop.getVariableScope(), loop.getStatementLabels());
 
         // Identify type of collection
         TypeChooser typeChooser = controller.getTypeChooser();
         Expression collectionExpression = loop.getCollectionExpression();
         ClassNode collectionType = typeChooser.resolveType(collectionExpression, controller.getClassNode());
+        Parameter loopVariable = loop.getVariable();
+        int size = operandStack.getStackLength();
+        if (collectionType.isArray() && loopVariable.getOriginType().equals(collectionType.getComponentType())) {
+            writeOptimizedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        } else if (ENUMERATION_CLASSNODE.equals(collectionType)) {
+            writeEnumerationBasedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        } else {
+            writeIteratorBasedForEachLoop(compileStack, operandStack, mv, loop, collectionExpression, collectionType, loopVariable);
+        }
+        operandStack.popDownTo(size);
+        compileStack.pop();
+    }
+
+    private void writeOptimizedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        AsmClassGenerator acg = controller.getAcg();
+
+        // load array on stack
+        collectionExpression.visit(acg);
+        mv.visitInsn(DUP);
+        int array = compileStack.defineTemporaryVariable("$arr", collectionType, true);
+        mv.visitJumpInsn(IFNULL, breakLabel);
+
+        // $len = array.length
+        mv.visitVarInsn(ALOAD, array);
+        mv.visitInsn(ARRAYLENGTH);
+        operandStack.push(ClassHelper.int_TYPE);
+        int arrayLen = compileStack.defineTemporaryVariable("$len", ClassHelper.int_TYPE, true);
+
+        // $idx = 0
+        mv.visitInsn(ICONST_0);
+        operandStack.push(ClassHelper.int_TYPE);
+        int loopIdx = compileStack.defineTemporaryVariable("$idx", ClassHelper.int_TYPE, true);
 
-        if (collectionType.implementsInterface(ITERABLE_CLASSNODE)) {
+        mv.visitLabel(continueLabel);
+        // $idx<$len?
+        mv.visitVarInsn(ILOAD, loopIdx);
+        mv.visitVarInsn(ILOAD, arrayLen);
+        mv.visitJumpInsn(IF_ICMPGE, breakLabel);
+
+        // get array element
+        loadFromArray(mv, variable, array, loopIdx);
+
+        // $idx++
+        mv.visitIincInsn(loopIdx, 1);
+
+        // loop body
+        loop.getLoopBlock().visit(acg);
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+
+        mv.visitLabel(breakLabel);
+
+    }
+
+    private void loadFromArray(MethodVisitor mv, BytecodeVariable variable, int array, int iteratorIdx) {
+        OperandStack os = controller.getOperandStack();
+        mv.visitVarInsn(ALOAD, array);
+        mv.visitVarInsn(ILOAD, iteratorIdx);
+
+        ClassNode varType = variable.getType();
+        boolean primitiveType = ClassHelper.isPrimitiveType(varType);
+        boolean isByte = ClassHelper.byte_TYPE.equals(varType);
+        boolean isShort = ClassHelper.short_TYPE.equals(varType);
+        boolean isInt = ClassHelper.int_TYPE.equals(varType);
+        boolean isLong = ClassHelper.long_TYPE.equals(varType);
+        boolean isFloat = ClassHelper.float_TYPE.equals(varType);
+        boolean isDouble = ClassHelper.double_TYPE.equals(varType);
+        boolean isChar = ClassHelper.char_TYPE.equals(varType);
+        boolean isBoolean = ClassHelper.boolean_TYPE.equals(varType);
+
+        if (primitiveType) {
+            if (isByte) {
+                mv.visitInsn(BALOAD);
+            }
+            if (isShort) {
+                mv.visitInsn(SALOAD);
+            }
+            if (isInt || isChar || isBoolean) {
+                mv.visitInsn(isChar ? CALOAD : isBoolean ? BALOAD : IALOAD);
+            }
+            if (isLong) {
+                mv.visitInsn(LALOAD);
+            }
+            if (isFloat) {
+                mv.visitInsn(FALOAD);
+            }
+            if (isDouble) {
+                mv.visitInsn(DALOAD);
+            }
+        } else {
+            mv.visitInsn(AALOAD);
+        }
+        os.push(varType);
+        os.storeVar(variable);
+    }
+
+    private void writeIteratorBasedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        // Declare the loop counter.
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(collectionType, ITERABLE_CLASSNODE)) {
             MethodCallExpression iterator = new MethodCallExpression(collectionExpression, "iterator", new ArgumentListExpression());
             iterator.setMethodTarget(collectionType.getMethod("iterator", Parameter.EMPTY_ARRAY));
             iterator.setImplicitThis(false);
@@ -82,7 +206,7 @@ public class StaticTypesStatementWriter extends StatementWriter {
 
         // Then get the iterator and generate the loop control
 
-        final int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
+        int iteratorIdx = compileStack.defineTemporaryVariable("iterator", ClassHelper.Iterator_TYPE, true);
 
         Label continueLabel = compileStack.getContinueLabel();
         Label breakLabel = compileStack.getBreakLabel();
@@ -104,6 +228,45 @@ public class StaticTypesStatementWriter extends StatementWriter {
         mv.visitJumpInsn(GOTO, continueLabel);
         mv.visitLabel(breakLabel);
 
-        compileStack.pop();
     }
+
+    private void writeEnumerationBasedForEachLoop(
+            CompileStack compileStack,
+            OperandStack operandStack,
+            MethodVisitor mv,
+            ForStatement loop,
+            Expression collectionExpression,
+            ClassNode collectionType,
+            Parameter loopVariable) {
+        // Declare the loop counter.
+        BytecodeVariable variable = compileStack.defineVariable(loopVariable, false);
+
+        collectionExpression.visit(controller.getAcg());
+
+        // Then get the iterator and generate the loop control
+
+        int enumIdx = compileStack.defineTemporaryVariable("$enum", ENUMERATION_CLASSNODE, true);
+
+        Label continueLabel = compileStack.getContinueLabel();
+        Label breakLabel = compileStack.getBreakLabel();
+
+        mv.visitLabel(continueLabel);
+        mv.visitVarInsn(ALOAD, enumIdx);
+        ENUMERATION_HASMORE_METHOD.call(mv);
+        // note: ifeq tests for ==0, a boolean is 0 if it is false
+        mv.visitJumpInsn(IFEQ, breakLabel);
+
+        mv.visitVarInsn(ALOAD, enumIdx);
+        ENUMERATION_NEXT_METHOD.call(mv);
+        operandStack.push(ClassHelper.OBJECT_TYPE);
+        operandStack.storeVar(variable);
+
+        // Generate the loop body
+        loop.getLoopBlock().visit(controller.getAcg());
+
+        mv.visitJumpInsn(GOTO, continueLabel);
+        mv.visitLabel(breakLabel);
+
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
index 8e3e86b..f77ed9f 100644
--- a/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
+++ b/src/main/org/codehaus/groovy/classgen/asm/sc/StaticTypesTypeChooser.java
@@ -50,6 +50,10 @@ public class StaticTypesTypeChooser extends StatementMetaTypeChooser {
             }
             return inferredType;
         }
+        if (target instanceof VariableExpression && ((VariableExpression) target).isThisExpression()) {
+            // AsmClassGenerator may create "this" expressions that the type checker knows nothing about
+            return current;
+        }
         return super.resolveType(exp, current);
     }
 
diff --git a/src/main/org/codehaus/groovy/control/BytecodeProcessor.java b/src/main/org/codehaus/groovy/control/BytecodeProcessor.java
new file mode 100644
index 0000000..0931d31
--- /dev/null
+++ b/src/main/org/codehaus/groovy/control/BytecodeProcessor.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.control;
+
+public interface BytecodeProcessor {
+    byte[] processBytecode(String name, byte[] original);
+}
diff --git a/src/main/org/codehaus/groovy/control/ClassNodeResolver.java b/src/main/org/codehaus/groovy/control/ClassNodeResolver.java
index f91e830..b0472d2 100644
--- a/src/main/org/codehaus/groovy/control/ClassNodeResolver.java
+++ b/src/main/org/codehaus/groovy/control/ClassNodeResolver.java
@@ -120,7 +120,6 @@ public class ClassNodeResolver {
         ClassNode res = getFromClassCache(name);
         if (res==NO_CLASS) return null;
         if (res!=null) return new LookupResult(null,res);
-        
         LookupResult lr = findClassNode(name, compilationUnit);
         if (lr != null) {
             if (lr.isClassNode()) cacheClass(name, lr.getClassNode());
@@ -185,7 +184,7 @@ public class ClassNodeResolver {
             LookupResult lr = tryAsScript(name, compilationUnit, null);
             return lr;
         } catch (CompilationFailedException cfe) {
-            throw new GroovyBugError("The lookup for "+name+" caused a failed compilaton. There should not have been any compilation from this call.");
+            throw new GroovyBugError("The lookup for "+name+" caused a failed compilaton. There should not have been any compilation from this call.", cfe);
         }
         //TODO: the case of a NoClassDefFoundError needs a bit more research
         // a simple recompilation is not possible it seems. The current class
diff --git a/src/main/org/codehaus/groovy/control/CompilationUnit.java b/src/main/org/codehaus/groovy/control/CompilationUnit.java
index 126f645..fb34d02 100644
--- a/src/main/org/codehaus/groovy/control/CompilationUnit.java
+++ b/src/main/org/codehaus/groovy/control/CompilationUnit.java
@@ -258,6 +258,11 @@ public class CompilationUnit extends ProcessingUnit {
         phaseOperations[phase].add(op);
     }
 
+    public void addFirstPhaseOperation(PrimaryClassNodeOperation op, int phase) {
+        if (phase < 0 || phase > Phases.ALL) throw new IllegalArgumentException("phase " + phase + " is unknown");
+        phaseOperations[phase].add(0, op);
+    }
+
     public void addPhaseOperation(GroovyClassOperation op) {
         phaseOperations[Phases.OUTPUT].addFirst(op);
     }
diff --git a/src/main/org/codehaus/groovy/control/CompilerConfiguration.java b/src/main/org/codehaus/groovy/control/CompilerConfiguration.java
index eaf02b0..98d59ed 100644
--- a/src/main/org/codehaus/groovy/control/CompilerConfiguration.java
+++ b/src/main/org/codehaus/groovy/control/CompilerConfiguration.java
@@ -161,6 +161,8 @@ public class CompilerConfiguration {
      */
     private Set<String> disabledGlobalASTTransformations;
 
+    private BytecodeProcessor bytecodePostprocessor;
+
     /**
      * Sets the Flags to defaults.
      */
@@ -828,4 +830,12 @@ public class CompilerConfiguration {
     public void setDisabledGlobalASTTransformations(final Set<String> disabledGlobalASTTransformations) {
         this.disabledGlobalASTTransformations = disabledGlobalASTTransformations;
     }
+
+    public BytecodeProcessor getBytecodePostprocessor() {
+        return bytecodePostprocessor;
+    }
+
+    public void setBytecodePostprocessor(final BytecodeProcessor bytecodePostprocessor) {
+        this.bytecodePostprocessor = bytecodePostprocessor;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/control/LabelVerifier.java b/src/main/org/codehaus/groovy/control/LabelVerifier.java
index fc5a682..b9531b4 100644
--- a/src/main/org/codehaus/groovy/control/LabelVerifier.java
+++ b/src/main/org/codehaus/groovy/control/LabelVerifier.java
@@ -26,6 +26,7 @@ import org.codehaus.groovy.ast.stmt.WhileStatement;
 
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.List;
 
 /**
  * This class checks the handling of labels in the AST
@@ -64,20 +65,24 @@ public class LabelVerifier extends ClassCodeVisitorSupport {
     }
 
     public void visitStatement(Statement statement) {
-        String label = statement.getStatementLabel();
-
-        if (label != null) {
-            for (Iterator<BreakStatement> iter = breakLabels.iterator(); iter.hasNext(); ) {
-                BreakStatement element = iter.next();
-                if (element.getLabel().equals(label)) iter.remove();
-            }
-
-            for (Iterator<ContinueStatement> iter = continueLabels.iterator(); iter.hasNext(); ) {
-                ContinueStatement element = iter.next();
-                if (element.getLabel().equals(label)) iter.remove();
+        List<String> labels = statement.getStatementLabels();
+
+        if (labels != null) {
+            for (String label : labels) {
+                if (breakLabels != null) {
+                    for (Iterator<BreakStatement> iter = breakLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (continueLabels != null) {
+                    for (Iterator<ContinueStatement> iter = continueLabels.iterator(); iter.hasNext(); ) {
+                        if (iter.next().getLabel().equals(label)) iter.remove();
+                    }
+                }
+                if (visitedLabels != null) {
+                    visitedLabels.add(label);
+                }
             }
-
-            visitedLabels.add(label);
         }
 
         super.visitStatement(statement);
diff --git a/src/main/org/codehaus/groovy/control/OptimizerVisitor.java b/src/main/org/codehaus/groovy/control/OptimizerVisitor.java
index 4635de6..2224e93 100644
--- a/src/main/org/codehaus/groovy/control/OptimizerVisitor.java
+++ b/src/main/org/codehaus/groovy/control/OptimizerVisitor.java
@@ -59,8 +59,10 @@ public class OptimizerVisitor extends ClassCodeExpressionTransformer {
 
     private void setConstField(ConstantExpression constantExpression) {
         final Object n = constantExpression.getValue();
-        if (!(n instanceof Number || n instanceof Character)) return;
+        if (!(n instanceof Number)) return;
         if (n instanceof Integer || n instanceof Double) return;
+        if (n instanceof Long && (0L== (Long) n || 1L==(Long) n )) return; // LCONST_0, LCONST_1
+
         FieldNode field = (FieldNode) const2Var.get(n);
         if (field!=null) {
             constantExpression.setConstantName(field.getName());
diff --git a/src/main/org/codehaus/groovy/control/ResolveVisitor.java b/src/main/org/codehaus/groovy/control/ResolveVisitor.java
index 63e9820..7bb057c 100644
--- a/src/main/org/codehaus/groovy/control/ResolveVisitor.java
+++ b/src/main/org/codehaus/groovy/control/ResolveVisitor.java
@@ -65,6 +65,39 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     private ClassNodeResolver classNodeResolver;
 
     /**
+     * A ConstructedNestedClass consists of an outer class and a name part, denoting a
+     * nested class with an unknown number of levels down. This allows resolve tests to
+     * skip this node for further inner class searches and combinations with imports, since
+     * the outer class we know is already resolved.
+     */
+    private static class ConstructedNestedClass extends ClassNode {
+        ClassNode knownEnclosingType;
+        String nestClassName;
+        public ConstructedNestedClass(ClassNode outer, String inner) {
+            super(outer.getName()+"$"+(inner=replacePoints(inner)), Opcodes.ACC_PUBLIC,ClassHelper.OBJECT_TYPE);
+            this.knownEnclosingType = outer;
+            this.nestClassName = inner;
+            this.isPrimaryNode = false;
+        }
+        public boolean hasPackageName() {
+            if (redirect()!=this) return super.hasPackageName();
+            return knownEnclosingType.hasPackageName();
+        }
+        public String setName(String name) {
+            if (redirect()!=this) {
+                return super.setName(name);
+            } else {
+                throw new GroovyBugError("ConstructedNestedClass#setName should not be called");
+            }
+        }
+    }
+
+
+    private static String replacePoints(String name) {
+        return name.replace('.','$');
+    }
+
+    /**
      * we use ConstructedClassWithPackage to limit the resolving the compiler
      * does when combining package names and class names. The idea
      * that if we use a package, then we do not want to replace the
@@ -191,6 +224,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         // if the type is a ConstructedClassWithPackage, because in this case we
         // are resolving the name at a different place already
         if (type instanceof ConstructedClassWithPackage) return false;
+        if (type instanceof ConstructedNestedClass) return false;
         String name = type.getName();
         String saved = name;
         while (true) {
@@ -200,19 +234,23 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             type.setName(name);
             if (resolve(type)) return true;
         }
-        if(resolveToInnerEnum (type)) return true;
+        if(resolveToNestedOfCurrent(type)) return true;
         
         type.setName(saved);
         return false;
     }
 
-    private boolean resolveToInnerEnum (ClassNode type) {
+    private boolean resolveToNestedOfCurrent(ClassNode type) {
+        if (type instanceof ConstructedNestedClass) return false;
         // GROOVY-3110: It may be an inner enum defined by this class itself, in which case it does not need to be
         // explicitly qualified by the currentClass name
         String name = type.getName();
-        if(currentClass != type && !name.contains(".") && type.getClass().equals(ClassNode.class)) {
-            type.setName(currentClass.getName() + "$" + name);
-            if (resolve(type)) return true;
+        if (currentClass != type && !name.contains(".") && type.getClass().equals(ClassNode.class)) {
+            ClassNode tmp = new ConstructedNestedClass(currentClass,name);
+            if (resolve(tmp)) {
+                type.setRedirect(tmp);
+                return true;
+            }
         }
         return false;
     }
@@ -275,6 +313,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     }
 
     private boolean resolveNestedClass(ClassNode type) {
+        if (type instanceof ConstructedNestedClass) return false;
         // we have for example a class name A, are in class X
         // and there is a nested class A$X. we want to be able 
         // to access that class directly, so A becomes a valid
@@ -282,22 +321,29 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         // GROOVY-4043: Do this check up the hierarchy, if needed
         Map<String, ClassNode> hierClasses = new LinkedHashMap<String, ClassNode>();
         ClassNode val;
-        String name;
         for(ClassNode classToCheck = currentClass; classToCheck != ClassHelper.OBJECT_TYPE; 
             classToCheck = classToCheck.getSuperClass()) {
             if(classToCheck == null || hierClasses.containsKey(classToCheck.getName())) break;
             hierClasses.put(classToCheck.getName(), classToCheck);
         }
-        
+
         for (ClassNode classToCheck : hierClasses.values()) {
-            name = classToCheck.getName()+"$"+type.getName();
-            val = ClassHelper.make(name);
+            val = new ConstructedNestedClass(classToCheck,type.getName());
             if (resolveFromCompileUnit(val)) {
                 type.setRedirect(val);
                 return true;
             }
+            // also check interfaces in case we have interfaces with nested classes
+            for (ClassNode next : classToCheck.getAllInterfaces()) {
+                if (type.getName().contains(next.getName())) continue;
+                val = new ConstructedNestedClass(next,type.getName());
+                if (resolve(val, false, false, false)) {
+                    type.setRedirect(val);
+                    return true;
+                }
+            }
         }
-        
+
         // another case we want to check here is if we are in a
         // nested class A$B$C and want to access B without
         // qualifying it by A.B. A alone will work, since that
@@ -323,15 +369,23 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         }
         // most outer class is now element 0
         for (ClassNode testNode : outerClasses) {
-            name = testNode.getName()+"$"+type.getName();
-            val = ClassHelper.make(name);
+            val = new ConstructedNestedClass(testNode,type.getName());
             if (resolveFromCompileUnit(val)) {
                 type.setRedirect(val);
                 return true;
             }
-        }        
-        
-        return false;   
+            // also check interfaces in case we have interfaces with nested classes
+            for (ClassNode next : testNode.getAllInterfaces()) {
+                if (type.getName().contains(next.getName())) continue;
+                val = new ConstructedNestedClass(next,type.getName());
+                if (resolve(val, false, false, false)) {
+                    type.setRedirect(val);
+                    return true;
+                }
+            }
+        }
+
+        return false;
     }
 
     private String replaceLastPoint(String name) {
@@ -345,6 +399,8 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     }
 
     private boolean resolveFromStaticInnerClasses(ClassNode type, boolean testStaticInnerClasses) {
+        if (type instanceof ConstructedNestedClass) return false;
+
         // a class consisting of a vanilla name can never be
         // a static inner class, because at least one dot is
         // required for this. Example: foo.bar -> foo$bar
@@ -462,7 +518,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 importNode = module.getStaticImports().get(pname);
                 if (importNode != null && importNode != currImportNode) {
                     // static alias only for inner classes and must be at end of chain
-                    ClassNode tmp = ClassHelper.make(importNode.getType().getName() + "$" + importNode.getFieldName());
+                    ClassNode tmp = new ConstructedNestedClass(importNode.getType(), importNode.getFieldName());
                     if (resolve(tmp, false, false, true)) {
                         if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
                             type.setRedirect(tmp.redirect());
@@ -505,6 +561,8 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
     }
 
     private boolean resolveFromModule(ClassNode type, boolean testModuleImports) {
+        if (type instanceof ConstructedNestedClass) return false;
+
         // we decided if we have a vanilla name starting with a lower case
         // letter that we will not try to resolve this name against .*
         // imports. Instead a full import is needed for these.
@@ -558,7 +616,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
             // check module static imports (for static inner classes)
             for (ImportNode importNode : module.getStaticImports().values()) {
                 if (importNode.getFieldName().equals(name)) {
-                    ClassNode tmp = ClassHelper.make(importNode.getType().getName() + "$" + name);
+                    ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
                     if (resolve(tmp, false, false, true)) {
                         if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
                             type.setRedirect(tmp.redirect());
@@ -585,7 +643,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
 
             // check for star imports (import static pkg.Outer.*) matching static inner classes
             for (ImportNode importNode : module.getStaticStarImports().values()) {
-                ClassNode tmp = ClassHelper.make(importNode.getClassName() + "$" + name);
+                ClassNode tmp = new ConstructedNestedClass(importNode.getType(), name);
                 if (resolve(tmp, false, false, true)) {
                     if ((tmp.getModifiers() & Opcodes.ACC_STATIC) != 0) {
                         ambiguousClass(type, tmp, name);
@@ -780,7 +838,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
         if (objectExpression instanceof ClassExpression && pe.getPropertyAsString() != null) {
             // possibly an inner class
             ClassExpression ce = (ClassExpression) objectExpression;
-            ClassNode type = ClassHelper.make(ce.getType().getName() + "$" + pe.getPropertyAsString());
+            ClassNode type = new ConstructedNestedClass(ce.getType(), pe.getPropertyAsString());
             if (resolve(type, false, false, false)) {
                 Expression ret = new ClassExpression(type);
                 ret.setSourcePosition(ce);
@@ -818,7 +876,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                 addError("The usage of 'Class.this' and 'Class.super' is only allowed in nested/inner classes.", expression);
                 return;
             }
-            if (!currentScope.isInStaticContext() && Traits.isTrait(type) && "super".equals(prop) && directlyImplementsTrait(type)) {
+            if (currentScope!=null && !currentScope.isInStaticContext() && Traits.isTrait(type) && "super".equals(prop) && directlyImplementsTrait(type)) {
                 return;
             }
             ClassNode iterType = currentClass;
@@ -831,7 +889,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                         currentClass.getName() + "' when using '.this' or '.super'.", expression);
             }
             if ((currentClass.getModifiers() & Opcodes.ACC_STATIC) == 0) return;
-            if (!currentScope.isInStaticContext()) return;
+            if (currentScope != null && !currentScope.isInStaticContext()) return;
             addError("The usage of 'Class.this' and 'Class.super' within static nested class '" +
                     currentClass.getName() + "' is not allowed in a static context.", expression);
         }
@@ -864,7 +922,7 @@ public class ResolveVisitor extends ClassCodeExpressionTransformer {
                   t = new LowerCaseClass(name);
                 }
                 isClass = resolve(t);
-                if(!isClass) isClass = resolveToInnerEnum(t);
+                if(!isClass) isClass = resolveToNestedOfCurrent(t);
             }
             if (isClass) {
                 // the name is a type so remove it from the scoping
diff --git a/src/main/org/codehaus/groovy/control/StaticImportVisitor.java b/src/main/org/codehaus/groovy/control/StaticImportVisitor.java
index 0f3a9d2..5c17eb8 100644
--- a/src/main/org/codehaus/groovy/control/StaticImportVisitor.java
+++ b/src/main/org/codehaus/groovy/control/StaticImportVisitor.java
@@ -284,6 +284,8 @@ public class StaticImportVisitor extends ClassCodeExpressionTransformer {
         result.setImplicitThis(mce.isImplicitThis());
         result.setSpreadSafe(mce.isSpreadSafe());
         result.setMethodTarget(mce.getMethodTarget());
+        // GROOVY-6757
+        result.setGenericsTypes(mce.getGenericsTypes());
         setSourcePosition(result, mce);
         return result;
     }
diff --git a/src/main/org/codehaus/groovy/reflection/CachedClass.java b/src/main/org/codehaus/groovy/reflection/CachedClass.java
index 1e6ba8b..3413707 100644
--- a/src/main/org/codehaus/groovy/reflection/CachedClass.java
+++ b/src/main/org/codehaus/groovy/reflection/CachedClass.java
@@ -19,6 +19,7 @@ import groovy.lang.*;
 
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.runtime.callsite.CallSiteClassLoader;
+import org.codehaus.groovy.runtime.metaclass.ClosureMetaClass;
 import org.codehaus.groovy.util.LazyReference;
 import org.codehaus.groovy.util.FastArray;
 import org.codehaus.groovy.util.ReferenceBundle;
@@ -35,6 +36,7 @@ import java.util.*;
  * @author Alex.Tkachman
  */
 public class CachedClass {
+    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
     private final Class cachedClass;
     public ClassInfo classInfo;
     
@@ -81,13 +83,18 @@ public class CachedClass {
             final Method[] declaredMethods = (Method[])
                AccessController.doPrivileged(new PrivilegedAction/*<Method[]>*/() {
                    public /*Method[]*/ Object run() {
-                       final Method[] dm = getTheClass().getDeclaredMethods();
                        try {
-                           AccessibleObject.setAccessible(dm, true);
-                       } catch (SecurityException e) {
-                           // swallow for strict security managers
+                           final Method[] dm = getTheClass().getDeclaredMethods();
+                           try {
+                               AccessibleObject.setAccessible(dm, true);
+                           } catch (SecurityException e) {
+                               // swallow for strict security managers
+                           }
+                           return dm;
+                       } catch (Throwable e) {
+                           // Typically, Android can throw ClassNotFoundException
+                           return EMPTY_METHOD_ARRAY;
                        }
-                       return dm;
                    }
                });
             List<CachedMethod> methods = new ArrayList<CachedMethod>(declaredMethods.length);
@@ -450,6 +457,10 @@ public class CachedClass {
         res.addAll(Arrays.asList(classInfo.newMetaMethods));
         res.addAll(arr);
         classInfo.newMetaMethods = res.toArray(new MetaMethod[res.size()]);
+        Class theClass = classInfo.getCachedClass().getTheClass();
+        if (theClass==Closure.class || theClass==Class.class) {
+            ClosureMetaClass.resetCachedMetaClasses();
+        }
     }
 
     public boolean isAssignableFrom(Class argument) {
diff --git a/src/main/org/codehaus/groovy/reflection/ClassInfo.java b/src/main/org/codehaus/groovy/reflection/ClassInfo.java
index ef826d8..a98732b 100644
--- a/src/main/org/codehaus/groovy/reflection/ClassInfo.java
+++ b/src/main/org/codehaus/groovy/reflection/ClassInfo.java
@@ -17,6 +17,7 @@ package org.codehaus.groovy.reflection;
 
 import groovy.lang.*;
 
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
 import org.codehaus.groovy.reflection.stdclasses.*;
 import org.codehaus.groovy.util.*;
 import org.codehaus.groovy.vmplugin.VMPluginFactory;
@@ -34,14 +35,13 @@ import java.util.concurrent.atomic.AtomicInteger;
  *
  * @author Alex.Tkachman
  */
-public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
-
-    private static final Set<ClassInfo> modifiedExpandos = new HashSet<ClassInfo>();
+public class ClassInfo {
 
     private final LazyCachedClassRef cachedClassRef;
     private final LazyClassLoaderRef artifactClassLoader;
     private final LockableObject lock = new LockableObject();
     public final int hash;
+    private final Class klazz;
 
     private volatile int version;
 
@@ -49,19 +49,31 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
     private ManagedReference<MetaClass> weakMetaClass;
     MetaMethod[] dgmMetaMethods = CachedClass.EMPTY;
     MetaMethod[] newMetaMethods = CachedClass.EMPTY;
-    private ManagedConcurrentMap perInstanceMetaClassMap;
+    private ManagedConcurrentMap<Object, MetaClass> perInstanceMetaClassMap;
     
     private static ReferenceBundle softBundle = ReferenceBundle.getSoftBundle();
     private static ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
-    private static final ClassInfoSet globalClassSet = new ClassInfoSet(softBundle);
-
-    ClassInfo(ManagedConcurrentMap.Segment segment, Class klazz, int hash) {
-        super (softBundle, segment, klazz, hash);
+    
+    private static final ManagedLinkedList<ClassInfo> modifiedExpandos = new ManagedLinkedList<ClassInfo>(weakBundle);
+
+    private static final GroovyClassValue<ClassInfo> globalClassValue = GroovyClassValueFactory.createGroovyClassValue(new ComputeValue<ClassInfo>(){
+		@Override
+		public ClassInfo computeValue(Class<?> type) {
+			ClassInfo ret = new ClassInfo(type);
+			globalClassSet.add(ret);
+			return ret;
+		}
+	});
+    
+    private static final GlobalClassSet globalClassSet = new GlobalClassSet();
 
+    ClassInfo(Class klazz) {
+    	this.hash = System.identityHashCode(klazz);
+    	this.klazz = klazz;
         if (ClassInfo.DebugRef.debug)
           new DebugRef(klazz);
+        new ClassInfoCleanup(this);
 
-        this.hash = hash;
         cachedClassRef = new LazyCachedClassRef(softBundle, this);
         artifactClassLoader = new LazyClassLoaderRef(softBundle, this);
     }
@@ -83,11 +95,13 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
     }
 
     public static void clearModifiedExpandos() {
-        for (Iterator<ClassInfo> it = modifiedExpandos.iterator(); it.hasNext(); ) {
-            ClassInfo info = it.next();
-            it.remove();
-            info.setStrongMetaClass(null);
-        }
+        synchronized(modifiedExpandos){
+	        for (Iterator<ClassInfo> it = modifiedExpandos.iterator(); it.hasNext(); ) {
+	            ClassInfo info = it.next();
+	            it.remove();
+	            info.setStrongMetaClass(null);
+	        }
+	    }
     }
 
     public CachedClass getCachedClass() {
@@ -101,7 +115,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
     public static ClassInfo getClassInfo (Class cls) {
         LocalMap map = getLocalClassInfoMap();
         if (map!=null) return map.get(cls);
-        return (ClassInfo) globalClassSet.getOrPut(cls,null);
+        return (ClassInfo) globalClassValue.get(cls);
     }
 
     private static LocalMap getLocalClassInfoMap() {
@@ -118,7 +132,19 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         return localClassInfos != null ? localClassInfos : getAllGlobalClassInfo();
     }
 
-    private static Collection getAllGlobalClassInfo() {
+    public static void onAllClassInfo(ClassInfoAction action) {
+        Collection<ClassInfo> localClassInfos = getAllLocalClassInfo();
+        if (localClassInfos!=null) {
+            for (ClassInfo localClassInfo : localClassInfos) {
+                action.onClassInfo(localClassInfo);
+            }
+        }
+        for (ClassInfo classInfo : getAllGlobalClassInfo()) {
+            action.onClassInfo(classInfo);
+        }
+    }
+
+    private static Collection<ClassInfo> getAllGlobalClassInfo() {
         return globalClassSet.values();
     }
 
@@ -141,14 +167,29 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         
         if (strongRef instanceof ExpandoMetaClass) {
           ((ExpandoMetaClass)strongRef).inRegistry = false;
-          modifiedExpandos.remove(this);
+          synchronized(modifiedExpandos){
+            for (Iterator<ClassInfo> it = modifiedExpandos.iterator(); it.hasNext(); ) {
+              ClassInfo info = it.next();
+              if(info == this){
+                it.remove();
+              }
+            }
+          }
         }
 
         strongMetaClass = answer;
 
         if (answer instanceof ExpandoMetaClass) {
           ((ExpandoMetaClass)answer).inRegistry = true;
-          modifiedExpandos.add(this);
+          synchronized(modifiedExpandos){
+            for (Iterator<ClassInfo> it = modifiedExpandos.iterator(); it.hasNext(); ) {
+              ClassInfo info = it.next();
+                if(info == this){
+                  it.remove();
+                }
+             }
+             modifiedExpandos.add(this);
+          }
         }
 
         replaceWeakMetaClassRef(null);
@@ -206,7 +247,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
             return answer;
         }
 
-        answer = mccHandle.create(get(), metaClassRegistry);
+        answer = mccHandle.create(klazz, metaClassRegistry);
         answer.initialize();
 
         if (GroovySystem.isKeepJavaMetaClasses()) {
@@ -259,14 +300,6 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         return globalClassSet.fullSize();
     }
 
-    public void finalizeRef() {
-        setStrongMetaClass(null);
-        cachedClassRef.clear();
-        artifactClassLoader.clear();
-
-        super.finalizeRef();
-    }
-
     private static CachedClass createCachedClass(Class klazz, ClassInfo classInfo) {
         if (klazz == Object.class)
             return new ObjectCachedClass(classInfo);
@@ -343,7 +376,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
 
         if (metaClass != null) {
             if (perInstanceMetaClassMap == null)
-              perInstanceMetaClassMap = new ManagedConcurrentMap(ReferenceBundle.getWeakBundle()); 
+              perInstanceMetaClassMap = new ManagedConcurrentMap<Object, MetaClass>(ReferenceBundle.getWeakBundle()); 
 
             perInstanceMetaClassMap.put(obj, metaClass);
         }
@@ -358,29 +391,6 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         return perInstanceMetaClassMap != null;
     }
 
-    public static class ClassInfoSet extends ManagedConcurrentMap<Class,ClassInfo> {
-        public ClassInfoSet(ReferenceBundle bundle) {
-            super(bundle);
-        }
-
-        protected Segment createSegment(Object segmentInfo,  int cap) {
-            ReferenceBundle bundle = (ReferenceBundle) segmentInfo;
-            if (bundle==null) throw new IllegalArgumentException("bundle must not be null ");
-
-            return new Segment(bundle, cap);
-        }
-
-        static final class Segment extends ManagedConcurrentMap.Segment<Class,ClassInfo> {
-            Segment(ReferenceBundle bundle, int initialCapacity) {
-                super(bundle, initialCapacity);
-            }
-
-            protected ClassInfo createEntry(Class key, int hash, ClassInfo unused) {
-                return new ClassInfo(this, key, hash);
-            }
-        }
-    }
-
     private static final class LocalMap extends HashMap<Class,ClassInfo> {
 
         private static final int CACHE_SIZE = 5;
@@ -397,7 +407,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         private int nextCacheEntry;
 
         private final ClassInfo[] cache = new ClassInfo[CACHE_SIZE];
-        private static final ClassInfo NOINFO = new ClassInfo(null,null,0);
+        private static final ClassInfo NOINFO = new ClassInfo(Void.class);
 
         private LocalMap() {
             for (int i = 0; i < cache.length; i++) {
@@ -414,7 +424,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
             if (info != null)
               return putToCache(info);
 
-            return putToCache((ClassInfo) globalClassSet.getOrPut(key,null));
+            return putToCache((ClassInfo) globalClassValue.get(key));
         }
 
         private ClassInfo getFromCache (Class klazz) {
@@ -423,7 +433,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
                   k += CACHE_SIZE;
 
                 final ClassInfo info = cache[k];
-                if (klazz == info.get()) {
+                if (klazz == info.klazz) {
                     nextCacheEntry = k+1;
                     if (nextCacheEntry == CACHE_SIZE)
                       nextCacheEntry = 0;
@@ -481,7 +491,7 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         }
 
         public CachedClass initValue() {
-            return createCachedClass(info.get(), info);
+            return createCachedClass(info.klazz, info);
         }
     }
 
@@ -494,7 +504,21 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         }
 
         public ClassLoaderForClassArtifacts initValue() {
-            return new ClassLoaderForClassArtifacts(info.get());
+            return new ClassLoaderForClassArtifacts(info.klazz);
+        }
+    }
+    
+    private static class ClassInfoCleanup extends ManagedReference<ClassInfo> {
+
+        public ClassInfoCleanup(ClassInfo classInfo) {
+            super(weakBundle, classInfo);
+        }
+
+        public void finalizeRef() {
+        	ClassInfo classInfo = get();
+        	classInfo.setStrongMetaClass(null);
+        	classInfo.cachedClassRef.clear();
+        	classInfo.artifactClassLoader.clear();
         }
     }
 
@@ -512,8 +536,38 @@ public class ClassInfo extends ManagedConcurrentMap.Entry<Class,ClassInfo> {
         }
 
         public void finalizeRef() {
-            System.out.println(name + " unloaded " + count.decrementAndGet() + " classes kept");
+            //System.out.println(name + " unloaded " + count.decrementAndGet() + " classes kept");
             super.finalizeReference();
         }
     }
+    
+    private static class GlobalClassSet {
+    	
+    	private ManagedLinkedList<ClassInfo> items = new ManagedLinkedList<ClassInfo>(weakBundle);
+    	
+    	public int size(){
+		return values().size();
+    	}
+    	
+    	public int fullSize(){
+		return values().size();
+    	}
+    	
+    	public Collection<ClassInfo> values(){
+    		synchronized(items){
+    			return Arrays.asList(items.toArray(new ClassInfo[0]));
+    		}
+    	}
+    	
+    	public void add(ClassInfo value){
+    		synchronized(items){
+    			items.add(value);
+    		}
+    	}
+
+    }
+
+    public static interface ClassInfoAction {
+        void onClassInfo(ClassInfo classInfo);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/reflection/GroovyClassValue.java b/src/main/org/codehaus/groovy/reflection/GroovyClassValue.java
new file mode 100644
index 0000000..61624d9
--- /dev/null
+++ b/src/main/org/codehaus/groovy/reflection/GroovyClassValue.java
@@ -0,0 +1,18 @@
+package org.codehaus.groovy.reflection;
+
+/** Abstraction for Java version dependent ClassValue implementations.
+ * @see java.lang.ClassValue
+ *
+ * @param <T>
+ */
+public interface GroovyClassValue<T> {
+	
+	public static interface ComputeValue<T>{
+		T computeValue(Class<?> type);
+	}
+	
+	T get(Class<?> type);
+	
+	void remove(Class<?> type);
+	
+}
diff --git a/src/main/org/codehaus/groovy/reflection/GroovyClassValueFactory.java b/src/main/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
new file mode 100644
index 0000000..71e9910
--- /dev/null
+++ b/src/main/org/codehaus/groovy/reflection/GroovyClassValueFactory.java
@@ -0,0 +1,36 @@
+package org.codehaus.groovy.reflection;
+
+import java.lang.reflect.Constructor;
+
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
+
+class GroovyClassValueFactory {
+	private static final Constructor groovyClassValueConstructor;
+
+	static {
+		Class groovyClassValueClass;
+		try{
+			Class.forName("java.lang.ClassValue");
+			try{
+				groovyClassValueClass = Class.forName("org.codehaus.groovy.reflection.v7.GroovyClassValueJava7");
+			}catch(Exception e){
+				throw new RuntimeException(e); // this should never happen, but if it does, let it propagate and be fatal
+			}
+		}catch(ClassNotFoundException e){
+			groovyClassValueClass = GroovyClassValuePreJava7.class;
+		}
+		try{
+			groovyClassValueConstructor = groovyClassValueClass.getConstructor(ComputeValue.class);
+		}catch(Exception e){
+			throw new RuntimeException(e); // this should never happen, but if it does, let it propagate and be fatal
+		}
+	}
+
+	public static <T> GroovyClassValue<T> createGroovyClassValue(ComputeValue<T> computeValue){
+		try {
+			return (GroovyClassValue<T>) groovyClassValueConstructor.newInstance(computeValue);
+		} catch (Exception e) {
+			throw new RuntimeException(e); // this should never happen, but if it does, let it propagate and be fatal
+		}
+	}
+}
diff --git a/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java b/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
new file mode 100644
index 0000000..eacb139
--- /dev/null
+++ b/src/main/org/codehaus/groovy/reflection/GroovyClassValuePreJava7.java
@@ -0,0 +1,76 @@
+package org.codehaus.groovy.reflection;
+
+import org.codehaus.groovy.util.ManagedConcurrentMap;
+import org.codehaus.groovy.util.ReferenceBundle;
+
+/** Approximation of Java 7's {@link java.lang.ClassValue} that works on earlier versions of Java.
+ * Note that this implementation isn't as good at Java 7's; it doesn't allow for some GC'ing that Java 7 would allow.
+ * But, it's good enough for our use.
+ *
+ * @param <T>
+ */
+class GroovyClassValuePreJava7<T> implements GroovyClassValue<T> {
+	private static final ReferenceBundle weakBundle = ReferenceBundle.getWeakBundle();
+
+	private class EntryWithValue extends ManagedConcurrentMap.EntryWithValue<Class<?>,T>{
+
+		public EntryWithValue(GroovyClassValuePreJava7Segment segment, Class<?> key, int hash) {
+			super(weakBundle, segment, key, hash, computeValue.computeValue(key));
+		}
+
+		@Override
+		public void setValue(T value) {
+			if(value!=null) super.setValue(value);
+		}
+	}
+
+	private class GroovyClassValuePreJava7Segment extends ManagedConcurrentMap.Segment<Class<?>,T> {
+
+		GroovyClassValuePreJava7Segment(ReferenceBundle bundle, int initialCapacity) {
+			super(bundle, initialCapacity);
+		}
+
+		@Override
+		protected EntryWithValue createEntry(Class<?> key, int hash,
+				T unused) {
+			return new EntryWithValue(this, key, hash);
+		}
+	}
+
+	private class GroovyClassValuePreJava7Map extends ManagedConcurrentMap<Class<?>,T> {
+
+		public GroovyClassValuePreJava7Map() {
+			super(weakBundle);
+		}
+
+		@Override
+		protected GroovyClassValuePreJava7Segment createSegment(Object segmentInfo, int cap) {
+			ReferenceBundle bundle = (ReferenceBundle) segmentInfo;
+			if (bundle==null) throw new IllegalArgumentException("bundle must not be null ");
+			return new GroovyClassValuePreJava7Segment(bundle, cap);
+		}
+
+	}
+
+	private final ComputeValue<T> computeValue;
+
+	private final GroovyClassValuePreJava7Map map = new GroovyClassValuePreJava7Map();
+
+	public GroovyClassValuePreJava7(ComputeValue<T> computeValue){
+		this.computeValue = computeValue;
+	}
+
+	@Override
+	public T get(Class<?> type) {
+		// the value isn't use in the getOrPut call - see the EntryWithValue constructor above
+		T value = ((EntryWithValue)map.getOrPut(type, null)).getValue();
+		//all entries are guaranteed to be EntryWithValue. Value can only be null if computeValue returns null
+		return value;
+	}
+
+	@Override
+	public void remove(Class<?> type) {
+		map.remove(type);
+	}
+
+}
diff --git a/src/main/org/codehaus/groovy/reflection/android/AndroidSupport.java b/src/main/org/codehaus/groovy/reflection/android/AndroidSupport.java
new file mode 100644
index 0000000..83cd4ec
--- /dev/null
+++ b/src/main/org/codehaus/groovy/reflection/android/AndroidSupport.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.reflection.android;
+
+public abstract class AndroidSupport {
+    private static final boolean IS_ANDROID;
+
+    static {
+        boolean isAndroid = true;
+        try {
+            Class.forName("android.app.Activity", false, AndroidSupport.class.getClassLoader());
+        } catch (ClassNotFoundException e) {
+            isAndroid = false;
+        }
+        IS_ANDROID = isAndroid;
+    }
+
+    public static boolean isRunningAndroid() {
+        return IS_ANDROID;
+    }
+
+}
diff --git a/src/main/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java b/src/main/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
index 8ec679e..5b8ad95 100644
--- a/src/main/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
+++ b/src/main/org/codehaus/groovy/reflection/stdclasses/CachedSAMClass.java
@@ -40,9 +40,10 @@ import org.codehaus.groovy.transform.trait.Traits;
 
 public class CachedSAMClass extends CachedClass {
 
-    private static final int ABSTRACT_STATIC_PRIVATE = 
+    private static final int ABSTRACT_STATIC_PRIVATE =
             Modifier.ABSTRACT|Modifier.PRIVATE|Modifier.STATIC;
     private static final int VISIBILITY = 5; // public|protected
+    private static final Method[] EMPTY_METHOD_ARRAY = new Method[0];
     private final Method method;
 
     public CachedSAMClass(Class klazz, ClassInfo classInfo) {
@@ -104,7 +105,7 @@ public class CachedSAMClass extends CachedClass {
         } catch (java.security.AccessControlException ace) {
             // swallow and do as if no method is available
         }
-        return new Method[0];
+        return EMPTY_METHOD_ARRAY;
     }
 
     private static void getAbstractMethods(Class c, List<Method> current) {
diff --git a/src/main/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java b/src/main/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java
new file mode 100644
index 0000000..771907f
--- /dev/null
+++ b/src/main/org/codehaus/groovy/reflection/v7/GroovyClassValueJava7.java
@@ -0,0 +1,20 @@
+package org.codehaus.groovy.reflection.v7;
+
+import org.codehaus.groovy.reflection.GroovyClassValue;
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue;
+
+/** GroovyClassValue implementaion that simply delegates to Java 7's java.lang.ClassValue
+ * @see java.lang.ClassValue
+ *
+ * @param <T>
+*/
+public class GroovyClassValueJava7<T> extends ClassValue<T> implements GroovyClassValue<T> {
+   private final ComputeValue<T> computeValue;
+   public GroovyClassValueJava7(ComputeValue<T> computeValue){
+      this.computeValue = computeValue;
+   }
+   @Override
+   protected T computeValue(Class<?> type) {
+      return computeValue.computeValue(type);
+   }
+}
diff --git a/src/main/org/codehaus/groovy/runtime/ConversionHandler.java b/src/main/org/codehaus/groovy/runtime/ConversionHandler.java
index e12ecd5..6791cb0 100644
--- a/src/main/org/codehaus/groovy/runtime/ConversionHandler.java
+++ b/src/main/org/codehaus/groovy/runtime/ConversionHandler.java
@@ -17,12 +17,16 @@
 package org.codehaus.groovy.runtime;
 
 import groovy.lang.GroovyRuntimeException;
+import org.codehaus.groovy.vmplugin.VMPlugin;
+import org.codehaus.groovy.vmplugin.VMPluginFactory;
 
 import java.io.Serializable;
 import java.lang.reflect.InvocationHandler;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
 import java.lang.reflect.Proxy;
+import java.util.concurrent.ConcurrentHashMap;
 
 /**
  * This class is a general adapter to map a call to a Java interface
@@ -34,6 +38,10 @@ import java.lang.reflect.Proxy;
 public abstract class ConversionHandler implements InvocationHandler, Serializable {
     private Object delegate;
     private static final long serialVersionUID = 1162833717190835227L;
+    private ConcurrentHashMap handleCache;
+    {
+        if (VMPluginFactory.getPlugin().getVersion()>=7) handleCache = new ConcurrentHashMap();
+    }
 
     /**
      * Creates a ConversionHandler with an delegate.
@@ -58,15 +66,19 @@ public abstract class ConversionHandler implements InvocationHandler, Serializab
     /**
      * This method is a default implementation for the invoke method given in
      * InvocationHandler. Any call to a method with a declaring class that is
-     * not Object, excluding toString(), is redirected to invokeCustom.
+     * not Object, excluding toString() and default methods is redirected to invokeCustom.
+     * <p>
      * Methods like equals and hashcode are called on the class itself instead
      * of the delegate because they are considered fundamental methods that should
      * not be overwritten. The toString() method gets special treatment as it is
      * deemed to be a method that you might wish to override when called from Groovy.
-     * <p>
+     * Interface default methods from Java 8 on the other hand are considered being
+     * default implementations you don't normally want to change. So they are called
+     * directly too
+     * </p><p>
      * In many scenarios, it is better to overwrite the invokeCustom method where
      * the core Object related methods are filtered out.
-     *
+     *</p>
      * @param proxy  the proxy
      * @param method the method
      * @param args   the arguments
@@ -76,6 +88,16 @@ public abstract class ConversionHandler implements InvocationHandler, Serializab
      * @see InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object[])
      */
     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
+        VMPlugin plugin = VMPluginFactory.getPlugin();
+        if (plugin.getVersion()>=7 && isDefaultMethod(method)) {
+            Object handle = handleCache.get(method);
+            if (handle == null) {
+                handle = plugin.getInvokeSpecialHandle(method, proxy);
+                handleCache.put(method, handle);
+            }
+            return plugin.invokeHandle(handle, args);
+        }
+
         if (!checkMethod(method)) {
             try {
                 return invokeCustom(proxy, method, args);
@@ -83,6 +105,7 @@ public abstract class ConversionHandler implements InvocationHandler, Serializab
                 throw ScriptBytecodeAdapter.unwrap(gre);
             }
         }
+
         try {
             return method.invoke(this, args);
         } catch (InvocationTargetException ite) {
@@ -90,6 +113,11 @@ public abstract class ConversionHandler implements InvocationHandler, Serializab
         }
     }
 
+    protected boolean isDefaultMethod(Method method) {
+        return ((method.getModifiers() & (Modifier.ABSTRACT | Modifier.PUBLIC | Modifier.STATIC)) ==
+                Modifier.PUBLIC) && method.getDeclaringClass().isInterface();
+    }
+
     protected boolean checkMethod(Method method) {
         return isCoreObjectMethod(method);
     }
diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
index 5f2c0aa..61ac5c7 100644
--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethods.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -66,6 +66,7 @@ import java.net.URISyntaxException;
 import java.net.URL;
 import java.security.AccessController;
 import java.security.PrivilegedAction;
+import java.text.MessageFormat;
 import java.util.*;
 import java.util.concurrent.BlockingQueue;
 import java.util.logging.Logger;
@@ -114,6 +115,7 @@ import java.util.regex.Pattern;
  * @author Tim Yates
  * @author Dinko Srkoc
  * @author Andre Steingress
+ * @author Yu Kobayashi
  */
 public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
@@ -164,6 +166,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 //            XmlGroovyMethods.class,
 //            NioGroovyMethods.class
     };
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
 
     /**
      * Identity check. Since == is overridden in Groovy with the meaning of equality
@@ -607,7 +610,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     public static void println(Closure self) {
         Object owner = getClosureOwner(self);
-        InvokerHelper.invokeMethod(owner, "println", new Object[0]);
+        InvokerHelper.invokeMethod(owner, "println", EMPTY_OBJECT_ARRAY);
     }
 
     private static Object getClosureOwner(Closure cls) {
@@ -996,7 +999,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Returns an iterator equivalent to this iterator all duplicated items removed
+     * Returns an iterator equivalent to this iterator with all duplicated items removed
      * by using the default comparator. The original iterator will become
      * exhausted of elements after determining the unique values. A new iterator
      * for the unique values will be returned.
@@ -1006,7 +1009,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> unique(Iterator<T> self) {
-        return toList(unique(toList(self))).listIterator();
+        return toList((Iterable<T>) unique(toList(self))).listIterator();
     }
 
     /**
@@ -1024,6 +1027,20 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Modifies this List to remove all duplicated items, using the
+     * default comparator.
+     * <pre class="groovyTestCase">assert [1,3] == [1,3,3].unique()</pre>
+     *
+     * @param self a List
+     * @return the now modified List
+     * @see #unique(Collection, boolean)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self) {
+        return (List<T>) unique((Collection<T>) self, true);
+    }
+
+    /**
      * Remove all duplicates from a given Collection using the default comparator.
      * If mutate is true, it works by modifying the original object (and also returning it).
      * If mutate is false, a new collection is returned leaving the original unchanged.
@@ -1063,6 +1080,29 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Remove all duplicates from a given List using the default comparator.
+     * If mutate is true, it works by modifying the original object (and also returning it).
+     * If mutate is false, a new collection is returned leaving the original unchanged.
+     * <pre class="groovyTestCase">
+     * assert [1,3] == [1,3,3].unique()
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2, 3]
+     * def uniq = orig.unique(false)
+     * assert orig == [1, 3, 2, 3]
+     * assert uniq == [1, 3, 2]
+     * </pre>
+     *
+     * @param self a List
+     * @param mutate false will cause a new List containing unique items from the List to be created, true will mutate List in place
+     * @return the now modified List
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, boolean mutate) {
+        return (List<T>) unique((Collection<T>) self, mutate);
+    }
+
+    /**
      * Provides a method that compares two comparables using Groovy's
      * default number aware comparator.
      *
@@ -1094,7 +1134,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> unique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return toList(unique(toList(self), closure)).listIterator();
+        return toList((Iterable<T>) unique(toList(self), closure)).listIterator();
     }
 
     /**
@@ -1122,16 +1162,37 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * A convenience method for making a collection unique using a Closure to determine duplicate (equal) items.
-     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * A convenience method for making a List unique using a Closure
+     * to determine duplicate (equal) items.
      * <p>
      * If the closure takes a single parameter, the
      * argument passed will be each element, and the closure
      * should return a value used for comparison (either using
      * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
-     * If the closure takes two parameters, two items from the collection
+     * If the closure takes two parameters, two items from the List
      * will be passed as arguments, and the closure should return an
      * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].unique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].unique { a, b -> a <=> b }</pre>
+     *
+     * @param self    a List
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @see #unique(Collection, boolean, Closure)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, true, closure);
+    }
+
+    /**
+     * A convenience method for making a collection unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the Collection will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
      * <pre class="groovyTestCase">
      * def orig = [1, 3, 4, 5]
      * def uniq = orig.unique(false) { it % 2 }
@@ -1155,9 +1216,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         // use a comparator of one item or two
         int params = closure.getMaximumNumberOfParameters();
         if (params == 1) {
-            OrderBy<T> by = new OrderBy<T>(closure);
-            by.setEqualityCheck(true);
-            self = unique(self, mutate, by);
+            self = unique(self, mutate, new OrderBy<T>(closure, true));
         } else {
             self = unique(self, mutate, new ClosureComparator<T>(closure));
         }
@@ -1165,6 +1224,37 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * A convenience method for making a List unique using a Closure to determine duplicate (equal) items.
+     * If mutate is true, it works on the receiver object and returns it. If mutate is false, a new collection is returned.
+     * <p>
+     * If the closure takes a single parameter, each element from the List will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the collection
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 4, 5]
+     * def uniq = orig.unique(false) { it % 2 }
+     * assert orig == [1, 3, 4, 5]
+     * assert uniq == [1, 4]
+     * </pre>
+     * <pre class="groovyTestCase">
+     * def orig = [2, 3, 3, 4]
+     * def uniq = orig.unique(false) { a, b -> a <=> b }
+     * assert orig == [2, 3, 3, 4]
+     * assert uniq == [2, 3, 4]
+     * </pre>
+     *
+     * @param self    a List
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine unique items
+     * @return self   without any duplicates
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return (List<T>) unique((Collection<T>) self, mutate, closure);
+    }
+
+    /**
      * Returns an iterator equivalent to this iterator with all duplicated
      * items removed by using the supplied comparator.
      *
@@ -1174,7 +1264,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> unique(Iterator<T> self, Comparator<T> comparator) {
-        return toList(unique(toList(self), comparator)).listIterator();
+        return toList((Iterable<T>) unique(toList(self), comparator)).listIterator();
     }
 
     /**
@@ -1229,6 +1319,57 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Remove all duplicates from a given List.
+     * Works on the original object (and also returns it).
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(new PersonComparator())
+     * assert( list2 == list && list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a List
+     * @param comparator a Comparator
+     * @return self      the now modified List without duplicates
+     * @see #unique(java.util.Collection, boolean, java.util.Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> unique(List<T> self, Comparator<T> comparator) {
+        return (List<T>) unique((Collection<T>) self, true, comparator);
+    }
+
+    /**
      * Remove all duplicates from a given Collection.
      * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new collection is returned.
      * The order of members in the Collection are compared by the given Comparator.
@@ -1296,98 +1437,653 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Iterates through an aggregate type or data structure,
-     * passing each item to the given closure.  Custom types may utilize this
-     * method by simply providing an "iterator()" method.  The items returned
-     * from the resulting iterator will be passed to the closure.
+     * Remove all duplicates from a given List.
+     * If mutate is true, it works on the original object (and also returns it). If mutate is false, a new List is returned.
+     * The order of members in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned
+     * by the given List's iterator is retained, but all other ones are removed.
+     * The given List's original order is preserved.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
      *
-     * @param self    the object over which we iterate
-     * @param closure the closure applied on each element found
-     * @return the self Object
-     * @since 1.0
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.unique(false, new PersonComparator())
+     * assert( list2 != list && list2 == [a, b, c] )
+     * </pre>
+     *
+     * @param self       a List
+     * @param mutate     false will always cause a new List to be created, true will mutate List in place
+     * @param comparator a Comparator
+     * @return self      the List without duplicates
+     * @since 2.4.0
      */
-    public static <T> T each(T self, Closure closure) {
-        each(InvokerHelper.asIterator(self), closure);
-        return self;
+    public static <T> List<T> unique(List<T> self, boolean mutate, Comparator<T> comparator) {
+        return (List<T>) unique((Collection<T>) self, mutate, comparator);
     }
 
     /**
-     * Iterates through an aggregate type or data structure,
-     * passing each item and the item's index (a counter starting at
-     * zero) to the given closure.
+     * Returns an iterator equivalent to this iterator but with all duplicated items
+     * removed where duplicate (equal) items are deduced by calling the supplied Closure condition.
+     * <p>
+     * If the supplied Closure takes a single parameter, the argument passed will be each element,
+     * and the closure should return a value used for comparison (either using
+     * {@link java.lang.Comparable#compareTo(java.lang.Object)} or {@link java.lang.Object#equals(java.lang.Object)}).
+     * If the closure takes two parameters, two items from the Iterator
+     * will be passed as arguments, and the closure should return an
+     * int value (with 0 indicating the items are not unique).
+     * <pre class="groovyTestCase">
+     * def items = "Hello".toList() + [null, null] + "there".toList()
+     * def toLower = { it == null ? null : it.toLowerCase() }
+     * def noDups = items.iterator().toUnique(toLower).toList()
+     * assert noDups == ['H', 'e', 'l', 'o', null, 't', 'r']
+     * </pre>
+     * <pre class="groovyTestCase">assert [1,4] == [1,3,4,5].toUnique { it % 2 }</pre>
+     * <pre class="groovyTestCase">assert [2,3,4] == [2,3,3,4].toUnique { a, b -> a <=> b }</pre>
      *
-     * @param self    an Object
-     * @param closure a Closure to operate on each item
-     * @return the self Object
-     * @since 1.0
+     * @param self an Iterator
+     * @param condition a Closure used to determine unique items
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> T eachWithIndex(T self, Closure closure) {
-        final Object[] args = new Object[2];
-        int counter = 0;
-        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
-            args[0] = iter.next();
-            args[1] = counter++;
-            closure.call(args);
+    public static <T> Iterator<T> toUnique(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        return new UniqueIterator<T>(self, condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition));
+    }
+
+    private static final class UniqueIterator<E> implements Iterator<E> {
+        private final Iterator<E> delegate;
+        private final Set<E> seen;
+        private boolean exhausted;
+        private E next;
+
+        private UniqueIterator(Iterator<E> delegate, Comparator<E> comparator) {
+            this.delegate = delegate;
+            seen = new TreeSet<E>(comparator);
+            advance();
+        }
+
+        public boolean hasNext() {
+            return !exhausted;
+        }
+
+        public E next() {
+            if (exhausted) throw new NoSuchElementException();
+            E result = next;
+            advance();
+            return result;
+        }
+
+        public void remove() {
+            if (exhausted) throw new NoSuchElementException();
+            delegate.remove();
+        }
+
+        private void advance() {
+            boolean foundNext = false;
+            while (!foundNext && !exhausted) {
+                exhausted = !delegate.hasNext();
+                if (!exhausted) {
+                    next = delegate.next();
+                    foundNext = seen.add(next);
+                }
+            }
         }
-        return self;
     }
 
     /**
-     * Iterates through an iterable type,
-     * passing each item and the item's index (a counter starting at
-     * zero) to the given closure.
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the supplied comparator.
      *
-     * @param self    an Iterable
-     * @param closure a Closure to operate on each item
-     * @return the self Iterable
-     * @since 2.3.0
+     * @param self an Iterator
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> Iterable<T> eachWithIndex(Iterable<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
-        eachWithIndex(self.iterator(), closure);
-        return self;
+    public static <T> Iterator<T> toUnique(Iterator<T> self, Comparator<T> comparator) {
+        return new UniqueIterator<T>(self, comparator);
     }
 
     /**
-     * Iterates through an iterator type,
-     * passing each item and the item's index (a counter starting at
-     * zero) to the given closure.
+     * Returns an iterator equivalent to this iterator with all duplicated
+     * items removed by using the natural ordering of the items.
      *
-     * @param self    an Iterable
-     * @param closure a Closure to operate on each item
-     * @return the self Iterable
-     * @since 2.3.0
+     * @param self an Iterator
+     * @return an Iterator with no duplicate items
+     * @since 2.4.0
      */
-    public static <T> Iterator<T> eachWithIndex(Iterator<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
-        final Object[] args = new Object[2];
-        int counter = 0;
-        while (self.hasNext()) {
-            args[0] = self.next();
-            args[1] = counter++;
-            closure.call(args);
-        }
-        return self;
-    }
-
-    public static <T> Iterable<T> each(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
-        each(self.iterator(), closure);
-        return self;
-    }
-
-    private static <T> Iterator<T> each(Iterator<T> iter, Closure closure) {
-        while (iter.hasNext()) {
-            Object arg = iter.next();
-            closure.call(arg);
-        }
-        return iter;
+    public static <T> Iterator<T> toUnique(Iterator<T> self) {
+        return new UniqueIterator<T>(self, null);
     }
 
     /**
-     * Allows a Map to be iterated through using a closure. If the
-     * closure takes one parameter then it will be passed the Map.Entry
-     * otherwise if the closure takes two parameters then it will be
-     * passed the key and the value.
-     * <pre class="groovyTestCase">def result = ""
-     * [a:1, b:3].each { key, value -> result += "$key$value" }
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert( list2 == list && list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       an Iterable
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self, Comparator<T> comparator) {
+        Collection<T> result = createSimilarCollection((Collection<T>) self);
+        addAll(result, toUnique(self.iterator(), comparator));
+        return result;
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Comparator.
+     * For each duplicate, the first member which is returned from the
+     * List is retained, but all other ones are removed.
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * class PersonComparator implements Comparator {
+     *     int compare(Object o1, Object o2) {
+     *         Person p1 = (Person) o1
+     *         Person p2 = (Person) o2
+     *         if (p1.lname != p2.lname)
+     *             return p1.lname.compareTo(p2.lname)
+     *         else
+     *             return p1.fname.compareTo(p2.fname)
+     *     }
+     *
+     *     boolean equals(Object obj) {
+     *         return this.equals(obj)
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * List list2 = list.toUnique(new PersonComparator())
+     * assert( list2 == list && list == [a, b, c] )
+     * </pre>
+     *
+     * @param self       an List
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the List of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self, Comparator<T> comparator) {
+        return (List<T>) toUnique((Iterable<T>) self, comparator);
+    }
+
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
+     *
+     * @param self       an Iterable
+     * @return the Collection of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self) {
+        return toUnique(self, (Comparator<T>) null);
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed
+     * using the natural ordering of the items to determine uniqueness.
+     * <p>
+     * <pre class="groovyTestCase">
+     * def letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * def expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique() == expected
+     * </pre>
+     *
+     * @param self       an List
+     * @return the List of non-duplicate items
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self) {
+        return toUnique(self, (Comparator<T>) null);
+    }
+
+    /**
+     * Returns a Collection containing the items from the Iterable but with duplicates removed.
+     * The items in the Iterable are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 -> p1.lname != p2.lname ? p1.lname <=> p2.lname : p1.fname <=> p2.fname }
+     * assert( list2 == [a, b, c] && list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] && list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      an Iterable
+     * @param condition a Closure used to determine unique items
+     * @return a new Collection
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> toUnique(Iterable<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition);
+        return toUnique(self, comparator);
+    }
+
+    /**
+     * Returns a List containing the items from the List but with duplicates removed.
+     * The items in the List are compared by the given Closure condition.
+     * For each duplicate, the first member which is returned from the
+     * Iterable is retained, but all other ones are removed.
+     * <p>
+     * If the closure takes a single parameter, each element from the Iterable will be passed to the closure. The closure
+     * should return a value used for comparison (either using {@link java.lang.Comparable#compareTo(java.lang.Object)} or
+     * {@link java.lang.Object#equals(java.lang.Object)}). If the closure takes two parameters, two items from the Iterable
+     * will be passed as arguments, and the closure should return an int value (with 0 indicating the items are not unique).
+     * <p>
+     * <pre class="groovyTestCase">
+     * class Person {
+     *     def fname, lname
+     *     String toString() {
+     *         return fname + " " + lname
+     *     }
+     * }
+     *
+     * Person a = new Person(fname:"John", lname:"Taylor")
+     * Person b = new Person(fname:"Clark", lname:"Taylor")
+     * Person c = new Person(fname:"Tom", lname:"Cruz")
+     * Person d = new Person(fname:"Clark", lname:"Taylor")
+     *
+     * def list = [a, b, c, d]
+     * def list2 = list.toUnique{ p1, p2 -> p1.lname != p2.lname ? p1.lname <=> p2.lname : p1.fname <=> p2.fname }
+     * assert( list2 == [a, b, c] && list == [a, b, c, d] )
+     * def list3 = list.toUnique{ it.toString() }
+     * assert( list3 == [a, b, c] && list == [a, b, c, d] )
+     * </pre>
+     *
+     * @param self      a List
+     * @param condition a Closure used to determine unique items
+     * @return a new List
+     * @see #toUnique(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> toUnique(List<T> self, @ClosureParams(value = FromString.class, options = {"T", "T,T"}) Closure condition) {
+        return (List<T>) toUnique((Iterable<T>) self, condition);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed with the supplied
+     * comparator determining which items are unique.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'A', 't', 'h', 'a', 'T']
+     * String[] lower = ['c', 'a', 't', 's', 'h']
+     * class LowerComparator implements Comparator {
+     *     int compare(let1, let2) { let1.toLowerCase() <=> let2.toLowerCase() }
+     * }
+     * assert letters.toUnique(new LowerComparator()) == lower
+     * </pre>
+     *
+     * @param self an array
+     * @param comparator a Comparator used to determine unique (equal) items
+     *        If {@code null}, the Comparable natural ordering of the elements will be used.
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self, Comparator<T> comparator) {
+        Collection<T> items = toUnique(toList(self), comparator);
+        T[] result = createSimilarArray(self, items.size());
+        return items.toArray(result);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed using the
+     * natural ordering of the items in the array.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'a', 't', 'h', 'a', 't']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * def result = letters.toUnique()
+     * assert result == expected
+     * assert result.class.componentType == String
+     * </pre>
+     *
+     * @param self an array
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self) {
+        return (T[]) toUnique(self, (Comparator) null);
+    }
+
+    /**
+     * Returns a new Array containing the items from the original Array but with duplicates removed with the supplied
+     * comparator determining which items are unique.
+     * <p>
+     * <pre class="groovyTestCase">
+     * String[] letters = ['c', 'a', 't', 's', 'A', 't', 'h', 'a', 'T']
+     * String[] expected = ['c', 'a', 't', 's', 'h']
+     * assert letters.toUnique{ p1, p2 -> p1.toLowerCase() <=> p2.toLowerCase() } == expected
+     * assert letters.toUnique{ it.toLowerCase() } == expected
+     * </pre>
+     *
+     * @param self an array
+     * @param condition a Closure used to determine unique items
+     * @return the unique items from the array
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] toUnique(T[] self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        Comparator<T> comparator = condition.getMaximumNumberOfParameters() == 1
+                ? new OrderBy<T>(condition, true)
+                : new ClosureComparator<T>(condition);
+        return toUnique(self, comparator);
+    }
+
+    /**
+     * Iterates through an aggregate type or data structure,
+     * passing each item to the given closure.  Custom types may utilize this
+     * method by simply providing an "iterator()" method.  The items returned
+     * from the resulting iterator will be passed to the closure.
+     *
+     * @param self    the object over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Object
+     * @since 1.0
+     */
+    public static <T> T each(T self, Closure closure) {
+        each(InvokerHelper.asIterator(self), closure);
+        return self;
+    }
+
+    /**
+     * Iterates through an aggregate type or data structure,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Object
+     * @param closure a Closure to operate on each item
+     * @return the self Object
+     * @since 1.0
+     */
+    public static <T> T eachWithIndex(T self, Closure closure) {
+        final Object[] args = new Object[2];
+        int counter = 0;
+        for (Iterator iter = InvokerHelper.asIterator(self); iter.hasNext();) {
+            args[0] = iter.next();
+            args[1] = counter++;
+            closure.call(args);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an iterable type,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Iterable
+     * @param closure a Closure to operate on each item
+     * @return the self Iterable
+     * @since 2.3.0
+     */
+    public static <T> Iterable<T> eachWithIndex(Iterable<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        eachWithIndex(self.iterator(), closure);
+        return self;
+    }
+
+    /**
+     * Iterates through an iterator type,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Iterable
+     * @param closure a Closure to operate on each item
+     * @return the self Iterable
+     * @since 2.3.0
+     */
+    public static <T> Iterator<T> eachWithIndex(Iterator<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        final Object[] args = new Object[2];
+        int counter = 0;
+        while (self.hasNext()) {
+            args[0] = self.next();
+            args[1] = counter++;
+            closure.call(args);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an Collection,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Collection
+     * @param closure a Closure to operate on each item
+     * @return the self Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> eachWithIndex(Collection<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        return (Collection<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an List,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an List
+     * @param closure a Closure to operate on each item
+     * @return the self List
+     * @since 2.4.0
+     */
+    public static <T> List<T> eachWithIndex(List<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        return (List<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an Set,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an Set
+     * @param closure a Closure to operate on each item
+     * @return the self Set
+     * @since 2.4.0
+     */
+    public static <T> Set<T> eachWithIndex(Set<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        return (Set<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an SortedSet,
+     * passing each item and the item's index (a counter starting at
+     * zero) to the given closure.
+     *
+     * @param self    an SortedSet
+     * @param closure a Closure to operate on each item
+     * @return the self SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> eachWithIndex(SortedSet<T> self, @ClosureParams(value=FromString.class, options="T,Integer") Closure closure) {
+        return (SortedSet<T>) eachWithIndex((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an Iterable, passing each item to the given closure.
+     *
+     * @param self    the Iterable over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Iterable
+     */
+    public static <T> Iterable<T> each(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        each(self.iterator(), closure);
+        return self;
+    }
+
+    /**
+     * Iterates through an Iterator, passing each item to the given closure.
+     *
+     * @param self    the Iterator over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Iterator
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> each(Iterator<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        while (self.hasNext()) {
+            Object arg = self.next();
+            closure.call(arg);
+        }
+        return self;
+    }
+
+    /**
+     * Iterates through an Collection, passing each item to the given closure.
+     *
+     * @param self    the Collection over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> each(Collection<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (Collection<T>) each((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an List, passing each item to the given closure.
+     *
+     * @param self    the List over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self List
+     * @since 2.4.0
+     */
+    public static <T> List<T> each(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<T>) each((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an Set, passing each item to the given closure.
+     *
+     * @param self    the Set over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self Set
+     * @since 2.4.0
+     */
+    public static <T> Set<T> each(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (Set<T>) each((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Iterates through an SortedSet, passing each item to the given closure.
+     *
+     * @param self    the SortedSet over which we iterate
+     * @param closure the closure applied on each element found
+     * @return the self SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> each(SortedSet<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (SortedSet<T>) each((Iterable<T>) self, closure);
+    }
+
+    /**
+     * Allows a Map to be iterated through using a closure. If the
+     * closure takes one parameter then it will be passed the Map.Entry
+     * otherwise if the closure takes two parameters then it will be
+     * passed the key and the value.
+     * <pre class="groovyTestCase">def result = ""
+     * [a:1, b:3].each { key, value -> result += "$key$value" }
      * assert result == "a1b3"</pre>
      * <pre class="groovyTestCase">def result = ""
      * [a:1, b:3].each { entry -> result += entry }
@@ -1461,7 +2157,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Iterate over each element of the list in the reverse order.
      * <pre class="groovyTestCase">def result = []
-     * [1,2,3].reverseEach { result << it }
+     * [1,2,3].reverseEach { result << it }
      * assert result == [3,2,1]</pre>
      *
      * @param self    a List
@@ -1477,7 +2173,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Iterate over each element of the array in the reverse order.
      *
-     * @param self    an Object array
+     * @param self    an array
      * @param closure a closure to which each item is passed
      * @return the original array
      * @since 1.5.2
@@ -1753,19 +2449,65 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Iterates over the array of items and returns a collection of items that match
+     * Iterates over the collection of items and returns each item that matches
      * the given filter - calling the <code>{@link #isCase(java.lang.Object, java.lang.Object)}</code>
-     * method used by switch statements. This method can be used with different
+     * method used by switch statements.  This method can be used with different
      * kinds of filters like regular expressions, classes, ranges etc.
      * Example:
      * <pre class="groovyTestCase">
-     * def list = ['a', 'b', 'aa', 'bc', 3, 4.5] as Object[]
+     * def list = ['a', 'b', 'aa', 'bc', 3, 4.5]
      * assert list.grep( ~/a+/ )  == ['a', 'aa']
      * assert list.grep( ~/../ )  == ['aa', 'bc']
      * assert list.grep( Number ) == [ 3, 4.5 ]
      * assert list.grep{ it.toString().size() == 1 } == [ 'a', 'b', 3 ]
      * </pre>
      *
+     * @param self   a List
+     * @param filter the filter to perform on each element of the collection (using the {@link #isCase(java.lang.Object, java.lang.Object)} method)
+     * @return a List of objects which match the filter
+     * @since 2.4.0
+     */
+    public static <T> List<T> grep(List<T> self, Object filter) {
+        return (List<T>) grep((Collection<T>) self, filter);
+    }
+
+    /**
+     * Iterates over the collection of items and returns each item that matches
+     * the given filter - calling the <code>{@link #isCase(java.lang.Object, java.lang.Object)}</code>
+     * method used by switch statements.  This method can be used with different
+     * kinds of filters like regular expressions, classes, ranges etc.
+     * Example:
+     * <pre class="groovyTestCase">
+     * def set = ['a', 'b', 'aa', 'bc', 3, 4.5] as Set
+     * assert set.grep( ~/a+/ )  == ['a', 'aa'] as Set
+     * assert set.grep( ~/../ )  == ['aa', 'bc'] as Set
+     * assert set.grep( Number ) == [ 3, 4.5 ] as Set
+     * assert set.grep{ it.toString().size() == 1 } == [ 'a', 'b', 3 ] as Set
+     * </pre>
+     *
+     * @param self   a Set
+     * @param filter the filter to perform on each element of the collection (using the {@link #isCase(java.lang.Object, java.lang.Object)} method)
+     * @return a Set of objects which match the filter
+     * @since 2.4.0
+     */
+    public static <T> Set<T> grep(Set<T> self, Object filter) {
+        return (Set<T>) grep((Collection<T>) self, filter);
+    }
+
+    /**
+     * Iterates over the array of items and returns a collection of items that match
+     * the given filter - calling the <code>{@link #isCase(java.lang.Object, java.lang.Object)}</code>
+     * method used by switch statements. This method can be used with different
+     * kinds of filters like regular expressions, classes, ranges etc.
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = ['a', 'b', 'aa', 'bc', 3, 4.5] as Object[]
+     * assert items.grep( ~/a+/ )  == ['a', 'aa']
+     * assert items.grep( ~/../ )  == ['aa', 'bc']
+     * assert items.grep( Number ) == [ 3, 4.5 ]
+     * assert items.grep{ it.toString().size() == 1 } == [ 'a', 'b', 3 ]
+     * </pre>
+     *
      * @param self   an array
      * @param filter the filter to perform on each element of the array (using the {@link #isCase(java.lang.Object, java.lang.Object)} method)
      * @return a collection of objects which match the filter
@@ -1797,7 +2539,45 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.1
      * @see Closure#IDENTITY
      */
-    public static Collection grep(Object self) {
+    public static Collection grep(Object self) {
+        return grep(self, Closure.IDENTITY);
+    }
+
+    /**
+     * Iterates over the collection returning each element that matches
+     * using the IDENTITY Closure as a filter - effectively returning all elements which satisfy Groovy truth.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.grep() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
+     *
+     * @param self a Collection
+     * @return a collection of elements satisfy Groovy truth
+     * @see Closure#IDENTITY
+     * @since 2.0
+     */
+    public static <T> Collection<T> grep(Collection<T> self) {
+        return grep(self, Closure.IDENTITY);
+    }
+
+    /**
+     * Iterates over the collection returning each element that matches
+     * using the IDENTITY Closure as a filter - effectively returning all elements which satisfy Groovy truth.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.grep() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
+     *
+     * @param self a List
+     * @return a List of elements satisfy Groovy truth
+     * @see Closure#IDENTITY
+     * @since 2.4.0
+     */
+    public static <T> List<T> grep(List<T> self) {
         return grep(self, Closure.IDENTITY);
     }
 
@@ -1807,17 +2587,16 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * <p>
      * Example:
      * <pre class="groovyTestCase">
-     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
-     * assert items.grep() == [1, 2, true, 'foo', [4, 5]]
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null] as Set
+     * assert items.grep() == [1, 2, true, 'foo', [4, 5]] as Set
      * </pre>
      *
-     * @param self a Collection
-     * @return a collection of elements satisfy Groovy truth
+     * @param self a Set
+     * @return a Set of elements satisfy Groovy truth
      * @see Closure#IDENTITY
-     * @since 2.0
+     * @since 2.4.0
      */
-    @SuppressWarnings("unchecked")
-    public static <T> Collection<T> grep(Collection<T> self) {
+    public static <T> Set<T> grep(Set<T> self) {
         return grep(self, Closure.IDENTITY);
     }
 
@@ -1967,7 +2746,6 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         return answer;
     }
 
-
     /**
      * Counts the number of occurrences of the given value inside this array.
      * Comparison is done using Groovy's == operator (using
@@ -2107,18 +2885,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Convert a Collection to a List. Always returns a new List
-     * even if the Collection is already a List.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">def x = [1,2,3] as HashSet
-     * assert x.class == HashSet
-     * assert x.toList() instanceof List</pre>
-     *
-     * @param self a collection
-     * @return a List
+     * @deprecated Use the Iterable version of toList instead
+     * @see #toList(Iterable)
      * @since 1.0
      */
+    @Deprecated
     public static <T> List<T> toList(Collection<T> self) {
         List<T> answer = new ArrayList<T>(self.size());
         answer.addAll(self);
@@ -2144,6 +2915,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Convert an Iterable to a List. The Iterable's iterator will
      * become exhausted of elements after making this conversion.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">def x = [1,2,3] as HashSet
+     * assert x.class == HashSet
+     * assert x.toList() instanceof List</pre>
      *
      * @param self an Iterable
      * @return a List
@@ -2169,86 +2945,119 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Collates this list into sub-lists of length <code>size</code>.
+     * Collates this iterable into sub-lists of length <code>size</code>.
      * Example:
      * <pre class="groovyTestCase">def list = [ 1, 2, 3, 4, 5, 6, 7 ]
      * def coll = list.collate( 3 )
      * assert coll == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7 ] ]</pre>
      *
-     * @param self          a List
+     * @param self          an Iterable
      * @param size          the length of each sub-list in the returned list
      * @return a List containing the data collated into sub-lists
+     * @since 2.4.0
+     */
+    public static <T> List<List<T>> collate(Iterable<T> self, int size) {
+        return collate(self, size, true);
+    }
+
+    /**
+     * @deprecated use the Iterable variant instead
+     * @see #collate(Iterable, int)
      * @since 1.8.6
      */
+    @Deprecated
     public static <T> List<List<T>> collate( List<T> self, int size ) {
-        return collate( self, size, size, true ) ;
+        return collate((Iterable<T>) self, size) ;
     }
 
     /**
-     * Collates this list into sub-lists of length <code>size</code> stepping through the code <code>step</code>
+     * Collates this iterable into sub-lists of length <code>size</code> stepping through the code <code>step</code>
      * elements for each subList.
      * Example:
      * <pre class="groovyTestCase">def list = [ 1, 2, 3, 4 ]
      * def coll = list.collate( 3, 1 )
      * assert coll == [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4 ], [ 4 ] ]</pre>
      *
-     * @param self          a List
+     * @param self          an Iterable
      * @param size          the length of each sub-list in the returned list
      * @param step          the number of elements to step through for each sub-list
      * @return a List containing the data collated into sub-lists
+     * @since 2.4.0
+     */
+    public static <T> List<List<T>> collate(Iterable<T> self, int size, int step) {
+        return collate(self, size, step, true);
+    }
+
+    /**
+     * @deprecated use the Iterable variant instead
+     * @see #collate(Iterable, int, int)
      * @since 1.8.6
      */
+    @Deprecated
     public static <T> List<List<T>> collate( List<T> self, int size, int step ) {
-        return collate( self, size, step, true ) ;
+        return collate((Iterable<T>) self, size, step) ;
     }
 
     /**
-     * Collates this list into sub-lists of length <code>size</code>. Any remaining elements in
-     * the list after the subdivision will be dropped if <code>keepRemainder</code> is false.
+     * Collates this iterable into sub-lists of length <code>size</code>. Any remaining elements in
+     * the iterable after the subdivision will be dropped if <code>keepRemainder</code> is false.
      * Example:
      * <pre class="groovyTestCase">def list = [ 1, 2, 3, 4, 5, 6, 7 ]
      * def coll = list.collate( 3, false )
      * assert coll == [ [ 1, 2, 3 ], [ 4, 5, 6 ] ]</pre>
      *
-     * @param self          a List
+     * @param self          an Iterable
      * @param size          the length of each sub-list in the returned list
-     * @param keepRemainder if true, any rmeaining elements are returned as sub-lists.  Otherwise they are discarded
+     * @param keepRemainder if true, any remaining elements are returned as sub-lists.  Otherwise they are discarded
      * @return a List containing the data collated into sub-lists
+     * @since 2.4.0
+     */
+    public static <T> List<List<T>> collate(Iterable<T> self, int size, boolean keepRemainder) {
+        return collate(self, size, size, keepRemainder);
+    }
+
+    /**
+     * @deprecated use the Iterable variant instead
+     * @see #collate(Iterable, int, boolean)
      * @since 1.8.6
      */
+    @Deprecated
     public static <T> List<List<T>> collate( List<T> self, int size, boolean keepRemainder ) {
-        return collate( self, size, size, keepRemainder ) ;
+        return collate((Iterable<T>) self, size, keepRemainder) ;
     }
 
     /**
-     * Collates this list into sub-lists of length <code>size</code> stepping through the code <code>step</code>
-     * elements for each sub-list.  Any remaining elements in the list after the subdivision will be dropped if
+     * Collates this iterable into sub-lists of length <code>size</code> stepping through the code <code>step</code>
+     * elements for each sub-list.  Any remaining elements in the iterable after the subdivision will be dropped if
      * <code>keepRemainder</code> is false.
      * Example:
-     * <pre class="groovyTestCase">def list = [ 1, 2, 3, 4 ]
+     * <pre class="groovyTestCase">
+     * def list = [ 1, 2, 3, 4 ]
+     * assert list.collate( 2, 2, true  ) == [ [ 1, 2 ], [ 3, 4 ] ]
      * assert list.collate( 3, 1, true  ) == [ [ 1, 2, 3 ], [ 2, 3, 4 ], [ 3, 4 ], [ 4 ] ]
-     * assert list.collate( 3, 1, false ) == [ [ 1, 2, 3 ], [ 2, 3, 4 ] ]</pre>
+     * assert list.collate( 3, 1, false ) == [ [ 1, 2, 3 ], [ 2, 3, 4 ] ]
+     * </pre>
      *
-     * @param self          a List
+     * @param self          an Iterable
      * @param size          the length of each sub-list in the returned list
      * @param step          the number of elements to step through for each sub-list
-     * @param keepRemainder if true, any rmeaining elements are returned as sub-lists.  Otherwise they are discarded
+     * @param keepRemainder if true, any remaining elements are returned as sub-lists.  Otherwise they are discarded
      * @return a List containing the data collated into sub-lists
-     * @since 1.8.6
+     * @since 2.4.0
      */
-    public static <T> List<List<T>> collate( List<T> self, int size, int step, boolean keepRemainder ) {
+    public static <T> List<List<T>> collate(Iterable<T> self, int size, int step, boolean keepRemainder) {
+        List<T> selfList = asList(self);
         List<List<T>> answer = new ArrayList<List<T>>();
-        if( size <= 0 || self.size() == 0 ) {
-            answer.add( self ) ;
-        }
-        else {
-            for( int pos = 0 ; pos < self.size() && pos > -1 ; pos += step ) {
-                if( !keepRemainder && pos > self.size() - size ) {
+        if (size <= 0 || selfList.size() == 0) {
+            answer.add(selfList);
+        } else {
+            for (int pos = 0; pos < selfList.size() && pos > -1; pos += step) {
+                if (!keepRemainder && pos > selfList.size() - size) {
                     break ;
                 }
                 List<T> element = new ArrayList<T>() ;
-                for( int offs = pos ; offs < pos + size && offs < self.size() ; offs++ ) {
-                    element.add( self.get( offs ) ) ;
+                for (int offs = pos; offs < pos + size && offs < selfList.size(); offs++) {
+                    element.add(selfList.get(offs));
                 }
                 answer.add( element ) ;
             }
@@ -2257,6 +3066,16 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated use the Iterable variant instead
+     * @see #collate(Iterable, int, int, boolean)
+     * @since 1.8.6
+     */
+    @Deprecated
+    public static <T> List<List<T>> collate( List<T> self, int size, int step, boolean keepRemainder ) {
+        return collate((Iterable<T>) self, size, step, keepRemainder);
+    }
+
+    /**
      * Iterates through this aggregate Object transforming each item into a new value using the
      * <code>transform</code> closure, returning a list of transformed values.
      * Example:
@@ -2344,7 +3163,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static <T,E> Collection<T> collect(Collection<E> self, Collection<T> collector, @ClosureParams(FirstParam.FirstGenericType.class) Closure<? extends T> transform) {
-        for (Object item : self) {
+        for (E item : self) {
             collector.add(transform.call(item));
             if (transform.getDirective() == Closure.DONE) {
                 break;
@@ -2359,6 +3178,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @deprecated Use collectNested instead
      * @see #collectNested(Collection, Closure)
      */
+    @Deprecated
     public static List collectAll(Collection self, Closure transform) {
         return collectNested(self, transform);
     }
@@ -2377,7 +3197,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.1
      */
     public static List collectNested(Collection self, Closure transform) {
-        return (List) collectNested(self, new ArrayList(self.size()), transform);
+        return (List) collectNested((Iterable) self, new ArrayList(self.size()), transform);
     }
 
     /**
@@ -2403,6 +3223,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @deprecated Use collectNested instead
      * @see #collectNested(Iterable, Collection, Closure)
      */
+    @Deprecated
     public static Collection collectAll(Collection self, Collection collector, Closure transform) {
         return collectNested((Iterable)self, collector, transform);
     }
@@ -2540,7 +3361,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.8
      */
     public static <T,K,V> Collection<T> collectMany(Map<K, V> self, Collection<T> collector, @ClosureParams(MapEntryOrKeyValue.class) Closure<Collection<? extends T>> projection) {
-        for (Map.Entry<?, ?> entry : self.entrySet()) {
+        for (Map.Entry<K, V> entry : self.entrySet()) {
             collector.addAll(callClosureForMapEntry(projection, entry));
         }
         return collector;
@@ -2574,7 +3395,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert squaresAndCubesOfEvens == [4, 8, 16, 64, 36, 216]
      * </pre>
      *
-     * @param self       an object array
+     * @param self       an array
      * @param projection a projecting Closure returning a collection of items
      * @return a list created from the projected collections concatenated (flattened) together
      * @see #sum(Object[], groovy.lang.Closure)
@@ -2647,6 +3468,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert [a:1, b:2].collectEntries( [30:'C'] ) { key, value ->
      *     [(value*10): key.toUpperCase()] } == [10:'A', 20:'B', 30:'C']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
+     * If your collector Map doesn't support null keys or values, you might get a runtime error, e.g. NullPointerException or IllegalArgumentException.
      *
      * @param self      a Map
      * @param collector the Map into which the transformed entries are put
@@ -2671,6 +3496,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert [a:1, b:2].collectEntries { key, value ->
      *     [(value*10): key.toUpperCase()] } == [10:'A', 20:'B']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
+     * If your Map doesn't support null keys or values, you might get a runtime error, e.g. NullPointerException or IllegalArgumentException.
      *
      * @param self      a Map
      * @param transform the closure used for transforming, which can take one (Map.Entry) or two (key, value) parameters and
@@ -2717,6 +3546,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * // collect letters with index using map style
      * assert (0..2).collectEntries { index -> [(index): letters[index]] } == [0:'a', 1:'b', 2:'c']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
      *
      * @param self      an Iterable
      * @param transform the closure used for transforming, which has an item from self as the parameter and
@@ -2793,7 +3625,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     public static <K, V, E> Map<K, V> collectEntries(Iterator<E> self, Map<K, V> collector, @ClosureParams(FirstParam.FirstGenericType.class) Closure<?> transform) {
         while (self.hasNext()) {
-            Object next = self.next();
+            E next = self.next();
             addEntry(collector, transform.call(next));
         }
         return collector;
@@ -2809,6 +3641,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert (0..2).collectEntries( [4:'d'] ) { index ->
      *     [(index+1): letters[index]] } == [1:'a', 2:'b', 3:'c', 4:'d']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
+     * If your collector Map doesn't support null keys or values, you might get a runtime error, e.g. NullPointerException or IllegalArgumentException.
      *
      * @param self      an Iterable
      * @param collector the Map into which the transformed entries are put
@@ -2871,8 +3707,12 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert nums.collectEntries( [4:'d'] ) { index ->
      *     [(index+1): letters[index]] } == [1:'a', 2:'b', 3:'c', 4:'d']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
+     * If your collector Map doesn't support null keys or values, you might get a runtime error, e.g. NullPointerException or IllegalArgumentException.
      *
-     * @param self      an Object array
+     * @param self      an array
      * @param collector the Map into which the transformed entries are put
      * @param transform the closure used for transforming, which has an item from self as the parameter and
      *                  should return a Map.Entry, a Map or a two-element list containing the resulting key and value
@@ -2888,13 +3728,13 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * A variant of collectEntries using the identity closure as the transform.
      *
-     * @param self      an Object array
+     * @param self      an array
      * @param collector the Map into which the transformed entries are put
      * @return the collector with all transformed values added to it
-     * @see #collectEntries(Object[], Map, Closure)
+     * @see #collectEntries(E[], Map, Closure)
      * @since 1.8.5
      */
-    public static <K, V> Map<K, V> collectEntries(Object[] self, Map<K, V> collector) {
+    public static <K, V, E> Map<K, V> collectEntries(E[] self, Map<K, V> collector) {
         return collectEntries(self, collector, Closure.IDENTITY);
     }
 
@@ -2909,6 +3749,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * // collect letters with index using map style
      * assert nums.collectEntries { index -> [(index): letters[index]] } == [0:'a', 1:'b', 2:'c']
      * </pre>
+     * Note: When using the list-style of result, the behavior is '<code>def (key, value) = listResultFromClosure</code>'.
+     * While we strongly discourage using a list of size other than 2, Groovy's normal semantics apply in this case;
+     * throwing away elements after the second one and using null for the key or value for the case of a shortened list.
      *
      * @param self      a Collection
      * @param transform the closure used for transforming, which has an item from self as the parameter and
@@ -2924,21 +3767,24 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * A variant of collectEntries using the identity closure as the transform.
      *
-     * @param self      an Object array
+     * @param self      an array
      * @return the collector with all transformed values added to it
-     * @see #collectEntries(Object[], Closure)
+     * @see #collectEntries(E[], Closure)
      * @since 1.8.5
      */
-    public static <K, V> Map<K, V> collectEntries(Object[] self) {
+    public static <K, V, E> Map<K, V> collectEntries(E[] self) {
         return collectEntries(self, Closure.IDENTITY);
     }
 
     private static <K, V> void addEntry(Map<K, V> result, Object newEntry) {
         if (newEntry instanceof Map) {
             leftShift(result, (Map)newEntry);
-        } else if (newEntry instanceof List && ((List)newEntry).size() == 2) {
+        } else if (newEntry instanceof List) {
             List list = (List) newEntry;
-            leftShift(result, new MapEntry(list.get(0), list.get(1)));
+            // def (key, value) == list
+            Object key = list.size() == 0 ? null : list.get(0);
+            Object value = list.size() <= 1 ? null : list.get(1);
+            leftShift(result, new MapEntry(key, value));
         } else {
             // TODO: enforce stricter behavior?
             // given Map.Entry is an interface, we get a proxy which gives us lots
@@ -3186,7 +4032,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     public static <T,K,V> Collection<T> findResults(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> filteringTransform) {
         List<T> result = new ArrayList<T>();
-        for (Map.Entry<?, ?> entry : self.entrySet()) {
+        for (Map.Entry<K, V> entry : self.entrySet()) {
             T transformed = callClosureForMapEntry(filteringTransform, entry);
             if (transformed != null) {
                 result.add(transformed);
@@ -3254,7 +4100,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.7.5
      */
     public static <T,K,V> T findResult(Map<K, V> self, @ClosureParams(MapEntryOrKeyValue.class) Closure<T> closure) {
-        for (Map.Entry<?, ?> entry : self.entrySet()) {
+        for (Map.Entry<K, V> entry : self.entrySet()) {
             T result = callClosureForMapEntry(closure, entry);
             if (result != null) {
                 return result;
@@ -3265,6 +4111,32 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
     /**
      * Finds all values matching the closure condition.
+     * <pre class="groovyTestCase">assert ([2,4] as Set) == ([1,2,3,4] as Set).findAll { it % 2 == 0 }</pre>
+     *
+     * @param self    a Set
+     * @param closure a closure condition
+     * @return a Set of matching values
+     * @since 2.4.0
+     */
+    public static <T> Set<T> findAll(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (Set<T>) findAll((Collection<T>) self, closure);
+    }
+
+    /**
+     * Finds all values matching the closure condition.
+     * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
+     *
+     * @param self    a List
+     * @param closure a closure condition
+     * @return a List of matching values
+     * @since 2.4.0
+     */
+    public static <T> List<T> findAll(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<T>) findAll((Collection<T>) self, closure);
+    }
+
+    /**
+     * Finds all values matching the closure condition.
      * <pre class="groovyTestCase">assert [2,4] == [1,2,3,4].findAll { it % 2 == 0 }</pre>
      *
      * @param self    a Collection
@@ -3300,16 +4172,52 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * <p>
      * Example:
      * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null] as Set
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]] as Set
+     * </pre>
+     *
+     * @param self    a Set
+     * @return a Set of the values found
+     * @since 2.4.0
+     * @see Closure#IDENTITY
+     */
+    public static <T> Set<T> findAll(Set<T> self) {
+        return findAll(self, Closure.IDENTITY);
+    }
+
+    /**
+     * Finds the items matching the IDENTITY Closure (i.e. matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
      * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
      * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
      * </pre>
      *
-     * @param self    a Collection
+     * @param self    a List
      * @return a List of the values found
+     * @since 2.4.0
+     * @see Closure#IDENTITY
+     */
+    public static <T> List<T> findAll(List<T> self) {
+        return findAll(self, Closure.IDENTITY);
+    }
+
+    /**
+     * Finds the items matching the IDENTITY Closure (i.e. matching Groovy truth).
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 0, false, true, '', 'foo', [], [4, 5], null]
+     * assert items.findAll() == [1, 2, true, 'foo', [4, 5]]
+     * </pre>
+     *
+     * @param self    a Collection
+     * @return a Collection of the values found
      * @since 1.8.1
      * @see Closure#IDENTITY
      */
-    public static <T> Collection<T>  findAll(Collection<T> self) {
+    public static <T> Collection<T> findAll(Collection<T> self) {
         return findAll(self, Closure.IDENTITY);
     }
 
@@ -3375,16 +4283,44 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Returns <tt>true</tt> if this collection contains all of the elements
+     * Returns <tt>true</tt> if this iterable contains the item.
+     *
+     * @param  self an Iterable to be checked for containment
+     * @param  item an Object to be checked for containment in this iterable
+     * @return <tt>true</tt> if this iterable contains the item
+     * @see    Collection#contains(Object)
+     * @since 2.4.0
+     */
+    public static boolean contains(Iterable self, Object item) {
+        for (Object e : self) {
+            if (item == null ? e == null : item.equals(e)) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    /**
+     * Returns <tt>true</tt> if this iterable contains all of the elements
      * in the specified array.
      *
-     * @param  self  a Collection to be checked for containment
-     * @param  items array to be checked for containment in this collection
+     * @param  self  an Iterable to be checked for containment
+     * @param  items array to be checked for containment in this iterable
      * @return <tt>true</tt> if this collection contains all of the elements
      *           in the specified array
      * @see    Collection#containsAll(Collection)
+     * @since 2.4.0
+     */
+    public static boolean containsAll(Iterable self, Object[] items) {
+        return asCollection(self).containsAll(Arrays.asList(items));
+    }
+
+    /**
+     * @deprecated use the Iterable variant instead
+     * @see #containsAll(Iterable, Object[])
      * @since 1.7.2
      */
+    @Deprecated
     public static boolean containsAll(Collection self, Object[] items) {
         return self.containsAll(Arrays.asList(items));
     }
@@ -3578,6 +4514,42 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Splits all items into two collections based on the closure condition.
+     * The first list contains all items which match the closure expression.
+     * The second list all those that don't.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">assert [[2,4],[1,3]] == [1,2,3,4].split { it % 2 == 0 }</pre>
+     *
+     * @param self    a List of values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 2.4.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List<List<T>> split(List<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<List<T>>) (List<?>) split((Collection<T>) self, closure);
+    }
+
+    /**
+     * Splits all items into two collections based on the closure condition.
+     * The first list contains all items which match the closure expression.
+     * The second list all those that don't.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">assert [[2,4] as Set, [1,3] as Set] == ([1,2,3,4] as Set).split { it % 2 == 0 }</pre>
+     *
+     * @param self    a Set of values
+     * @param closure a closure condition
+     * @return a List whose first item is the accepted values and whose second item is the rejected values
+     * @since 2.4.0
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> List<Set<T>> split(Set<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
+        return (List<Set<T>>) (List<?>) split((Collection<T>) self, closure);
+    }
+
+    /**
      * @deprecated Use the Iterable version of combinations instead
      * @see #combinations(Iterable)
      * @since 1.5.0
@@ -3652,17 +4624,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Finds all permutations of a collection.
+     * Finds all permutations of an iterable.
      * <p>
      * Example usage:
      * <pre class="groovyTestCase">def result = [1, 2, 3].permutations()
      * assert result == [[3, 2, 1], [3, 1, 2], [1, 3, 2], [2, 3, 1], [2, 1, 3], [1, 2, 3]] as Set</pre>
      *
-     * @param self the Collection of items
+     * @param self the Iterable of items
      * @return the permutations from the list
      * @since 1.7.0
      */
-    public static <T> Set<List<T>> permutations(List<T> self) {
+    public static <T> Set<List<T>> permutations(Iterable<T> self) {
         Set<List<T>> ans = new HashSet<List<T>>();
         PermutationGenerator<T> generator = new PermutationGenerator<T>(self);
         while (generator.hasNext()) {
@@ -3672,29 +4644,58 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Finds all permutations of a collection, applies a function to each permutation and collects the result
+     * @deprecated Use the Iterable version of permutations instead
+     * @see #permutations(Iterable)
+     * @since 1.7.0
+     */
+    @Deprecated
+    public static <T> Set<List<T>> permutations(List<T> self) {
+        return permutations((Iterable<T>) self);
+    }
+
+    /**
+     * Finds all permutations of an iterable, applies a function to each permutation and collects the result
      * into a list.
      * <p>
      * Example usage:
      * <pre class="groovyTestCase">Set result = [1, 2, 3].permutations { it.collect { v -> 2*v }}
      * assert result == [[6, 4, 2], [6, 2, 4], [2, 6, 4], [4, 6, 2], [4, 2, 6], [2, 4, 6]] as Set</pre>
      *
-     * @param self the Collection of items
+     * @param self the Iterable of items
      * @param function the function to apply on each permutation
      * @return the list of results of the application of the function on each permutation
      * @since 2.2.0
      */
-    public static <T,V> List<V> permutations(List<T> self, Closure<V> function) {
+    public static <T,V> List<V> permutations(Iterable<T> self, Closure<V> function) {
         return collect(permutations(self),function);
     }
 
+    /**
+     * @deprecated Use the Iterable version of permutations instead
+     * @see #permutations(Iterable, Closure)
+     * @since 2.2.0
+     */
+    @Deprecated
+    public static <T, V> List<V> permutations(List<T> self, Closure<V> function) {
+        return permutations((Iterable<T>) self, function);
+    }
+
+    /**
+     * @deprecated Use the Iterable version of eachPermutation instead
+     * @see #eachPermutation(Iterable, Closure)
+     * @since 1.7.0
+     */
+    @Deprecated
+    public static <T> Iterator<List<T>> eachPermutation(Collection<T> self, Closure closure) {
+        return eachPermutation((Iterable<T>) self, closure);
+    }
 
     /**
      * Iterates over all permutations of a collection, running a closure for each iteration.
      * <p>
      * Example usage:
      * <pre class="groovyTestCase">def permutations = []
-     * [1, 2, 3].eachPermutation{ permutations << it }
+     * [1, 2, 3].eachPermutation{ permutations << it }
      * assert permutations == [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]]</pre>
      *
      * @param self the Collection of items
@@ -3702,7 +4703,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @return the permutations from the list
      * @since 1.7.0
      */
-    public static <T> Iterator<List<T>> eachPermutation(Collection<T> self, Closure closure) {
+    public static <T> Iterator<List<T>> eachPermutation(Iterable<T> self, Closure closure) {
         Iterator<List<T>> generator = new PermutationGenerator<T>(self);
         while (generator.hasNext()) {
             closure.call(generator.next());
@@ -3876,7 +4877,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         // inject([:]) { a,e -> a << [(e.key): e.value.groupBy(tail)] }
         Map<Object, Map> acc = new LinkedHashMap<Object, Map>();
         for (Map.Entry<Object, List> item : first.entrySet()) {
-            acc.put(item.getKey(), groupBy(item.getValue(), tail));
+            acc.put(item.getKey(), groupBy((Iterable)item.getValue(), tail));
         }
 
         return acc;
@@ -3898,35 +4899,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Sorts all collection members into (sub)groups determined by the supplied
-     * mapping closures. Each closure should return the key that this item
-     * should be grouped by. The returned LinkedHashMap will have an entry for each
-     * distinct 'key path' returned from the closures, with each value being a list
-     * of items for that 'group path'.
-     *
-     * Example usage:
-     * <pre class="groovyTestCase">def result = [1,2,3,4,5,6].groupBy([{ it % 2 }, { it < 4 }])
-     * assert result == [1:[(true):[1, 3], (false):[5]], 0:[(true):[2], (false):[4, 6]]]</pre>
-     *
-     * Another example:
-     * <pre>def sql = groovy.sql.Sql.newInstance(/* ... */)
-     * def data = sql.rows("SELECT * FROM a_table").groupBy([{ it.column1 }, { it.column2 }, { it.column3 }])
-     * if (data.val1.val2.val3) {
-     *     // there exists a record where:
-     *     //   a_table.column1 == val1
-     *     //   a_table.column2 == val2, and
-     *     //   a_table.column3 == val3
-     * } else {
-     *     // there is no such record
-     * }</pre>
-     * If an empty list of closures is supplied the IDENTITY Closure will be used.
-     *
-     * @param self     a collection to group
-     * @param closures a list of closures, each mapping entries on keys
-     * @return a new Map grouped by keys on each criterion
+     * @deprecated Use the Iterable version of groupBy instead
+     * @see #groupBy(Iterable, List)
      * @since 1.8.1
-     * @see Closure#IDENTITY
      */
+    @Deprecated
     public static Map groupBy(Collection self, List<Closure> closures) {
         return groupBy((Iterable)self, closures);
     }
@@ -4023,7 +5000,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Example usage:
      * <pre class="groovyTestCase">assert ([1,2,2,2,3] as Object[]).countBy{ it % 2 } == [1:2, 0:3]</pre>
      *
-     * @param self    an object array to group and count
+     * @param self    an array to group and count
      * @param closure a closure mapping items to the frequency keys
      * @return a new Map grouped by keys with frequency counts
      * @see #countBy(Collection, Closure)
@@ -4289,11 +5266,14 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if( self.isEmpty() ) {
             throw new NoSuchElementException( "Cannot call inject() on an empty collection without passing an initial value." ) ;
         }
-        List<T> list = asList( self ) ;
-        if( list.size() == 1 ) {
-            return list.get( 0 ) ;
+        Iterator<T> iter = self.iterator();
+        T head = iter.next();
+        Collection<T> tail = tail(self);
+        if (!tail.iterator().hasNext()) {
+            return head;
         }
-        return (T) inject( drop( list, 1 ), head( list ), closure );
+        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
+        return (T) inject((Collection) tail, head, closure);
     }
 
     /**
@@ -4337,7 +5317,8 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static <E, T, U extends T, V extends T> T inject(Collection<E> self, U initialValue, @ClosureParams(value=FromString.class,options="U,E") Closure<V> closure) {
-        return (T) inject(self.iterator(), initialValue, closure);
+        // cast with explicit weaker generics for now to keep jdk6 happy, TODO: find better fix
+        return (T) inject((Iterator) self.iterator(), initialValue, closure);
     }
 
     /**
@@ -4362,9 +5343,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @return the result of the last closure call
      * @since 1.8.1
      */
-    public static <Key,Value, T, U extends T, V extends T> T inject(Map<Key, Value> self, U initialValue, @ClosureParams(value=FromString.class,options={"U,Map.Entry<Key,Value>","U,Key,Value"})  Closure<V> closure) {
+    public static <K, V, T, U extends T, W extends T> T inject(Map<K, V> self, U initialValue, @ClosureParams(value=FromString.class,options={"U,Map.Entry<K,V>","U,K,V"})  Closure<W> closure) {
         T value = initialValue;
-        for (Map.Entry<?, ?> entry : self.entrySet()) {
+        for (Map.Entry<K, V> entry : self.entrySet()) {
             if (closure.getMaximumNumberOfParameters() == 3) {
                 value = closure.call(value, entry.getKey(), entry.getValue());
             } else {
@@ -4525,12 +5506,96 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * "plus" method on all items from the Iterator. The iterator will become
      * exhausted of elements after determining the sum value.
      *
-     * @param self an Iterator for the values to add together
+     * @param self an Iterator for the values to add together
+     * @return The sum of all of the items
+     * @since 1.5.5
+     */
+    public static Object sum(Iterator<Object> self) {
+        return sum(toList(self), null, true);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as byte) == ([1,2,3,4] as byte[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static byte sum(byte[] self) {
+        return sum(self, (byte) 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as short) == ([1,2,3,4] as short[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static short sum(short[] self) {
+        return sum(self, (short) 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert 1+2+3+4 == ([1,2,3,4] as int[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static int sum(int[] self) {
+        return sum(self, 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as long) == ([1,2,3,4] as long[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static long sum(long[] self) {
+        return sum(self, (long) 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as char) == ([1,2,3,4] as char[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static char sum(char[] self) {
+        return sum(self, (char) 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as float) == ([1,2,3,4] as float[]).sum()</pre>
+     *
+     * @param self The array of values to add together
+     * @return The sum of all of the items
+     * @since 2.4.2
+     */
+    public static float sum(float[] self) {
+        return sum(self, (float) 0);
+    }
+
+    /**
+     * Sums the items in an array.
+     * <pre class="groovyTestCase">assert (1+2+3+4 as double) == ([1,2,3,4] as double[]).sum()</pre>
+     *
+     * @param self The array of values to add together
      * @return The sum of all of the items
-     * @since 1.5.5
+     * @since 2.4.2
      */
-    public static Object sum(Iterator<Object> self) {
-        return sum(toList(self), null, true);
+    public static double sum(double[] self) {
+        return sum(self, (double) 0);
     }
 
     /**
@@ -4601,6 +5666,125 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as byte) == ([1,2,3,4] as byte[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static byte sum(byte[] self, byte initialValue) {
+        byte s = initialValue;
+        for (byte v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as short) == ([1,2,3,4] as short[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static short sum(short[] self, short initialValue) {
+        short s = initialValue;
+        for (short v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert 5+1+2+3+4 == ([1,2,3,4] as int[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static int sum(int[] self, int initialValue) {
+        int s = initialValue;
+        for (int v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as long) == ([1,2,3,4] as long[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static long sum(long[] self, long initialValue) {
+        long s = initialValue;
+        for (long v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as char) == ([1,2,3,4] as char[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static char sum(char[] self, char initialValue) {
+        char s = initialValue;
+        for (char v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as float) == ([1,2,3,4] as float[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static float sum(float[] self, float initialValue) {
+        float s = initialValue;
+        for (float v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
+     * Sums the items in an array, adding the result to some initial value.
+     * <pre class="groovyTestCase">assert (5+1+2+3+4 as double) == ([1,2,3,4] as double[]).sum(5)</pre>
+     *
+     * @param self         an array of values to sum
+     * @param initialValue the items in the array will be summed to this initial value
+     * @return The sum of all of the items.
+     * @since 2.4.2
+     */
+    public static double sum(double[] self, double initialValue) {
+        double s = initialValue;
+        for (double v : self) {
+            s += v;
+        }
+        return s;
+    }
+
+    /**
      * @deprecated Use the Iterable version of sum instead
      * @see #sum(Iterable, Closure)
      * @since 1.0
@@ -4614,7 +5798,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Sums the result of apply a closure to each item of an Iterable.
      * <code>coll.sum(closure)</code> is equivalent to:
      * <code>coll.collect(closure).sum()</code>.
-     * <pre class="groovyTestCase">assert 4+6+10+12 == [2,3,5,6].sum() { it * 2 }</pre>
+     * <pre class="groovyTestCase">assert 4+6+10+12 == [2,3,5,6].sum { it * 2 }</pre>
      *
      * @param self    an Iterable
      * @param closure a single parameter closure that returns a numeric value.
@@ -4701,116 +5885,332 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Sums the result of applying a closure to each item of an Iterator to some initial value.
-     * <code>iter.sum(initVal, closure)</code> is equivalent to:
-     * <code>iter.collect(closure).sum(initVal)</code>. The iterator will become
-     * exhausted of elements after determining the sum value.
+     * Sums the result of applying a closure to each item of an Iterator to some initial value.
+     * <code>iter.sum(initVal, closure)</code> is equivalent to:
+     * <code>iter.collect(closure).sum(initVal)</code>. The iterator will become
+     * exhausted of elements after determining the sum value.
+     *
+     * @param self         an Iterator
+     * @param closure      a single parameter closure that returns a numeric value.
+     * @param initialValue the closure results will be summed to this initial value
+     * @return The sum of the values returned by applying the closure to each
+     *         item from the Iterator.
+     * @since 1.7.1
+     */
+    public static Object sum(Iterator<Object> self, Object initialValue, Closure closure) {
+        return sum(toList(self), initialValue, closure, false);
+    }
+
+    private static Object sum(Iterable self, Object initialValue, Closure closure, boolean first) {
+        Object result = initialValue;
+        Object[] closureParam = new Object[1];
+        Object[] plusParam = new Object[1];
+        for (Object next : self) {
+            closureParam[0] = next;
+            plusParam[0] = closure.call(closureParam);
+            if (first) {
+                result = plusParam[0];
+                first = false;
+                continue;
+            }
+            MetaClass metaClass = InvokerHelper.getMetaClass(result);
+            result = metaClass.invokeMethod(result, "plus", plusParam);
+        }
+        return result;
+    }
+
+    /**
+     * Concatenates the <code>toString()</code> representation of each
+     * item from the iterator, with the given String as a separator between
+     * each item. The iterator will become exhausted of elements after
+     * determining the resulting conjoined value.
+     *
+     * @param self      an Iterator of items
+     * @param separator a String separator
+     * @return the joined String
+     * @since 1.5.5
+     */
+    public static String join(Iterator<Object> self, String separator) {
+        return join((Iterable)toList(self), separator);
+    }
+
+    /**
+     * @deprecated Use the Iterable version of join instead
+     * @see #join(Iterable, String)
+     * @since 1.0
+     */
+    @Deprecated
+    public static String join(Collection self, String separator) {
+        return join((Iterable)self, separator);
+    }
+
+    /**
+     * Concatenates the <code>toString()</code> representation of each
+     * item in this Iterable, with the given String as a separator between each item.
+     * <pre class="groovyTestCase">assert "1, 2, 3" == [1,2,3].join(", ")</pre>
+     *
+     * @param self      an Iterable of objects
+     * @param separator a String separator
+     * @return the joined String
+     * @since 1.0
+     */
+    public static String join(Iterable self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (Object value : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(InvokerHelper.toString(value));
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates the <code>toString()</code> representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
+     *
+     * @param self      an array of Object
+     * @param separator a String separator
+     * @return the joined String
+     * @since 1.0
+     */
+    public static String join(Object[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (Object next : self) {
+            String value = InvokerHelper.toString(next);
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(value);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
+     *
+     * @param self      an array of boolean
+     * @param separator a String separator
+     * @return the joined String
+     * @since 2.4.1
+     */
+    public static String join(boolean[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (boolean next : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(next);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
+     *
+     * @param self      an array of byte
+     * @param separator a String separator
+     * @return the joined String
+     * @since 2.4.1
+     */
+    public static String join(byte[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (byte next : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(next);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
+     *
+     * @param self      an array of char
+     * @param separator a String separator
+     * @return the joined String
+     * @since 2.4.1
+     */
+    public static String join(char[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (char next : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(next);
+        }
+        return buffer.toString();
+    }
+
+    /**
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
      *
-     * @param self         an Iterator
-     * @param closure      a single parameter closure that returns a numeric value.
-     * @param initialValue the closure results will be summed to this initial value
-     * @return The sum of the values returned by applying the closure to each
-     *         item from the Iterator.
-     * @since 1.7.1
+     * @param self      an array of double
+     * @param separator a String separator
+     * @return the joined String
+     * @since 2.4.1
      */
-    public static Object sum(Iterator<Object> self, Object initialValue, Closure closure) {
-        return sum(toList(self), initialValue, closure, false);
-    }
+    public static String join(double[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
 
-    private static Object sum(Iterable self, Object initialValue, Closure closure, boolean first) {
-        Object result = initialValue;
-        Object[] closureParam = new Object[1];
-        Object[] plusParam = new Object[1];
-        for (Object next : self) {
-            closureParam[0] = next;
-            plusParam[0] = closure.call(closureParam);
+        if (separator == null) separator = "";
+
+        for (double next : self) {
             if (first) {
-                result = plusParam[0];
                 first = false;
-                continue;
+            } else {
+                buffer.append(separator);
             }
-            MetaClass metaClass = InvokerHelper.getMetaClass(result);
-            result = metaClass.invokeMethod(result, "plus", plusParam);
+            buffer.append(next);
         }
-        return result;
+        return buffer.toString();
     }
 
     /**
-     * Concatenates the <code>toString()</code> representation of each
-     * item from the iterator, with the given String as a separator between
-     * each item. The iterator will become exhausted of elements after
-     * determining the resulting conjoined value.
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
      *
-     * @param self      an Iterator of items
+     * @param self      an array of float
      * @param separator a String separator
      * @return the joined String
-     * @since 1.5.5
+     * @since 2.4.1
      */
-    public static String join(Iterator<Object> self, String separator) {
-        return join(toList(self), separator);
+    public static String join(float[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (float next : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(next);
+        }
+        return buffer.toString();
     }
 
     /**
-     * @deprecated Use the Iterable version of join instead
-     * @see #join(Iterable, String)
-     * @since 1.0
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
+     *
+     * @param self      an array of int
+     * @param separator a String separator
+     * @return the joined String
+     * @since 2.4.1
      */
-    @Deprecated
-    public static String join(Collection self, String separator) {
-        return join((Iterable)self, separator);
+    public static String join(int[] self, String separator) {
+        StringBuilder buffer = new StringBuilder();
+        boolean first = true;
+
+        if (separator == null) separator = "";
+
+        for (int next : self) {
+            if (first) {
+                first = false;
+            } else {
+                buffer.append(separator);
+            }
+            buffer.append(next);
+        }
+        return buffer.toString();
     }
 
     /**
-     * Concatenates the <code>toString()</code> representation of each
-     * item in this Iterable, with the given String as a separator between each item.
-     * <pre class="groovyTestCase">assert "1, 2, 3" == [1,2,3].join(", ")</pre>
+     * Concatenates the string representation of each
+     * items in this array, with the given String as a separator between each
+     * item.
      *
-     * @param self      an Iterable of objects
+     * @param self      an array of long
      * @param separator a String separator
      * @return the joined String
-     * @since 1.0
+     * @since 2.4.1
      */
-    public static String join(Iterable self, String separator) {
+    public static String join(long[] self, String separator) {
         StringBuilder buffer = new StringBuilder();
         boolean first = true;
 
         if (separator == null) separator = "";
 
-        for (Object value : self) {
+        for (long next : self) {
             if (first) {
                 first = false;
             } else {
                 buffer.append(separator);
             }
-            buffer.append(InvokerHelper.toString(value));
+            buffer.append(next);
         }
         return buffer.toString();
     }
 
     /**
-     * Concatenates the <code>toString()</code> representation of each
+     * Concatenates the string representation of each
      * items in this array, with the given String as a separator between each
      * item.
      *
-     * @param self      an array of Object
+     * @param self      an array of short
      * @param separator a String separator
      * @return the joined String
-     * @since 1.0
+     * @since 2.4.1
      */
-    public static String join(Object[] self, String separator) {
+    public static String join(short[] self, String separator) {
         StringBuilder buffer = new StringBuilder();
         boolean first = true;
 
         if (separator == null) separator = "";
 
-        for (Object next : self) {
-            String value = InvokerHelper.toString(next);
+        for (short next : self) {
             if (first) {
                 first = false;
             } else {
                 buffer.append(separator);
             }
-            buffer.append(value);
+            buffer.append(next);
         }
         return buffer.toString();
     }
@@ -4848,19 +6248,19 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> T min(Iterator<T> self) {
-        return min(toList(self));
+        return min((Iterable<T>)toList(self));
     }
 
     /**
      * Adds min() method to Object arrays.
      *
-     * @param self an Object array
+     * @param self an array
      * @return the minimum value
      * @see #min(java.util.Collection)
      * @since 1.5.5
      */
     public static <T> T min(T[] self) {
-        return min(toList(self));
+        return min((Iterable<T>)toList(self));
     }
 
     /**
@@ -4879,13 +6279,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self       an Iterable
      * @param comparator a Comparator
-     * @return the minimum value
+     * @return the minimum value or null for an empty Iterable
      * @since 2.2.0
      */
     public static <T> T min(Iterable<T> self, Comparator<T> comparator) {
         T answer = null;
+        boolean first = true;
         for (T value : self) {
-            if (answer == null || comparator.compare(value, answer) < 0) {
+            if (first) {
+                first = false;
+                answer = value;
+            } else if (comparator.compare(value, answer) < 0) {
                 answer = value;
             }
         }
@@ -4902,20 +6306,20 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> T min(Iterator<T> self, Comparator<T> comparator) {
-        return min(toList(self), comparator);
+        return min((Iterable<T>)toList(self), comparator);
     }
 
     /**
      * Selects the minimum value found from the Object array using the given comparator.
      *
-     * @param self       an Object array
+     * @param self       an array
      * @param comparator a Comparator
      * @return the minimum value
      * @see #min(java.util.Collection, java.util.Comparator)
      * @since 1.5.5
      */
     public static <T> T min(T[] self, Comparator<T> comparator) {
-        return min(toList(self), comparator);
+        return min((Iterable<T>)toList(self), comparator);
     }
 
     /**
@@ -4929,10 +6333,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Selects an item in the collection having the minimum
-     * value as determined by the supplied closure.
-     * If more than one item has the minimum value,
-     * an arbitrary choice is made between the items having the minimum value.
+     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
+     * minimum value. A null return value represents the least possible return value. If more than one item
+     * has the minimum value, an arbitrary choice is made between the items having the minimum value.
      * <p>
      * If the closure has two parameters
      * it is used like a traditional Comparator. I.e. it should compare
@@ -4957,7 +6360,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self    an Iterable
      * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return the minimum value
+     * @return an item from the Iterable having the minimum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
      * @since 1.0
      */
     public static <T> T min(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
@@ -4965,13 +6368,18 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if (params != 1) {
             return min(self, new ClosureComparator<T>(closure));
         }
+        boolean first = true;
         T answer = null;
-        Object answer_value = null;
+        Object answerValue = null;
         for (T item : self) {
             Object value = closure.call(item);
-            if (answer == null || ScriptBytecodeAdapter.compareLessThan(value, answer_value)) {
+            if (first) {
+                first = false;
+                answer = item;
+                answerValue = value;
+            } else if (ScriptBytecodeAdapter.compareLessThan(value, answerValue)) {
                 answer = item;
-                answer_value = value;
+                answerValue = value;
             }
         }
         return answer;
@@ -5012,7 +6420,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.7.6
      */
     public static <K, V> Map.Entry<K, V> min(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>", "Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
-        return min(self.entrySet(), closure);
+        return min((Iterable<Map.Entry<K, V>>)self.entrySet(), closure);
     }
 
     /**
@@ -5091,7 +6499,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Comparable (typically an Integer) which is then used for
      * further comparison.
      *
-     * @param self    an Object array
+     * @param self    an array
      * @param closure a Closure used to determine the correct ordering
      * @return the minimum value
      * @see #min(java.util.Collection, groovy.lang.Closure)
@@ -5142,7 +6550,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Adds max() method to Object arrays.
      *
-     * @param self an Object array
+     * @param self an array
      * @return the maximum value
      * @see #max(java.util.Collection)
      * @since 1.5.5
@@ -5162,10 +6570,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Selects an item in the collection having the maximum
-     * value as determined by the supplied closure.
-     * If more than one item has the maximum value,
-     * an arbitrary choice is made between the items having the maximum value.
+     * Selects the item in the iterable which when passed as a parameter to the supplied closure returns the
+     * maximum value. A null return value represents the least possible return value, so any item for which
+     * the supplied closure returns null, won't be selected (unless all items return null). If more than one item
+     * has the maximum value, an arbitrary choice is made between the items having the maximum value.
      * <p>
      * If the closure has two parameters
      * it is used like a traditional Comparator. I.e. it should compare
@@ -5185,7 +6593,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self    an Iterable
      * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return the maximum value
+     * @return an item from the Iterable having the maximum value returned by calling the supplied closure with that item as parameter or null for an empty Iterable
      * @since 2.2.0
      */
     public static <T> T max(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure closure) {
@@ -5193,11 +6601,16 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         if (params != 1) {
             return max(self, new ClosureComparator<T>(closure));
         }
+        boolean first = true;
         T answer = null;
         Object answerValue = null;
         for (T item : self) {
             Object value = closure.call(item);
-            if (answer == null || ScriptBytecodeAdapter.compareLessThan(answerValue, value)) {
+            if (first) {
+                first = false;
+                answer = item;
+                answerValue = value;
+            } else if (ScriptBytecodeAdapter.compareLessThan(answerValue, value)) {
                 answer = item;
                 answerValue = value;
             }
@@ -5242,7 +6655,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Comparable (typically an Integer) which is then used for
      * further comparison.
      *
-     * @param self    an Object array
+     * @param self    an array
      * @param closure a Closure used to determine the correct ordering
      * @return the maximum value
      * @see #max(java.util.Collection, groovy.lang.Closure)
@@ -5270,13 +6683,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self       an Iterable
      * @param comparator a Comparator
-     * @return the maximum value
+     * @return the maximum value or null for an empty Iterable
      * @since 2.2.0
      */
     public static <T> T max(Iterable<T> self, Comparator<T> comparator) {
         T answer = null;
+        boolean first = true;
         for (T value : self) {
-            if (answer == null || comparator.compare(value, answer) > 0) {
+            if (first) {
+                first = false;
+                answer = value;
+            } else if (comparator.compare(value, answer) > 0) {
                 answer = value;
             }
         }
@@ -5298,7 +6715,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Selects the maximum value found from the Object array using the given comparator.
      *
-     * @param self       an Object array
+     * @param self       an array
      * @param comparator a Comparator
      * @return the maximum value
      * @since 1.5.5
@@ -5308,6 +6725,39 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Returns indices of the collection.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert 0..2 == [5, 6, 7].indices
+     * </pre>
+     *
+     * @param self a collection
+     * @return an index range
+     * @since 2.4.0
+     */
+    public static IntRange getIndices(Collection self) {
+        return new IntRange(false, 0, self.size());
+    }
+
+    /**
+     * Returns indices of the array.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * String[] letters = ['a', 'b', 'c', 'd']
+     * assert 0..<4 == letters.indices
+     * </pre>
+     *
+     * @param self an array
+     * @return an index range
+     * @since 2.4.0
+     */
+    public static <T> IntRange getIndices(T[] self) {
+        return new IntRange(false, 0, self.length);
+    }
+
+    /**
      * Provide the standard Groovy <code>size()</code> method for <code>Iterator</code>.
      * The iterator will become exhausted of elements after determining the size value.
      *
@@ -5325,6 +6775,22 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Provide the standard Groovy <code>size()</code> method for <code>Iterable</code>.
+     * <pre class="groovyTestCase">
+     * def items = [1, 2, 3]
+     * def iterable = { [ hasNext:{ !items.isEmpty() }, next:{ items.pop() } ] as Iterator } as Iterable
+     * assert iterable.size() == 3
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return the length of the Iterable
+     * @since 2.3.8
+     */
+    public static int size(Iterable self) {
+        return size(self.iterator());
+    }
+
+    /**
      * Provide the standard Groovy <code>size()</code> method for an array.
      *
      * @param self an Array of objects
@@ -5471,10 +6937,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Select a List of items from an Object array using a Collection to
+     * Select a List of items from an array using a Collection to
      * identify the indices to be selected.
      *
-     * @param self    an Array of Objects
+     * @param self    an array
      * @param indices a Collection of indices
      * @return a new list of the values at the given indices
      * @since 1.0
@@ -5507,7 +6973,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     public static <K, V> Map<K, V> subMap(Map<K, V> map, Collection<K> keys) {
         Map<K, V> answer = new LinkedHashMap<K, V>(keys.size());
         for (K key : keys) {
-            answer.put(key, map.get(key));
+            if (map.containsKey(key)) {
+                answer.put(key, map.get(key));
+            }
         }
         return answer;
     }
@@ -5531,7 +6999,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     public static <K, V> Map<K, V> subMap(Map<K, V> map, K[] keys) {
         Map<K, V> answer = new LinkedHashMap<K, V>(keys.length);
         for (K key : keys) {
-            answer.put(key, map.get(key));
+            if (map.containsKey(key)) {
+                answer.put(key, map.get(key));
+            }
         }
         return answer;
     }
@@ -5541,7 +7011,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * there is no entry for the given key in which case add the default value
      * to the map and return that.
      * <pre class="groovyTestCase">def map=[:]
-     * map.get("a", []) << 5
+     * map.get("a", []) << 5
      * assert map == [a:[5]]</pre>
      *
      * @param map          a Map
@@ -5891,8 +7361,8 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         }
     }
 
-    // helper method for putAt(Splice)
     // todo: remove after putAt(Splice) gets deleted
+    @Deprecated
     protected static List getSubList(List self, List splice) {
         int left /* = 0 */;
         int right = 0;
@@ -6073,9 +7543,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * A convenience method for creating an immutable Collection.
      * <pre class="groovyTestCase">def mutable = [1,2,3]
      * def immutable = mutable.asImmutable()
-     * mutable << 4
+     * mutable << 4
      * try {
-     *   immutable << 4
+     *   immutable << 4
      *   assert false
      * } catch (UnsupportedOperationException) {
      *   assert true
@@ -6237,6 +7707,22 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Creates a spreadable map from this iterable.
+     * <p>
+     * @param self an iterable
+     * @return a newly created SpreadMap
+     * @see groovy.lang.SpreadMap#SpreadMap(java.util.List)
+     * @see #toSpreadMap(java.util.Map)
+     * @since 2.4.0
+     */
+    public static SpreadMap toSpreadMap(Iterable self) {
+        if (self == null)
+            throw new GroovyRuntimeException("Fail to convert Iterable to SpreadMap, because it is null.");
+        else
+            return toSpreadMap(asList(self));
+    }
+
+    /**
      * Wraps a map using the decorator pattern with a wrapper that intercepts all calls
      * to <code>get(key)</code>. If an unknown key is found, a default value will be
      * stored into the Map before being returned. The default value stored will be the
@@ -6363,13 +7849,213 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Zips an Iterable with indices in (value, index) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [["a", 0], ["b", 1]] == ["a", "b"].withIndex()
+     * assert ["0: a", "1: b"] == ["a", "b"].withIndex().collect { str, idx -> "$idx: $str" }
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a zipped list with indices
+     * @see #indexed(Iterable)
+     * @since 2.4.0
+     */
+    public static <E> List<Tuple2<E, Integer>> withIndex(Iterable<E> self) {
+        return withIndex(self, 0);
+    }
+
+    /**
+     * Zips an Iterable with indices in (index, value) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [0: "a", 1: "b"] == ["a", "b"].indexed()
+     * assert ["0: a", "1: b"] == ["a", "b"].indexed().collect { idx, str -> "$idx: $str" }
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a zipped map with indices
+     * @see #withIndex(Iterable)
+     * @since 2.4.0
+     */
+    public static <E> Map<Integer, E> indexed(Iterable<E> self) {
+        return indexed(self, 0);
+    }
+
+    /**
+     * Zips an Iterable with indices in (value, index) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [["a", 5], ["b", 6]] == ["a", "b"].withIndex(5)
+     * assert ["1: a", "2: b"] == ["a", "b"].withIndex(1).collect { str, idx -> "$idx: $str" }
+     * </pre>
+     *
+     * @param self   an Iterable
+     * @param offset an index to start from
+     * @return a zipped list with indices
+     * @see #indexed(Iterable, int)
+     * @since 2.4.0
+     */
+    public static <E> List<Tuple2<E, Integer>> withIndex(Iterable<E> self, int offset) {
+        return toList(withIndex(self.iterator(), offset));
+    }
+
+    /**
+     * Zips an Iterable with indices in (index, value) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [5: "a", 6: "b"] == ["a", "b"].indexed(5)
+     * assert ["1: a", "2: b"] == ["a", "b"].indexed(1).collect { idx, str -> "$idx: $str" }
+     * </pre>
+     *
+     * @param self   an Iterable
+     * @param offset an index to start from
+     * @return a Map (since the keys/indices are unique) containing the elements from the iterable zipped with indices
+     * @see #withIndex(Iterable, int)
+     * @since 2.4.0
+     */
+    public static <E> Map<Integer, E> indexed(Iterable<E> self, int offset) {
+        LinkedHashMap<Integer, E> result = new LinkedHashMap<Integer, E>();
+        Iterator<Tuple2<Integer, E>> indexed = indexed(self.iterator(), offset);
+        while (indexed.hasNext()) {
+            Tuple2<Integer, E> next = indexed.next();
+            result.put(next.getFirst(), next.getSecond());
+        }
+        return result;
+    }
+
+    /**
+     * Zips an iterator with indices in (value, index) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [["a", 0], ["b", 1]] == ["a", "b"].iterator().withIndex().toList()
+     * assert ["0: a", "1: b"] == ["a", "b"].iterator().withIndex().collect { str, idx -> "$idx: $str" }.toList()
+     * </pre>
+     *
+     * @param self an iterator
+     * @return a zipped iterator with indices
+     * @see #indexed(Iterator)
+     * @since 2.4.0
+     */
+    public static <E> Iterator<Tuple2<E, Integer>> withIndex(Iterator<E> self) {
+        return withIndex(self, 0);
+    }
+
+    /**
+     * Zips an iterator with indices in (index, value) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [[0, "a"], [1, "b"]] == ["a", "b"].iterator().indexed().collect{ e -> [e.key, e.value] }
+     * assert ["0: a", "1: b"] == ["a", "b"].iterator().indexed().collect { idx, str -> "$idx: $str" }.toList()
+     * </pre>
+     *
+     * @param self an iterator
+     * @return a zipped iterator with indices
+     * @see #withIndex(Iterator)
+     * @since 2.4.0
+     */
+    public static <E> Iterator<Tuple2<Integer, E>> indexed(Iterator<E> self) {
+        return indexed(self, 0);
+    }
+
+    /**
+     * Zips an iterator with indices in (value, index) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [["a", 5], ["b", 6]] == ["a", "b"].iterator().withIndex(5).toList()
+     * assert ["1: a", "2: b"] == ["a", "b"].iterator().withIndex(1).collect { str, idx -> "$idx: $str" }.toList()
+     * </pre>
+     *
+     * @param self   an iterator
+     * @param offset an index to start from
+     * @return a zipped iterator with indices
+     * @see #indexed(Iterator, int)
+     * @since 2.4.0
+     */
+    public static <E> Iterator<Tuple2<E, Integer>> withIndex(Iterator<E> self, int offset) {
+        return new ZipPostIterator<E>(self, offset);
+    }
+
+    /**
+     * Zips an iterator with indices in (index, value) order.
+     * <p/>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert [[5, "a"], [6, "b"]] == ["a", "b"].iterator().indexed(5).toList()
+     * assert ["a: 1", "b: 2"] == ["a", "b"].iterator().indexed(1).collect { idx, str -> "$str: $idx" }.toList()
+     * </pre>
+     *
+     * @param self   an iterator
+     * @param offset an index to start from
+     * @return a zipped iterator with indices
+     * @see #withIndex(Iterator, int)
+     * @since 2.4.0
+     */
+    public static <E> Iterator<Tuple2<Integer, E>> indexed(Iterator<E> self, int offset) {
+        return new ZipPreIterator<E>(self, offset);
+    }
+
+    private static final class ZipPostIterator<E> implements Iterator<Tuple2<E, Integer>> {
+        private final Iterator<E> delegate;
+        private int index;
+
+        private ZipPostIterator(Iterator<E> delegate, int offset) {
+            this.delegate = delegate;
+            this.index = offset;
+        }
+
+        public boolean hasNext() {
+            return delegate.hasNext();
+        }
+
+        public Tuple2<E, Integer> next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            return new Tuple2<E, Integer>(delegate.next(), index++);
+        }
+
+        public void remove() {
+            delegate.remove();
+        }
+    }
+
+    private static final class ZipPreIterator<E> implements Iterator<Tuple2<Integer, E>> {
+        private final Iterator<E> delegate;
+        private int index;
+
+        private ZipPreIterator(Iterator<E> delegate, int offset) {
+            this.delegate = delegate;
+            this.index = offset;
+        }
+
+        public boolean hasNext() {
+            return delegate.hasNext();
+        }
+
+        public Tuple2<Integer, E> next() {
+            if (!hasNext()) throw new NoSuchElementException();
+            return new Tuple2<Integer, E>(index++, delegate.next());
+        }
+
+        public void remove() {
+            delegate.remove();
+        }
+    }
+
+    /**
      * @deprecated Use the Iterable version of sort instead
      * @see #sort(Iterable,boolean)
      * @since 1.0
      */
     @Deprecated
     public static <T> List<T> sort(Collection<T> self) {
-        return sort((Iterable<T>)self, true);
+        return sort((Iterable<T>) self, true);
     }
 
     /**
@@ -6396,7 +8082,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     @Deprecated
     public static <T> List<T> sort(Collection<T> self, boolean mutate) {
-        return sort((Iterable<T>)self, mutate);
+        return sort((Iterable<T>) self, mutate);
     }
 
     /**
@@ -6413,9 +8099,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert sorted == [1, 2, 3]
      * </pre>
      *
-     * @param self   the collection to be sorted
+     * @param self   the iterable to be sorted
      * @param mutate false will always cause a new list to be created, true will mutate lists in place
-     * @return the sorted collection as a List
+     * @return the sorted iterable as a List
      * @since 2.2.0
      */
     public static <T> List<T> sort(Iterable<T> self, boolean mutate) {
@@ -6438,8 +8124,8 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     public static <K, V> Map<K, V> sort(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>","Map.Entry<K,V>,Map.Entry<K,V>"}) Closure closure) {
         Map<K, V> result = new LinkedHashMap<K, V>();
-        List<Map.Entry<K, V>> entries = asList(self.entrySet());
-        sort(entries, closure);
+        List<Map.Entry<K, V>> entries = asList((Iterable<Map.Entry<K, V>>) self.entrySet());
+        sort((Iterable<Map.Entry<K, V>>) entries, closure);
         for (Map.Entry<K, V> entry : entries) {
             result.put(entry.getKey(), entry.getValue());
         }
@@ -6529,7 +8215,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> sort(Iterator<T> self) {
-        return sort(toList(self)).listIterator();
+        return sort((Iterable<T>) toList(self)).listIterator();
     }
 
     /**
@@ -6543,7 +8229,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> sort(Iterator<T> self, Comparator<T> comparator) {
-        return sort(toList(self), comparator).listIterator();
+        return sort((Iterable<T>) toList(self), true, comparator).listIterator();
     }
 
     /**
@@ -6553,7 +8239,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     @Deprecated
     public static <T> List<T> sort(Collection<T> self, Comparator<T> comparator) {
-        return sort((Iterable<T>)self, true, comparator);
+        return sort((Iterable<T>) self, true, comparator);
     }
 
     /**
@@ -6563,7 +8249,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      */
     @Deprecated
     public static <T> List<T> sort(Collection<T> self, boolean mutate, Comparator<T> comparator) {
-        return sort((Iterable<T>)self, mutate, comparator);
+        return sort((Iterable<T>) self, mutate, comparator);
     }
 
     /**
@@ -6646,7 +8332,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.5.5
      */
     public static <T> Iterator<T> sort(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return sort(toList(self), closure).listIterator();
+        return sort((Iterable<T>) toList(self), closure).listIterator();
     }
 
     /**
@@ -6670,161 +8356,419 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Modifies this array so that its elements are in sorted order using the Closure to determine the correct ordering.
-     * If mutate is false, a new array is returned and the original array remains unchanged.
-     * Otherwise, the original array is sorted in place and returned.
+     * Modifies this array so that its elements are in sorted order using the Closure to determine the correct ordering.
+     * If mutate is false, a new array is returned and the original array remains unchanged.
+     * Otherwise, the original array is sorted in place and returned.
+     * <p>
+     * If the closure has two parameters it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer, zero, or a positive integer when the
+     * first parameter is less than, equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a Comparable (typically an Integer)
+     * which is then used for further comparison.
+     * <pre class="groovyTestCase">
+     * def orig = ["hello","hi","Hey"] as String[]
+     * def sorted = orig.sort(false) { it.size() }
+     * assert orig == ["hello","hi","Hey"] as String[]
+     * assert sorted == ["hi","Hey","hello"] as String[]
+     * orig.sort(true) { it.size() }
+     * assert orig == ["hi","Hey","hello"] as String[]
+     * </pre>
+     *
+     * @param self    the array to be sorted
+     * @param mutate  false will always cause a new array to be created, true will mutate arrays in place
+     * @param closure a Closure used to determine the correct ordering
+     * @return the sorted array
+     * @since 1.8.1
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] sort(T[] self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        T[] answer = (T[]) sort((Iterable<T>) toList(self), closure).toArray();
+        if (mutate) {
+            System.arraycopy(answer, 0, self, 0, answer.length);
+        }
+        return mutate ? self : answer;
+    }
+
+    /**
+     * @deprecated Use the Iterable version of sort instead
+     * @see #sort(Iterable, boolean, Closure)
+     * @since 1.8.1
+     */
+    @Deprecated
+    public static <T> List<T> sort(Collection<T> self, boolean mutate, Closure closure) {
+        return sort((Iterable<T>)self, mutate, closure);
+    }
+
+    /**
+     * @deprecated Use the Iterable version of sort instead
+     * @see #sort(Iterable, Closure)
+     * @since 1.0
+     */
+    @Deprecated
+    public static <T> List<T> sort(Collection<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return sort((Iterable<T>)self, closure);
+    }
+
+    /**
+     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List,
+     * it is sorted in place and returned. Otherwise, the elements are first placed
+     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * <p>
+     * If the Closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
+     *
+     * @param self    the Iterable to be sorted
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return a newly created sorted List
+     * @see #sort(Collection, boolean, Closure)
+     * @since 2.2.0
+     */
+    public static <T> List<T> sort(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        return sort(self, true, closure);
+    }
+
+    /**
+     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List
+     * and mutate is true, it is sorted in place and returned. Otherwise, the elements are first placed
+     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * <p>
+     * If the closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
+     * <pre class="groovyTestCase">
+     * def orig = ["hello","hi","Hey"]
+     * def sorted = orig.sort(false) { it.toUpperCase() }
+     * assert orig == ["hello","hi","Hey"]
+     * assert sorted == ["hello","Hey","hi"]
+     * </pre>
+     *
+     * @param self    the Iterable to be sorted
+     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return a newly created sorted List
+     * @since 2.2.0
+     */
+    public static <T> List<T> sort(Iterable<T> self, boolean mutate, Closure closure) {
+        List<T> list = mutate ? asList(self) : toList(self);
+        // use a comparator of one item or two
+        int params = closure.getMaximumNumberOfParameters();
+        if (params == 1) {
+            Collections.sort(list, new OrderBy<T>(closure));
+        } else {
+            Collections.sort(list, new ClosureComparator<T>(closure));
+        }
+        return list;
+    }
+
+    /**
+     * Avoids doing unnecessary work when sorting an already sorted set (i.e. an identity function for an already sorted set).
+     *
+     * @param self an already sorted set
+     * @return the set
+     * @since 1.0
+     */
+    public static <T> SortedSet<T> sort(SortedSet<T> self) {
+        return self;
+    }
+
+    /**
+     * Avoids doing unnecessary work when sorting an already sorted map (i.e. an identity function for an already sorted map).
+     *
+     * @param self an already sorted map
+     * @return the map
+     * @since 1.8.1
+     */
+    public static <K, V> SortedMap<K, V> sort(SortedMap<K, V> self) {
+        return self;
+    }
+
+    /**
+     * Sorts the Iterable. Assumes that the Iterable elements are
+     * comparable and uses a {@link NumberAwareComparator} to determine the resulting order.
+     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
+     * natural ordering of the Iterable elements. The elements are first placed into a new list which
+     * is then sorted and returned - leaving the original Iterable unchanged.
+     * <pre class="groovyTestCase">
+     * def orig = [1, 3, 2]
+     * def sorted = orig.toSorted()
+     * assert orig == [1, 3, 2]
+     * assert sorted == [1, 2, 3]
+     * </pre>
+     *
+     * @param self   the Iterable to be sorted
+     * @return the sorted iterable as a List
+     * @see #toSorted(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> toSorted(Iterable<T> self) {
+        return toSorted(self, new NumberAwareComparator<T>());
+    }
+
+    /**
+     * Sorts the Iterable using the given Comparator. The elements are first placed
+     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * <pre class="groovyTestCase">
+     * def orig = ["hello","hi","Hey"]
+     * def sorted = orig.toSorted(String.CASE_INSENSITIVE_ORDER)
+     * assert orig == ["hello","hi","Hey"]
+     * assert sorted == ["hello","Hey","hi"]
+     * </pre>
+     *
+     * @param self       the Iterable to be sorted
+     * @param comparator a Comparator used for the comparison
+     * @return a sorted List
+     * @since 2.4.0
+     */
+    public static <T> List<T> toSorted(Iterable<T> self, Comparator<T> comparator) {
+        List<T> list = toList(self);
+        Collections.sort(list, comparator);
+        return list;
+    }
+
+    /**
+     * Sorts this Iterable using the given Closure to determine the correct ordering. The elements are first placed
+     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * <p>
+     * If the Closure has two parameters
+     * it is used like a traditional Comparator. I.e. it should compare
+     * its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than,
+     * equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single parameter and return a
+     * Comparable (typically an Integer) which is then used for
+     * further comparison.
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
+     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
+     *
+     * @param self    the Iterable to be sorted
+     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
+     * @return a newly created sorted List
+     * @see #toSorted(Iterable, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> List<T> toSorted(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<T>(closure) : new ClosureComparator<T>(closure);
+        return toSorted(self, comparator);
+    }
+
+    /**
+     * Sorts the Iterator. Assumes that the Iterator elements are
+     * comparable and uses a {@link NumberAwareComparator} to determine the resulting order.
+     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
+     * natural ordering of the Iterator elements.
+     * A new iterator is produced that traverses the items in sorted order.
+     *
+     * @param self       the Iterator to be sorted
+     * @return the sorted items as an Iterator
+     * @see #toSorted(Iterator, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toSorted(Iterator<T> self) {
+        return toSorted(self, new NumberAwareComparator<T>());
+    }
+
+    /**
+     * Sorts the given iterator items using the comparator. The
+     * original iterator will become exhausted of elements after completing this method call.
+     * A new iterator is produced that traverses the items in sorted order.
+     *
+     * @param self       the Iterator to be sorted
+     * @param comparator a Comparator used for comparing items
+     * @return the sorted items as an Iterator
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toSorted(Iterator<T> self, Comparator<T> comparator) {
+        return toSorted(toList(self), comparator).listIterator();
+    }
+
+    /**
+     * Sorts the given iterator items into a sorted iterator using the Closure to determine the correct ordering.
+     * The original iterator will be fully processed after the method call.
+     * <p>
+     * If the closure has two parameters it is used like a traditional Comparator.
+     * I.e. it should compare its two parameters for order, returning a negative integer,
+     * zero, or a positive integer when the first parameter is less than, equal to,
+     * or greater than the second respectively. Otherwise, the Closure is assumed
+     * to take a single parameter and return a Comparable (typically an Integer)
+     * which is then used for further comparison.
+     *
+     * @param self    the Iterator to be sorted
+     * @param closure a Closure used to determine the correct ordering
+     * @return the sorted items as an Iterator
+     * @see #toSorted(Iterator, Comparator)
+     * @since 2.4.0
+     */
+    public static <T> Iterator<T> toSorted(Iterator<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
+        Comparator<T> comparator = (closure.getMaximumNumberOfParameters() == 1) ? new OrderBy<T>(closure) : new ClosureComparator<T>(closure);
+        return toSorted(self, comparator);
+    }
+
+    /**
+     * Returns a sorted version of the given array using the supplied comparator.
+     *
+     * @param self the array to be sorted
+     * @return the sorted array
+     * @see #toSorted(Object[], Comparator)
+     * @since 2.4.0
+     */
+    public static <T> T[] toSorted(T[] self) {
+        return toSorted(self, new NumberAwareComparator<T>());
+    }
+
+    /**
+     * Returns a sorted version of the given array using the supplied comparator to determine the resulting order.
+     * <pre class="groovyTestCase">
+     * def sumDigitsComparator = [compare: { num1, num2 -> num1.toString().toList()*.toInteger().sum() <=> num2.toString().toList()*.toInteger().sum() }] as Comparator
+     * Integer[] nums = [9, 44, 222, 7000]
+     * def result = nums.toSorted(sumDigitsComparator)
+     * assert result instanceof Integer[]
+     * assert result == [222, 7000, 44, 9]
+     * </pre>
+     *
+     * @param self the array to be sorted
+     * @param comparator a Comparator used for the comparison
+     * @return the sorted array
+     * @since 2.4.0
+     */
+    public static <T> T[] toSorted(T[] self, Comparator<T> comparator) {
+        T[] answer = self.clone();
+        Arrays.sort(answer, comparator);
+        return answer;
+    }
+
+    /**
+     * Sorts the elements from this array into a newly created array using
+     * the Closure to determine the correct ordering.
      * <p>
      * If the closure has two parameters it is used like a traditional Comparator. I.e. it should compare
      * its two parameters for order, returning a negative integer, zero, or a positive integer when the
      * first parameter is less than, equal to, or greater than the second respectively. Otherwise,
      * the Closure is assumed to take a single parameter and return a Comparable (typically an Integer)
      * which is then used for further comparison.
-     * <pre class="groovyTestCase">
-     * def orig = ["hello","hi","Hey"] as String[]
-     * def sorted = orig.sort(false) { it.size() }
-     * assert orig == ["hello","hi","Hey"] as String[]
-     * assert sorted == ["hi","Hey","hello"] as String[]
-     * orig.sort(true) { it.size() }
-     * assert orig == ["hi","Hey","hello"] as String[]
-     * </pre>
      *
-     * @param self    the array to be sorted
-     * @param mutate  false will always cause a new array to be created, true will mutate arrays in place
-     * @param closure a Closure used to determine the correct ordering
-     * @return the sorted array
-     * @since 1.8.1
+     * @param self the array containing the elements to be sorted
+     * @param condition a Closure used to determine the correct ordering
+     * @return a sorted array
+     * @see #toSorted(Object[], Comparator)
+     * @since 2.4.0
      */
-    @SuppressWarnings("unchecked")
-    public static <T> T[] sort(T[] self, boolean mutate, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        T[] answer = (T[]) sort(toList(self), closure).toArray();
-        if (mutate) {
-            System.arraycopy(answer, 0, self, 0, answer.length);
-        }
-        return mutate ? self : answer;
+    public static <T> T[] toSorted(T[] self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure condition) {
+        Comparator<T> comparator = (condition.getMaximumNumberOfParameters() == 1) ? new OrderBy<T>(condition) : new ClosureComparator<T>(condition);
+        return toSorted(self, comparator);
     }
 
     /**
-     * Sorts this Collection using the given Closure to determine the correct ordering. If the Collection is a List,
-     * it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Collection unchanged.
-     * <p>
-     * If the Closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
+     * Sorts the elements from the given map into a new ordered map using
+     * a {@link NumberAwareComparator} on map entry values to determine the resulting order.
+     * {@code NumberAwareComparator} has special treatment for numbers but otherwise uses the
+     * natural ordering of the Iterator elements. The original map is unchanged.
+     * <pre class="groovyTestCase">
+     * def map = [a:5L, b:3, c:6, d:4.0].toSorted()
+     * assert map.toString() == '[b:3, d:4.0, a:5, c:6]'
+     * </pre>
      *
-     * @param self    a Collection to be sorted
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @see #sort(Collection, boolean, Closure)
-     * @since 1.0
+     * @param self the original unsorted map
+     * @return the sorted map
+     * @since 2.4.0
      */
-    public static <T> List<T> sort(Collection<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return sort((Iterable<T>)self, closure);
+    public static <K, V> Map<K, V> toSorted(Map<K, V> self) {
+        return toSorted(self, new NumberAwareValueComparator<K, V>());
     }
 
-    /**
-     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List,
-     * it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
-     * <p>
-     * If the Closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
-     *
-     * @param self    the Iterable to be sorted
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @see #sort(Collection, boolean, Closure)
-     * @since 2.2.0
-     */
-    public static <T> List<T> sort(Iterable<T> self, @ClosureParams(value=FromString.class, options={"T","T,T"}) Closure closure) {
-        return sort(self, true, closure);
+    private static class NumberAwareValueComparator<K, V> implements Comparator<Map.Entry<K, V>> {
+        private Comparator<V> delegate = new NumberAwareComparator<V>();
+
+        @Override
+        public int compare(Map.Entry<K, V> e1, Map.Entry<K, V> e2) {
+            return delegate.compare(e1.getValue(), e2.getValue());
+        }
     }
 
     /**
-     * @deprecated Use the Iterable version of sort instead
-     * @see #sort(Iterable, boolean, Closure)
-     * @since 1.8.1
+     * Sorts the elements from the given map into a new ordered map using
+     * the supplied comparator to determine the ordering. The original map is unchanged.
+     * <pre class="groovyTestCase">
+     * def keyComparator = [compare: { e1, e2 -> e1.key <=> e2.key }] as Comparator
+     * def valueComparator = [compare: { e1, e2 -> e1.value <=> e2.value }] as Comparator
+     * def map1 = [a:5, b:3, d:4, c:6].toSorted(keyComparator)
+     * assert map1.toString() == '[a:5, b:3, c:6, d:4]'
+     * def map2 = [a:5, b:3, d:4, c:6].toSorted(valueComparator)
+     * assert map2.toString() == '[b:3, d:4, a:5, c:6]'
+     * </pre>
+     *
+     * @param self the original unsorted map
+     * @param comparator a Comparator used for the comparison
+     * @return the sorted map
+     * @since 2.4.0
      */
-    @Deprecated
-    public static <T> List<T> sort(Collection<T> self, boolean mutate, Closure closure) {
-        return sort((Iterable<T>)self, mutate, closure);
+    public static <K, V> Map<K, V> toSorted(Map<K, V> self, Comparator<Map.Entry<K, V>> comparator) {
+        List<Map.Entry<K, V>> sortedEntries = toSorted(self.entrySet(), comparator);
+        Map<K, V> result = new LinkedHashMap<K, V>();
+        for (Map.Entry<K, V> entry : sortedEntries) {
+            result.put(entry.getKey(), entry.getValue());
+        }
+        return result;
     }
 
     /**
-     * Sorts this Iterable using the given Closure to determine the correct ordering. If the Iterable is a List
-     * and mutate is true, it is sorted in place and returned. Otherwise, the elements are first placed
-     * into a new list which is then sorted and returned - leaving the original Iterable unchanged.
+     * Sorts the elements from the given map into a new ordered map using
+     * the supplied Closure condition as a comparator to determine the ordering. The original map is unchanged.
      * <p>
-     * If the closure has two parameters
-     * it is used like a traditional Comparator. I.e. it should compare
-     * its two parameters for order, returning a negative integer,
-     * zero, or a positive integer when the first parameter is less than,
-     * equal to, or greater than the second respectively. Otherwise,
-     * the Closure is assumed to take a single parameter and return a
-     * Comparable (typically an Integer) which is then used for
-     * further comparison.
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { it.length() }</pre>
-     * <pre class="groovyTestCase">assert ["hi","hey","hello"] == ["hello","hi","hey"].sort { a, b -> a.length() <=> b.length() }</pre>
+     * If the closure has two parameters it is used like a traditional Comparator. I.e. it should compare
+     * its two entry parameters for order, returning a negative integer, zero, or a positive integer when the
+     * first parameter is less than, equal to, or greater than the second respectively. Otherwise,
+     * the Closure is assumed to take a single entry parameter and return a Comparable (typically an Integer)
+     * which is then used for further comparison.
      * <pre class="groovyTestCase">
-     * def orig = ["hello","hi","Hey"]
-     * def sorted = orig.sort(false) { it.toUpperCase() }
-     * assert orig == ["hello","hi","Hey"]
-     * assert sorted == ["hello","Hey","hi"]
+     * def map = [a:5, b:3, c:6, d:4].toSorted { a, b -> a.value <=> b.value }
+     * assert map.toString() == '[b:3, d:4, a:5, c:6]'
      * </pre>
      *
-     * @param self    the Iterable to be sorted
-     * @param mutate  false will always cause a new list to be created, true will mutate lists in place
-     * @param closure a 1 or 2 arg Closure used to determine the correct ordering
-     * @return a newly created sorted List
-     * @since 2.2.0
+     * @param self the original unsorted map
+     * @param condition a Closure used as a comparator
+     * @return the sorted map
+     * @since 2.4.0
      */
-    public static <T> List<T> sort(Iterable<T> self, boolean mutate, Closure closure) {
-        List<T> list = mutate ? asList(self) : toList(self);
-        // use a comparator of one item or two
-        int params = closure.getMaximumNumberOfParameters();
-        if (params == 1) {
-            Collections.sort(list, new OrderBy<T>(closure));
-        } else {
-            Collections.sort(list, new ClosureComparator<T>(closure));
-        }
-        return list;
+    public static <K, V> Map<K, V> toSorted(Map<K, V> self, @ClosureParams(value=FromString.class, options={"Map.Entry<K,V>","Map.Entry<K,V>,Map.Entry<K,V>"}) Closure condition) {
+        Comparator<Map.Entry<K,V>> comparator = (condition.getMaximumNumberOfParameters() == 1) ? new OrderBy<Map.Entry<K,V>>(condition) : new ClosureComparator<Map.Entry<K,V>>(condition);
+        return toSorted(self, comparator);
     }
 
     /**
-     * Avoids doing unnecessary work when sorting an already sorted set (i.e. an identity function for an already sorted set).
+     * Avoids doing unnecessary work when sorting an already sorted set
      *
      * @param self an already sorted set
-     * @return the set
-     * @since 1.0
+     * @return an ordered copy of the sorted set
+     * @since 2.4.0
      */
-    public static <T> SortedSet<T> sort(SortedSet<T> self) {
-        return self;
+    public static <T> Set<T> toSorted(SortedSet<T> self) {
+        return new LinkedHashSet<T>(self);
     }
 
     /**
-     * Avoids doing unnecessary work when sorting an already sorted map (i.e. an identity function for an already sorted map).
+     * Avoids doing unnecessary work when sorting an already sorted map
      *
      * @param self an already sorted map
-     * @return the map
-     * @since 1.8.1
+     * @return an ordered copy of the map
+     * @since 2.4.0
      */
-    public static <K, V> SortedMap<K, V> sort(SortedMap<K, V> self) {
-        return self;
+    public static <K, V> Map<K, V> toSorted(SortedMap<K, V> self) {
+        return new LinkedHashMap<K, V>(self);
     }
 
     /**
@@ -7032,106 +8976,325 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Returns the first item from the List.
-     * <pre class="groovyTestCase">def list = [3, 4, 2]
-     * assert list.head() == 3
-     * assert list == [3, 4, 2]</pre>
+     * Returns the first item from the Iterable.
+     * <pre class="groovyTestCase">
+     * def set = [3, 4, 2] as LinkedHashSet
+     * assert set.head() == 3
+     * // check original is unaltered
+     * assert set == [3, 4, 2] as Set
+     * </pre>
+     * The first element returned by the Iterable's iterator is returned.
+     * If the Iterable doesn't guarantee a defined order it may appear like
+     * a random element is returned.
+     *
+     * @param self an Iterable
+     * @return the first item from the Iterable
+     * @throws NoSuchElementException if the Iterable is empty and you try to access the head() item.
+     * @since 2.4.0
+     */
+    public static <T> T head(Iterable<T> self) {
+        return first(self);
+    }
+
+    /**
+     * Returns the first item from the List.
+     * <pre class="groovyTestCase">def list = [3, 4, 2]
+     * assert list.head() == 3
+     * assert list == [3, 4, 2]</pre>
+     *
+     * @param self a List
+     * @return the first item from the List
+     * @throws NoSuchElementException if the list is empty and you try to access the head() item.
+     * @since 1.5.5
+     */
+    public static <T> T head(List<T> self) {
+        return first(self);
+    }
+
+    /**
+     * Returns the first item from the Object array.
+     * <pre class="groovyTestCase">def array = [3, 4, 2].toArray()
+     * assert array.head() == 3</pre>
+     *
+     * @param self an array
+     * @return the first item from the Object array
+     * @throws NoSuchElementException if the array is empty and you try to access the head() item.
+     * @since 1.7.3
+     */
+    public static <T> T head(T[] self) {
+        return first(self);
+    }
+
+    /**
+     * Returns the items from the List excluding the first item.
+     * <pre class="groovyTestCase">
+     * def list = [3, 4, 2]
+     * assert list.tail() == [4, 2]
+     * assert list == [3, 4, 2]
+     * </pre>
+     *
+     * @param self an List
+     * @return a List without its first element
+     * @throws NoSuchElementException if the List is empty and you try to access the tail()
+     * @since 1.5.6
+     */
+    public static <T> List<T> tail(List<T> self) {
+        return (List<T>) tail((Iterable<T>)self);
+    }
+
+    /**
+     * Returns the items from the SortedSet excluding the first item.
+     * <pre class="groovyTestCase">
+     * def sortedSet = [3, 4, 2] as SortedSet
+     * assert sortedSet.tail() == [3, 4] as SortedSet
+     * assert sortedSet == [3, 4, 2] as SortedSet
+     * </pre>
+     *
+     * @param self an SortedSet
+     * @return a SortedSet without its first element
+     * @throws NoSuchElementException if the SortedSet is empty and you try to access the tail()
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> tail(SortedSet<T> self) {
+        return (SortedSet<T>) tail((Iterable<T>) self);
+    }
+
+    /**
+     * Returns the items from the Iterable excluding the first item.
+     * <pre class="groovyTestCase">
+     * def list = [3, 4, 2]
+     * assert list.tail() == [4, 2]
+     * assert list == [3, 4, 2]
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a collection without its first element
+     * @throws NoSuchElementException if the iterable is empty and you try to access the tail()
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> tail(Iterable<T> self) {
+        if (!self.iterator().hasNext()) {
+            throw new NoSuchElementException("Cannot access tail() for an empty iterable");
+        }
+        Collection<T> result = createSimilarCollection(self);
+        addAll(result, tail(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Returns the items from the array excluding the first item.
+     * <pre class="groovyTestCase">
+     * String[] strings = ["a", "b", "c"]
+     * def result = strings.tail()
+     * assert result.class.componentType == String
+     * String[] expected = ["b", "c"]
+     * assert result == expected
+     * </pre>
+     *
+     * @param self an array
+     * @return an array without its first element
+     * @throws NoSuchElementException if the array is empty and you try to access the tail()
+     * @since 1.7.3
+     */
+    @SuppressWarnings("unchecked")
+    public static <T> T[] tail(T[] self) {
+        if (self.length == 0) {
+            throw new NoSuchElementException("Cannot access tail() for an empty array");
+        }
+        T[] result = createSimilarArray(self, self.length - 1);
+        System.arraycopy(self, 1, result, 0, self.length - 1);
+        return result;
+    }
+
+    /**
+     * Returns the original iterator after throwing away the first element.
+     *
+     * @param self the original iterator
+     * @return the iterator without its first element
+     * @throws NoSuchElementException if the array is empty and you try to access the tail()
+     * @since 1.8.1
+     */
+    public static <T> Iterator<T> tail(Iterator<T> self) {
+        if (!self.hasNext()) {
+            throw new NoSuchElementException("Cannot access tail() for an empty Iterator");
+        }
+        self.next();
+        return self;
+    }
+
+    /**
+     * Returns the items from the Iterable excluding the last item. Leaves the original Iterable unchanged.
+     * <pre class="groovyTestCase">
+     * def list = [3, 4, 2]
+     * assert list.init() == [3, 4]
+     * assert list == [3, 4, 2]
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a Collection without its last element
+     * @throws NoSuchElementException if the iterable is empty and you try to access init()
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> init(Iterable<T> self) {
+        if (!self.iterator().hasNext()) {
+            throw new NoSuchElementException("Cannot access init() for an empty Iterable");
+        }
+        Collection<T> result;
+        if (self instanceof Collection) {
+            Collection<T> selfCol = (Collection<T>) self;
+            result = createSimilarCollection(selfCol, selfCol.size() - 1);
+        } else {
+            result = new ArrayList<T>();
+        }
+        addAll(result, init(self.iterator()));
+        return result;
+    }
+
+    /**
+     * Returns the items from the List excluding the last item. Leaves the original List unchanged.
+     * <pre class="groovyTestCase">
+     * def list = [3, 4, 2]
+     * assert list.init() == [3, 4]
+     * assert list == [3, 4, 2]
+     * </pre>
      *
-     * @param self a List
-     * @return the first item from the List
-     * @throws NoSuchElementException if the list is empty and you try to access the head() item.
-     * @since 1.5.5
+     * @param self an List
+     * @return a List without its last element
+     * @throws NoSuchElementException if the List is empty and you try to access init()
+     * @since 2.4.0
      */
-    public static <T> T head(List<T> self) {
-        return first(self);
+    public static <T> List<T> init(List<T> self) {
+        return (List<T>) init((Iterable<T>) self);
     }
 
     /**
-     * Returns the first item from the Object array.
-     * <pre class="groovyTestCase">def array = [3, 4, 2].toArray()
-     * assert array.head() == 3</pre>
+     * Returns the items from the SortedSet excluding the last item. Leaves the original SortedSet unchanged.
+     * <pre class="groovyTestCase">
+     * def sortedSet = [3, 4, 2] as SortedSet
+     * assert sortedSet.init() == [3, 4] as SortedSet
+     * assert sortedSet == [3, 4, 2] as SortedSet
+     * </pre>
      *
-     * @param self an Object array
-     * @return the first item from the Object array
-     * @throws NoSuchElementException if the array is empty and you try to access the head() item.
-     * @since 1.7.3
+     * @param self an SortedSet
+     * @return a SortedSet without its last element
+     * @throws NoSuchElementException if the SortedSet is empty and you try to access init()
+     * @since 2.4.0
      */
-    public static <T> T head(T[] self) {
-        return first(self);
+    public static <T> SortedSet<T> init(SortedSet<T> self) {
+        return (SortedSet<T>) init((Iterable<T>) self);
     }
 
     /**
-     * Returns the items from the List excluding the first item.
-     * <pre class="groovyTestCase">def list = [3, 4, 2]
-     * assert list.tail() == [4, 2]
-     * assert list == [3, 4, 2]</pre>
+     * Returns an Iterator containing all of the items from this iterator except the last one.
+     * <pre class="groovyTestCase">
+     * def iter = [3, 4, 2].listIterator()
+     * def result = iter.init()
+     * assert result.toList() == [3, 4]
+     * </pre>
      *
-     * @param self a List
-     * @return a list without its first element
-     * @throws NoSuchElementException if the list is empty and you try to access the tail() item.
-     * @since 1.5.6
+     * @param self an Iterator
+     * @return an Iterator without the last element from the original Iterator
+     * @throws NoSuchElementException if the iterator is empty and you try to access init()
+     * @since 2.4.0
      */
-    public static <T> List<T> tail(List<T> self) {
-        if (self.isEmpty()) {
-            throw new NoSuchElementException("Cannot access tail() for an empty List");
+    public static <T> Iterator<T> init(Iterator<T> self) {
+        if (!self.hasNext()) {
+            throw new NoSuchElementException("Cannot access init() for an empty Iterator");
+        }
+        return new InitIterator<T>(self);
+    }
+
+    private static final class InitIterator<E> implements Iterator<E> {
+        private final Iterator<E> delegate;
+        private boolean exhausted;
+        private E next;
+
+        private InitIterator(Iterator<E> delegate) {
+            this.delegate = delegate;
+            advance();
+        }
+
+        public boolean hasNext() {
+            return !exhausted;
+        }
+
+        public E next() {
+            if (exhausted) throw new NoSuchElementException();
+            E result = next;
+            advance();
+            return result;
+        }
+
+        public void remove() {
+            if (exhausted) throw new NoSuchElementException();
+            advance();
+        }
+
+        private void advance() {
+            next = delegate.next();
+            exhausted = !delegate.hasNext();
         }
-        List<T> result = new ArrayList<T>(self);
-        result.remove(0);
-        return result;
     }
 
     /**
-     * Returns the items from the Object array excluding the first item.
+     * Returns the items from the Object array excluding the last item.
      * <pre class="groovyTestCase">
      *     String[] strings = ["a", "b", "c"]
-     *     def result = strings.tail()
+     *     def result = strings.init()
+     *     assert result.length == 2
      *     assert strings.class.componentType == String
      * </pre>
      *
-     * @param self an Object array
-     * @return an Object array without its first element
-     * @throws NoSuchElementException if the list is empty and you try to access the tail() item.
-     * @since 1.7.3
+     * @param self an array
+     * @return an array without its last element
+     * @throws NoSuchElementException if the array is empty and you try to access the init() item.
+     * @since 2.4.0
      */
-    public static <T> T[] tail(T[] self) {
+    public static <T> T[] init(T[] self) {
         if (self.length == 0) {
-            throw new NoSuchElementException("Cannot access tail() for an empty Object array");
+            throw new NoSuchElementException("Cannot access init() for an empty Object array");
         }
-        Class<T> componentType = (Class<T>) self.getClass().getComponentType();
-        T[] result = (T[]) Array.newInstance(componentType, self.length - 1);
-        System.arraycopy(self, 1, result, 0, self.length - 1);
+        T[] result = createSimilarArray(self, self.length - 1);
+        System.arraycopy(self, 0, result, 0, self.length - 1);
         return result;
     }
 
     /**
-     * Returns the first <code>num</code> elements from the head of this list.
+     * Returns the first <code>num</code> elements from the head of this List.
      * <pre class="groovyTestCase">
      * def strings = [ 'a', 'b', 'c' ]
      * assert strings.take( 0 ) == []
      * assert strings.take( 2 ) == [ 'a', 'b' ]
      * assert strings.take( 5 ) == [ 'a', 'b', 'c' ]
      * </pre>
-     * Similar to {@link #take(Iterable, int)}
-     * except that it attempts to preserve the type of the original list.
      *
-     * @param self the original list
-     * @param num  the number of elements to take from this list
-     * @return a list consisting of the first <code>num</code> elements of this list,
-     *         or else the whole list if it has less then <code>num</code> elements.
+     * @param self the original List
+     * @param num  the number of elements to take from this List
+     * @return a List consisting of the first <code>num</code> elements from this List,
+     *         or else all the elements from the List if it has less then <code>num</code> elements.
      * @since 1.8.1
      */
     public static <T> List<T> take(List<T> self, int num) {
-        if (self.isEmpty() || num <= 0) {
-            return createSimilarList(self, 0);
-        }
-        if (self.size() <= num) {
-            List<T> ret = createSimilarList(self, self.size());
-            ret.addAll(self);
-            return ret;
-        }
-        List<T> ret = createSimilarList(self, num);
-        ret.addAll(self.subList(0, num));
-        return ret;
+        return (List<T>) take((Iterable<T>)self, num);
+    }
+
+    /**
+     * Returns the first <code>num</code> elements from the head of this SortedSet.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.take( 0 ) == [] as SortedSet
+     * assert strings.take( 2 ) == [ 'a', 'b' ] as SortedSet
+     * assert strings.take( 5 ) == [ 'a', 'b', 'c' ] as SortedSet
+     * </pre>
+     *
+     * @param self the original SortedSet
+     * @param num  the number of elements to take from this SortedSet
+     * @return a SortedSet consisting of the first <code>num</code> elements from this List,
+     *         or else all the elements from the SortedSet if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> take(SortedSet<T> self, int num) {
+        return (SortedSet<T>) take((Iterable<T>) self, num);
     }
 
     /**
@@ -7168,6 +9331,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Returns the first <code>num</code> elements from the head of this Iterable.
      * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.take( 0 ) == []
+     * assert strings.take( 2 ) == [ 'a', 'b' ]
+     * assert strings.take( 5 ) == [ 'a', 'b', 'c' ]
+     *
      * class AbcIterable implements Iterable<String> {
      *     Iterator<String> iterator() { "abc".iterator() }
      * }
@@ -7180,12 +9348,45 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self the original Iterable
      * @param num  the number of elements to take from this Iterable
-     * @return a List consisting of the first <code>num</code> elements from this Iterable,
+     * @return a Collection consisting of the first <code>num</code> elements from this Iterable,
      *         or else all the elements from the Iterable if it has less then <code>num</code> elements.
      * @since 1.8.7
      */
-    public static <T> List<T> take(Iterable<T> self, int num) {
-        return toList(take(self.iterator(), num));
+    public static <T> Collection<T> take(Iterable<T> self, int num) {
+        Collection<T> result = self instanceof Collection ? createSimilarCollection((Collection<T>) self, num < 0 ? 0 : num) : new ArrayList<T>();
+        addAll(result, take(self.iterator(), num));
+        return result;
+    }
+
+    /**
+     * Adds all items from the iterator to the Collection.
+     *
+     * @param self the collection
+     * @param items the items to add
+     * @return true if the collection changed
+     */
+    public static <T> boolean addAll(Collection<T> self, Iterator<T> items) {
+        boolean changed = false;
+        while (items.hasNext()) {
+            T next =  items.next();
+            if (self.add(next)) changed = true;
+        }
+        return changed;
+    }
+
+    /**
+     * Adds all items from the iterable to the Collection.
+     *
+     * @param self the collection
+     * @param items the items to add
+     * @return true if the collection changed
+     */
+    public static <T> boolean addAll(Collection<T> self, Iterable<T> items) {
+        boolean changed = false;
+        for (T next : items) {
+            if (self.add(next)) changed = true;
+        }
+        return changed;
     }
 
     /**
@@ -7238,12 +9439,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @return an iterator consisting of up to the first <code>num</code> elements of this iterator.
      * @since 1.8.1
      */
-    @SuppressWarnings("unchecked")
     public static <T> Iterator<T> take(Iterator<T> self, int num) {
-        return new TakeIterator(self, num);
+        return new TakeIterator<T>(self, num);
     }
 
-    private static class TakeIterator<E> implements Iterator<E> {
+    private static final class TakeIterator<E> implements Iterator<E> {
         private final Iterator<E> delegate;
         private Integer num;
 
@@ -7257,7 +9457,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         }
 
         public E next() {
-            if (num == 0) throw new NoSuchElementException();
+            if (num <= 0) throw new NoSuchElementException();
             num--;
             return delegate.next();
         }
@@ -7273,41 +9473,159 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Drops the given number of elements from the head of this list
-     * if they are available.
+     * Returns the last <code>num</code> elements from the tail of this array.
+     * <pre class="groovyTestCase">
+     * String[] strings = [ 'a', 'b', 'c' ]
+     * assert strings.takeRight( 0 ) == [] as String[]
+     * assert strings.takeRight( 2 ) == [ 'b', 'c' ] as String[]
+     * assert strings.takeRight( 5 ) == [ 'a', 'b', 'c' ] as String[]
+     * </pre>
+     *
+     * @param self the original array
+     * @param num  the number of elements to take from this array
+     * @return an array consisting of the last <code>num</code> elements of this array,
+     *         or else the whole array if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> T[] takeRight(T[] self, int num) {
+        if (self.length == 0 || num <= 0) {
+            return createSimilarArray(self, 0);
+        }
+
+        if (self.length <= num) {
+            T[] ret = createSimilarArray(self, self.length);
+            System.arraycopy(self, 0, ret, 0, self.length);
+            return ret;
+        }
+
+        T[] ret = createSimilarArray(self, num);
+        System.arraycopy(self, self.length - num, ret, 0, num);
+        return ret;
+    }
+
+    /**
+     * Returns the last <code>num</code> elements from the tail of this Iterable.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.takeRight( 0 ) == []
+     * assert strings.takeRight( 2 ) == [ 'b', 'c' ]
+     * assert strings.takeRight( 5 ) == [ 'a', 'b', 'c' ]
+     *
+     * class AbcIterable implements Iterable<String> {
+     *     Iterator<String> iterator() { "abc".iterator() }
+     * }
+     * def abc = new AbcIterable()
+     * assert abc.takeRight(0) == []
+     * assert abc.takeRight(1) == ['c']
+     * assert abc.takeRight(3) == ['a', 'b', 'c']
+     * assert abc.takeRight(5) == ['a', 'b', 'c']
+     * </pre>
+     *
+     * @param self the original Iterable
+     * @param num  the number of elements to take from this Iterable
+     * @return a Collection consisting of the last <code>num</code> elements from this Iterable,
+     *         or else all the elements from the Iterable if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> takeRight(Iterable<T> self, int num) {
+        if (!self.iterator().hasNext() || num <= 0) {
+            return self instanceof Collection ? createSimilarCollection((Collection<T>) self, 0) : new ArrayList<T>();
+        }
+        Collection<T> selfCol = self instanceof Collection ? (Collection<T>) self : toList(self);
+        if (selfCol.size() <= num) {
+            Collection<T> ret = createSimilarCollection(selfCol, selfCol.size());
+            ret.addAll(selfCol);
+            return ret;
+        }
+        Collection<T> ret = createSimilarCollection(selfCol, num);
+        ret.addAll(asList((Iterable<T>) selfCol).subList(selfCol.size() - num, selfCol.size()));
+        return ret;
+    }
+
+    /**
+     * Returns the last <code>num</code> elements from the tail of this List.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.takeRight( 0 ) == []
+     * assert strings.takeRight( 2 ) == [ 'b', 'c' ]
+     * assert strings.takeRight( 5 ) == [ 'a', 'b', 'c' ]
+     * </pre>
+     *
+     * @param self the original List
+     * @param num  the number of elements to take from this List
+     * @return a List consisting of the last <code>num</code> elements from this List,
+     *         or else all the elements from the List if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> List<T> takeRight(List<T> self, int num) {
+        return (List<T>) takeRight((Iterable<T>) self, num);
+    }
+
+    /**
+     * Returns the last <code>num</code> elements from the tail of this SortedSet.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.takeRight( 0 ) == [] as SortedSet
+     * assert strings.takeRight( 2 ) == [ 'b', 'c' ] as SortedSet
+     * assert strings.takeRight( 5 ) == [ 'a', 'b', 'c' ] as SortedSet
+     * </pre>
+     *
+     * @param self the original SortedSet
+     * @param num  the number of elements to take from this SortedSet
+     * @return a SortedSet consisting of the last <code>num</code> elements from this SortedSet,
+     *         or else all the elements from the SortedSet if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> takeRight(SortedSet<T> self, int num) {
+        return (SortedSet<T>) takeRight((Iterable<T>) self, num);
+    }
+
+    /**
+     * Drops the given number of elements from the head of this List.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.drop( 0 ) == [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.drop( 2 ) == [ 'c' ] as SortedSet
+     * assert strings.drop( 5 ) == [] as SortedSet
+     * </pre>
+     *
+     * @param self the original SortedSet
+     * @param num  the number of elements to drop from this Iterable
+     * @return a SortedSet consisting of all the elements of this Iterable minus the first <code>num</code> elements,
+     *         or an empty list if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> drop(SortedSet<T> self, int num) {
+        return (SortedSet<T>) drop((Iterable<T>) self, num);
+    }
+
+    /**
+     * Drops the given number of elements from the head of this List.
      * <pre class="groovyTestCase">
      * def strings = [ 'a', 'b', 'c' ]
      * assert strings.drop( 0 ) == [ 'a', 'b', 'c' ]
      * assert strings.drop( 2 ) == [ 'c' ]
      * assert strings.drop( 5 ) == []
      * </pre>
-     * Similar to {@link #drop(Iterable, int)}
-     * except that it attempts to preserve the type of the original list.
      *
-     * @param self the original list
-     * @param num  the number of elements to drop from this list
-     * @return a list consisting of all elements of this list except the first
-     *         <code>num</code> ones, or else the empty list, if this list has
-     *         less than <code>num</code> elements.
+     * @param self the original List
+     * @param num  the number of elements to drop from this Iterable
+     * @return a List consisting of all the elements of this Iterable minus the first <code>num</code> elements,
+     *         or an empty list if it has less then <code>num</code> elements.
      * @since 1.8.1
      */
     public static <T> List<T> drop(List<T> self, int num) {
-        if (self.size() <= num) {
-            return createSimilarList(self, 0);
-        }
-        if (num <= 0) {
-            List<T> ret = createSimilarList(self, self.size());
-            ret.addAll(self);
-            return ret;
-        }
-        List<T> ret = createSimilarList(self, self.size() - num);
-        ret.addAll(self.subList(num, self.size()));
-        return ret;
+        return (List<T>) drop((Iterable<T>) self, num);
     }
 
     /**
      * Drops the given number of elements from the head of this Iterable.
      * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.drop( 0 ) == [ 'a', 'b', 'c' ]
+     * assert strings.drop( 2 ) == [ 'c' ]
+     * assert strings.drop( 5 ) == []
+     *
      * class AbcIterable implements Iterable<String> {
      *     Iterator<String> iterator() { "abc".iterator() }
      * }
@@ -7320,12 +9638,14 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self the original Iterable
      * @param num  the number of elements to drop from this Iterable
-     * @return a List consisting of all the elements of this Iterable minus the first <code>num</code> elements,
+     * @return a Collection consisting of all the elements of this Iterable minus the first <code>num</code> elements,
      *         or an empty list if it has less then <code>num</code> elements.
      * @since 1.8.7
      */
-    public static <T> List<T> drop(Iterable<T> self, int num) {
-        return toList(drop(self.iterator(), num));
+    public static <T> Collection<T> drop(Iterable<T> self, int num) {
+        Collection<T> result = createSimilarCollection(self);
+        addAll(result, drop(self.iterator(), num));
+        return result;
     }
 
     /**
@@ -7378,47 +9698,180 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      *         less than <code>num</code> elements.
      * @since 1.8.1
      */
-    public static <K, V> Map<K, V> drop(Map<K, V> self, int num) {
-        if (self.size() <= num) {
-            return createSimilarMap(self);
-        }
-        if (num == 0) {
-            return cloneSimilarMap(self);
+    public static <K, V> Map<K, V> drop(Map<K, V> self, int num) {
+        if (self.size() <= num) {
+            return createSimilarMap(self);
+        }
+        if (num == 0) {
+            return cloneSimilarMap(self);
+        }
+        Map<K, V> ret = createSimilarMap(self);
+        for (K key : self.keySet()) {
+            if (num-- <= 0) {
+                ret.put(key, self.get(key));
+            }
+        }
+        return ret;
+    }
+
+    /**
+     * Drops the given number of elements from the head of this iterator if they are available.
+     * The original iterator is stepped along by <code>num</code> elements.
+     * <pre class="groovyTestCase">
+     * def iteratorCompare( Iterator a, List b ) {
+     *     a.collect { it } == b
+     * }
+     * def iter = [ 1, 2, 3, 4, 5 ].listIterator()
+     * assert iteratorCompare( iter.drop( 0 ), [ 1, 2, 3, 4, 5 ] )
+     * iter = [ 1, 2, 3, 4, 5 ].listIterator()
+     * assert iteratorCompare( iter.drop( 2 ), [ 3, 4, 5 ] )
+     * iter = [ 1, 2, 3, 4, 5 ].listIterator()
+     * assert iteratorCompare( iter.drop( 5 ), [] )
+     * </pre>
+     *
+     * @param self the original iterator
+     * @param num  the number of elements to drop from this iterator
+     * @return The iterator stepped along by <code>num</code> elements if they exist.
+     * @since 1.8.1
+     */
+    public static <T> Iterator<T> drop(Iterator<T> self, int num) {
+        while (num-- > 0 && self.hasNext()) {
+            self.next();
+        }
+        return self;
+    }
+
+    /**
+     * Drops the given number of elements from the tail of this SortedSet.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.dropRight( 0 ) == [ 'a', 'b', 'c' ] as SortedSet
+     * assert strings.dropRight( 2 ) == [ 'a' ] as SortedSet
+     * assert strings.dropRight( 5 ) == [] as SortedSet
+     * </pre>
+     *
+     * @param self the original SortedSet
+     * @param num  the number of elements to drop from this SortedSet
+     * @return a List consisting of all the elements of this SortedSet minus the last <code>num</code> elements,
+     *         or an empty SortedSet if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> dropRight(SortedSet<T> self, int num) {
+        return (SortedSet<T>) dropRight((Iterable<T>) self, num);
+    }
+
+    /**
+     * Drops the given number of elements from the tail of this List.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.dropRight( 0 ) == [ 'a', 'b', 'c' ]
+     * assert strings.dropRight( 2 ) == [ 'a' ]
+     * assert strings.dropRight( 5 ) == []
+     * </pre>
+     *
+     * @param self the original List
+     * @param num  the number of elements to drop from this List
+     * @return a List consisting of all the elements of this List minus the last <code>num</code> elements,
+     *         or an empty List if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> List<T> dropRight(List<T> self, int num) {
+        return (List<T>) dropRight((Iterable<T>) self, num);
+    }
+
+    /**
+     * Drops the given number of elements from the tail of this Iterable.
+     * <pre class="groovyTestCase">
+     * def strings = [ 'a', 'b', 'c' ]
+     * assert strings.dropRight( 0 ) == [ 'a', 'b', 'c' ]
+     * assert strings.dropRight( 2 ) == [ 'a' ]
+     * assert strings.dropRight( 5 ) == []
+     *
+     * class AbcIterable implements Iterable<String> {
+     *     Iterator<String> iterator() { "abc".iterator() }
+     * }
+     * def abc = new AbcIterable()
+     * assert abc.dropRight(0) == ['a', 'b', 'c']
+     * assert abc.dropRight(1) == ['a', 'b']
+     * assert abc.dropRight(3) == []
+     * assert abc.dropRight(5) == []
+     * </pre>
+     *
+     * @param self the original Iterable
+     * @param num  the number of elements to drop from this Iterable
+     * @return a Collection consisting of all the elements of this Iterable minus the last <code>num</code> elements,
+     *         or an empty list if it has less then <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> dropRight(Iterable<T> self, int num) {
+        Collection<T> selfCol = self instanceof Collection ? (Collection<T>) self : toList(self);
+        if (selfCol.size() <= num) {
+            return createSimilarCollection(selfCol, 0);
         }
-        Map<K, V> ret = createSimilarMap(self);
-        for (K key : self.keySet()) {
-            if (num-- <= 0) {
-                ret.put(key, self.get(key));
-            }
+        if (num <= 0) {
+            Collection<T> ret = createSimilarCollection(selfCol, selfCol.size());
+            ret.addAll(selfCol);
+            return ret;
         }
+        Collection<T> ret = createSimilarCollection(selfCol, selfCol.size() - num);
+        ret.addAll(asList((Iterable<T>)selfCol).subList(0, selfCol.size() - num));
         return ret;
     }
 
     /**
-     * Drops the given number of elements from the head of this iterator if they are available.
-     * The original iterator is stepped along by <code>num</code> elements.
+     * Drops the given number of elements from the tail of this Iterator.
      * <pre class="groovyTestCase">
-     * def iteratorCompare( Iterator a, List b ) {
-     *     a.collect { it } == b
-     * }
-     * def iter = [ 1, 2, 3, 4, 5 ].listIterator()
-     * assert iteratorCompare( iter.drop( 0 ), [ 1, 2, 3, 4, 5 ] )
-     * iter = [ 1, 2, 3, 4, 5 ].listIterator()
-     * assert iteratorCompare( iter.drop( 2 ), [ 3, 4, 5 ] )
-     * iter = [ 1, 2, 3, 4, 5 ].listIterator()
-     * assert iteratorCompare( iter.drop( 5 ), [] )
+     * def obliterator = "obliter8".iterator()
+     * assert abc.dropRight(-1) == ['o', 'b', 'l', 'i', 't', 'e', 'r', '8']
+     * assert abc.dropRight(0) == ['o', 'b', 'l', 'i', 't', 'e', 'r', '8']
+     * assert abc.dropRight(1) == ['o', 'b', 'l', 'i', 't', 'e', 'r']
+     * assert abc.dropRight(4) == ['o', 'b', 'l', 'i']
+     * assert abc.dropRight(7) == ['o']
+     * assert abc.dropRight(8) == []
+     * assert abc.dropRight(9) == []
      * </pre>
      *
-     * @param self the original iterator
-     * @param num  the number of elements to drop from this iterator
-     * @return The iterator stepped along by <code>num</code> elements if they exist.
-     * @since 1.8.1
+     * @param self the original Iterator
+     * @param num  the number of elements to drop
+     * @return an Iterator consisting of all the elements of this Iterator minus the last <code>num</code> elements,
+     *         or an empty Iterator if it has less then <code>num</code> elements.
+     * @since 2.4.0
      */
-    public static <T> Iterator<T> drop(Iterator<T> self, int num) {
-        while (num-- > 0 && self.hasNext()) {
-            self.next();
+    public static <T> Iterator<T> dropRight(Iterator<T> self, int num) {
+        List<T> result = dropRight(toList(self), num);
+        return result.listIterator();
+    }
+
+    /**
+     * Drops the given number of elements from the tail of this array
+     * if they are available.
+     * <pre class="groovyTestCase">
+     * String[] strings = [ 'a', 'b', 'c' ]
+     * assert strings.dropRight( 0 ) == [ 'a', 'b', 'c' ] as String[]
+     * assert strings.dropRight( 2 ) == [ 'a' ] as String[]
+     * assert strings.dropRight( 5 ) == [] as String[]
+     * </pre>
+     *
+     * @param self the original array
+     * @param num  the number of elements to drop from this array
+     * @return an array consisting of all elements of this array except the
+     *         last <code>num</code> ones, or else the empty array, if this
+     *         array has less than <code>num</code> elements.
+     * @since 2.4.0
+     */
+    public static <T> T[] dropRight(T[] self, int num) {
+        if (self.length <= num) {
+            return createSimilarArray(self, 0);
         }
-        return self;
+        if (num <= 0) {
+            T[] ret = createSimilarArray(self, self.length);
+            System.arraycopy(self, 0, ret, 0, self.length);
+            return ret;
+        }
+
+        T[] ret = createSimilarArray(self, self.length - num);
+        System.arraycopy(self, 0, ret, 0, self.length - num);
+        return ret;
     }
 
     /**
@@ -7454,7 +9907,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Returns a List containing the longest prefix of the elements from this Iterable
+     * Returns a Collection containing the longest prefix of the elements from this Iterable
      * where each element passed to the given closure evaluates to true.
      * <pre class="groovyTestCase">
      * class AbcIterable implements Iterable<String> {
@@ -7468,12 +9921,37 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @param self      an Iterable
      * @param condition the closure that must evaluate to true to
      *                  continue taking elements
-     * @return a List containing a prefix of the elements from the given Iterable where
+     * @return a Collection containing a prefix of the elements from the given Iterable where
      *         each element passed to the given closure evaluates to true
      * @since 1.8.7
      */
-    public static <T> List<T> takeWhile(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
-        return toList(takeWhile(self.iterator(), condition));
+    public static <T> Collection<T> takeWhile(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        Collection<T> result = createSimilarCollection(self);
+        addAll(result, takeWhile(self.iterator(), condition));
+        return result;
+    }
+
+    /**
+     * Returns the longest prefix of this SortedSet where each element
+     * passed to the given closure condition evaluates to true.
+     * Similar to {@link #takeWhile(Iterable, groovy.lang.Closure)}
+     * except that it attempts to preserve the type of the original SortedSet.
+     * <pre class="groovyTestCase">
+     * def nums = [ 1, 2, 3 ] as SortedSet
+     * assert nums.takeWhile{ it < 1 } == [] as SortedSet
+     * assert nums.takeWhile{ it < 2 } == [ 1 ] as SortedSet
+     * assert nums.takeWhile{ it < 4 } == [ 1, 2, 3 ] as SortedSet
+     * </pre>
+     *
+     * @param self      the original SortedSet
+     * @param condition the closure that must evaluate to true to
+     *                  continue taking elements
+     * @return a prefix of the given SortedSet where each element passed to
+     *         the given closure evaluates to true
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> takeWhile(SortedSet<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure condition) {
+        return (SortedSet<T>) takeWhile((Iterable<T>) self, condition);
     }
 
     /**
@@ -7563,7 +10041,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         return new TakeWhileIterator<T>(self, condition);
     }
 
-    private static class TakeWhileIterator<E> implements Iterator<E> {
+    private static final class TakeWhileIterator<E> implements Iterator<E> {
         private final Iterator<E> delegate;
         private final BooleanClosureWrapper condition;
         private boolean exhausted;
@@ -7604,6 +10082,29 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Returns a suffix of this SortedSet where elements are dropped from the front
+     * while the given Closure evaluates to true.
+     * Similar to {@link #dropWhile(Iterable, groovy.lang.Closure)}
+     * except that it attempts to preserve the type of the original SortedSet.
+     * <pre class="groovyTestCase">
+     * def nums = [ 1, 2, 3 ] as SortedSet
+     * assert nums.dropWhile{ it < 4 } == [] as SortedSet
+     * assert nums.dropWhile{ it < 2 } == [ 2, 3 ] as SortedSet
+     * assert nums.dropWhile{ it != 3 } == [ 3 ] as SortedSet
+     * assert nums.dropWhile{ it == 0 } == [ 1, 2, 3 ] as SortedSet
+     * </pre>
+     *
+     * @param self      the original SortedSet
+     * @param condition the closure that must evaluate to true to continue dropping elements
+     * @return the shortest suffix of the given SortedSet such that the given closure condition
+     *         evaluates to true for each element dropped from the front of the SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> dropWhile(SortedSet<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<?> condition) {
+        return (SortedSet<T>) dropWhile((Iterable<T>) self, condition);
+    }
+
+    /**
      * Returns a suffix of this List where elements are dropped from the front
      * while the given Closure evaluates to true.
      * Similar to {@link #dropWhile(Iterable, groovy.lang.Closure)}
@@ -7639,22 +10140,25 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Returns a suffix of this Iterable where elements are dropped from the front
      * while the given closure evaluates to true.
      * <pre class="groovyTestCase">
-     * class AbcIterable implements Iterable<String> {
-     *     Iterator<String> iterator() { "abc".iterator() }
+     * class HorseIterable implements Iterable<String> {
+     *     Iterator<String> iterator() { "horse".iterator() }
      * }
-     * def abc = new AbcIterable()
-     * assert abc.dropWhile{ it < 'b' } == ['b', 'c']
-     * assert abc.dropWhile{ it <= 'b' } == ['c']
+     * def horse = new HorseIterable()
+     * assert horse.dropWhile{ it < 'r' } == ['r', 's', 'e']
+     * assert horse.dropWhile{ it <= 'r' } == ['s', 'e']
      * </pre>
      *
      * @param self      an Iterable
      * @param condition the closure that must evaluate to true to continue dropping elements
-     * @return the shortest suffix of the given Iterable such that the given closure condition
+     * @return a Collection containing the shortest suffix of the given Iterable such that the given closure condition
      *         evaluates to true for each element dropped from the front of the Iterable
      * @since 1.8.7
      */
-    public static <T> List<T> dropWhile(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<?> condition) {
-        return toList(dropWhile(self.iterator(), condition));
+    public static <T> Collection<T> dropWhile(Iterable<T> self, @ClosureParams(FirstParam.FirstGenericType.class) Closure<?> condition) {
+        Collection<T> selfCol = self instanceof Collection ? (Collection<T>) self : toList(self);
+        Collection<T> result = createSimilarCollection(selfCol);
+        addAll(result, dropWhile(self.iterator(), condition));
+        return result;
     }
 
     /**
@@ -7745,7 +10249,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         return new DropWhileIterator<T>(self, condition);
     }
 
-    private static class DropWhileIterator<E> implements Iterator<E> {
+    private static final class DropWhileIterator<E> implements Iterator<E> {
         private final Iterator<E> delegate;
         private final Closure condition;
         private boolean buffering = false;
@@ -7795,6 +10299,27 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Converts this Iterable to a Collection. Returns the original Iterable
+     * if it is already a Collection.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * assert new HashSet().asCollection() instanceof Collection
+     * </pre>
+     *
+     * @param self an Iterable to be converted into a Collection
+     * @return a newly created List if this Iterable is not already a Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> asCollection(Iterable<T> self) {
+        if (self instanceof Collection) {
+            return (Collection<T>) self;
+        } else {
+            return toList(self);
+        }
+    }
+
+    /**
      * @deprecated Use the Iterable version of asList instead
      * @see #asList(Iterable)
      * @since 1.0
@@ -8066,7 +10591,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
             return (T) col;
         }
         if (clazz == List.class) {
-            return (T) asList(col);
+            return (T) asList((Iterable) col);
         }
         if (clazz == Set.class) {
             if (col instanceof Set) return (T) col;
@@ -8284,7 +10809,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         }
         List<T> items = Arrays.asList(self);
         Collections.reverse(items);
-        System.arraycopy((T[])items.toArray(), 0, self, 0, items.size());
+        System.arraycopy(items.toArray(), 0, self, 0, items.size());
         return self;
     }
 
@@ -8396,6 +10921,22 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a Collection as a union of two iterables. If the left iterable
+     * is a Set, then the returned collection will be a Set otherwise a List.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     * <pre class="groovyTestCase">assert [1,2,3,4] == [1,2] + [3,4]</pre>
+     *
+     * @param left  the left Iterable
+     * @param right the right Iterable
+     * @return the merged Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> plus(Iterable<T> left, Iterable<T> right) {
+        return plus(asCollection(left), asCollection(right));
+    }
+
+    /**
      * Create a Collection as a union of a Collection and an Iterable. If the left collection
      * is a Set, then the returned collection will be a Set otherwise a List.
      * This operation will always create a new object for the result,
@@ -8408,7 +10949,97 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #plus(Collection, Collection)
      */
     public static <T> Collection<T> plus(Collection<T> left, Iterable<T> right) {
-        return plus(left, toList(right));
+        return plus(left, asCollection(right));
+    }
+
+    /**
+     * Create a List as a union of a List and an Iterable.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left List
+     * @param right the right Iterable
+     * @return the merged List
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> List<T> plus(List<T> left, Iterable<T> right) {
+        return (List<T>) plus((Collection<T>) left, asCollection(right));
+    }
+
+    /**
+     * Create a List as a union of a List and an Collection.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left List
+     * @param right the right Collection
+     * @return the merged List
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> List<T> plus(List<T> left, Collection<T> right) {
+        return (List<T>) plus((Collection<T>) left, right);
+    }
+
+    /**
+     * Create a Set as a union of a Set and an Iterable.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left Set
+     * @param right the right Iterable
+     * @return the merged Set
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> Set<T> plus(Set<T> left, Iterable<T> right) {
+        return (Set<T>) plus((Collection<T>) left, asCollection(right));
+    }
+
+    /**
+     * Create a Set as a union of a Set and an Collection.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left Set
+     * @param right the right Collection
+     * @return the merged Set
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> Set<T> plus(Set<T> left, Collection<T> right) {
+        return (Set<T>) plus((Collection<T>) left, right);
+    }
+
+    /**
+     * Create a SortedSet as a union of a SortedSet and an Iterable.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left SortedSet
+     * @param right the right Iterable
+     * @return the merged SortedSet
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> SortedSet<T> plus(SortedSet<T> left, Iterable<T> right) {
+        return (SortedSet<T>) plus((Collection<T>) left, asCollection(right));
+    }
+
+    /**
+     * Create a SortedSet as a union of a SortedSet and an Collection.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     *
+     * @param left  the left SortedSet
+     * @param right the right Collection
+     * @return the merged SortedSet
+     * @since 2.4.0
+     * @see #plus(Collection, Collection)
+     */
+    public static <T> SortedSet<T> plus(SortedSet<T> left, Collection<T> right) {
+        return (SortedSet<T>) plus((Collection<T>) left, right);
     }
 
     /**
@@ -8508,26 +11139,119 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Create a List composed of the elements of this list, repeated
+     * Create a collection as a union of an Iterable and an Object. If the iterable
+     * is a Set, then the returned collection will be a Set otherwise a List.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     * <pre class="groovyTestCase">assert [1,2,3] == [1,2] + 3</pre>
+     *
+     * @param left  an Iterable
+     * @param right an object to add/append
+     * @return the resulting Collection
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> plus(Iterable<T> left, T right) {
+        return plus(asCollection(left), right);
+    }
+
+    /**
+     * Create a List as a union of a List and an Object.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     * <pre class="groovyTestCase">assert [1,2,3] == [1,2] + 3</pre>
+     *
+     * @param left  a List
+     * @param right an object to add/append
+     * @return the resulting List
+     * @since 2.4.0
+     */
+    public static <T> List<T> plus(List<T> left, T right) {
+        return (List<T>) plus((Collection<T>) left, right);
+    }
+
+    /**
+     * Create a Set as a union of a Set and an Object.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     * <pre class="groovyTestCase">assert [1,2,3] == [1,2] + 3</pre>
+     *
+     * @param left  a Set
+     * @param right an object to add/append
+     * @return the resulting Set
+     * @since 2.4.0
+     */
+    public static <T> Set<T> plus(Set<T> left, T right) {
+        return (Set<T>) plus((Collection<T>) left, right);
+    }
+
+    /**
+     * Create a SortedSet as a union of a SortedSet and an Object.
+     * This operation will always create a new object for the result,
+     * while the operands remain unchanged.
+     * <pre class="groovyTestCase">assert [1,2,3] == [1,2] + 3</pre>
+     *
+     * @param left  a SortedSet
+     * @param right an object to add/append
+     * @return the resulting SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> plus(SortedSet<T> left, T right) {
+        return (SortedSet<T>) plus((Collection<T>) left, right);
+    }
+
+    /**
+     * @deprecated use the Iterable variant instead
+     * @see #multiply(Iterable, Number)
+     * @since 1.0
+     */
+    @Deprecated
+    public static <T> Collection<T> multiply(Collection<T> self, Number factor) {
+        return multiply((Iterable<T>) self, factor);
+    }
+
+    /**
+     * Create a Collection composed of the elements of this Iterable, repeated
      * a certain number of times.  Note that for non-primitive
      * elements, multiple references to the same instance will be added.
      * <pre class="groovyTestCase">assert [1,2,3,1,2,3] == [1,2,3] * 2</pre>
      *
-     * @param self   a Collection
+     * Note: if the Iterable happens to not support duplicates, e.g. a Set, then the
+     * method will effectively return a Collection with a single copy of the Iterable's items.
+     *
+     * @param self   an Iterable
      * @param factor the number of times to append
-     * @return the multiplied list
-     * @since 1.0
+     * @return the multiplied Collection
+     * @since 2.4.0
      */
-    public static <T> List<T> multiply(Collection<T> self, Number factor) {
+    public static <T> Collection<T> multiply(Iterable<T> self, Number factor) {
+        Collection<T> selfCol = asCollection(self);
         int size = factor.intValue();
-        List<T> answer = new ArrayList<T>(self.size() * size);
+        Collection<T> answer = createSimilarCollection(selfCol, selfCol.size() * size);
         for (int i = 0; i < size; i++) {
-            answer.addAll(self);
+            answer.addAll(selfCol);
         }
         return answer;
     }
 
     /**
+     * Create a List composed of the elements of this Iterable, repeated
+     * a certain number of times.  Note that for non-primitive
+     * elements, multiple references to the same instance will be added.
+     * <pre class="groovyTestCase">assert [1,2,3,1,2,3] == [1,2,3] * 2</pre>
+     *
+     * Note: if the Iterable happens to not support duplicates, e.g. a Set, then the
+     * method will effectively return a Collection with a single copy of the Iterable's items.
+     *
+     * @param self   an List
+     * @param factor the number of times to append
+     * @return the multiplied List
+     * @since 2.4.0
+     */
+    public static <T> List<T> multiply(List<T> self, Number factor) {
+        return (List<T>) multiply((Iterable<T>) self, factor);
+    }
+
+    /**
      * Create a Collection composed of the intersection of both collections.  Any
      * elements that exist in both collections are added to the resultant collection.
      * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
@@ -8563,6 +11287,62 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a Collection composed of the intersection of both iterables.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+     *
+     * @param left  an Iterable
+     * @param right an Iterable
+     * @return a Collection as an intersection of both iterables
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> intersect(Iterable<T> left, Iterable<T> right) {
+        return intersect(asCollection(left), asCollection(right));
+    }
+
+    /**
+     * Create a List composed of the intersection of a List and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [4,5] == [1,2,3,4,5].intersect([4,5,6,7,8])</pre>
+     *
+     * @param left  a List
+     * @param right an Iterable
+     * @return a List as an intersection of a List and an Iterable
+     * @since 2.4.0
+     */
+    public static <T> List<T> intersect(List<T> left, Iterable<T> right) {
+        return (List<T>) intersect((Collection<T>) left, asCollection(right));
+    }
+
+    /**
+     * Create a Set composed of the intersection of a Set and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [4,5] as Set == ([1,2,3,4,5] as Set).intersect([4,5,6,7,8])</pre>
+     *
+     * @param left  a Set
+     * @param right an Iterable
+     * @return a Set as an intersection of a Set and an Iterable
+     * @since 2.4.0
+     */
+    public static <T> Set<T> intersect(Set<T> left, Iterable<T> right) {
+        return (Set<T>) intersect((Collection<T>) left, asCollection(right));
+    }
+
+    /**
+     * Create a SortedSet composed of the intersection of a SortedSet and an Iterable.  Any
+     * elements that exist in both iterables are added to the resultant collection.
+     * <pre class="groovyTestCase">assert [4,5] as SortedSet == ([1,2,3,4,5] as SortedSet).intersect([4,5,6,7,8])</pre>
+     *
+     * @param left  a SortedSet
+     * @param right an Iterable
+     * @return a Set as an intersection of a SortedSet and an Iterable
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> intersect(SortedSet<T> left, Iterable<T> right) {
+        return (SortedSet<T>) intersect((Collection<T>) left, asCollection(right));
+    }
+
+    /**
      * Create a Map composed of the intersection of both maps.
      * Any entries that exist in both maps are added to the resultant map.
      * <pre class="groovyTestCase">assert [4:4,5:5] == [1:1,2:2,3:3,4:4,5:5].intersect([4:4,5:5,6:6,7:7,8:8])</pre>
@@ -8588,25 +11368,27 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Returns <code>true</code> if the intersection of two collections is empty.
+     * Returns <code>true</code> if the intersection of two iterables is empty.
      * <pre class="groovyTestCase">assert [1,2,3].disjoint([3,4,5]) == false</pre>
      * <pre class="groovyTestCase">assert [1,2].disjoint([3,4]) == true</pre>
      *
-     * @param left  a Collection
-     * @param right a Collection
-     * @return boolean   <code>true</code> if the intersection of two collections
+     * @param left  an Iterable
+     * @param right an Iterable
+     * @return boolean   <code>true</code> if the intersection of two iterables
      *         is empty, <code>false</code> otherwise.
-     * @since 1.0
+     * @since 2.4.0
      */
-    public static boolean disjoint(Collection left, Collection right) {
+    public static boolean disjoint(Iterable left, Iterable right) {
+        Collection leftCol = asCollection(left);
+        Collection rightCol = asCollection(right);
 
-        if (left.isEmpty() || right.isEmpty())
+        if (leftCol.isEmpty() || rightCol.isEmpty())
             return true;
 
         Collection pickFrom = new TreeSet(new NumberAwareComparator());
-        pickFrom.addAll(right);
+        pickFrom.addAll(rightCol);
 
-        for (final Object o : left) {
+        for (final Object o : leftCol) {
             if (pickFrom.contains(o))
                 return false;
         }
@@ -8614,6 +11396,16 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated use the Iterable variant instead
+     * @see #disjoint(Iterable, Iterable)
+     * @since 1.0
+     */
+    @Deprecated
+    public static boolean disjoint(Collection left, Collection right) {
+        return disjoint((Iterable) left, (Iterable) right);
+    }
+
+    /**
      * Compare the contents of this array to the contents of the given array.
      *
      * @param left  an int array
@@ -8872,7 +11664,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.7
      */
     public static <T> Set<T> minus(Set<T> self, Iterable<?> removeMe) {
-        return minus(self, toList(removeMe));
+        return minus(self, asCollection(removeMe));
     }
 
     /**
@@ -8894,10 +11686,48 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Create a SortedSet composed of the elements of the first SortedSet minus the
+     * elements of the given Collection.
+     *
+     * @param self     a SortedSet object
+     * @param removeMe the items to remove from the SortedSet
+     * @return the resulting SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> minus(SortedSet<T> self, Collection<?> removeMe) {
+        return (SortedSet<T>) minus((Set<T>) self, removeMe);
+    }
+
+    /**
+     * Create a SortedSet composed of the elements of the first SortedSet minus the
+     * elements of the given Iterable.
+     *
+     * @param self     a SortedSet object
+     * @param removeMe the items to remove from the SortedSet
+     * @return the resulting SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> minus(SortedSet<T> self, Iterable<?> removeMe) {
+        return (SortedSet<T>) minus((Set<T>) self, removeMe);
+    }
+
+    /**
+     * Create a SortedSet composed of the elements of the first SortedSet minus the given element.
+     *
+     * @param self     a SortedSet object
+     * @param removeMe the element to remove from the SortedSet
+     * @return the resulting SortedSet
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> minus(SortedSet<T> self, Object removeMe) {
+        return (SortedSet<T>) minus((Set<T>) self, removeMe);
+    }
+
+    /**
      * Create an array composed of the elements of the first array minus the
      * elements of the given Iterable.
      *
-     * @param self     an object array
+     * @param self     an array
      * @param removeMe a Collection of elements to remove
      * @return an array with the supplied elements removed
      * @since 1.5.5
@@ -8911,7 +11741,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Create an array composed of the elements of the first array minus the
      * elements of the given array.
      *
-     * @param self     an object array
+     * @param self     an array
      * @param removeMe an array of elements to remove
      * @return an array with the supplied elements removed
      * @since 1.5.5
@@ -8932,9 +11762,24 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static <T> List<T> minus(List<T> self, Collection<?> removeMe) {
+        return (List<T>) minus((Collection<T>) self, removeMe);
+    }
 
+    /**
+     * Create a new Collection composed of the elements of the first Collection minus
+     * every occurrence of elements of the given Collection.
+     * <pre class="groovyTestCase">assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]</pre>
+     *
+     * @param self     a Collection
+     * @param removeMe a Collection of elements to remove
+     * @return a Collection with the given elements removed
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> minus(Collection<T> self, Collection<?> removeMe) {
+        Collection<T> ansCollection = createSimilarCollection(self);
         if (self.size() == 0)
-            return new ArrayList<T>();
+            return ansCollection;
+        T head = self.iterator().next();
 
         boolean nlgnSort = sameType(new Collection[]{self, removeMe});
 
@@ -8944,10 +11789,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
         Comparator<T> numberComparator = new NumberAwareComparator<T>();
 
-        if (nlgnSort && (self.get(0) instanceof Comparable)) {
+        if (nlgnSort && (head instanceof Comparable)) {
             //n*LOG(n) version
             Set<T> answer;
-            if (Number.class.isInstance(self.get(0))) {
+            if (Number.class.isInstance(head)) {
                 answer = new TreeSet<T>(numberComparator);
                 answer.addAll(self);
                 for (T t : self) {
@@ -8969,12 +11814,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                 answer.removeAll(removeMe);
             }
 
-            List<T> ansList = new ArrayList<T>();
             for (T o : self) {
                 if (answer.contains(o))
-                    ansList.add(o);
+                    ansCollection.add(o);
             }
-            return ansList;
         } else {
             //n*n version
             List<T> tmpAnswer = new LinkedList<T>(self);
@@ -8983,7 +11826,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                 boolean elementRemoved = false;
                 for (Iterator<?> iterator = removeMe.iterator(); iterator.hasNext() && !elementRemoved;) {
                     Object elt = iterator.next();
-                    if (numberComparator.compare(element, (T)elt) == 0) {
+                    if (DefaultTypeTransformation.compareEqual(element, elt)) {
                         iter.remove();
                         elementRemoved = true;
                     }
@@ -8992,41 +11835,67 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
             //remove duplicates
             //can't use treeset since the base classes are different
-            return new ArrayList<T>(tmpAnswer);
+            ansCollection.addAll(tmpAnswer);
         }
+        return ansCollection;
     }
 
     /**
-     * Create a List composed of the elements of the first list minus
+     * Create a new List composed of the elements of the first List minus
      * every occurrence of elements of the given Iterable.
-     * <pre class="groovyTestCase">
-     * class AbcIterable implements Iterable<String> {
-     *     Iterator<String> iterator() { "abc".iterator() }
-     * }
-     * assert "backtrack".toList() - new AbcIterable() == ["k", "t", "r", "k"]
-     * </pre>
+     * <pre class="groovyTestCase">assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]</pre>
      *
      * @param self     a List
-     * @param removeMe an Iterable of elements to remove
-     * @return a List with the supplied elements removed
+     * @param removeMe a Iterable of elements to remove
+     * @return a new List with the given elements removed
      * @since 1.8.7
      */
     public static <T> List<T> minus(List<T> self, Iterable<?> removeMe) {
-        return minus(self, toList(removeMe));
+        return (List<T>) minus((Iterable<T>) self, removeMe);
     }
 
     /**
-     * Create a new List composed of the elements of the first list minus every occurrence of the
+     * Create a new Collection composed of the elements of the first Iterable minus
+     * every occurrence of elements of the given Iterable.
+     * <pre class="groovyTestCase">
+     * assert [1, "a", true, true, false, 5.3] - [true, 5.3] == [1, "a", false]
+     * </pre>
+     *
+     * @param self     an Iterable
+     * @param removeMe an Iterable of elements to remove
+     * @return a new Collection with the given elements removed
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> minus(Iterable<T> self, Iterable<?> removeMe) {
+        return minus(asCollection(self), asCollection(removeMe));
+    }
+
+    /**
+     * Create a new List composed of the elements of the first List minus every occurrence of the
      * given element to remove.
      * <pre class="groovyTestCase">assert ["a", 5, 5, true] - 5 == ["a", true]</pre>
      *
      * @param self     a List object
-     * @param removeMe an element to remove from the list
+     * @param removeMe an element to remove from the List
      * @return the resulting List with the given element removed
      * @since 1.0
      */
     public static <T> List<T> minus(List<T> self, Object removeMe) {
-        List<T> ansList = new ArrayList<T>();
+        return (List<T>) minus((Iterable<T>) self, removeMe);
+    }
+
+    /**
+     * Create a new Collection composed of the elements of the first Iterable minus every occurrence of the
+     * given element to remove.
+     * <pre class="groovyTestCase">assert ["a", 5, 5, true] - 5 == ["a", true]</pre>
+     *
+     * @param self     an Iterable object
+     * @param removeMe an element to remove from the Iterable
+     * @return the resulting Collection with the given element removed
+     * @since 2.4.0
+     */
+    public static <T> Collection<T> minus(Iterable<T> self, Object removeMe) {
+        Collection<T> ansList = createSimilarCollection(self);
         for (T t : self) {
             if (!coercedEquals(t, removeMe)) ansList.add(t);
         }
@@ -9037,14 +11906,14 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Create a new object array composed of the elements of the first array
      * minus the element to remove.
      *
-     * @param self    an object array
+     * @param self    an array
      * @param removeMe an element to remove from the array
      * @return a new array with the operand removed
      * @since 1.5.5
      */
     @SuppressWarnings("unchecked")
     public static <T> T[] minus(T[] self, Object removeMe) {
-        return (T[]) minus(toList(self), removeMe).toArray();
+        return (T[]) minus((Iterable<T>) toList(self), removeMe).toArray();
     }
 
     /**
@@ -9072,7 +11941,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Flatten a collection.  This collection and any nested arrays or
+     * Flatten a Collection.  This Collection and any nested arrays or
      * collections have their contents (recursively) added to the new collection.
      * <pre class="groovyTestCase">assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()</pre>
      *
@@ -9094,7 +11963,46 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static Collection<?> flatten(Iterable<?> self) {
-        return flatten(self, createSimilarCollection(asList(self)));
+        return flatten(self, createSimilarCollection(self));
+    }
+
+    /**
+     * Flatten a List.  This List and any nested arrays or
+     * collections have their contents (recursively) added to the new List.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] == [1,[2,3],[[4]],[],5].flatten()</pre>
+     *
+     * @param self a List to flatten
+     * @return a flattened List
+     * @since 2.4.0
+     */
+    public static List<?> flatten(List<?> self) {
+        return (List<?>) flatten((Collection<?>) self);
+    }
+
+    /**
+     * Flatten a Set.  This Set and any nested arrays or
+     * collections have their contents (recursively) added to the new Set.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] as Set == ([1,[2,3],[[4]],[],5] as Set).flatten()</pre>
+     *
+     * @param self a Set to flatten
+     * @return a flattened Set
+     * @since 2.4.0
+     */
+    public static Set<?> flatten(Set<?> self) {
+        return (Set<?>) flatten((Collection<?>) self);
+    }
+
+    /**
+     * Flatten a SortedSet.  This SortedSet and any nested arrays or
+     * collections have their contents (recursively) added to the new SortedSet.
+     * <pre class="groovyTestCase">assert [1,2,3,4,5] as SortedSet == ([1,[2,3],[[4]],[],5] as SortedSet).flatten()</pre>
+     *
+     * @param self a SortedSet to flatten
+     * @return a flattened SortedSet
+     * @since 2.4.0
+     */
+    public static SortedSet<?> flatten(SortedSet<?> self) {
+        return (SortedSet<?>) flatten((Collection<?>) self);
     }
 
     /**
@@ -9220,17 +12128,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Flatten a collection.  This collection and any nested arrays or
-     * collections have their contents (recursively) added to the new collection.
-     * For any non-Array, non-Collection object which represents some sort
-     * of collective type, the supplied closure should yield the contained items;
-     * otherwise, the closure should just return any element which corresponds to a leaf.
-     *
-     * @param self a Collection
-     * @param flattenUsing a closure to determine how to flatten non-Array, non-Collection elements
-     * @return a flattened Collection
+     * @deprecated Use the Iterable version of flatten instead
+     * @see #flatten(Iterable, Closure)
      * @since 1.6.0
      */
+    @Deprecated
     public static <T> Collection<T> flatten(Collection<T> self, Closure<? extends T> flattenUsing) {
         return flatten(self, createSimilarCollection(self), flattenUsing);
     }
@@ -9248,7 +12150,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.6.0
      */
     public static <T> Collection<T> flatten(Iterable<T> self, Closure<? extends T> flattenUsing) {
-        return flatten(self, createSimilarCollection(asList(self)), flattenUsing);
+        return flatten(self, createSimilarCollection(self), flattenUsing);
     }
 
     private static <T> Collection<T> flatten(Iterable elements, Collection<T> addTo, Closure<? extends T> flattenUsing) {
@@ -9261,7 +12163,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                 T flattened = flattenUsing.call(new Object[]{element});
                 boolean returnedSelf = flattened == element;
                 if (!returnedSelf && flattened instanceof Collection) {
-                    List<?> list = toList((Collection<?>) flattened);
+                    List<?> list = toList((Iterable<?>) flattened);
                     if (list.size() == 1 && list.get(0) == element) {
                         returnedSelf = true;
                     }
@@ -9280,7 +12182,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
      * Overloads the left shift operator to provide an easy way to append
      * objects to a Collection.
      * <pre class="groovyTestCase">def list = [1,2]
-     * list << 3
+     * list << 3
      * assert list == [1,2,3]</pre>
      *
      * @param self  a Collection
@@ -9295,10 +12197,58 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
     /**
      * Overloads the left shift operator to provide an easy way to append
+     * objects to a List.
+     * <pre class="groovyTestCase">def list = [1,2]
+     * list << 3
+     * assert list == [1,2,3]</pre>
+     *
+     * @param self  a List
+     * @param value an Object to be added to the List.
+     * @return same List, after the value was added to it.
+     * @since 2.4.0
+     */
+    public static <T> List<T> leftShift(List<T> self, T value) {
+        return (List<T>) leftShift((Collection<T>) self, value);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append
+     * objects to a Set.
+     * <pre class="groovyTestCase">def set = [1,2] as Set
+     * set << 3
+     * assert set == [1,2,3] as Set</pre>
+     *
+     * @param self  a Set
+     * @param value an Object to be added to the Set.
+     * @return same Set, after the value was added to it.
+     * @since 2.4.0
+     */
+    public static <T> Set<T> leftShift(Set<T> self, T value) {
+        return (Set<T>) leftShift((Collection<T>) self, value);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append
+     * objects to a SortedSet.
+     * <pre class="groovyTestCase">def set = [1,2] as SortedSet
+     * set << 3
+     * assert set == [1,2,3] as SortedSet</pre>
+     *
+     * @param self  a SortedSet
+     * @param value an Object to be added to the SortedSet.
+     * @return same SortedSet, after the value was added to it.
+     * @since 2.4.0
+     */
+    public static <T> SortedSet<T> leftShift(SortedSet<T> self, T value) {
+        return (SortedSet<T>) leftShift((Collection<T>) self, value);
+    }
+
+    /**
+     * Overloads the left shift operator to provide an easy way to append
      * objects to a BlockingQueue.
      * In case of bounded queue the method will block till space in the queue become available
      * <pre class="groovyTestCase">def list = new java.util.concurrent.LinkedBlockingQueue ()
-     * list << 3 << 2 << 1
+     * list << 3 << 2 << 1
      * assert list.iterator().collect{it} == [3,2,1]</pre>
      *
      * @param self  a Collection
@@ -9328,11 +12278,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     /**
      * Overloads the left shift operator to provide an easy way to put
      * one maps entries into another map. This allows the compact syntax
-     * <code>map1 << map2</code>; otherwise it's just a synonym for
+     * <code>map1 << map2</code>; otherwise it's just a synonym for
      * <code>putAll</code> though it returns the original map rather than
      * being a <code>void</code> method. Example usage:
      * <pre class="groovyTestCase">def map = [a:1, b:2]
-     * map << [c:3, d:4]
+     * map << [c:3, d:4]
      * assert map == [a:1, b:2, c:3, d:4]</pre>
      *
      * @param self  a Map
@@ -10272,6 +13222,25 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Convert an Iterable to a Set. Always returns a new Set
+     * even if the Iterable is already a Set.
+     * <p>
+     * Example usage:
+     * <pre class="groovyTestCase">
+     * def result = [1, 2, 2, 2, 3].toSet()
+     * assert result instanceof Set
+     * assert result == [1, 2, 3] as Set
+     * </pre>
+     *
+     * @param self an Iterable
+     * @return a Set
+     * @since 2.4.0
+     */
+    public static <T> Set<T> toSet(Iterable<T> self) {
+        return toSet(self.iterator());
+    }
+
+    /**
      * Convert an iterator to a Set. The iterator will become
      * exhausted of elements after making this conversion.
      *
@@ -10990,7 +13959,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Power of a Number to a certain exponent.  Called by the '**' operator.
+     * Power of a Number to a certain exponent. Called by the '**' operator.
      *
      * @param self     a Number
      * @param exponent a Number exponent
@@ -11013,7 +13982,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Power of a BigDecimal to an integer certain exponent.  If the
+     * Power of a BigDecimal to an integer certain exponent. If the
      * exponent is positive, call the BigDecimal.pow(int) method to
      * maintain precision. Called by the '**' operator.
      *
@@ -11030,7 +13999,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Power of a BigInteger to an integer certain exponent.  If the
+     * Power of a BigInteger to an integer certain exponent. If the
      * exponent is positive, call the BigInteger.pow(int) method to
      * maintain precision. Called by the '**' operator.
      *
@@ -11047,7 +14016,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Power of an integer to an integer certain exponent.  If the
+     * Power of an integer to an integer certain exponent. If the
      * exponent is positive, convert to a BigInteger and call
      * BigInteger.pow(int) method to maintain precision. Called by the
      * '**' operator.
@@ -11070,7 +14039,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Power of a long to an integer certain exponent.  If the
+     * Power of a long to an integer certain exponent. If the
      * exponent is positive, convert to a BigInteger and call
      * BigInteger.pow(int) method to maintain precision. Called by the
      * '**' operator.
@@ -11093,6 +14062,23 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Power of a BigInteger to an BigInteger certain exponent. Called by the
+     * '**' operator.
+     *
+     * @param self     a BigInteger
+     * @param exponent an BigInteger exponent
+     * @return a BigInteger to the power of a the exponent
+     * @since 2.3.8
+     */
+    public static BigInteger power(BigInteger self, BigInteger exponent) {
+        if ((exponent.signum() >= 0) && (exponent.compareTo(BI_INT_MAX) <= 0)) {
+            return self.pow(exponent.intValue());
+        } else {
+            return BigDecimal.valueOf(Math.pow(self.doubleValue(), exponent.doubleValue())).toBigInteger();
+        }
+    }
+
+    /**
      * Divide a Character by a Number. The ordinal value of the Character
      * is used in the division (the ordinal value is the unicode
      * value which for simple character sets is the ASCII value).
@@ -11281,7 +14267,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Bitwise XOR together two Numbers.  Called when the '|' operator is used.
+     * Bitwise XOR together two Numbers.  Called when the '^' operator is used.
      *
      * @param left  a Number
      * @param right another Number to bitwse XOR
@@ -11515,8 +14501,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i);
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to upto() cannot be less than the value (" + self + ") it's called on.");
+                throw new GroovyRuntimeException(
+                        MessageFormat.format(
+                                "The argument ({0}) to upto() cannot be less than the value ({1}) it''s called on.",
+                                to, self));
         } else if (to instanceof BigInteger) {
             final BigInteger one = BigInteger.valueOf(1);
             BigInteger to1 = (BigInteger) to;
@@ -11525,8 +14513,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i);
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to upto() cannot be less than the value (" + self + ") it's called on.");
+                throw new GroovyRuntimeException(
+                        MessageFormat.format("The argument ({0}) to upto() cannot be less than the value ({1}) it''s called on.",
+                                to, self));
         } else {
             final BigInteger one = BigInteger.valueOf(1);
             BigInteger to1 = new BigInteger(to.toString());
@@ -11535,8 +14524,9 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i);
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to upto() cannot be less than the value (" + self + ") it's called on.");
+                throw new GroovyRuntimeException(MessageFormat.format(
+                        "The argument ({0}) to upto() cannot be less than the value ({1}) it''s called on.",
+                        to, self));
         }
     }
 
@@ -11741,8 +14731,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i.toBigInteger());
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to downto() cannot be greater than the value (" + self + ") it's called on.");        } else if (to instanceof BigInteger) {
+                throw new GroovyRuntimeException(
+                        MessageFormat.format(
+                                "The argument ({0}) to downto() cannot be greater than the value ({1}) it''s called on.",
+                                to, self));
+        } else if (to instanceof BigInteger) {
             final BigInteger one = BigInteger.valueOf(1);
             final BigInteger to1 = (BigInteger) to;
             if (self.compareTo(to1) >= 0) {
@@ -11750,8 +14743,11 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i);
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to downto() cannot be greater than the value (" + self + ") it's called on.");        } else {
+                throw new GroovyRuntimeException(
+                        MessageFormat.format(
+                                "The argument ({0}) to downto() cannot be greater than the value ({1}) it''s called on.",
+                                to, self));
+        } else {
             final BigInteger one = BigInteger.valueOf(1);
             final BigInteger to1 = new BigInteger(to.toString());
             if (self.compareTo(to1) >= 0) {
@@ -11759,8 +14755,10 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
                     closure.call(i);
                 }
             } else
-                throw new GroovyRuntimeException("The argument (" + to + 
-                        ") to downto() cannot be greater than the value (" + self + ") it's called on.");        }
+                throw new GroovyRuntimeException(
+                        MessageFormat.format("The argument ({0}) to downto() cannot be greater than the value ({1}) it''s called on.",
+                                to, self));
+        }
     }
 
     /**
@@ -12704,7 +15702,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
             metaClass = ((HandleMetaClass)metaClass).getAdaptee();
 
         if (self instanceof Class) {
-            ((MetaClassRegistryImpl)GroovySystem.getMetaClassRegistry()).setMetaClass((Class) self, metaClass);
+            GroovySystem.getMetaClassRegistry().setMetaClass((Class) self, metaClass);
         } else {
             ((MetaClassRegistryImpl)GroovySystem.getMetaClassRegistry()).setMetaClass(self, metaClass);
         }
@@ -13100,12 +16098,12 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
 
     @Deprecated
     public static String eachMatch(CharSequence self, CharSequence regex, Closure closure) {
-        return StringGroovyMethods.eachMatch(self, regex, closure);
+        return (String) StringGroovyMethods.eachMatch(self, regex, closure);
     }
 
     @Deprecated
     public static String eachMatch(CharSequence self, Pattern pattern, Closure closure) {
-        return StringGroovyMethods.eachMatch(self, pattern, closure);
+        return (String) StringGroovyMethods.eachMatch(self, pattern, closure);
     }
 
     @Deprecated
@@ -13189,7 +16187,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static List<CharSequence> findAll(CharSequence self, CharSequence regex) {
+    public static List<String> findAll(CharSequence self, CharSequence regex) {
         return StringGroovyMethods.findAll(self, regex);
     }
 
@@ -13199,7 +16197,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static List<CharSequence> findAll(CharSequence self, Pattern pattern) {
+    public static List<String> findAll(CharSequence self, Pattern pattern) {
         return StringGroovyMethods.findAll(self, pattern);
     }
 
@@ -13564,7 +16562,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static List<CharSequence> readLines(CharSequence self) throws IOException {
+    public static List<String> readLines(CharSequence self) throws IOException {
         return StringGroovyMethods.readLines(self);
     }
 
@@ -13824,17 +16822,17 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static List<CharSequence> tokenize(CharSequence self) {
+    public static List<String> tokenize(CharSequence self) {
         return StringGroovyMethods.tokenize(self);
     }
 
     @Deprecated
-    public static List<CharSequence> tokenize(CharSequence self, Character token) {
+    public static List<String> tokenize(CharSequence self, Character token) {
         return StringGroovyMethods.tokenize(self, token);
     }
 
     @Deprecated
-    public static List<CharSequence> tokenize(CharSequence self, CharSequence token) {
+    public static List<String> tokenize(CharSequence self, CharSequence token) {
         return StringGroovyMethods.tokenize(self, token);
     }
 
@@ -13856,7 +16854,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static List<CharSequence> toList(CharSequence self) {
+    public static List<String> toList(CharSequence self) {
         return StringGroovyMethods.toList(self);
     }
 
@@ -13876,7 +16874,7 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     @Deprecated
-    public static Set<CharSequence> toSet(CharSequence self) {
+    public static Set<String> toSet(CharSequence self) {
         return StringGroovyMethods.toSet(self);
     }
 
@@ -14912,4 +17910,255 @@ public class DefaultGroovyMethods extends DefaultGroovyMethodsSupport {
         Collections.addAll(interfaces, traits);
         return ProxyGenerator.INSTANCE.instantiateDelegate(interfaces, self);
     }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert [1, 3, 2, 4] == [1, 2, 3, 4].swap(1, 2)
+     * </pre>
+     *
+     * @param self a List
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @see Collections#swap(List, int, int)
+     * @since 2.4.0
+     */
+    public static <T> List<T> swap(List<T> self, int i, int j) {
+        Collections.swap(self, i, j);
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert (["a", "c", "b", "d"] as String[]) == (["a", "b", "c", "d"] as String[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self an array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static <T> T[] swap(T[] self, int i, int j) {
+        T tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([false, true, false, true] as boolean[]) == ([false, false, true, true] as boolean[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static boolean[] swap(boolean[] self, int i, int j) {
+        boolean tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as byte[]) == ([1, 2, 3, 4] as byte[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static byte[] swap(byte[] self, int i, int j) {
+        byte tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as char[]) == ([1, 2, 3, 4] as char[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static char[] swap(char[] self, int i, int j) {
+        char tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as double[]) == ([1, 2, 3, 4] as double[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static double[] swap(double[] self, int i, int j) {
+        double tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as float[]) == ([1, 2, 3, 4] as float[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static float[] swap(float[] self, int i, int j) {
+        float tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as int[]) == ([1, 2, 3, 4] as int[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static int[] swap(int[] self, int i, int j) {
+        int tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as long[]) == ([1, 2, 3, 4] as long[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static long[] swap(long[] self, int i, int j) {
+        long tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Swaps two elements at the specified positions.
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * assert ([1, 3, 2, 4] as short[]) == ([1, 2, 3, 4] as short[]).swap(1, 2)
+     * </pre>
+     *
+     * @param self a boolean array
+     * @param i a position
+     * @param j a position
+     * @return self
+     * @since 2.4.0
+     */
+    public static short[] swap(short[] self, int i, int j) {
+        short tmp = self[i];
+        self[i] = self[j];
+        self[j] = tmp;
+        return self;
+    }
+
+    /**
+     * Modifies this list by removing the element at the specified position
+     * in this list. Returns the removed element. Essentially an alias for
+     * {@link List#remove(int)} but with no ambiguity for List<Integer>.
+     * <p/>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def list = [1, 2, 3]
+     * list.removeAt(1)
+     * assert [1, 3] == list
+     * </pre>
+     *
+     * @param self a List
+     * @param index the index of the element to be removed
+     * @return the element previously at the specified position
+     * @since 2.4.0
+     */
+    public static <E> E removeAt(List<E> self, int index) {
+        return self.remove(index);
+    }
+
+    /**
+     * Modifies this collection by removing a single instance of the specified
+     * element from this collection, if it is present. Essentially an alias for
+     * {@link Collection#remove(Object)} but with no ambiguity for Collection<Integer>.
+     * <p/>
+     * Example:
+     * <pre class="groovyTestCase">
+     * def list = [1, 2, 3, 2]
+     * list.removeElement(2)
+     * assert [1, 3, 2] == list
+     * </pre>
+     *
+     * @param self a Collection
+     * @param o element to be removed from this collection, if present
+     * @return true if an element was removed as a result of this call
+     * @since 2.4.0
+     */
+    public static <E> boolean removeElement(Collection<E> self, Object o) {
+        return self.remove(o);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
index 155b52e..6cfdc91 100644
--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
+++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyMethodsSupport.java
@@ -32,6 +32,7 @@ import java.util.logging.Logger;
 public class DefaultGroovyMethodsSupport {
 
     private static final Logger LOG = Logger.getLogger(DefaultGroovyMethodsSupport.class.getName());
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
 
     // helper method for getAt and putAt
     protected static RangeInfo subListBorders(int size, Range range) {
@@ -119,7 +120,7 @@ public class DefaultGroovyMethodsSupport {
     private static Object cloneObject(Object orig) {
         if (orig instanceof Cloneable) {
             try {
-                return InvokerHelper.invokeMethod(orig, "clone", new Object[0]);
+                return InvokerHelper.invokeMethod(orig, "clone", EMPTY_OBJECT_ARRAY);
             } catch (Exception ex) {
                 // ignore
             }
@@ -134,6 +135,14 @@ public class DefaultGroovyMethodsSupport {
         return new ArrayList();
     }
 
+    protected static <T> Collection<T> createSimilarCollection(Iterable<T> iterable) {
+        if (iterable instanceof Collection) {
+            return createSimilarCollection((Collection<T>) iterable);
+        } else {
+            return new ArrayList<T>();
+        }
+    }
+
     protected static <T> Collection<T> createSimilarCollection(Collection<T> collection) {
         return createSimilarCollection(collection, collection.size());
     }
diff --git a/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java b/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
index a7d59ba..fbed08b 100644
--- a/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/DefaultGroovyStaticMethods.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -24,6 +24,7 @@ import java.text.SimpleDateFormat;
 import java.util.Date;
 import java.util.ResourceBundle;
 import java.util.Locale;
+import java.util.TimeZone;
 import java.util.regex.Matcher;
 
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation;
@@ -38,7 +39,7 @@ import org.codehaus.groovy.reflection.ReflectionUtils;
  * @author Dierk Koenig
  * @author Joachim Baumann
  * @author Paul King
- * @version $Revision$
+ * @author Kent Inge Fagerland Simonsen
  */
 public class DefaultGroovyStaticMethods {
 
@@ -184,6 +185,28 @@ public class DefaultGroovyStaticMethods {
     }
 
     /**
+     * Parse a String into a Date instance using the given pattern and TimeZone.
+     * This convenience method acts as a wrapper for {@link java.text.SimpleDateFormat}.
+     * <p>
+     * Note that a new SimpleDateFormat instance is created for every
+     * invocation of this method (for thread safety).
+     *
+     * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+     * @param format pattern used to parse the input string.
+     * @param input  String to be parsed to create the date instance
+     * @param zone   TimeZone to use when parsing
+     * @return a new Date instance representing the parsed input string
+     * @throws ParseException if there is a parse error
+     * @see java.text.SimpleDateFormat#parse(java.lang.String)
+     * @since 2.4.1
+     */
+    public static Date parse(Date self, String format, String input, TimeZone zone) throws ParseException {
+        SimpleDateFormat sdf = new SimpleDateFormat(format);
+        sdf.setTimeZone(zone);
+        return sdf.parse(input);
+    }
+
+    /**
      * Parse a String matching the pattern EEE MMM dd HH:mm:ss zzz yyyy
      * containing US-locale-constants only (e.g. Sat for Saturdays).
      * Such a string is generated by the toString method of {@link java.util.Date}
@@ -274,4 +297,16 @@ public class DefaultGroovyStaticMethods {
         return tempFile;
     }
 
+  /**
+   * Get the current time in seconds
+   *
+   * @param self   placeholder variable used by Groovy categories; ignored for default static methods
+   * @return  the difference, measured in seconds, between
+   *          the current time and midnight, January 1, 1970 UTC.
+   * @see     System#currentTimeMillis()
+   */
+  public static long currentTimeSeconds(System self){
+    return System.currentTimeMillis() / 1000;
+  }
+
 }
diff --git a/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
index 34c9e1f..c4543fb 100644
--- a/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/IOGroovyMethods.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -19,13 +19,31 @@ import groovy.io.GroovyPrintWriter;
 import groovy.lang.Closure;
 import groovy.lang.StringWriterIOException;
 import groovy.lang.Writable;
-
 import groovy.transform.stc.ClosureParams;
+import groovy.transform.stc.FirstParam;
 import groovy.transform.stc.FromString;
 import groovy.transform.stc.SimpleType;
 import org.codehaus.groovy.runtime.callsite.BooleanClosureWrapper;
 
-import java.io.*;
+import java.io.BufferedReader;
+import java.io.BufferedWriter;
+import java.io.ByteArrayOutputStream;
+import java.io.Closeable;
+import java.io.DataInputStream;
+import java.io.EOFException;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.InputStreamReader;
+import java.io.ObjectInputStream;
+import java.io.ObjectOutputStream;
+import java.io.ObjectStreamClass;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.io.PrintWriter;
+import java.io.Reader;
+import java.io.StringWriter;
+import java.io.UnsupportedEncodingException;
+import java.io.Writer;
 import java.util.Arrays;
 import java.util.Formatter;
 import java.util.Iterator;
@@ -1181,7 +1199,7 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws IOException if an IOException occurs.
      * @since 1.5.2
      */
-    public static <T> T withStream(InputStream stream, @ClosureParams(value=SimpleType.class, options="java.io.InputStream") Closure<T> closure) throws IOException {
+    public static <T, U extends InputStream> T withStream(U stream, @ClosureParams(value=FirstParam.class) Closure<T> closure) throws IOException {
         try {
             T result = closure.call(stream);
 
@@ -1293,7 +1311,7 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws IOException if an IOException occurs.
      * @since 1.5.2
      */
-    public static <T> T withStream(OutputStream os, @ClosureParams(value=SimpleType.class, options="java.io.OutputStream") Closure<T> closure) throws IOException {
+    public static <T, U extends OutputStream> T withStream(U os, @ClosureParams(value=FirstParam.class) Closure<T> closure) throws IOException {
         try {
             T result = closure.call(os);
             os.flush();
@@ -1586,4 +1604,28 @@ public class IOGroovyMethods extends DefaultGroovyMethodsSupport {
         filterLine(newReader(self, charset), writer, predicate);
     }
 
+    /**
+     * Allows this closeable to be used within the closure, ensuring that it
+     * is closed once the closure has been executed and before this method returns.
+     *
+     * @param self the Closeable
+     * @param action the closure taking the Closeable as parameter
+     * @return the value returned by the closure
+     * @throws IOException if an IOException occurs.
+     * @since 2.4.0
+     */
+    public static <T, U extends Closeable> T withCloseable(U self, @ClosureParams(value=FirstParam.class) Closure<T> action) throws IOException {
+        try {
+            T result = action.call(self);
+
+            Closeable temp = self;
+            self = null;
+            temp.close();
+
+            return result;
+        } finally {
+            DefaultGroovyMethodsSupport.closeWithWarning(self);
+        }
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/runtime/InvokerHelper.java b/src/main/org/codehaus/groovy/runtime/InvokerHelper.java
index e7f88d4..f0e640a 100644
--- a/src/main/org/codehaus/groovy/runtime/InvokerHelper.java
+++ b/src/main/org/codehaus/groovy/runtime/InvokerHelper.java
@@ -30,6 +30,7 @@ import java.io.InputStreamReader;
 import java.io.Reader;
 import java.io.StringWriter;
 import java.io.Writer;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
 import java.math.BigDecimal;
@@ -406,29 +407,42 @@ public class InvokerHelper {
         return invokeMethod(script, "run", EMPTY_ARGS);
     }
 
+    static class NullScript extends Script {
+        public NullScript() { this(new Binding()); }
+        public NullScript(Binding context) { super(context); }
+        public Object run() { return null; }
+    }
+
     public static Script createScript(Class scriptClass, Binding context) {
-        Script script = null;
-        // for empty scripts
+        Script script;
+
         if (scriptClass == null) {
-            script = new Script() {
-                public Object run() {
-                    return null;
-                }
-            };
+            script = new NullScript(context);
         } else {
             try {
-                final GroovyObject object = (GroovyObject) scriptClass.newInstance();
-                if (object instanceof Script) {
-                    script = (Script) object;
+                if (Script.class.isAssignableFrom(scriptClass)) {
+                    try {
+                        Constructor constructor = scriptClass.getConstructor(Binding.class);
+                        script = (Script) constructor.newInstance(context);
+                    } catch (NoSuchMethodException e) {
+                        // Fallback for non-standard "Script" classes.
+                        script = (Script) scriptClass.newInstance();
+                        script.setBinding(context);
+                    }
                 } else {
+                    final GroovyObject object = (GroovyObject) scriptClass.newInstance();
                     // it could just be a class, so let's wrap it in a Script
                     // wrapper; though the bindings will be ignored
-                    script = new Script() {
+                    script = new Script(context) {
                         public Object run() {
-                            Object args = getBinding().getVariables().get("args");
                             Object argsToPass = EMPTY_MAIN_ARGS;
-                            if (args != null && args instanceof String[]) {
-                                argsToPass = args;
+                            try {
+                                Object args = getProperty("args");
+                                if (args instanceof String[]) {
+                                    argsToPass = args;
+                                }
+                            } catch (MissingPropertyException e) {
+                                // They'll get empty args since none exist in the context.
                             }
                             object.invokeMethod("main", argsToPass);
                             return null;
@@ -449,7 +463,6 @@ public class InvokerHelper {
                                 + scriptClass + ". Reason: " + e, e);
             }
         }
-        script.setBinding(context);
         return script;
     }
 
diff --git a/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java b/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
index 0654b66..8abaa18 100644
--- a/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
+++ b/src/main/org/codehaus/groovy/runtime/MetaClassHelper.java
@@ -707,9 +707,11 @@ public class MetaClassHelper {
     }
 
     public static boolean isAssignableFrom(Class classToTransformTo, Class classToTransformFrom) {
-        if (classToTransformTo == classToTransformFrom) return true;
-        if (classToTransformFrom == null) return true;
-        if (classToTransformTo == Object.class) return true;
+        if (classToTransformTo == classToTransformFrom
+                || classToTransformFrom == null
+                || classToTransformTo == Object.class) {
+            return true;
+        }
 
         classToTransformTo = ReflectionCache.autoboxType(classToTransformTo);
         classToTransformFrom = ReflectionCache.autoboxType(classToTransformFrom);
@@ -717,14 +719,12 @@ public class MetaClassHelper {
 
         // note: there is no coercion for boolean and char. Range matters, precision doesn't
         if (classToTransformTo == Integer.class) {
-            if (classToTransformFrom == Integer.class
-                    || classToTransformFrom == Short.class
+            if (classToTransformFrom == Short.class
                     || classToTransformFrom == Byte.class
                     || classToTransformFrom == BigInteger.class)
                 return true;
         } else if (classToTransformTo == Double.class) {
-            if (classToTransformFrom == Double.class
-                    || classToTransformFrom == Integer.class
+            if (classToTransformFrom == Integer.class
                     || classToTransformFrom == Long.class
                     || classToTransformFrom == Short.class
                     || classToTransformFrom == Byte.class
@@ -739,36 +739,30 @@ public class MetaClassHelper {
                     || classToTransformFrom == Short.class
                     || classToTransformFrom == Byte.class
                     || classToTransformFrom == Float.class
-                    || classToTransformFrom == BigDecimal.class
                     || classToTransformFrom == BigInteger.class)
                 return true;
         } else if (classToTransformTo == BigInteger.class) {
             if (classToTransformFrom == Integer.class
                     || classToTransformFrom == Long.class
                     || classToTransformFrom == Short.class
-                    || classToTransformFrom == Byte.class
-                    || classToTransformFrom == BigInteger.class)
+                    || classToTransformFrom == Byte.class)
                 return true;
         } else if (classToTransformTo == Long.class) {
-            if (classToTransformFrom == Long.class
-                    || classToTransformFrom == Integer.class
+            if (classToTransformFrom == Integer.class
                     || classToTransformFrom == Short.class
                     || classToTransformFrom == Byte.class)
                 return true;
         } else if (classToTransformTo == Float.class) {
-            if (classToTransformFrom == Float.class
-                    || classToTransformFrom == Integer.class
+            if (classToTransformFrom == Integer.class
                     || classToTransformFrom == Long.class
                     || classToTransformFrom == Short.class
                     || classToTransformFrom == Byte.class)
                 return true;
         } else if (classToTransformTo == Short.class) {
-            if (classToTransformFrom == Short.class
-                    || classToTransformFrom == Byte.class)
+            if (classToTransformFrom == Byte.class)
                 return true;
         } else if (classToTransformTo == String.class) {
-            if (classToTransformFrom == String.class ||
-                    GString.class.isAssignableFrom(classToTransformFrom)) {
+            if (GString.class.isAssignableFrom(classToTransformFrom)) {
                 return true;
             }
         }
diff --git a/src/main/org/codehaus/groovy/runtime/MethodClosure.java b/src/main/org/codehaus/groovy/runtime/MethodClosure.java
index 8233d42..a7c4957 100644
--- a/src/main/org/codehaus/groovy/runtime/MethodClosure.java
+++ b/src/main/org/codehaus/groovy/runtime/MethodClosure.java
@@ -30,6 +30,7 @@ import java.util.List;
  */
 public class MethodClosure extends Closure {
 
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
     private String method;
     
     public MethodClosure(Object owner, String method) {
@@ -39,7 +40,7 @@ public class MethodClosure extends Closure {
         final Class clazz = owner.getClass()==Class.class?(Class) owner:owner.getClass();
         
         maximumNumberOfParameters = 0;
-        parameterTypes = new Class [0];
+        parameterTypes = EMPTY_CLASS_ARRAY;
 
         List<MetaMethod> methods = InvokerHelper.getMetaClass(clazz).respondsTo(owner, method);
         
diff --git a/src/main/org/codehaus/groovy/runtime/MethodRankHelper.java b/src/main/org/codehaus/groovy/runtime/MethodRankHelper.java
index f4ae991..2baa4a9 100644
--- a/src/main/org/codehaus/groovy/runtime/MethodRankHelper.java
+++ b/src/main/org/codehaus/groovy/runtime/MethodRankHelper.java
@@ -49,7 +49,8 @@ public class MethodRankHelper{
     public static final int MAX_METHOD_SCORE = 50;
     public static final int MAX_CONSTRUCTOR_SCORE = 20;
     public static final int MAX_FIELD_SCORE = 30;
-    
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
     private static final class Pair<U,V> {
         private U u;
         private V v;
@@ -227,7 +228,7 @@ public class MethodRankHelper{
      */
     private static List<MetaMethod> rankMethods(String name, Object[] original, List<MetaMethod> methods) {
         List<RankableMethod> rm = new ArrayList<RankableMethod>(methods.size());
-        if (original==null) original = new Object[0];
+        if (original==null) original = EMPTY_OBJECT_ARRAY;
         Class[] ta = new Class[original.length];
     
         Class nullC =  NullObject.class;
diff --git a/src/main/org/codehaus/groovy/runtime/NumberAwareComparator.java b/src/main/org/codehaus/groovy/runtime/NumberAwareComparator.java
index 179eb96..8586c76 100644
--- a/src/main/org/codehaus/groovy/runtime/NumberAwareComparator.java
+++ b/src/main/org/codehaus/groovy/runtime/NumberAwareComparator.java
@@ -37,10 +37,15 @@ public class NumberAwareComparator<T> implements Comparator<T> {
         // since the object does not have a valid compareTo method
         // we compare using the hashcodes. null cases are handled by
         // DefaultTypeTransformation.compareTo
+        // This is not exactly a mathematical valid approach, since we compare object
+        // that cannot be compared. To avoid strange side effects we do a pseudo order
+        // using hashcodes, but without equality. Since then an x and y with the same
+        // hashcodes will behave different depending on if we compare x with y or
+        // x with y, the result might be unstable as well. Setting x and y to equal
+        // may mean the removal of x or y in a sorting operation, which we don't want.
         int x1 = o1.hashCode();
         int x2 = o2.hashCode();
-        if (x1 == x2) return 0;
-        if (x1 < x2) return -1;
-        return 1;
+        if (x1 > x2) return 1;
+        return -1;
     }
 }
diff --git a/src/main/org/codehaus/groovy/runtime/ProcessGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/ProcessGroovyMethods.java
index af35557..a1e59c0 100644
--- a/src/main/org/codehaus/groovy/runtime/ProcessGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/ProcessGroovyMethods.java
@@ -173,6 +173,8 @@ public class ProcessGroovyMethods extends DefaultGroovyMethodsSupport {
      * to keep the process from blocking due to a full output buffer.
      * The processed stream data is appended to the supplied Appendable.
      * For this, two Threads are started, so this method will return immediately.
+     * The threads will not be join()ed, even if waitFor() is called. To wait
+     * for the output to be fully consumed call waitForProcessOutput().
      *
      * @param self a Process
      * @param output an Appendable to capture the process stdout
@@ -189,6 +191,8 @@ public class ProcessGroovyMethods extends DefaultGroovyMethodsSupport {
      * to keep the process from blocking due to a full output buffer.
      * The processed stream data is appended to the supplied OutputStream.
      * For this, two Threads are started, so this method will return immediately.
+     * The threads will not be join()ed, even if waitFor() is called. To wait
+     * for the output to be fully consumed call waitForProcessOutput().
      *
      * @param self a Process
      * @param output an OutputStream to capture the process stdout
diff --git a/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java b/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
index 4d7eb30..5172e3f 100644
--- a/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
+++ b/src/main/org/codehaus/groovy/runtime/ProxyGeneratorAdapter.java
@@ -21,6 +21,7 @@ import groovy.lang.GroovyClassLoader;
 import groovy.lang.GroovyObject;
 import groovy.lang.GroovyRuntimeException;
 import groovy.transform.Trait;
+import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
@@ -30,6 +31,7 @@ import org.codehaus.groovy.control.ErrorCollector;
 import org.codehaus.groovy.control.Phases;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.tools.GroovyClass;
+import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.ClassVisitor;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
@@ -234,7 +236,15 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
     private void collectTraits(final Class clazz, final Set<ClassNode> traits) {
         Annotation annotation = clazz.getAnnotation(Trait.class);
         if (annotation!=null) {
-            traits.add(ClassHelper.make(clazz));
+            ClassNode trait = ClassHelper.make(clazz);
+            traits.add(trait.getPlainNodeReference());
+            LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
+            Traits.collectSelfTypes(trait, selfTypes, true, true);
+            for (ClassNode selfType : selfTypes) {
+                if (Traits.isTrait(selfType)) {
+                    traits.add(selfType.getPlainNodeReference());
+                }
+            }
         }
     }
 
@@ -702,7 +712,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
         Type[] args = Type.getArgumentTypes(desc);
         BytecodeHelper.pushConstant(mv, args.length);
         mv.visitTypeInsn(ANEWARRAY, "java/lang/Object");
-        size = 3;
+        size = 6;
         int idx = 1;
         for (int i = 0; i < args.length; i++) {
             Type arg = args[i];
@@ -716,7 +726,7 @@ public class ProxyGeneratorAdapter extends ClassVisitor implements Opcodes {
             } else {
                 mv.visitVarInsn(ALOAD, idx); // load argument i
             }
-            size = Math.max(6, 5+registerLen(arg));
+            size = Math.max(size, 5+registerLen(arg));
             idx += registerLen(arg);
             mv.visitInsn(AASTORE); // store value into array
         }
diff --git a/src/main/org/codehaus/groovy/runtime/ResourceGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
index dd24001..b37a4ee 100644
--- a/src/main/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/ResourceGroovyMethods.java
@@ -605,7 +605,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.0
      */
     public static String getText(URL url) throws IOException {
-        return getText(url, CharsetToolkit.getDefaultSystemCharset().toString());
+        return getText(url, CharsetToolkit.getDefaultSystemCharset().name());
     }
 
     /**
@@ -627,7 +627,7 @@ public class ResourceGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.1
      */
     public static String getText(URL url, Map parameters) throws IOException {
-        return getText(url, parameters, CharsetToolkit.getDefaultSystemCharset().toString());
+        return getText(url, parameters, CharsetToolkit.getDefaultSystemCharset().name());
     }
 
     /**
diff --git a/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java b/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
index 9cde723..8df8145 100644
--- a/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
+++ b/src/main/org/codehaus/groovy/runtime/ScriptBytecodeAdapter.java
@@ -45,14 +45,16 @@ public class ScriptBytecodeAdapter {
     //                   exception handling
     //  --------------------------------------------------------
     public static Throwable unwrap(GroovyRuntimeException gre) {
-        if (gre instanceof MissingPropertyExceptionNoStack) {
-            MissingPropertyExceptionNoStack noStack = (MissingPropertyExceptionNoStack) gre;
-            return new MissingPropertyException(noStack.getProperty(), noStack.getType());
-        }
+        if (gre.getCause()==null) {
+            if (gre instanceof MissingPropertyExceptionNoStack) {
+                MissingPropertyExceptionNoStack noStack = (MissingPropertyExceptionNoStack) gre;
+                return new MissingPropertyException(noStack.getProperty(), noStack.getType());
+            }
 
-        if (gre instanceof MissingMethodExceptionNoStack) {
-            MissingMethodExceptionNoStack noStack = (MissingMethodExceptionNoStack) gre;
-            return new MissingMethodException(noStack.getMethod(), noStack.getType(), noStack.getArguments(), noStack.isStatic());
+            if (gre instanceof MissingMethodExceptionNoStack) {
+                MissingMethodExceptionNoStack noStack = (MissingMethodExceptionNoStack) gre;
+                return new MissingMethodException(noStack.getMethod(), noStack.getType(), noStack.getArguments(), noStack.isStatic());
+            }
         }
 
         Throwable th = gre;
@@ -665,6 +667,18 @@ public class ScriptBytecodeAdapter {
     }
 
     public static boolean compareEqual(Object left, Object right) {
+        if (left==right) return true;
+        Class<?> leftClass = left==null?null:left.getClass();
+        Class<?> rightClass = right==null?null:right.getClass();
+        if (leftClass ==Integer.class && rightClass==Integer.class) {
+            return left.equals(right);
+        }
+        if (leftClass ==Double.class && rightClass==Double.class) {
+            return left.equals(right);
+        }
+        if (leftClass ==Long.class && rightClass==Long.class) {
+            return left.equals(right);
+        }
         return DefaultTypeTransformation.compareEqual(left, right);
     }
 
@@ -682,18 +696,62 @@ public class ScriptBytecodeAdapter {
     }
 
     public static boolean compareLessThan(Object left, Object right) {
+        Class<?> leftClass = left==null?null:left.getClass();
+        Class<?> rightClass = right==null?null:right.getClass();
+        if (leftClass ==Integer.class && rightClass==Integer.class) {
+            return (Integer) left < (Integer) right;
+        }
+        if (leftClass ==Double.class && rightClass==Double.class) {
+            return (Double) left < (Double) right;
+        }
+        if (leftClass ==Long.class && rightClass==Long.class) {
+            return (Long) left < (Long) right;
+        }
         return compareTo(left, right).intValue() < 0;
     }
 
     public static boolean compareLessThanEqual(Object left, Object right) {
+        Class<?> leftClass = left==null?null:left.getClass();
+        Class<?> rightClass = right==null?null:right.getClass();
+        if (leftClass ==Integer.class && rightClass==Integer.class) {
+            return (Integer) left <= (Integer) right;
+        }
+        if (leftClass ==Double.class && rightClass==Double.class) {
+            return (Double) left <= (Double) right;
+        }
+        if (leftClass ==Long.class && rightClass==Long.class) {
+            return (Long) left <= (Long) right;
+        }
         return compareTo(left, right).intValue() <= 0;
     }
 
     public static boolean compareGreaterThan(Object left, Object right) {
+        Class<?> leftClass = left==null?null:left.getClass();
+        Class<?> rightClass = right==null?null:right.getClass();
+        if (leftClass ==Integer.class && rightClass==Integer.class) {
+            return (Integer) left > (Integer) right;
+        }
+        if (leftClass ==Double.class && rightClass==Double.class) {
+            return (Double) left > (Double) right;
+        }
+        if (leftClass ==Long.class && rightClass==Long.class) {
+            return (Long) left > (Long) right;
+        }
         return compareTo(left, right).intValue() > 0;
     }
 
     public static boolean compareGreaterThanEqual(Object left, Object right) {
+        Class<?> leftClass = left==null?null:left.getClass();
+        Class<?> rightClass = right==null?null:right.getClass();
+        if (leftClass ==Integer.class && rightClass==Integer.class) {
+            return (Integer) left >= (Integer) right;
+        }
+        if (leftClass ==Double.class && rightClass==Double.class) {
+            return (Double) left >= (Double) right;
+        }
+        if (leftClass ==Long.class && rightClass==Long.class) {
+            return (Long) left >= (Long) right;
+        }
         return compareTo(left, right).intValue() >= 0;
     }
 
diff --git a/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java b/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
index 9e39b5f..bb430b6 100644
--- a/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
+++ b/src/main/org/codehaus/groovy/runtime/StringGroovyMethods.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -226,30 +226,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Turns a String into a regular expression Pattern
-     *
-     * @param self a String to convert into a regular expression
-     * @return the regular expression pattern
-     * @since 1.5.0
+     * @deprecated Use the CharSequence version
+     * @see #bitwiseNegate(CharSequence)
      */
+    @Deprecated
     public static Pattern bitwiseNegate(String self) {
-        return Pattern.compile(self);
-    }
-
-    /**
-     * Convenience method to capitalize the first letter of a CharSequence.
-     *
-     * @param self The CharSequence to capitalize
-     * @return The capitalized CharSequence
-     * @see #capitalize(String)
-     * @since 1.8.2
-     */
-    public static CharSequence capitalize(CharSequence self) {
-        return capitalize(self.toString());
+        return bitwiseNegate((CharSequence) self);
     }
 
     /**
-     * Convenience method to capitalize the first letter of a string
+     * Convenience method to capitalize the first letter of a CharSequence
      * (typically the first letter of a word). Example usage:
      * <pre class="groovyTestCase">
      * assert 'h'.capitalize() == 'H'
@@ -259,44 +245,28 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *     'hello world'.split(' ').collect{ it.capitalize() }.join(' ')
      * </pre>
      *
-     * @param self The string to capitalize
-     * @return The capitalized String
-     * @since 1.7.3
-     */
-    public static String capitalize(String self) {
-        if (self == null || self.length() == 0) return self;
-        return Character.toUpperCase(self.charAt(0)) + self.substring(1);
-    }
-
-    /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space character around it as many times as needed so that it remains centered.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
-     * @return the CharSequence centered with padded characters around it
-     * @see #center(String, Number)
+     * @param self The CharSequence to capitalize
+     * @return A String containing the capitalized toString() of the CharSequence
+     * @see #capitalize(String)
      * @since 1.8.2
      */
-    public static CharSequence center(CharSequence self, Number numberOfChars) {
-        return center(self.toString(), numberOfChars);
+    public static String capitalize(CharSequence self) {
+        String s = self.toString();
+        if (s == null || s.length() == 0) return s;
+        return Character.toUpperCase(s.charAt(0)) + s.substring(1);
     }
 
     /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, appending the supplied padding CharSequence around the original as many times as needed keeping it centered.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
-     * @param padding       the characters used for padding
-     * @return the CharSequence centered with padded characters around it
-     * @see #center(String, Number, String)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #capitalize(CharSequence)
      */
-    public static CharSequence center(CharSequence self, Number numberOfChars, CharSequence padding) {
-        return center(self.toString(), numberOfChars, padding.toString());
+    @Deprecated
+    public static String capitalize(String self) {
+        return capitalize((CharSequence) self);
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt> by adding the space character around it as many times as needed so that it remains centered.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space character around it as many times as needed so that it remains centered.
      *
      * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
      * <pre>
@@ -310,18 +280,18 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * | DDDD |
      * </pre>
      *
-     * @param self          a String object
-     * @param numberOfChars the total minimum number of characters of the resulting string
-     * @return the String centered with padded characters around it
-     * @see #center(String, Number, String)
-     * @since 1.0
+     * @param self          a CharSequence object
+     * @param numberOfChars the total minimum number of characters of the result
+     * @return the centered toString() of this CharSequence with padded characters around it
+     * @see #center(String, Number)
+     * @since 1.8.2
      */
-    public static String center(String self, Number numberOfChars) {
+    public static String center(CharSequence self, Number numberOfChars) {
         return center(self, numberOfChars, " ");
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt>, appending the supplied padding String around the original as many times as needed keeping it centered.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, appending the supplied padding CharSequence around the original as many times as needed keeping it centered.
      *
      * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
      * <pre>
@@ -335,29 +305,50 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * |+DDDD+|
      * </pre>
      *
-     * @param self          a String object
-     * @param numberOfChars the total minimum number of characters of the resulting string
+     * @param self          a CharSequence object
+     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
      * @param padding       the characters used for padding
-     * @return the String centered with padded characters around it
-     * @since 1.0
+     * @return the centered toString() of this CharSequence with padded characters around it
+     * @see #center(String, Number, String)
+     * @since 1.8.2
      */
-    public static String center(String self, Number numberOfChars, String padding) {
+    public static String center(CharSequence self, Number numberOfChars, CharSequence padding) {
+        String s = self.toString();
+        String padding1 = padding.toString();
         int numChars = numberOfChars.intValue();
-        if (numChars <= self.length()) {
-            return self;
+        if (numChars <= s.length()) {
+            return s;
         } else {
-            int charsToAdd = numChars - self.length();
+            int charsToAdd = numChars - s.length();
             String semiPad = charsToAdd % 2 == 1 ?
-                    getPadding(padding, charsToAdd / 2 + 1) :
-                    getPadding(padding, charsToAdd / 2);
+                    getPadding(padding1, charsToAdd / 2 + 1) :
+                    getPadding(padding1, charsToAdd / 2);
             if (charsToAdd % 2 == 0)
-                return semiPad + self + semiPad;
+                return semiPad + s + semiPad;
             else
-                return semiPad.substring(0, charsToAdd / 2) + self + semiPad;
+                return semiPad.substring(0, charsToAdd / 2) + s + semiPad;
         }
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #center(CharSequence, Number)
+     */
+    @Deprecated
+    public static String center(String self, Number numberOfChars) {
+        return center((CharSequence) self, numberOfChars);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #center(CharSequence, Number, CharSequence)
+     */
+    @Deprecated
+    public static String center(String self, Number numberOfChars, String padding) {
+        return center((CharSequence) self, numberOfChars, (CharSequence) padding);
+    }
+
+    /**
      * Provide an implementation of contains() like
      * {@link java.util.Collection#contains(Object)} to make CharSequences more polymorphic.
      *
@@ -368,22 +359,17 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean contains(CharSequence self, CharSequence text) {
-        return contains(self.toString(), text.toString());
+        int idx = self.toString().indexOf(text.toString());
+        return idx >= 0;
     }
 
     /**
-     * Provide an implementation of contains() like
-     * {@link java.util.Collection#contains(Object)} to make Strings more polymorphic.
-     * This method is not required on JDK 1.5 onwards
-     *
-     * @param self a String
-     * @param text a String to look for
-     * @return true if this string contains the given text
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #contains(CharSequence, CharSequence)
      */
+    @Deprecated
     public static boolean contains(String self, String text) {
-        int idx = self.indexOf(text);
-        return idx >= 0;
+        return contains((CharSequence) self, (CharSequence) text);
     }
 
     /**
@@ -396,21 +382,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static int count(CharSequence self, CharSequence text) {
-        return count(self.toString(), text.toString());
-    }
-
-    /**
-     * Count the number of occurrences of a substring.
-     *
-     * @param self a String
-     * @param text a substring
-     * @return the number of occurrences of the given string inside this String
-     * @since 1.0
-     */
-    public static int count(String self, String text) {
         int answer = 0;
         for (int idx = 0; true; idx++) {
-            idx = self.indexOf(text, idx);
+            idx = self.toString().indexOf(text.toString(), idx);
             // break once idx goes to -1 or for case of empty string once
             // we get to the end to avoid JDK library bug (see GROOVY-5858)
             if (idx < answer) break;
@@ -419,6 +393,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
         return answer;
     }
 
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #contains(CharSequence, CharSequence)
+     */
+    @Deprecated
+    public static int count(String self, String text) {
+        return count((CharSequence) self, (CharSequence) text);
+    }
+
     private static StringBufferWriter createStringBufferWriter(StringBuffer self) {
         return new StringBufferWriter(self);
     }
@@ -434,23 +417,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * terminated by the platform specific line separator.
      *
      * @param self a CharSequence object
-     * @return the denormalized CharSequence
+     * @return the denormalized toString() of this CharSequence
      * @see #denormalize(String)
      * @since 1.8.2
      */
-    public static CharSequence denormalize(final CharSequence self) {
-        return denormalize(self.toString());
-    }
-
-    /**
-     * Return a String with lines (separated by LF, CR/LF, or CR)
-     * terminated by the platform specific line separator.
-     *
-     * @param self a String object
-     * @return the denormalized string
-     * @since 1.6.0
-     */
-    public static String denormalize(final String self) {
+    public static String denormalize(final CharSequence self) {
+        final String s = self.toString();
         // Don't do this in static initializer because we may never be needed.
         // TODO: Put this lineSeparator property somewhere everyone can use it.
         if (lineSeparator == null) {
@@ -469,10 +441,10 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
             }
         }
 
-        final int len = self.length();
+        final int len = s.length();
 
         if (len < 1) {
-            return self;
+            return s;
         }
 
         final StringBuilder sb = new StringBuilder((110 * len) / 100);
@@ -480,14 +452,14 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
         int i = 0;
 
         while (i < len) {
-            final char ch = self.charAt(i++);
+            final char ch = s.charAt(i++);
 
             switch (ch) {
                 case '\r':
                     sb.append(lineSeparator);
 
                     // Eat the following LF if any.
-                    if ((i < len) && (self.charAt(i) == '\n')) {
+                    if ((i < len) && (s.charAt(i) == '\n')) {
                         ++i;
                     }
 
@@ -507,6 +479,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #denormalize(CharSequence)
+     */
+    @Deprecated
+    public static String denormalize(final String self) {
+        return denormalize((CharSequence) self);
+    }
+
+    /**
      * Drops the given number of chars from the head of this CharSequence
      * if they are available.
      * <pre class="groovyTestCase">
@@ -533,6 +514,20 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * A GString variant of the equivalent CharSequence method.
+     *
+     * @param self the original GString
+     * @param num the number of characters to drop from this iterator
+     * @return a String consisting of all characters except the first <code>num</code> ones,
+     *         or else an empty String, if the toString() of this GString has less than <code>num</code> characters.
+     * @see #drop(CharSequence, int)
+     * @since 2.3.7
+     */
+    public static String drop(GString self, int num) {
+        return drop(self.toString(), num).toString();
+    }
+
+    /**
      * Create a suffix of the given CharSequence by dropping as many characters as possible from the
      * front of the original CharSequence such that calling the given closure condition evaluates to
      * true when passed each of the dropped characters.
@@ -567,6 +562,21 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * A GString variant of the equivalent CharSequence method.
+     *
+     * @param self      the original GString
+     * @param condition the closure that while continuously evaluating to true will cause us to drop elements from
+     *                  the front of the original GString
+     * @return the shortest suffix of the given GString such that the given closure condition
+     *         evaluates to true for each element dropped from the front of the CharSequence
+     * @see #dropWhile(CharSequence, groovy.lang.Closure)
+     * @since 2.3.7
+     */
+    public static String dropWhile(GString self, @ClosureParams(value=SimpleType.class, options="char") Closure condition) {
+        return dropWhile(self.toString(), condition).toString();
+    }
+
+    /**
      * Iterates through this CharSequence line by line.  Each line is passed
      * to the given 1 or 2 arg closure. If a 2 arg closure is found
      * the line count is passed as the second argument.
@@ -579,7 +589,7 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static <T> T eachLine(CharSequence self, @ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure) throws IOException {
-        return eachLine(self.toString(), closure);
+        return eachLine(self.toString(), 0, closure);
     }
 
     /**
@@ -596,45 +606,31 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static <T> T eachLine(CharSequence self, int firstLine, @ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure) throws IOException {
-        return eachLine(self.toString(), firstLine, closure);
+        int count = firstLine;
+        T result = null;
+        for (String line : readLines(self.toString())) {
+            result = callClosureForLine(closure, line, count);
+            count++;
+        }
+        return result;
     }
 
     /**
-     * Iterates through this String line by line.  Each line is passed
-     * to the given 1 or 2 arg closure. If a 2 arg closure is found
-     * the line count is passed as the second argument.
-     *
-     * @param self    a String
-     * @param closure a closure
-     * @return the last value returned by the closure
-     * @throws java.io.IOException if an error occurs
-     * @see #eachLine(String, int, groovy.lang.Closure)
-     * @since 1.5.5
+     * @deprecated Use the CharSequence version
+     * @see #eachLine(CharSequence, groovy.lang.Closure)
      */
+    @Deprecated
     public static <T> T eachLine(String self, @ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure) throws IOException {
-        return eachLine(self, 0, closure);
+        return eachLine((CharSequence) self, closure);
     }
 
     /**
-     * Iterates through this String line by line.  Each line is passed
-     * to the given 1 or 2 arg closure. If a 2 arg closure is found
-     * the line count is passed as the second argument.
-     *
-     * @param self    a String
-     * @param firstLine the line number value used for the first line (default is 1, set to 0 to start counting from 0)
-     * @param closure a closure (arg 1 is line, optional arg 2 is line number)
-     * @return the last value returned by the closure
-     * @throws java.io.IOException if an error occurs
-     * @since 1.5.7
+     * @deprecated Use the CharSequence version
+     * @see #eachLine(CharSequence, int, groovy.lang.Closure)
      */
+    @Deprecated
     public static <T> T eachLine(String self, int firstLine, @ClosureParams(value=FromString.class, options={"String","String,Integer"}) Closure<T> closure) throws IOException {
-        int count = firstLine;
-        T result = null;
-        for (String line : readLines(self)) {
-            result = callClosureForLine(closure, line, count);
-            count++;
-        }
-        return result;
+        return eachLine((CharSequence) self, firstLine, closure);
     }
 
     /**
@@ -690,8 +686,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachMatch(String, String, groovy.lang.Closure)
      * @since 1.8.2
      */
-    public static String eachMatch(CharSequence self, CharSequence regex, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return eachMatch(self.toString(), regex.toString(), closure);
+    public static <T extends CharSequence> T eachMatch(T self, CharSequence regex, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
+        eachMatch(self.toString(), regex.toString(), closure);
+        return self;
     }
 
     /**
@@ -707,8 +704,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachMatch(String, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 1.8.2
      */
-    public static String eachMatch(CharSequence self, Pattern pattern, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return eachMatch(self.toString(), pattern, closure);
+    public static <T extends CharSequence> T eachMatch(T self, Pattern pattern, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
+        eachMatch(self.toString(), pattern, closure);
+        return self;
     }
 
     /**
@@ -749,12 +747,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * Expands all tabs into spaces with tabStops of size 8.
      *
      * @param self A CharSequence to expand
-     * @return The expanded CharSequence
+     * @return The expanded toString() of this CharSequence
      * @see #expand(String)
      * @since 1.8.2
      */
-    public static CharSequence expand(CharSequence self) {
-        return expand(self.toString(), 8);
+    public static String expand(CharSequence self) {
+        return expand(self, 8);
     }
 
     /**
@@ -764,99 +762,106 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self A CharSequence to expand
      * @param tabStop The number of spaces a tab represents
-     * @return The expanded CharSequence
+     * @return The expanded toString() of this CharSequence
      * @see #expand(String, int)
      * @since 1.8.2
      */
-    public static CharSequence expand(CharSequence self, int tabStop) {
-        return expand(self.toString(), tabStop);
-    }
-
-    /**
-     * Expands all tabs into spaces with tabStops of size 8.
-     *
-     * @param self A String to expand
-     * @return The expanded String
-     * @since 1.7.3
-     * @see #expand(String, int)
-     */
-    public static String expand(String self) {
-        return expand(self, 8);
-    }
-
-    /**
-     * Expands all tabs into spaces. If the String has multiple
-     * lines, expand each line - restarting tab stops at the start
-     * of each line.
-     *
-     * @param self A String to expand
-     * @param tabStop The number of spaces a tab represents
-     * @return The expanded String
-     * @since 1.7.3
-     */
-    public static String expand(String self, int tabStop) {
-        if (self.length() == 0) return self;
+    public static String expand(CharSequence self, int tabStop) {
+        String s = self.toString();
+        if (s.length() == 0) return s;
         try {
             StringBuilder builder = new StringBuilder();
-            for (String line : readLines(self)) {
+            for (String line : readLines(s)) {
                 builder.append(expandLine(line, tabStop));
                 builder.append("\n");
             }
             // remove the normalized ending line ending if it was not present
-            if (!self.endsWith("\n")) {
+            if (!s.endsWith("\n")) {
                 builder.deleteCharAt(builder.length() - 1);
             }
             return builder.toString();
         } catch (IOException e) {
             /* ignore */
         }
-        return self;
+        return s;
     }
 
     /**
-     * Expands all tabs into spaces. Assumes the CharSequence represents a single line of text.
-     *
-     * @param self A line to expand
-     * @param tabStop The number of spaces a tab represents
-     * @return The expanded CharSequence
-     * @see #expandLine(String, int)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #expand(CharSequence)
+     */
+    @Deprecated
+    public static String expand(String self) {
+        return expand((CharSequence) self);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #expand(CharSequence, int)
      */
-    public static CharSequence expandLine(CharSequence self, int tabStop) {
-        return expandLine(self.toString(), tabStop);
+    @Deprecated
+    public static String expand(String self, int tabStop) {
+        return expand((CharSequence) self, tabStop);
     }
 
     /**
-     * Expands all tabs into spaces. Assumes the String represents a single line of text.
+     * Expands all tabs into spaces. Assumes the CharSequence represents a single line of text.
      *
      * @param self A line to expand
      * @param tabStop The number of spaces a tab represents
-     * @return The expanded String
-     * @since 1.7.3
+     * @return The expanded toString() of this CharSequence
+     * @see #expandLine(String, int)
+     * @since 1.8.2
      */
-    public static String expandLine(String self, int tabStop) {
+    public static String expandLine(CharSequence self, int tabStop) {
+        String s = self.toString();
         int index;
-        while ((index = self.indexOf('\t')) != -1) {
-            StringBuilder builder = new StringBuilder(self);
+        while ((index = s.indexOf('\t')) != -1) {
+            StringBuilder builder = new StringBuilder(s);
             int count = tabStop - index % tabStop;
             builder.deleteCharAt(index);
             for (int i = 0; i < count; i++) builder.insert(index, " ");
-            self = builder.toString();
+            s = builder.toString();
         }
-        return self;
+        return s;
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #expand(CharSequence, int)
+     */
+    @Deprecated
+    public static String expandLine(String self, int tabStop) {
+        return expandLine((CharSequence) self, tabStop);
     }
 
     /**
-     * Finds the first occurrence of a regular expression CharSequence within a CharSequence.
+     * Finds the first occurrence of a regular expression String within a String.
+     * If the regex doesn't match, null will be returned.
+     * <p>
+     * For example, if the regex doesn't match the result is null:
+     * <pre>
+     *     assert null == "New York, NY".find(/\d{5}/)
+     * </pre>
+     *
+     * If it does match, we get the matching string back:
+     * <pre>
+     *      assert "10292" == "New York, NY 10292-0098".find(/\d{5}/)
+     * </pre>
+     *
+     * If we have capture groups in our expression, we still get back the full match
+     * <pre>
+     *      assert "10292-0098" == "New York, NY 10292-0098".find(/(\d{5})-?(\d{4})/)
+     * </pre>
      *
      * @param self  a CharSequence
      * @param regex the capturing regex
-     * @return a CharSequence containing the matched portion, or null if the regex doesn't match
+     * @return a String containing the matched portion, or null if the regex doesn't match
      * @see #find(String, java.util.regex.Pattern)
      * @since 1.8.2
      */
-    public static CharSequence find(CharSequence self, CharSequence regex) {
-        return find(self.toString(), Pattern.compile(regex.toString()));
+    public static String find(CharSequence self, CharSequence regex) {
+        return find(self, Pattern.compile(regex.toString()));
     }
 
     /**
@@ -866,43 +871,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @param self    a CharSequence
      * @param regex   the capturing regex CharSequence
      * @param closure the closure that will be passed the full match, plus each of the capturing groups (if any)
-     * @return a CharSequence containing the result of calling the closure (calling toString() if needed), or null if the regex pattern doesn't match
+     * @return a String containing the result of calling the closure (calling toString() if needed), or null if the regex pattern doesn't match
      * @see #find(String, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 1.8.2
      */
-    public static CharSequence find(CharSequence self, CharSequence regex, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
+    public static String find(CharSequence self, CharSequence regex, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
         return find(self.toString(), Pattern.compile(regex.toString()), closure);
     }
 
     /**
-     * Finds the first occurrence of a compiled regular expression Pattern within a CharSequence.
-     *
-     * @param self    a CharSequence
-     * @param pattern the compiled regex Pattern
-     * @return a CharSequence containing the matched portion, or null if the regex pattern doesn't match
-     * @see #find(String, java.util.regex.Pattern)
-     * @since 1.8.2
-     */
-    public static CharSequence find(CharSequence self, Pattern pattern) {
-        return find(self.toString(), pattern);
-    }
-
-    /**
-     * Returns the result of calling a closure with the first occurrence of a regular expression found within a
-     * CharSequence. If the regex doesn't match, the closure will not be called and find will return null.
-     *
-     * @param self    a CharSequence
-     * @param pattern the compiled regex Pattern
-     * @param closure the closure that will be passed the full match, plus each of the capturing groups (if any)
-     * @return a CharSequence containing the result of calling the closure (calling toString() if needed), or null if the regex pattern doesn't match
-     * @see #find(String, java.util.regex.Pattern, groovy.lang.Closure)
-     * @since 1.8.2
-     */
-    public static CharSequence find(CharSequence self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
-        return find(self.toString(), pattern, closure);
-    }
-
-    /**
      * Finds the first occurrence of a compiled regular expression Pattern within a String.
      * If the pattern doesn't match, null will be returned.
      * <p>
@@ -924,13 +901,14 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * If you need to work with capture groups, then use the closure version
      * of this method or use Groovy's matcher operators or use <tt>eachMatch</tt>.
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the compiled regex Pattern
      * @return a String containing the matched portion, or null if the regex pattern doesn't match
-     * @since 1.6.1
+     * @see #find(String, java.util.regex.Pattern)
+     * @since 1.8.2
      */
-    public static String find(String self, Pattern pattern) {
-        Matcher matcher = pattern.matcher(self);
+    public static String find(CharSequence self, Pattern pattern) {
+        Matcher matcher = pattern.matcher(self.toString());
         if (matcher.find()) {
             return matcher.group(0);
         }
@@ -985,14 +963,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *      }
      * </pre>
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the compiled regex Pattern
      * @param closure the closure that will be passed the full match, plus each of the capturing groups (if any)
      * @return a String containing the result of calling the closure (calling toString() if needed), or null if the regex pattern doesn't match
-     * @since 1.6.1
+     * @see #find(String, java.util.regex.Pattern, groovy.lang.Closure)
+     * @since 1.8.2
      */
-    public static String find(String self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
-        Matcher matcher = pattern.matcher(self);
+    public static String find(CharSequence self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
+        Matcher matcher = pattern.matcher(self.toString());
         if (matcher.find()) {
             if (hasGroup(matcher)) {
                 int count = matcher.groupCount();
@@ -1009,147 +988,99 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Finds the first occurrence of a regular expression String within a String.
-     * If the regex doesn't match, null will be returned.
-     * <p>
-     * For example, if the regex doesn't match the result is null:
-     * <pre>
-     *     assert null == "New York, NY".find(/\d{5}/)
-     * </pre>
-     *
-     * If it does match, we get the matching string back:
-     * <pre>
-     *      assert "10292" == "New York, NY 10292-0098".find(/\d{5}/)
-     * </pre>
-     *
-     * If we have capture groups in our expression, we still get back the full match
-     * <pre>
-     *      assert "10292-0098" == "New York, NY 10292-0098".find(/(\d{5})-?(\d{4})/)
-     * </pre>
-     *
-     * @param self  a String
-     * @param regex the capturing regex
-     * @return a String containing the matched portion, or null if the regex doesn't match
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #find(CharSequence, java.util.regex.Pattern)
+     */
+    @Deprecated
+    public static String find(String self, Pattern pattern) {
+        return find((CharSequence) self, pattern);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #find(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
+     */
+    @Deprecated
+    public static String find(String self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
+        return find((CharSequence) self, pattern, closure);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #find(CharSequence, CharSequence)
      */
+    @Deprecated
     public static String find(String self, String regex) {
-        return find(self, Pattern.compile(regex));
+        return find((CharSequence) self, (CharSequence) regex);
     }
 
     /**
-     * Returns the result of calling a closure with the first occurrence of a regular expression found within a String.
-     * If the regex doesn't match, the closure will not be called and find will return null.
-     * <p>
-     * For example, if the regex doesn't match, the result is null:
-     * <pre>
-     *     assert null == "New York, NY".find(~/\d{5}/) { match -> return "-$match-"}
-     * </pre>
-     *
-     * If it does match and we don't have any capture groups in our regex, there is a single parameter
-     * on the closure that the match gets passed to:
-     * <pre>
-     *      assert "-10292-" == "New York, NY 10292-0098".find(~/\d{5}/) { match -> return "-$match-"}
-     * </pre>
-     *
-     * If we have capture groups in our expression, our closure has one parameter for the match, followed by
-     * one for each of the capture groups:
-     * <pre>
-     *      assert "10292" == "New York, NY 10292-0098".find(~/(\d{5})-?(\d{4})/) { match, zip, plusFour ->
-     *          assert match == "10292-0098"
-     *          assert zip == "10292"
-     *          assert plusFour == "0098"
-     *          return zip
-     *      }
-     * </pre>
-     * If we have capture groups in our expression, and our closure has one parameter,
-     * the closure will be passed an array with the first element corresponding to the whole match,
-     * followed by an element for each of the capture groups:
-     * <pre>
-     *      assert "10292" == "New York, NY 10292-0098".find(~/(\d{5})-?(\d{4})/) { match, zip, plusFour ->
-     *          assert array[0] == "10292-0098"
-     *          assert array[1] == "10292"
-     *          assert array[2] == "0098"
-     *          return array[1]
-     *      }
-     * </pre>
-     * If a capture group is optional, and doesn't match, then the corresponding value
-     * for that capture group passed to the closure will be null as illustrated here:
-     * <pre>
-     *      assert "2339999" == "adsf 233-9999 adsf".find(~/(\d{3})?-?(\d{3})-(\d{4})/) { match, areaCode, exchange, stationNumber ->
-     *          assert "233-9999" == match
-     *          assert null == areaCode
-     *          assert "233" == exchange
-     *          assert "9999" == stationNumber
-     *          return "$exchange$stationNumber"
-     *      }
-     * </pre>
-     *
-     * @param self    a String
-     * @param regex   the capturing regex string
-     * @param closure the closure that will be passed the full match, plus each of the capturing groups (if any)
-     * @return a String containing the result of the closure (calling toString() if needed), or null if the regex pattern doesn't match
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #find(CharSequence, CharSequence, groovy.lang.Closure)
      */
+    @Deprecated
     public static String find(String self, String regex, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure closure) {
-        return find(self, Pattern.compile(regex), closure);
+        return find((CharSequence) self, (CharSequence) regex, closure);
     }
 
     /**
-     * Returns a (possibly empty) list of all occurrences of a regular expression (in CharSequence format) found within a CharSequence.
+     * Returns a (possibly empty) list of all occurrences of a regular expression (provided as a CharSequence) found within a CharSequence.
+     * <p>
+     * For example, if the regex doesn't match, it returns an empty list:
+     * <pre>
+     * assert [] == "foo".findAll(/(\w*) Fish/)
+     * </pre>
+     * Any regular expression matches are returned in a list, and all regex capture groupings are ignored, only the full match is returned:
+     * <pre>
+     * def expected = ["One Fish", "Two Fish", "Red Fish", "Blue Fish"]
+     * assert expected == "One Fish, Two Fish, Red Fish, Blue Fish".findAll(/(\w*) Fish/)
+     * </pre>
+     * If you need to work with capture groups, then use the closure version
+     * of this method or use Groovy's matcher operators or use <tt>eachMatch</tt>.
      *
      * @param self  a CharSequence
      * @param regex the capturing regex CharSequence
      * @return a List containing all full matches of the regex within the CharSequence, an empty list will be returned if there are no matches
-     * @see #findAll(String, String)
+     * @see #findAll(CharSequence, Pattern)
      * @since 1.8.2
      */
-    public static List<CharSequence> findAll(CharSequence self, CharSequence regex) {
-        return new ArrayList<CharSequence>(findAll(self.toString(), regex.toString()));
+    public static List<String> findAll(CharSequence self, CharSequence regex) {
+        return findAll(self, Pattern.compile(regex.toString()));
     }
 
     /**
-     * Finds all occurrences of a capturing regular expression CharSequence within a CharSequence.
+     * Finds all occurrences of a regular expression string within a CharSequence.   Any matches are passed to the specified closure.  The closure
+     * is expected to have the full match in the first parameter.  If there are any capture groups, they will be placed in subsequent parameters.
+     * <p>
+     * If there are no matches, the closure will not be called, and an empty List will be returned.
+     * <p>
+     * For example, if the regex doesn't match, it returns an empty list:
+     * <pre>
+     * assert [] == "foo".findAll(/(\w*) Fish/) { match, firstWord -> return firstWord }
+     * </pre>
+     * Any regular expression matches are passed to the closure, if there are no capture groups, there will be one parameter for the match:
+     * <pre>
+     * assert ["couldn't", "wouldn't"] == "I could not, would not, with a fox.".findAll(/.ould/) { match -> "${match}n't"}
+     * </pre>
+     * If there are capture groups, the first parameter will be the match followed by one parameter for each capture group:
+     * <pre>
+     * def orig = "There's a Wocket in my Pocket"
+     * assert ["W > Wocket", "P > Pocket"] == orig.findAll(/(.)ocket/) { match, firstLetter -> "$firstLetter > $match" }
+     * </pre>
      *
      * @param self    a CharSequence
      * @param regex   the capturing regex CharSequence
      * @param closure will be passed the full match plus each of the capturing groups (if any)
      * @return a List containing all results from calling the closure with each full match (and potentially capturing groups) of the regex within the CharSequence, an empty list will be returned if there are no matches
-     * @see #findAll(String, String, groovy.lang.Closure)
+     * @see #findAll(CharSequence, Pattern, groovy.lang.Closure)
      * @since 1.8.2
      */
     public static <T> List<T> findAll(CharSequence self, CharSequence regex, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
-        return findAll(self.toString(), regex.toString(), closure);
+        return findAll(self, Pattern.compile(regex.toString()), closure);
     }
 
     /**
      * Returns a (possibly empty) list of all occurrences of a regular expression (in Pattern format) found within a CharSequence.
-     *
-     * @param self    a CharSequence
-     * @param pattern the compiled regex Pattern
-     * @return a List containing all full matches of the Pattern within the CharSequence, an empty list will be returned if there are no matches
-     * @see #findAll(String, java.util.regex.Pattern)
-     * @since 1.8.2
-     */
-    public static List<CharSequence> findAll(CharSequence self, Pattern pattern) {
-        return new ArrayList<CharSequence>(findAll(self.toString(), pattern));
-    }
-
-    /**
-     * Finds all occurrences of a compiled regular expression Pattern within a CharSequence.
-     *
-     * @param self    a CharSequence
-     * @param pattern the compiled regex Pattern
-     * @param closure will be passed the full match plus each of the capturing groups (if any)
-     * @return a List containing all results from calling the closure with each full match (and potentially capturing groups) of the regex pattern within the CharSequence, an empty list will be returned if there are no matches
-     * @see #findAll(String, java.util.regex.Pattern, groovy.lang.Closure)
-     * @since 1.8.2
-     */
-    public static <T> List<T> findAll(CharSequence self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
-        return findAll(self.toString(), pattern, closure);
-    }
-
-    /**
-     * Returns a (possibly empty) list of all occurrences of a regular expression (in Pattern format) found within a String.
      * <p>
      * For example, if the pattern doesn't match, it returns an empty list:
      * <pre>
@@ -1161,27 +1092,30 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert expected == "One Fish, Two Fish, Red Fish, Blue Fish".findAll(~/(\w*) Fish/)
      * </pre>
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the compiled regex Pattern
-     * @return a List containing all full matches of the Pattern within the string, an empty list will be returned if there are no matches
-     * @since 1.6.1
+     * @return a List containing all full matches of the Pattern within the CharSequence, an empty list will be returned if there are no matches
+     * @see #findAll(String, java.util.regex.Pattern)
+     * @since 1.8.2
      */
-    public static List<String> findAll(String self, Pattern pattern) {
-        Matcher matcher = pattern.matcher(self);
+    public static List<String> findAll(CharSequence self, Pattern pattern) {
+        Matcher matcher = pattern.matcher(self.toString());
+        boolean hasGroup = hasGroup(matcher);
         List<String> list = new ArrayList<String>();
         for (Iterator iter = iterator(matcher); iter.hasNext();) {
-            if (hasGroup(matcher)) {
+            if (hasGroup) {
                 list.add((String) ((List) iter.next()).get(0));
             } else {
                 list.add((String) iter.next());
             }
         }
-        return list;
+        return new ArrayList<String>(list);
     }
 
     /**
-     * Finds all occurrences of a compiled regular expression Pattern within a String.   Any matches are passed to the specified closure.  The closure
-     * is expected to have the full match in the first parameter.  If there are any capture groups, they will be placed in subsequent parameters.
+     * Finds all occurrences of a compiled regular expression Pattern within a CharSequence. Any matches are passed to
+     * the specified closure.  The closure is expected to have the full match in the first parameter.  If there are any
+     * capture groups, they will be placed in subsequent parameters.
      * <p>
      * If there are no matches, the closure will not be called, and an empty List will be returned.
      * <p>
@@ -1189,7 +1123,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * <pre>
      * assert [] == "foo".findAll(~/(\w*) Fish/) { match, firstWord -> return firstWord }
      * </pre>
-     * Any regular expression matches are passed to the closure, if there are no capture groups, there will be one parameter for the match:
+     * Any regular expression matches are passed to the closure, if there are no capture groups, there will be one
+     * parameter for the match:
      * <pre>
      * assert ["couldn't", "wouldn't"] == "I could not, would not, with a fox.".findAll(~/.ould/) { match -> "${match}n't"}
      * </pre>
@@ -1199,69 +1134,52 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert ["W > Wocket", "P > Pocket"] == orig.findAll(~/(.)ocket/) { match, firstLetter -> "$firstLetter > $match" }
      * </pre>
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the compiled regex Pattern
      * @param closure will be passed the full match plus each of the capturing groups (if any)
-     * @return a List containing all results from calling the closure with each full match (and potentially capturing groups) of the regex pattern within the String, an empty list will be returned if there are no matches
-     * @since 1.6.1
+     * @return a List containing all results from calling the closure with each full match (and potentially capturing groups) of the regex pattern within the CharSequence, an empty list will be returned if there are no matches
+     * @see #findAll(String, java.util.regex.Pattern, groovy.lang.Closure)
+     * @since 1.8.2
      */
-    public static <T> List<T> findAll(String self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
-        Matcher matcher = pattern.matcher(self);
+    public static <T> List<T> findAll(CharSequence self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
+        Matcher matcher = pattern.matcher(self.toString());
         return DefaultGroovyMethods.collect(matcher, closure);
     }
 
     /**
-     * Returns a (possibly empty) list of all occurrences of a regular expression (in String format) found within a String.
-     * <p>
-     * For example, if the regex doesn't match, it returns an empty list:
-     * <pre>
-     * assert [] == "foo".findAll(/(\w*) Fish/)
-     * </pre>
-     * Any regular expression matches are returned in a list, and all regex capture groupings are ignored, only the full match is returned:
-     * <pre>
-     * def expected = ["One Fish", "Two Fish", "Red Fish", "Blue Fish"]
-     * assert expected == "One Fish, Two Fish, Red Fish, Blue Fish".findAll(/(\w*) Fish/)
-     * </pre>
-     * If you need to work with capture groups, then use the closure version
-     * of this method or use Groovy's matcher operators or use <tt>eachMatch</tt>.
-     *
-     * @param self  a String
-     * @param regex the capturing regex String
-     * @return a List containing all full matches of the regex within the string, an empty list will be returned if there are no matches
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #findAll(CharSequence, java.util.regex.Pattern)
      */
+    @Deprecated
+    public static List<String> findAll(String self, Pattern pattern) {
+        return findAll((CharSequence) self, pattern);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #findAll(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
+     */
+    @Deprecated
+    public static <T> List<T> findAll(String self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
+        return findAll((CharSequence) self, pattern, closure);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #findAll(CharSequence, CharSequence)
+     */
+    @Deprecated
     public static List<String> findAll(String self, String regex) {
-        return findAll(self, Pattern.compile(regex));
+        return findAll((CharSequence) self, (CharSequence) regex);
     }
 
     /**
-     * Finds all occurrences of a regular expression string within a String.   Any matches are passed to the specified closure.  The closure
-     * is expected to have the full match in the first parameter.  If there are any capture groups, they will be placed in subsequent parameters.
-     * <p>
-     * If there are no matches, the closure will not be called, and an empty List will be returned.
-     * <p>
-     * For example, if the regex doesn't match, it returns an empty list:
-     * <pre>
-     * assert [] == "foo".findAll(/(\w*) Fish/) { match, firstWord -> return firstWord }
-     * </pre>
-     * Any regular expression matches are passed to the closure, if there are no capture groups, there will be one parameter for the match:
-     * <pre>
-     * assert ["couldn't", "wouldn't"] == "I could not, would not, with a fox.".findAll(/.ould/) { match -> "${match}n't"}
-     * </pre>
-     * If there are capture groups, the first parameter will be the match followed by one parameter for each capture group:
-     * <pre>
-     * def orig = "There's a Wocket in my Pocket"
-     * assert ["W > Wocket", "P > Pocket"] == orig.findAll(/(.)ocket/) { match, firstLetter -> "$firstLetter > $match" }
-     * </pre>
-     *
-     * @param self    a String
-     * @param regex   the capturing regex String
-     * @param closure will be passed the full match plus each of the capturing groups (if any)
-     * @return a List containing all results from calling the closure with each full match (and potentially capturing groups) of the regex within the String, an empty list will be returned if there are no matches
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #findAll(CharSequence, CharSequence, groovy.lang.Closure)
      */
+    @Deprecated
     public static <T> List<T> findAll(String self, String regex, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") Closure<T> closure) {
-        return findAll(self, Pattern.compile(regex), closure);
+        return findAll((CharSequence) self, (CharSequence) regex, closure);
     }
 
     // TODO expose this for stream based scenarios?
@@ -1278,10 +1196,10 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self    a CharSequence
      * @param indices a Collection of indices
-     * @return a CharSequence consisting of the characters at the given indices
+     * @return a String consisting of the characters at the given indices
      * @since 1.0
      */
-    public static CharSequence getAt(CharSequence self, Collection indices) {
+    public static String getAt(CharSequence self, Collection indices) {
         StringBuilder answer = new StringBuilder();
         for (Object value : indices) {
             if (value instanceof Range) {
@@ -1301,10 +1219,10 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param text  a CharSequence
      * @param range an EmptyRange
-     * @return the subsequence CharSequence
+     * @return the empty String
      * @since 1.5.0
      */
-    public static CharSequence getAt(CharSequence text, EmptyRange range) {
+    public static String getAt(CharSequence text, EmptyRange range) {
         return "";
     }
 
@@ -1322,7 +1240,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Support the range subscript operator for CharSequence or StringBuffer with IntRange
+     * Support the subscript operator for GString.
+     *
+     * @param text  a GString
+     * @param index the index of the Character to get
+     * @return the Character at the given index
+     * @since 2.3.7
+     */
+    public static String getAt(GString text, int index) {
+        return (String) getAt(text.toString(), index);
+    }
+
+    /**
+     * Support the range subscript operator for CharSequence with IntRange
      *
      * @param text  a CharSequence
      * @param range an IntRange
@@ -1334,6 +1264,18 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * Support the range subscript operator for GString with IntRange
+     *
+     * @param text  a GString
+     * @param range an IntRange
+     * @return the String of characters corresponding to the provided range
+     * @since 2.3.7
+     */
+    public static String getAt(GString text, IntRange range) {
+        return getAt(text, (Range) range);
+    }
+
+    /**
      * Support the range subscript operator for CharSequence
      *
      * @param text  a CharSequence
@@ -1344,7 +1286,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     public static CharSequence getAt(CharSequence text, Range range) {
         RangeInfo info = subListBorders(text.length(), range);
         CharSequence sequence = text.subSequence(info.from, info.to);
-        return info.reverse ? reverse((String) sequence) : sequence;
+        return info.reverse ? reverse(sequence) : sequence;
+    }
+
+    /**
+     * Support the range subscript operator for GString
+     *
+     * @param text  a GString
+     * @param range a Range
+     * @return the String of characters corresponding to the provided range
+     * @since 2.3.7
+     */
+    public static String getAt(GString text, Range range) {
+        return getAt(text.toString(), range);
     }
 
     /**
@@ -1464,28 +1418,21 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Select a List of characters from a String using a Collection
-     * to identify the indices to be selected.
-     *
-     * @param self    a String
-     * @param indices a Collection of indices
-     * @return a String consisting of the characters at the given indices
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #getAt(CharSequence, java.util.Collection)
      */
+    @Deprecated
     public static String getAt(String self, Collection indices) {
-        return (String) getAt((CharSequence) self, indices);
+        return getAt((CharSequence) self, indices);
     }
 
     /**
-     * Support the range subscript operator for String with EmptyRange
-     *
-     * @param text  a String
-     * @param range an EmptyRange
-     * @return the resulting String
-     * @since 1.5.0
+     * @deprecated Use the CharSequence version
+     * @see #getAt(CharSequence, groovy.lang.EmptyRange)
      */
+    @Deprecated
     public static String getAt(String text, EmptyRange range) {
-        return "";
+        return getAt((CharSequence) text, range);
     }
 
     /**
@@ -1539,20 +1486,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static char[] getChars(CharSequence self) {
-        return getChars(self.toString());
+        return self.toString().toCharArray();
     }
 
     /**
-     * Converts the given String into an array of characters.
-     * Alias for toCharArray.
-     *
-     * @param self a String
-     * @return an array of characters
-     * @see String#toCharArray()
-     * @since 1.6.0
+     * @deprecated Use the CharSequence version
+     * @see #getChars(CharSequence)
      */
+    @Deprecated
     public static char[] getChars(String self) {
-        return self.toCharArray();
+        return getChars((CharSequence) self);
     }
 
     /**
@@ -1630,23 +1573,21 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isAllWhitespace(CharSequence self) {
-        return isAllWhitespace(self.toString());
+        String s = self.toString();
+        for (int i = 0; i < s.length(); i++) {
+            if (!Character.isWhitespace(s.charAt(i)))
+                return false;
+        }
+        return true;
     }
 
     /**
-     * True if a String only contains whitespace characters.
-     *
-     * @param self The String to check the characters in
-     * @return true If all characters are whitespace characters
-     * @see Character#isWhitespace(char)
-     * @since 1.6
+     * @deprecated Use the CharSequence version
+     * @see #isAllWhitespace(CharSequence)
      */
+    @Deprecated
     public static boolean isAllWhitespace(String self) {
-        for (int i = 0; i < self.length(); i++) {
-            if (!Character.isWhitespace(self.charAt(i)))
-                return false;
-        }
-        return true;
+        return isAllWhitespace((CharSequence) self);
     }
 
     /**
@@ -1658,19 +1599,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isBigDecimal(CharSequence self) {
-        return isBigDecimal(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into a BigDecimal.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isBigDecimal(String self) {
         try {
-            new BigDecimal(self.trim());
+            new BigDecimal(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1678,6 +1608,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #isBigDecimal(CharSequence)
+     */
+    @Deprecated
+    public static boolean isBigDecimal(String self) {
+        return isBigDecimal((CharSequence) self);
+    }
+
+    /**
      * Determine if a CharSequence can be parsed as a BigInteger.
      *
      * @param self a CharSequence
@@ -1686,19 +1625,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isBigInteger(CharSequence self) {
-        return isBigInteger(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into a BigInteger.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isBigInteger(String self) {
         try {
-            new BigInteger(self.trim());
+            new BigInteger(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1706,7 +1634,26 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * 'Case' implementation for a CharSequence, which simply calls the equivalent method for String.
+     * @deprecated Use the CharSequence version
+     * @see #isBigInteger(CharSequence)
+     */
+    @Deprecated
+    public static boolean isBigInteger(String self) {
+        return isBigInteger((CharSequence) self);
+    }
+
+    /**
+     * 'Case' implementation for a CharSequence, which uses equals between the
+     * toString() of the caseValue and the switchValue. This allows CharSequence
+     * values to be used in switch statements. For example:
+     * <pre>
+     * switch( str ) {
+     *   case 'one' :
+     *   // etc...
+     * }
+     * </pre>
+     * Note that this returns <code>true</code> for the case where both the
+     * 'switch' and 'case' operand is <code>null</code>.
      *
      * @param caseValue   the case value
      * @param switchValue the switch value
@@ -1714,19 +1661,20 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isCase(CharSequence caseValue, Object switchValue) {
-        return isCase(caseValue.toString(), switchValue);
+        String s = caseValue.toString();
+        if (switchValue == null) {
+            return s == null;
+        }
+        return s.equals(switchValue.toString());
     }
 
     /**
-     * 'Case' implementation for a GString, which simply calls the equivalent method for String.
-     *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the switchValue's toString() equals the caseValue
-     * @since 1.6.0
+     * @deprecated Use the CharSequence version
+     * @see #isCase(CharSequence, Object)
      */
+    @Deprecated
     public static boolean isCase(GString caseValue, Object switchValue) {
-        return isCase(caseValue.toString(), switchValue);
+        return isCase((CharSequence) caseValue, switchValue);
     }
 
     /**
@@ -1760,26 +1708,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * 'Case' implementation for a String, which uses String#equals(Object)
-     * in order to allow Strings to be used in switch statements.
-     * For example:
-     * <pre>switch( str ) {
-     *   case 'one' :
-     *   // etc...
-     * }</pre>
-     * Note that this returns <code>true</code> for the case where both the
-     * 'switch' and 'case' operand is <code>null</code>.
-     *
-     * @param caseValue   the case value
-     * @param switchValue the switch value
-     * @return true if the switchValue's toString() equals the caseValue
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #isCase(CharSequence, Object)
      */
+    @Deprecated
     public static boolean isCase(String caseValue, Object switchValue) {
-        if (switchValue == null) {
-            return caseValue == null;
-        }
-        return caseValue.equals(switchValue.toString());
+        return isCase((CharSequence) caseValue, switchValue);
     }
 
     /**
@@ -1791,19 +1725,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isDouble(CharSequence self) {
-        return isDouble(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into a Double.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isDouble(String self) {
         try {
-            Double.valueOf(self.trim());
+            Double.valueOf(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1811,6 +1734,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #isDouble(CharSequence)
+     */
+    @Deprecated
+    public static boolean isDouble(String self) {
+        return isDouble((CharSequence) self);
+    }
+
+    /**
      * Determine if a CharSequence can be parsed as a Float.
      *
      * @param self a CharSequence
@@ -1819,19 +1751,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isFloat(CharSequence self) {
-        return isFloat(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into a Float.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isFloat(String self) {
         try {
-            Float.valueOf(self.trim());
+            Float.valueOf(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1839,6 +1760,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #isFloat(CharSequence)
+     */
+    @Deprecated
+    public static boolean isFloat(String self) {
+        return isFloat((CharSequence) self);
+    }
+
+    /**
      * Determine if a CharSequence can be parsed as an Integer.
      *
      * @param self a CharSequence
@@ -1847,19 +1777,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isInteger(CharSequence self) {
-        return isInteger(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into an Integer.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isInteger(String self) {
         try {
-            Integer.valueOf(self.trim());
+            Integer.valueOf(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1867,6 +1786,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #isInteger(CharSequence)
+     */
+    @Deprecated
+    public static boolean isInteger(String self) {
+        return isInteger((CharSequence) self);
+    }
+
+    /**
      * Determine if a CharSequence can be parsed as a Long.
      *
      * @param self a CharSequence
@@ -1875,19 +1803,8 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static boolean isLong(CharSequence self) {
-        return isLong(self.toString());
-    }
-
-    /**
-     * Determine if a String can be parsed into a Long.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @since 1.5.0
-     */
-    public static boolean isLong(String self) {
         try {
-            Long.valueOf(self.trim());
+            Long.valueOf(self.toString().trim());
             return true;
         } catch (NumberFormatException nfe) {
             return false;
@@ -1895,29 +1812,34 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #isLong(CharSequence)
+     */
+    @Deprecated
+    public static boolean isLong(String self) {
+        return isLong((CharSequence) self);
+    }
+
+    /**
      * Determine if a CharSequence can be parsed as a Number.
      * Synonym for 'isBigDecimal()'.
      *
      * @param self a CharSequence
      * @return true if the CharSequence can be parsed
-     * @see #isNumber(String)
+     * @see #isBigDecimal(CharSequence)
      * @since 1.8.2
      */
     public static boolean isNumber(CharSequence self) {
-        return isNumber(self.toString());
+        return isBigDecimal(self);
     }
 
     /**
-     * Determine if a String can be parsed into a Number.
-     * Synonym for 'isBigDecimal()'.
-     *
-     * @param self a String
-     * @return true if the string can be parsed
-     * @see #isBigDecimal(String)
-     * @since 1.5.0
+     * @deprecated Use the CharSequence version
+     * @see #isNumber(CharSequence)
      */
+    @Deprecated
     public static boolean isNumber(String self) {
-        return isBigDecimal(self);
+        return isNumber((CharSequence) self);
     }
 
     /**
@@ -2044,17 +1966,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Tells whether or not self matches the given
-     * compiled regular expression Pattern.
-     *
-     * @param   self the string that is to be matched
-     * @param   pattern the regex Pattern to which the string of interest is to be matched
-     * @return  true if the string matches
-     * @see String#matches(String)
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #matches(CharSequence, Pattern)
      */
+    @Deprecated
     public static boolean matches(String self, Pattern pattern) {
-        return pattern.matcher(self).matches();
+        return matches((CharSequence) self, pattern);
     }
 
     /**
@@ -2063,107 +1980,98 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self   a CharSequence
      * @param target an object representing the part to remove
-     * @return a CharSequence minus the part to be removed
+     * @return a String containing the original minus the part to be removed
      * @see #minus(String, Object)
      * @since 1.8.2
      */
-    public static CharSequence minus(CharSequence self, Object target) {
-        return minus(self.toString(), target);
+    public static String minus(CharSequence self, Object target) {
+        String s = self.toString();
+        String text = DefaultGroovyMethods.toString(target);
+        int index = s.indexOf(text);
+        if (index == -1) return s;
+        int end = index + text.length();
+        if (s.length() > end) {
+            return s.substring(0, index) + s.substring(end);
+        }
+        return s.substring(0, index);
     }
 
     /**
-     * Remove a part of a String. This replaces the first occurrence
-     * of the regex pattern within self with '' and returns the result. 
+     * Remove a part of a CharSequence. This replaces the first occurrence
+     * of the pattern within self with '' and returns the result.
      *
      * @param self   a String
      * @param pattern a Pattern representing the part to remove
      * @return a String minus the part to be removed
      * @since 2.2.0
      */
-    public static String minus(String self, Pattern pattern) {
+    public static String minus(CharSequence self, Pattern pattern) {
         return pattern.matcher(self).replaceFirst("");
     }
 
     /**
-     * Remove a part of a String. This replaces the first occurrence
-     * of target.toString() within self with '' and returns the result. 
-     *
-     * @param self   a String
-     * @param target an object representing the part to remove
-     * @return a String minus the part to be removed
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #minus(CharSequence, java.util.regex.Pattern)
      */
-    public static String minus(String self, Object target) {
-        String text = DefaultGroovyMethods.toString(target);
-        int index = self.indexOf(text);
-        if (index == -1) return self;
-        int end = index + text.length();
-        if (self.length() > end) {
-            return self.substring(0, index) + self.substring(end);
-        }
-        return self.substring(0, index);
+    @Deprecated
+    public static String minus(String self, Pattern pattern) {
+        return minus((CharSequence) self, pattern);
     }
 
     /**
-     * Repeat a CharSequence a certain number of times.
-     *
-     * @param self   a CharSequence to be repeated
-     * @param factor the number of times the CharSequence should be repeated
-     * @return a CharSequence composed of a repetition
-     * @throws IllegalArgumentException if the number of repetitions is < 0
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #minus(CharSequence, Object)
      */
-    public static CharSequence multiply(CharSequence self, Number factor) {
-        return multiply(self.toString(), factor);
+    @Deprecated
+    public static String minus(String self, Object target) {
+        return minus((CharSequence) self, target);
     }
 
     /**
-     * Repeat a String a certain number of times.
+     * Repeat a CharSequence a certain number of times.
      *
-     * @param self   a String to be repeated
-     * @param factor the number of times the String should be repeated
+     * @param self   a CharSequence to be repeated
+     * @param factor the number of times the CharSequence should be repeated
      * @return a String composed of a repetition
      * @throws IllegalArgumentException if the number of repetitions is < 0
-     * @since 1.0
+     * @since 1.8.2
      */
-    public static String multiply(String self, Number factor) {
+    public static String multiply(CharSequence self, Number factor) {
+        String s = self.toString();
         int size = factor.intValue();
         if (size == 0)
             return "";
         else if (size < 0) {
             throw new IllegalArgumentException("multiply() should be called with a number of 0 or greater not: " + size);
         }
-        StringBuilder answer = new StringBuilder(self);
+        StringBuilder answer = new StringBuilder(s);
         for (int i = 1; i < size; i++) {
-            answer.append(self);
+            answer.append(s);
         }
         return answer.toString();
     }
 
     /**
-     * This method is called by the ++ operator for the class CharSequence.
-     *
-     * @param self a CharSequence
-     * @return an incremented CharSequence
-     * @see #next(String)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #multiply(CharSequence, Number)
      */
-    public static CharSequence next(CharSequence self) {
-        return next(self.toString());
+    @Deprecated
+    public static String multiply(String self, Number factor) {
+        return multiply((CharSequence) self, factor);
     }
 
     /**
-     * This method is called by the ++ operator for the class String.
-     * It increments the last character in the given string. If the
-     * character in the string is Character.MAX_VALUE a Character.MIN_VALUE
-     * will be appended. The empty string is incremented to a string
+     * This method is called by the ++ operator for the class CharSequence.
+     * It increments the last character in the given CharSequence. If the last
+     * character in the CharSequence is Character.MAX_VALUE a Character.MIN_VALUE
+     * will be appended. The empty CharSequence is incremented to a string
      * consisting of the character Character.MIN_VALUE.
      *
-     * @param self a String
-     * @return an incremented String
-     * @since 1.0
+     * @param self a CharSequence
+     * @return a value obtained by incrementing the toString() of the CharSequence
+     * @since 1.8.2
      */
-    public static String next(String self) {
+    public static String next(CharSequence self) {
         StringBuilder buffer = new StringBuilder(self);
         if (buffer.length() == 0) {
             buffer.append(Character.MIN_VALUE);
@@ -2181,84 +2089,66 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Return a CharSequence with linefeeds and carriage returns normalized to linefeeds.
-     *
-     * @param self a CharSequence object
-     * @return the normalized CharSequence
-     * @see #normalize(String)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #next(CharSequence)
      */
-    public static CharSequence normalize(final CharSequence self) {
-        return normalize(self.toString());
+    @Deprecated
+    public static String next(String self) {
+        return next((CharSequence) self);
     }
 
     /**
      * Return a String with linefeeds and carriage returns normalized to linefeeds.
      *
-     * @param self a String object
-     * @return the normalized string
-     * @since 1.6.0
+     * @param self a CharSequence object
+     * @return the normalized toString() for the CharSequence
+     * @see #normalize(String)
+     * @since 1.8.2
      */
-    public static String normalize(final String self) {
-        int nx = self.indexOf('\r');
+    public static String normalize(final CharSequence self) {
+        final String s = self.toString();
+        int nx = s.indexOf('\r');
 
         if (nx < 0) {
-            return self;
+            return s;
         }
 
-        final int len = self.length();
+        final int len = s.length();
         final StringBuilder sb = new StringBuilder(len);
 
         int i = 0;
 
         do {
-            sb.append(self, i, nx);
+            sb.append(s, i, nx);
             sb.append('\n');
 
             if ((i = nx + 1) >= len) break;
 
-            if (self.charAt(i) == '\n') {
+            if (s.charAt(i) == '\n') {
                 // skip the LF in CR LF
                 if (++i >= len) break;
             }
 
-            nx = self.indexOf('\r', i);
+            nx = s.indexOf('\r', i);
         } while (nx > 0);
 
-        sb.append(self, i, len);
+        sb.append(s, i, len);
 
         return sb.toString();
     }
 
     /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space character to the left as many times as needed.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
-     * @return the CharSequence padded to the left
-     * @see #padLeft(CharSequence, Number, CharSequence)
-     * @since 1.8.2
-     */
-    public static CharSequence padLeft(CharSequence self, Number numberOfChars) {
-        return padLeft(self, numberOfChars, " ");
-    }
-
-    /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied padding CharSequence as many times as needed to the left.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
-     * @param padding       the characters used for padding
-     * @return the CharSequence padded to the left
-     * @see #padLeft(String, Number, String)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #normalize(CharSequence)
      */
-    public static CharSequence padLeft(CharSequence self, Number numberOfChars, CharSequence padding) {
-        return padLeft(self.toString(), numberOfChars, padding.toString());
+    @Deprecated
+    public static String normalize(final String self) {
+        return normalize((CharSequence) self);
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt> by adding the space character to the left as many times as needed.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space character
+     * to the left as many times as needed.
      *
      * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
      * <pre>
@@ -2274,20 +2164,22 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *  1000
      * </pre>
      *
-     * @param self          a String object
-     * @param numberOfChars the total minimum number of characters of the resulting string
-     * @return the String padded to the left
-     * @see #padLeft(String, Number, String)
-     * @since 1.0
+     * @param self          a CharSequence object
+     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
+     * @return the CharSequence padded to the left as a String
+     * @see #padLeft(CharSequence, Number, CharSequence)
+     * @since 1.8.2
      */
-    public static String padLeft(String self, Number numberOfChars) {
+    public static String padLeft(CharSequence self, Number numberOfChars) {
         return padLeft(self, numberOfChars, " ");
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied padding String as many times as needed to the left.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied
+     * padding CharSequence as many times as needed to the left.
      *
-     * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
+     * If the CharSequence is already the same size or bigger than the target <tt>numberOfChars</tt>, then the
+     * toString() of the original CharSequence is returned. An example:
      * <pre>
      * println 'Numbers:'
      * [1, 10, 100, 1000].each{ println it.toString().padLeft(5, '*') }
@@ -2306,52 +2198,47 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * *2000
      * </pre>
      *
-     * @param self          a String object
-     * @param numberOfChars the total minimum number of characters of the resulting string
+     * @param self          a CharSequence object
+     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
      * @param padding       the characters used for padding
-     * @return the String padded to the left
-     * @since 1.0
+     * @return the CharSequence padded to the left as a String
+     * @see #padLeft(String, Number, String)
+     * @since 1.8.2
      */
-    public static String padLeft(String self, Number numberOfChars, String padding) {
+    public static String padLeft(CharSequence self, Number numberOfChars, CharSequence padding) {
+        String s = self.toString();
         int numChars = numberOfChars.intValue();
-        if (numChars <= self.length()) {
-            return self;
+        if (numChars <= s.length()) {
+            return s;
         } else {
-            return getPadding(padding, numChars - self.length()) + self;
+            return getPadding(padding.toString(), numChars - s.length()) + s;
         }
     }
 
     /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space character to the right as many times as needed.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting string
-     * @return the CharSequence padded to the right
-     * @see #padRight(String, Number)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #padLeft(CharSequence, Number)
      */
-    public static CharSequence padRight(CharSequence self, Number numberOfChars) {
-        return padRight(self.toString(), numberOfChars);
+    @Deprecated
+    public static String padLeft(String self, Number numberOfChars) {
+        return padLeft((CharSequence) self, numberOfChars);
     }
 
     /**
-     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied padding CharSequence as many times as needed to the right.
-     *
-     * @param self          a CharSequence object
-     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
-     * @param padding       the characters used for padding
-     * @return the CharSequence padded to the right
-     * @see #padRight(String, Number, String)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #padLeft(CharSequence, Number, CharSequence)
      */
-    public static CharSequence padRight(CharSequence self, Number numberOfChars, CharSequence padding) {
-        return padRight(self.toString(), numberOfChars, padding.toString());
+    @Deprecated
+    public static String padLeft(String self, Number numberOfChars, String padding) {
+        return padLeft((CharSequence) self, numberOfChars,(CharSequence) padding);
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt> by adding the space character to the right as many times as needed.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt> by adding the space
+     * character to the right as many times as needed.
      *
-     * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
+     * If the CharSequence is already the same size or bigger than the target <tt>numberOfChars</tt>,
+     * then the toString() of the original CharSequence is returned. An example:
      * <pre>
      * ['A', 'BB', 'CCC', 'DDDD'].each{ println it.padRight(5) + it.size() }
      * </pre>
@@ -2363,19 +2250,22 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * DDDD 4
      * </pre>
      *
-     * @param self          a String object
+     * @param self          a CharSequence object
      * @param numberOfChars the total minimum number of characters of the resulting string
-     * @return the String padded to the right
-     * @since 1.0
+     * @return the CharSequence padded to the right as a String
+     * @see #padRight(String, Number)
+     * @since 1.8.2
      */
-    public static String padRight(String self, Number numberOfChars) {
+    public static String padRight(CharSequence self, Number numberOfChars) {
         return padRight(self, numberOfChars, " ");
     }
 
     /**
-     * Pad a String to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied padding String as many times as needed to the right.
+     * Pad a CharSequence to a minimum length specified by <tt>numberOfChars</tt>, adding the supplied padding
+     * CharSequence as many times as needed to the right.
      *
-     * If the String is already the same size or bigger than the target <tt>numberOfChars</tt>, then the original String is returned. An example:
+     * If the CharSequence is already the same size or bigger than the target <tt>numberOfChars</tt>,
+     * then the toString() of the original CharSequence is returned. An example:
      * <pre>
      * ['A', 'BB', 'CCC', 'DDDD'].each{ println it.padRight(5, '#') + it.size() }
      * </pre>
@@ -2387,30 +2277,49 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * DDDD#4
      * </pre>
      *
-     * @param self          a String object
-     * @param numberOfChars the total minimum number of characters of the resulting string
+     * @param self          a CharSequence object
+     * @param numberOfChars the total minimum number of characters of the resulting CharSequence
      * @param padding       the characters used for padding
-     * @return the String padded to the right
-     * @since 1.0
+     * @return the CharSequence padded to the right as a String
+     * @since 1.8.2
      */
-    public static String padRight(String self, Number numberOfChars, String padding) {
+    public static String padRight(CharSequence self, Number numberOfChars, CharSequence padding) {
+        String s = self.toString();
         int numChars = numberOfChars.intValue();
-        if (numChars <= self.length()) {
-            return self;
+        if (numChars <= s.length()) {
+            return s;
         } else {
-            return self + getPadding(padding, numChars - self.length());
+            return s + getPadding(padding.toString(), numChars - s.length());
         }
     }
 
     /**
-     * Appends the String representation of the given operand to this string.
+     * @deprecated Use the CharSequence version
+     * @see #padRight(CharSequence, Number)
+     */
+    @Deprecated
+    public static String padRight(String self, Number numberOfChars) {
+        return padRight((CharSequence) self, numberOfChars, (CharSequence) " ");
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #padRight(CharSequence, Number, CharSequence)
+     */
+    @Deprecated
+    public static String padRight(String self, Number numberOfChars, String padding) {
+        return padRight((CharSequence) self, numberOfChars, (CharSequence) padding);
+    }
+
+    /**
+     * Appends the String representation of the given operand to this CharSequence.
      *
      * @param left  a CharSequence
      * @param value any Object
-     * @return the new CharSequence with the object appended
+     * @return the original toString() of the CharSequence with the object appended
      * @since 1.8.2
      */
-    public static CharSequence plus(CharSequence left, Object value) {
+    public static String plus(CharSequence left, Object value) {
         return left + DefaultGroovyMethods.toString(value);
     }
 
@@ -2427,15 +2336,12 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Appends the String representation of the given operand to this string.
-     *
-     * @param left  a String
-     * @param value any Object
-     * @return the new string with the object appended
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #plus(CharSequence, Object)
      */
+    @Deprecated
     public static String plus(String left, Object value) {
-        return left + DefaultGroovyMethods.toString(value);
+        return plus((CharSequence) left, value);
     }
 
     /**
@@ -2464,27 +2370,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
 
     /**
      * This method is called by the -- operator for the class CharSequence.
+     * It decrements the last character in the given CharSequence. If the
+     * last character in the CharSequence is Character.MIN_VALUE it will be deleted.
+     * The empty CharSequence can't be decremented.
      *
      * @param self a CharSequence
-     * @return a CharSequence with a decremented digit at the end
+     * @return a String with a decremented character at the end
      * @see #previous(String)
      * @since 1.8.2
      */
-    public static CharSequence previous(CharSequence self) {
-        return previous(self.toString());
-    }
-
-    /**
-     * This method is called by the -- operator for the class String.
-     * It decrements the last character in the given string. If the
-     * character in the string is Character.MIN_VALUE it will be deleted.
-     * The empty string can't be decremented.
-     *
-     * @param self a String
-     * @return a String with a decremented digit at the end
-     * @since 1.0
-     */
-    public static String previous(String self) {
+    public static String previous(CharSequence self) {
         StringBuilder buffer = new StringBuilder(self);
         if (buffer.length() == 0) throw new IllegalArgumentException("the string is empty");
         char last = buffer.charAt(buffer.length() - 1);
@@ -2499,6 +2394,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * @deprecated Use the CharSequence version
+     * @see #previous(CharSequence)
+     */
+    @Deprecated
+    public static String previous(String self) {
+        return previous((CharSequence) self);
+    }
+
+    /**
      * Support the range subscript operator for StringBuffer.
      *
      * @param self  a StringBuffer
@@ -2526,27 +2430,24 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Return the lines of a CharSequence as a List of CharSequence.
+     * Return the lines of a CharSequence as a List of String.
      *
      * @param self a CharSequence object
      * @return a list of lines
      * @throws java.io.IOException if an error occurs
      * @since 1.8.2
      */
-    public static List<CharSequence> readLines(CharSequence self) throws IOException {
-        return new ArrayList<CharSequence>(readLines(self.toString()));
+    public static List<String> readLines(CharSequence self) throws IOException {
+        return IOGroovyMethods.readLines(new StringReader(self.toString()));
     }
 
     /**
-     * Return the lines of a String as a List of Strings.
-     *
-     * @param self a String object
-     * @return a list of lines
-     * @throws java.io.IOException if an error occurs
-     * @since 1.5.5
+     * @deprecated Use the CharSequence version
+     * @see #readLines(CharSequence)
      */
+    @Deprecated
     public static List<String> readLines(String self) throws IOException {
-        return IOGroovyMethods.readLines(new StringReader(self));
+        return readLines((CharSequence) self);
     }
 
     /**
@@ -2555,66 +2456,85 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self        a CharSequence
      * @param regex       the capturing regex
-     * @param replacement the capturing regex
-     * @return a CharSequence with replaced content
+     * @param replacement the string to be substituted for each match
+     * @return the toString() of the CharSequence with content replaced
      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
      * @see String#replaceAll(String, String)
      * @since 1.8.2
      */
-    public static CharSequence replaceAll(final CharSequence self, final CharSequence regex, final CharSequence replacement) {
+    public static String replaceAll(final CharSequence self, final CharSequence regex, final CharSequence replacement) {
         return self.toString().replaceAll(regex.toString(), replacement.toString());
     }
 
     /**
      * Replaces all occurrences of a captured group by the result of a closure on that text.
+     * <p>
+     * For examples,
+     * <pre>
+     *     assert "hellO wOrld" == "hello world".replaceAll("(o)") { it[0].toUpperCase() }
+     *
+     *     assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
+     *
+     *     Here,
+     *          it[0] is the global string of the matched group
+     *          it[1] is the first string in the matched group
+     *          it[2] is the second string in the matched group
+     *
+     *     assert "FOO-FOO-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { x, y, z -> z.toUpperCase() })
+     *
+     *     Here,
+     *          x is the global string of the matched group
+     *          y is the first string in the matched group
+     *          z is the second string in the matched group
+     * </pre>
+     * Note that unlike String.replaceAll(String regex, String replacement), where the replacement string
+     * treats '$' and '\' specially (for group substitution), the result of the closure is converted to a string
+     * and that value is used literally for the replacement.
      *
      * @param self    a CharSequence
      * @param regex   the capturing regex
      * @param closure the closure to apply on each captured group
-     * @return a CharSequence with replaced content
+     * @return the toString() of the CharSequence with content replaced
      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
      * @since 1.8.2
      * @see #replaceAll(String, java.util.regex.Pattern, groovy.lang.Closure)
      */
-    public static CharSequence replaceAll(final CharSequence self, final CharSequence regex, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) final Closure closure) {
-        return replaceAll(self.toString(), Pattern.compile(regex.toString()), closure);
+    public static String replaceAll(final CharSequence self, final CharSequence regex, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) final Closure closure) {
+        return replaceAll(self, Pattern.compile(regex.toString()), closure);
     }
 
     /**
      * Replaces all substrings of a CharSequence that match the given
      * compiled regular expression with the given replacement.
+     * <p>
+     * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
+     * replacement string may cause the results to be different than if it were
+     * being treated as a literal replacement string; see
+     * {@link java.util.regex.Matcher#replaceAll}.
+     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
+     * meaning of these characters, if desired.
+     * <p>
+     * <pre class="groovyTestCase">
+     * assert "foo".replaceAll('o', 'X') == 'fXX'
+     * </pre>
      *
      * @param   self the CharSequence that is to be matched
      * @param   pattern the regex Pattern to which the CharSequence of interest is to be matched
      * @param   replacement the CharSequence to be substituted for the first match
-     * @return  The resulting <tt>CharSequence</tt>
+     * @return  The resulting <tt>String</tt>
      * @see #replaceAll(String, java.util.regex.Pattern, String)
      * @since 1.8.2
      */
-    public static CharSequence replaceAll(CharSequence self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") CharSequence replacement) {
+    public static String replaceAll(CharSequence self, Pattern pattern, CharSequence replacement) {
         return pattern.matcher(self).replaceAll(replacement.toString());
     }
 
     /**
      * Replaces all occurrences of a captured group by the result of a closure call on that text.
-     *
-     * @param self    a CharSequence
-     * @param pattern the capturing regex Pattern
-     * @param closure the closure to apply on each captured group
-     * @return a CharSequence with replaced content
-     * @since 1.8.2
-     * @see #replaceAll(String, java.util.regex.Pattern, groovy.lang.Closure)
-     */
-    public static String replaceAll(final CharSequence self, final Pattern pattern, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) final Closure closure) {
-        return replaceAll(self.toString(), pattern, closure);
-    }
-
-    /**
-     * Replaces all occurrences of a captured group by the result of a closure call on that text.
-     * <p>
-     * For examples,
-     * <pre>
-     *     assert "hellO wOrld" == "hello world".replaceAll(~"(o)") { it[0].toUpperCase() }
+     * <p>
+     * For examples,
+     * <pre>
+     *     assert "hellO wOrld" == "hello world".replaceAll(~"(o)") { it[0].toUpperCase() }
      *
      *     assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll(~"(([fF][oO]{2})[bB]ar)", { it[0].toUpperCase() })
      *
@@ -2641,17 +2561,18 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * treats '$' and '\' specially (for group substitution), the result of the closure is converted to a string
      * and that value is used literally for the replacement.
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the capturing regex Pattern
      * @param closure the closure to apply on each captured group
-     * @return a String with replaced content
-     * @since 1.6.8
+     * @return the toString() of the CharSequence with replaced content
      * @see java.util.regex.Matcher#quoteReplacement(String)
+     * @since 1.8.2
      */
-    public static String replaceAll(final String self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        final Matcher matcher = pattern.matcher(self);
+    public static String replaceAll(final CharSequence self, final Pattern pattern, @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) final Closure closure) {
+        final String s = self.toString();
+        final Matcher matcher = pattern.matcher(s);
         if (matcher.find()) {
-            final StringBuffer sb = new StringBuffer(self.length() + 16);
+            final StringBuffer sb = new StringBuffer(s.length() + 16);
             do {
                 String replacement = getReplacement(matcher, closure);
                 matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
@@ -2659,72 +2580,35 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
             matcher.appendTail(sb);
             return sb.toString();
         } else {
-            return self;
+            return s;
         }
     }
 
     /**
-     * Replaces all substrings of a String that match the given
-     * compiled regular expression with the given replacement.
-     * <p>
-     * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
-     * replacement string may cause the results to be different than if it were
-     * being treated as a literal replacement string; see
-     * {@link java.util.regex.Matcher#replaceAll}.
-     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
-     * meaning of these characters, if desired.
-     * <p>
-     * <pre class="groovyTestCase">
-     * assert "foo".replaceAll('o', 'X') == 'fXX'
-     * </pre>
-     *
-     * @param   self the string that is to be matched
-     * @param   pattern the regex Pattern to which the string of interest is to be matched
-     * @param   replacement the string to be substituted for the first match
-     * @return  The resulting <tt>String</tt>
-     * @see String#replaceAll(String, String)
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #replaceAll(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
+     */
+    @Deprecated
+    public static String replaceAll(final String self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
+        return replaceAll((CharSequence) self, pattern, closure);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #replaceAll(CharSequence, java.util.regex.Pattern, CharSequence)
      */
-    public static String replaceAll(String self, Pattern pattern, @ClosureParams(value=SimpleType.class, options="java.lang.String[]") String replacement) {
+    @Deprecated
+    public static String replaceAll(String self, Pattern pattern, String replacement) {
         return pattern.matcher(self).replaceAll(replacement);
     }
 
     /**
-     * Replaces all occurrences of a captured group by the result of a closure on that text.
-     * <p>
-     * For examples,
-     * <pre>
-     *     assert "hellO wOrld" == "hello world".replaceAll("(o)") { it[0].toUpperCase() }
-     *
-     *     assert "FOOBAR-FOOBAR-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { Object[] it -> it[0].toUpperCase() })
-     *
-     *     Here,
-     *          it[0] is the global string of the matched group
-     *          it[1] is the first string in the matched group
-     *          it[2] is the second string in the matched group
-     *
-     *     assert "FOO-FOO-" == "foobar-FooBar-".replaceAll("(([fF][oO]{2})[bB]ar)", { x, y, z -> z.toUpperCase() })
-     *
-     *     Here,
-     *          x is the global string of the matched group
-     *          y is the first string in the matched group
-     *          z is the second string in the matched group
-     * </pre>
-     * Note that unlike String.replaceAll(String regex, String replacement), where the replacement string
-     * treats '$' and '\' specially (for group substitution), the result of the closure is converted to a string
-     * and that value is used literally for the replacement.
-     *
-     * @param self    a String
-     * @param regex   the capturing regex
-     * @param closure the closure to apply on each captured group
-     * @return a String with replaced content
-     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
-     * @since 1.0
-     * @see java.util.regex.Matcher#quoteReplacement(String)
-     * @see #replaceAll(String, java.util.regex.Pattern, groovy.lang.Closure)
+     * @deprecated Use the CharSequence version
+     * @see #replaceAll(CharSequence, CharSequence, groovy.lang.Closure)
      */
+    @Deprecated
     public static String replaceAll(final String self, final String regex, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return replaceAll(self, Pattern.compile(regex), closure);
+        return replaceAll((CharSequence) self, (CharSequence) regex, closure);
     }
 
     /**
@@ -2733,10 +2617,10 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self        a CharSequence
      * @param regex       the capturing regex
-     * @param replacement the capturing regex
+     * @param replacement the CharSequence to be substituted for each match
      * @return a CharSequence with replaced content
      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
-     * @see String#replaceAll(String, String)
+     * @see String#replaceFirst(String, String)
      * @since 1.8.2
      */
     public static String replaceFirst(final CharSequence self, final CharSequence regex, final CharSequence replacement) {
@@ -2745,6 +2629,15 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
 
     /**
      * Replaces the first occurrence of a captured group by the result of a closure call on that text.
+     * <p>
+     * For example (with some replaceAll variants thrown in for comparison purposes),
+     * <pre>
+     * assert "hellO world" == "hello world".replaceFirst("(o)") { it[0].toUpperCase() } // first match
+     * assert "hellO wOrld" == "hello world".replaceAll("(o)") { it[0].toUpperCase() }   // all matches
+     *
+     * assert '1-FISH, two fish' == "one fish, two fish".replaceFirst(/([a-z]{3})\s([a-z]{4})/) { [one:1, two:2][it[1]] + '-' + it[2].toUpperCase() }
+     * assert '1-FISH, 2-FISH' == "one fish, two fish".replaceAll(/([a-z]{3})\s([a-z]{4})/) { [one:1, two:2][it[1]] + '-' + it[2].toUpperCase() }
+     * </pre>
      *
      * @param self    a CharSequence
      * @param regex   the capturing regex
@@ -2755,40 +2648,37 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static String replaceFirst(final CharSequence self, final CharSequence regex, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return replaceFirst(self.toString(), regex.toString(), closure);
+        return replaceFirst(self, Pattern.compile(regex.toString()), closure);
     }
 
     /**
      * Replaces the first substring of a CharSequence that matches the given
      * compiled regular expression with the given replacement.
+     * <p>
+     * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
+     * replacement string may cause the results to be different than if it were
+     * being treated as a literal replacement string; see
+     * {@link java.util.regex.Matcher#replaceFirst}.
+     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
+     * meaning of these characters, if desired.
+     * <p>
+     * <pre class="groovyTestCase">
+     * assert "foo".replaceFirst('o', 'X') == 'fXo'
+     * </pre>
      *
      * @param   self the CharSequence that is to be matched
      * @param   pattern the regex Pattern to which the CharSequence of interest is to be matched
      * @param   replacement the CharSequence to be substituted for the first match
-     * @return  The resulting <tt>CharSequence</tt>
+     * @return  The resulting <tt>String</tt>
      * @see #replaceFirst(String, java.util.regex.Pattern, String)
      * @since 1.8.2
      */
-    public static CharSequence replaceFirst(CharSequence self, Pattern pattern, CharSequence replacement) {
+    public static String replaceFirst(CharSequence self, Pattern pattern, CharSequence replacement) {
         return pattern.matcher(self).replaceFirst(replacement.toString());
     }
 
     /**
      * Replaces the first occurrence of a captured group by the result of a closure call on that text.
-     *
-     * @param self    a CharSequence
-     * @param pattern the capturing regex Pattern
-     * @param closure the closure to apply on the first captured group
-     * @return a CharSequence with replaced content
-     * @see #replaceFirst(String, java.util.regex.Pattern, groovy.lang.Closure)
-     * @since 1.8.2
-     */
-    public static String replaceFirst(final CharSequence self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return replaceFirst(self.toString(), pattern, closure);
-    }
-
-    /**
-     * Replaces the first occurrence of a captured group by the result of a closure call on that text.
      * <p>
      * For example (with some replaceAll variants thrown in for comparison purposes),
      * <pre>
@@ -2799,99 +2689,72 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert '1-FISH, 2-FISH' == "one fish, two fish".replaceAll(~/([a-z]{3})\s([a-z]{4})/) { [one:1, two:2][it[1]] + '-' + it[2].toUpperCase() }
      * </pre>
      *
-     * @param self    a String
+     * @param self    a CharSequence
      * @param pattern the capturing regex Pattern
      * @param closure the closure to apply on the first captured group
-     * @return a String with replaced content
-     * @since 1.7.7
-     * @see #replaceAll(String, java.util.regex.Pattern, groovy.lang.Closure)
+     * @return a CharSequence with replaced content
+     * @since 1.8.2
      */
-    public static String replaceFirst(final String self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        final Matcher matcher = pattern.matcher(self);
+    public static String replaceFirst(final CharSequence self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
+        final String s = self.toString();
+        final Matcher matcher = pattern.matcher(s);
         if (matcher.find()) {
-            final StringBuffer sb = new StringBuffer(self.length() + 16);
+            final StringBuffer sb = new StringBuffer(s.length() + 16);
             String replacement = getReplacement(matcher, closure);
             matcher.appendReplacement(sb, Matcher.quoteReplacement(replacement));
             matcher.appendTail(sb);
             return sb.toString();
         } else {
-            return self;
+            return s;
         }
     }
 
     /**
-     * Replaces the first substring of a String that matches the given
-     * compiled regular expression with the given replacement.
-     * <p>
-     * Note that backslashes (<tt>\</tt>) and dollar signs (<tt>$</tt>) in the
-     * replacement string may cause the results to be different than if it were
-     * being treated as a literal replacement string; see
-     * {@link java.util.regex.Matcher#replaceFirst}.
-     * Use {@link java.util.regex.Matcher#quoteReplacement} to suppress the special
-     * meaning of these characters, if desired.
-     * <p>
-     * <pre class="groovyTestCase">
-     * assert "foo".replaceFirst('o', 'X') == 'fXo'
-     * </pre>
-     *
-     * @param   self the string that is to be matched
-     * @param   pattern the regex Pattern to which the string of interest is to be matched
-     * @param   replacement the string to be substituted for the first match
-     * @return  The resulting <tt>String</tt>
-     * @see String#replaceFirst(String, String)
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #replaceFirst(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
+     */
+    @Deprecated
+    public static String replaceFirst(final String self, final Pattern pattern, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
+        return replaceFirst((CharSequence) self, pattern, closure);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #replaceFirst(CharSequence, java.util.regex.Pattern, CharSequence)
      */
+    @Deprecated
     public static String replaceFirst(String self, Pattern pattern, String replacement) {
         return pattern.matcher(self).replaceFirst(replacement);
     }
 
     /**
-     * Replaces the first occurrence of a captured group by the result of a closure call on that text.
-     * <p>
-     * For example (with some replaceAll variants thrown in for comparison purposes),
-     * <pre>
-     * assert "hellO world" == "hello world".replaceFirst("(o)") { it[0].toUpperCase() } // first match
-     * assert "hellO wOrld" == "hello world".replaceAll("(o)") { it[0].toUpperCase() }   // all matches
-     *
-     * assert '1-FISH, two fish' == "one fish, two fish".replaceFirst(/([a-z]{3})\s([a-z]{4})/) { [one:1, two:2][it[1]] + '-' + it[2].toUpperCase() }
-     * assert '1-FISH, 2-FISH' == "one fish, two fish".replaceAll(/([a-z]{3})\s([a-z]{4})/) { [one:1, two:2][it[1]] + '-' + it[2].toUpperCase() }
-     * </pre>
-     *
-     * @param self    a String
-     * @param regex   the capturing regex
-     * @param closure the closure to apply on the first captured group
-     * @return a String with replaced content
-     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
-     * @since 1.7.7
-     * @see java.util.regex.Matcher#quoteReplacement(String)
-     * @see #replaceFirst(String, java.util.regex.Pattern, groovy.lang.Closure)
+     * @deprecated Use the CharSequence version
+     * @see #replaceFirst(CharSequence, CharSequence, groovy.lang.Closure)
      */
+    @Deprecated
     public static String replaceFirst(final String self, final String regex, final @ClosureParams(value=FromString.class, options={"List<String>","String[]"}) Closure closure) {
-        return replaceFirst(self, Pattern.compile(regex), closure);
+        return replaceFirst((CharSequence) self, (CharSequence) regex, closure);
     }
 
     /**
-     * Creates a new CharSequence which is the reverse (backwards) of this string
+     * Creates a String which is the reverse (backwards) of this CharSequence
      *
      * @param self a CharSequence
-     * @return a new CharSequence with all the characters reversed.
+     * @return a new String with all the characters reversed.
      * @see #reverse(String)
      * @since 1.8.2
      */
-    public static CharSequence reverse(CharSequence self) {
+    public static String reverse(CharSequence self) {
         return new StringBuilder(self).reverse().toString();
     }
 
     /**
-     * Creates a new string which is the reverse (backwards) of this string
-     *
-     * @param self a String
-     * @return a new string with all the characters reversed.
-     * @since 1.0
-     * @see StringBuilder#reverse()
+     * @deprecated Use the CharSequence version
+     * @see #reverse(CharSequence)
      */
+    @Deprecated
     public static String reverse(String self) {
-        return new StringBuilder(self).reverse().toString();
+        return reverse((CharSequence) self);
     }
 
     /**
@@ -2968,49 +2831,43 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
 
     /**
      * Convenience method to split a CharSequence (with whitespace as delimiter).
-     * Similar to tokenize, but returns an Array of CharSequence instead of a List.
+     * Similar to tokenize, but returns an Array of String instead of a List.
      *
      * @param self the CharSequence to split
-     * @return CharSequence[] result of split
+     * @return String[] result of split
      * @see #split(String)
      * @since 1.8.2
      */
-    public static CharSequence[] split(CharSequence self) {
-        return split(self.toString());
+    public static String[] split(CharSequence self) {
+        StringTokenizer st = new StringTokenizer(self.toString());
+        String[] strings = new String[st.countTokens()];
+        for (int i = 0; i < strings.length; i++) {
+            strings[i] = st.nextToken();
+        }
+        return strings;
     }
 
     /**
-     * Convenience method to split a GString (with whitespace as delimiter).
-     *
-     * @param self the GString to split
-     * @return String[] result of split
-     * @see #split(String)
-     * @since 1.6.1
+     * @deprecated Use the CharSequence version
+     * @see #split(CharSequence)
      */
+    @Deprecated
     public static String[] split(GString self) {
-        return split(self.toString());
+        return split((CharSequence) self);
     }
 
     /**
-     * Convenience method to split a string (with whitespace as delimiter)
-     * Like tokenize, but returns an Array of Strings instead of a List
-     *
-     * @param self the string to split
-     * @return String[] result of split
-     * @since 1.5.0
+     * @deprecated Use the CharSequence version
+     * @see #split(CharSequence)
      */
+    @Deprecated
     public static String[] split(String self) {
-        StringTokenizer st = new StringTokenizer(self);
-        String[] strings = new String[st.countTokens()];
-        for (int i = 0; i < strings.length; i++) {
-            strings[i] = st.nextToken();
-        }
-        return strings;
+        return split((CharSequence) self);
     }
 
     /**
      * Iterates through the given CharSequence line by line, splitting each line using
-     * the given separator.  The list of tokens for each line is then passed to
+     * the given regex delimiter.  The list of tokens for each line is then passed to
      * the given closure.
      *
      * @param self    a CharSequence
@@ -3019,11 +2876,11 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @return the last value returned by the closure
      * @throws java.io.IOException if an error occurs
      * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
-     * @see #splitEachLine(String, String, groovy.lang.Closure)
+     * @see #splitEachLine(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 1.8.2
      */
     public static <T> T splitEachLine(CharSequence self, CharSequence regex, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
-        return splitEachLine(self.toString(), regex.toString(), closure);
+        return splitEachLine(self, Pattern.compile(regex.toString()), closure);
     }
 
     /**
@@ -3036,27 +2893,9 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @param closure a closure
      * @return the last value returned by the closure
      * @throws java.io.IOException if an error occurs
-     * @see #splitEachLine(String, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 1.8.2
      */
     public static <T> T splitEachLine(CharSequence self, Pattern pattern, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
-        return splitEachLine(self.toString(), pattern, closure);
-    }
-
-    /**
-     * Iterates through the given String line by line, splitting each line using
-     * the given separator Pattern.  The list of tokens for each line is then passed to
-     * the given closure.
-     *
-     * @param self    a String
-     * @param pattern the regular expression Pattern for the delimiter
-     * @param closure a closure
-     * @return the last value returned by the closure
-     * @throws java.io.IOException if an error occurs
-     * @see java.util.regex.Pattern#split(CharSequence)
-     * @since 1.6.8
-     */
-    public static <T> T splitEachLine(String self, Pattern pattern, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
         final List<String> list = readLines(self);
         T result = null;
         for (String line : list) {
@@ -3067,53 +2906,25 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Iterates through the given String line by line, splitting each line using
-     * the given separator.  The list of tokens for each line is then passed to
-     * the given closure.
-     *
-     * @param self    a String
-     * @param regex   the delimiting regular expression
-     * @param closure a closure
-     * @return the last value returned by the closure
-     * @throws java.io.IOException if an error occurs
-     * @throws java.util.regex.PatternSyntaxException if the regular expression's syntax is invalid
-     * @see String#split(String)
-     * @since 1.5.5
+     * @deprecated Use the CharSequence version
+     * @see #splitEachLine(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
      */
-    public static <T> T splitEachLine(String self, String regex, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
-        return splitEachLine(self, Pattern.compile(regex), closure);
-    }
-
-    /**
-     * Strip leading spaces from every line in a CharSequence. The
-     * line with the least number of leading spaces determines
-     * the number to remove. Lines only containing whitespace are
-     * ignored when calculating the number of leading spaces to strip.
-     *
-     * @param self     The CharSequence to strip the leading spaces from
-     * @return the stripped CharSequence
-     * @see #stripIndent(String)
-     * @since 1.8.2
-     */
-    public static CharSequence stripIndent(CharSequence self) {
-        return stripIndent(self.toString());
+    @Deprecated
+    public static <T> T splitEachLine(String self, Pattern pattern, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+        return splitEachLine((CharSequence) self, pattern, closure);
     }
 
     /**
-     * Strip <tt>numChar</tt> leading characters from
-     * every line in a CharSequence.
-     *
-     * @param self     The CharSequence to strip the characters from
-     * @param numChars The number of characters to strip
-     * @return the stripped CharSequence
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #splitEachLine(CharSequence, java.util.regex.Pattern, groovy.lang.Closure)
      */
-    public static CharSequence stripIndent(CharSequence self, int numChars) {
-        return stripIndent(self);
+    @Deprecated
+    public static <T> T splitEachLine(String self, String regex, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+        return splitEachLine((CharSequence) self, (CharSequence) regex, closure);
     }
 
     /**
-     * Strip leading spaces from every line in a String. The
+     * Strip leading spaces from every line in a CharSequence. The
      * line with the least number of leading spaces determines
      * the number to remove. Lines only containing whitespace are
      * ignored when calculating the number of leading spaces to strip.
@@ -3121,18 +2932,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * assert '  A\n B\nC' == '   A\n  B\n C'.stripIndent()
      * </pre>
      *
-     * @param self     The String to strip the leading spaces from
-     * @return the stripped String
-     * @see #stripIndent(String, int)
-     * @since 1.7.3
+     * @param self     The CharSequence to strip the leading spaces from
+     * @return the stripped toString() of the CharSequence
+     * @see #stripIndent(String)
+     * @since 1.8.2
      */
-    public static String stripIndent(String self) {
-        if (self.length() == 0) return self;
+    public static String stripIndent(CharSequence self) {
+        String s = self.toString();
+        if (s.length() == 0) return s;
         int runningCount = -1;
         try {
-            for (String line : readLines(self)) {
+            for (String line : readLines((CharSequence) s)) {
                 // don't take blank lines into account for calculating the indent
-                if (isAllWhitespace(line)) continue;
+                if (isAllWhitespace((CharSequence) line)) continue;
                 if (runningCount == -1) runningCount = line.length();
                 runningCount = findMinimumLeadingSpaces(line, runningCount);
                 if (runningCount == 0) break;
@@ -3140,159 +2952,168 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
         } catch (IOException e) {
             /* ignore */
         }
-        return stripIndent(self, runningCount == -1 ? 0 : runningCount);
+        return stripIndent(s, runningCount == -1 ? 0 : runningCount);
     }
 
     /**
      * Strip <tt>numChar</tt> leading characters from
-     * every line in a String.
+     * every line in a CharSequence.
      * <pre class="groovyTestCase">
      * assert 'DEF\n456' == '''ABCDEF\n123456'''.stripIndent(3)
      * </pre>
      *
-     * @param self     The String to strip the characters from
+     * @param self     The CharSequence to strip the characters from
      * @param numChars The number of characters to strip
      * @return the stripped String
-     * @since 1.7.3
+     * @since 1.8.2
      */
-    public static String stripIndent(String self, int numChars) {
-        if (self.length() == 0 || numChars <= 0) return self;
+    public static String stripIndent(CharSequence self, int numChars) {
+        String s = self.toString();
+        if (s.length() == 0 || numChars <= 0) return s;
         try {
             StringBuilder builder = new StringBuilder();
-            for (String line : readLines(self)) {
+            for (String line : readLines((CharSequence) s)) {
                 // normalize an empty or whitespace line to \n
                 // or strip the indent for lines containing non-space characters
-                if (!isAllWhitespace(line)) {
+                if (!isAllWhitespace((CharSequence) line)) {
                     builder.append(stripIndentFromLine(line, numChars));
                 }
                 builder.append("\n");
             }
             // remove the normalized ending line ending if it was not present
-            if (!self.endsWith("\n")) {
+            if (!s.endsWith("\n")) {
                 builder.deleteCharAt(builder.length() - 1);
             }
             return builder.toString();
         } catch (IOException e) {
             /* ignore */
         }
-        return self;
-    }
-
-    // TODO expose this for stream based stripping?
-    private static String stripIndentFromLine(String line, int numChars) {
-        int length = line.length();
-        return numChars <= length ? line.substring(numChars) : "";
+        return s;
     }
 
     /**
-     * Strip leading whitespace/control characters followed by '|' from
-     * every line in a CharSequence.
-     *
-     * @param self The CharSequence to strip the margin from
-     * @return the stripped CharSequence
-     * @see #stripMargin(CharSequence, char)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #stripIndent(CharSequence)
      */
-    public static CharSequence stripMargin(CharSequence self) {
-        return stripMargin(self, '|');
+    @Deprecated
+    public static String stripIndent(String self) {
+        return stripIndent((CharSequence) self);
     }
 
     /**
-     * Strip leading whitespace/control characters followed by <tt>marginChar</tt> from
-     * every line in a String.
-     *
-     * @param self       The CharSequence to strip the margin from
-     * @param marginChar Any character that serves as margin delimiter
-     * @return the stripped CharSequence
-     * @see #stripMargin(String, char)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #stripIndent(CharSequence)
      */
-    public static CharSequence stripMargin(CharSequence self, char marginChar) {
-        return stripMargin(self.toString(), marginChar);
+    @Deprecated
+    public static String stripIndent(String self, int numChars) {
+        return stripIndent((CharSequence) self, numChars);
     }
 
-    /**
-     * Strip leading whitespace/control characters followed by <tt>marginChar</tt> from
-     * every line in a CharSequence.
-     *
-     * @param self       The CharSequence to strip the margin from
-     * @param marginChar Any character that serves as margin delimiter
-     * @return the stripped CharSequence
-     * @see #stripMargin(String, String)
-     * @since 1.8.2
-     */
-    public static String stripMargin(CharSequence self, CharSequence marginChar) {
-        return stripMargin(self.toString(), marginChar.toString());
+    // TODO expose this for stream based stripping?
+    private static String stripIndentFromLine(String line, int numChars) {
+        int length = line.length();
+        return numChars <= length ? line.substring(numChars) : "";
     }
 
     /**
      * Strip leading whitespace/control characters followed by '|' from
-     * every line in a String.
+     * every line in a CharSequence.
      * <pre class="groovyTestCase">
      * assert 'ABC\n123\n456' == '''ABC
      *                             |123
      *                             |456'''.stripMargin()
      * </pre>
      *
-     * @param self The String to strip the margin from
+     * @param self The CharSequence to strip the margin from
      * @return the stripped String
-     * @see #stripMargin(String, char)
-     * @since 1.7.3
+     * @see #stripMargin(CharSequence, char)
+     * @since 1.8.2
      */
-    public static String stripMargin(String self) {
+    public static String stripMargin(CharSequence self) {
         return stripMargin(self, '|');
     }
 
     /**
      * Strip leading whitespace/control characters followed by <tt>marginChar</tt> from
-     * every line in a String.
+     * every line in a CharSequence.
      * <pre class="groovyTestCase">
      * assert 'ABC\n123\n456' == '''ABC
      *                             *123
      *                             *456'''.stripMargin('*')
      * </pre>
      *
-     * @param self       The String to strip the margin from
+     * @param self       The CharSequence to strip the margin from
      * @param marginChar Any character that serves as margin delimiter
      * @return the stripped String
-     * @since 1.7.3
+     * @see #stripMargin(String, char)
+     * @since 1.8.2
      */
-    public static String stripMargin(String self, char marginChar) {
-        if (self.length() == 0) return self;
+    public static String stripMargin(CharSequence self, char marginChar) {
+        String s = self.toString();
+        if (s.length() == 0) return s;
         try {
             StringBuilder builder = new StringBuilder();
-            for (String line : readLines(self)) {
+            for (String line : readLines((CharSequence) s)) {
                 builder.append(stripMarginFromLine(line, marginChar));
                 builder.append("\n");
             }
             // remove the normalized ending line ending if it was not present
-            if (!self.endsWith("\n")) {
+            if (!s.endsWith("\n")) {
                 builder.deleteCharAt(builder.length() - 1);
             }
             return builder.toString();
         } catch (IOException e) {
             /* ignore */
         }
-        return self;
+        return s;
     }
 
     /**
      * Strip leading whitespace/control characters followed by <tt>marginChar</tt> from
-     * every line in a String.
+     * every line in a CharSequence.
      *
-     * @param self       The String to strip the margin from
+     * @param self       The CharSequence to strip the margin from
      * @param marginChar Any character that serves as margin delimiter
-     * @return the stripped String
-     * @see #stripMargin(String, char)
-     * @since 1.7.3
+     * @return the stripped CharSequence
+     * @see #stripMargin(String, String)
+     * @since 1.8.2
      */
-    public static String stripMargin(String self, String marginChar) {
-        if (marginChar == null || marginChar.length() == 0) return stripMargin(self, '|');
+    public static String stripMargin(CharSequence self, CharSequence marginChar) {
+        String s = self.toString();
+        String mc = marginChar.toString();
+        if (mc == null || mc.length() == 0) return stripMargin((CharSequence) s, '|');
         // TODO IllegalArgumentException for marginChar.length() > 1 ? Or support String as marker?
-        return stripMargin(self, marginChar.charAt(0));
+        return stripMargin((CharSequence) s, mc.charAt(0));
     }
 
-    // TODO expose this for stream based stripping?
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #stripMargin(CharSequence)
+     */
+    @Deprecated
+    public static String stripMargin(String self) {
+        return stripMargin((CharSequence) self);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #stripMargin(CharSequence, char)
+     */
+    @Deprecated
+    public static String stripMargin(String self, char marginChar) {
+        return stripMargin((CharSequence) self, marginChar);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #stripMargin(CharSequence, char)
+     */
+    @Deprecated
+    public static String stripMargin(String self, String marginChar) {
+        return stripMargin((CharSequence) self, (CharSequence) marginChar);
+    }
+
+    // TODO expose this for other usage scenarios, e.g. stream based stripping?
     private static String stripMarginFromLine(String line, char marginChar) {
         int length = line.length();
         int index = 0;
@@ -3326,6 +3147,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * A GString variant of the equivalent CharSequence method.
+     *
+     * @param self the original GString
+     * @param num  the number of chars to take from this GString
+     * @return a String consisting of the first <code>num</code> chars,
+     *         or else the whole GString if it has less then <code>num</code> elements.
+     * @since 2.3.7
+     */
+    public static String take(GString self, int num) {
+        return (String) take(self.toString(), num);
+    }
+
+    /**
      * Returns the longest prefix of this CharSequence where each
      * element passed to the given closure evaluates to true.
      * <p>
@@ -3358,6 +3192,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
+     * A GString variant of the equivalent GString method.
+     *
+     * @param self      the original GString
+     * @param condition the closure that must evaluate to true to continue taking elements
+     * @return a prefix of elements in the GString where each
+     *         element passed to the given closure evaluates to true
+     * @since 2.3.7
+     */
+    public static String takeWhile(GString self, @ClosureParams(value=SimpleType.class, options="char") Closure condition) {
+        return (String) takeWhile(self.toString(), condition);
+    }
+
+    /**
      * Parse a CharSequence into a BigDecimal
      *
      * @param self a CharSequence
@@ -3366,18 +3213,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static BigDecimal toBigDecimal(CharSequence self) {
-        return toBigDecimal(self.toString());
+        return new BigDecimal(self.toString().trim());
     }
 
     /**
-     * Parse a String into a BigDecimal
-     *
-     * @param self a String
-     * @return a BigDecimal
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toBigDecimal(CharSequence)
      */
+    @Deprecated
     public static BigDecimal toBigDecimal(String self) {
-        return new BigDecimal(self.trim());
+        return toBigDecimal((CharSequence) self);
     }
 
     /**
@@ -3389,18 +3234,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static BigInteger toBigInteger(CharSequence self) {
-        return toBigInteger(self.toString());
+        return new BigInteger(self.toString().trim());
     }
 
     /**
-     * Parse a String into a BigInteger
-     *
-     * @param self a String
-     * @return a BigInteger
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toBigInteger(CharSequence)
      */
+    @Deprecated
     public static BigInteger toBigInteger(String self) {
-        return new BigInteger(self.trim());
+        return toBigInteger((CharSequence) self);
     }
 
     /**
@@ -3443,18 +3286,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static Double toDouble(CharSequence self) {
-        return toDouble(self.toString());
+        return Double.valueOf(self.toString().trim());
     }
 
     /**
-     * Parse a String into a Double
-     *
-     * @param self a String
-     * @return a Double
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toDouble(CharSequence)
      */
+    @Deprecated
     public static Double toDouble(String self) {
-        return Double.valueOf(self.trim());
+        return toDouble((CharSequence) self);
     }
 
     /**
@@ -3466,18 +3307,16 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static Float toFloat(CharSequence self) {
-        return toFloat(self.toString());
+        return Float.valueOf(self.toString().trim());
     }
 
     /**
-     * Parse a String into a Float
-     *
-     * @param self a String
-     * @return a Float
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toFloat(CharSequence)
      */
+    @Deprecated
     public static Float toFloat(String self) {
-        return Float.valueOf(self.trim());
+        return toFloat((CharSequence) self);
     }
 
     /**
@@ -3485,22 +3324,19 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self a CharSequence
      * @return an Integer
-     * @see #toInteger(String)
      * @since 1.8.2
      */
     public static Integer toInteger(CharSequence self) {
-        return toInteger(self.toString());
+        return Integer.valueOf(self.toString().trim());
     }
 
     /**
-     * Parse a String into an Integer
-     *
-     * @param self a String
-     * @return an Integer
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toInteger(CharSequence)
      */
+    @Deprecated
     public static Integer toInteger(String self) {
-        return Integer.valueOf(self.trim());
+        return toInteger((CharSequence) self);
     }
 
     /**
@@ -3508,23 +3344,29 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self a CharSequence
      * @return a List of tokens
-     * @see #tokenize(String)
+     * @see java.util.StringTokenizer#StringTokenizer(String)
      * @since 1.8.2
      */
-    public static List<CharSequence> tokenize(CharSequence self) {
-        return new ArrayList<CharSequence>(tokenize(self.toString()));
+    @SuppressWarnings("unchecked")
+    public static List<String> tokenize(CharSequence self) {
+        return InvokerHelper.asList(new StringTokenizer(self.toString()));
     }
 
     /**
      * Tokenize a CharSequence based on the given character delimiter.
+     * For example:
+     * <pre class="groovyTestCase">
+     * char pathSep = ':'
+     * assert "/tmp:/usr".tokenize(pathSep) == ["/tmp", "/usr"]
+     * </pre>
      *
      * @param self  a CharSequence
      * @param token the delimiter
      * @return a List of tokens
-     * @see #tokenize(String, Character)
+     * @see java.util.StringTokenizer#StringTokenizer(String, String)
      * @since 1.8.2
      */
-    public static List<CharSequence> tokenize(CharSequence self, Character token) {
+    public static List<String> tokenize(CharSequence self, Character token) {
         return tokenize(self, token.toString());
     }
 
@@ -3534,84 +3376,66 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @param self  a CharSequence
      * @param token the delimiter
      * @return a List of tokens
-     * @see #tokenize(String, String)
+     * @see java.util.StringTokenizer#StringTokenizer(String, String)
      * @since 1.8.2
      */
-    public static List<CharSequence> tokenize(CharSequence self, CharSequence token) {
-        return new ArrayList<CharSequence>(tokenize(self.toString(), token.toString()));
+    @SuppressWarnings("unchecked")
+    public static List<String> tokenize(CharSequence self, CharSequence token) {
+        return InvokerHelper.asList(new StringTokenizer(self.toString(), token.toString()));
     }
 
     /**
-     * Tokenize a String (with a whitespace as the delimiter).
-     *
-     * @param self a String
-     * @return a List of tokens
-     * @see java.util.StringTokenizer#StringTokenizer(String)
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #tokenize(CharSequence)
      */
-    @SuppressWarnings("unchecked")
+    @Deprecated
     public static List<String> tokenize(String self) {
-        return InvokerHelper.asList(new StringTokenizer(self));
+        return tokenize((CharSequence) self);
     }
 
     /**
-     * Tokenize a String based on the given character delimiter.
-     * For example:
-     * <pre class="groovyTestCase">
-     * char pathSep = ':'
-     * assert "/tmp:/usr".tokenize(pathSep) == ["/tmp", "/usr"]
-     * </pre>
-     *
-     * @param self  a String
-     * @param token the delimiter
-     * @return a List of tokens
-     * @see java.util.StringTokenizer#StringTokenizer(String, String)
-     * @since 1.7.2
+     * @deprecated Use the CharSequence version
+     * @see #tokenize(CharSequence, Character)
      */
+    @Deprecated
     public static List<String> tokenize(String self, Character token) {
-        return tokenize(self, token.toString());
+        return tokenize((CharSequence) self, token);
     }
 
     /**
-     * Tokenize a String based on the given string delimiter.
-     *
-     * @param self  a String
-     * @param token the delimiter
-     * @return a List of tokens
-     * @see java.util.StringTokenizer#StringTokenizer(String, String)
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #tokenize(CharSequence, CharSequence)
      */
-    @SuppressWarnings("unchecked")
+    @Deprecated
     public static List<String> tokenize(String self, String token) {
-        return InvokerHelper.asList(new StringTokenizer(self, token));
+        return tokenize((CharSequence) self, (CharSequence) token);
     }
 
     /**
-     * Converts the given CharSequence into a List of CharSequence of one character.
+     * Converts the given CharSequence into a List of Strings of one character.
      *
      * @param self a CharSequence
-     * @return a List of characters (a 1-character CharSequence)
+     * @return a List of characters (a 1-character String)
      * @see #toSet(String)
      * @since 1.8.2
      */
-    public static List<CharSequence> toList(CharSequence self) {
-        return new ArrayList<CharSequence>(toList(self.toString()));
+    public static List<String> toList(CharSequence self) {
+        String s = self.toString();
+        int size = s.length();
+        List<String> answer = new ArrayList<String>(size);
+        for (int i = 0; i < size; i++) {
+            answer.add(s.substring(i, i + 1));
+        }
+        return answer;
     }
 
     /**
-     * Converts the given String into a List of strings of one character.
-     *
-     * @param self a String
-     * @return a List of characters (a 1-character String)
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toList(CharSequence)
      */
+    @Deprecated
     public static List<String> toList(String self) {
-        int size = self.length();
-        List<String> answer = new ArrayList<String>(size);
-        for (int i = 0; i < size; i++) {
-            answer.add(self.substring(i, i + 1));
-        }
-        return answer;
+        return toList((CharSequence) self);
     }
 
     /**
@@ -3623,47 +3447,37 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 1.8.2
      */
     public static Long toLong(CharSequence self) {
-        return toLong(self.toString());
+        return Long.valueOf(self.toString().trim());
     }
 
     /**
-     * Parse a String into a Long
-     *
-     * @param self a String
-     * @return a Long
-     * @since 1.0
+     * @deprecated Use the CharSequence version
+     * @see #toLong(CharSequence)
      */
+    @Deprecated
     public static Long toLong(String self) {
-        return Long.valueOf(self.trim());
+        return toLong((CharSequence) self);
     }
 
     /**
-     * Converts the given CharSequence into a Set of unique CharSequence of one character.
+     * Converts the given CharSequence into a Set of unique String of one character.
      *
      * @param self a CharSequence
-     * @return a Set of unique character CharSequence (each a 1-character CharSequence)
+     * @return a Set of unique characters (each a 1-character String)
      * @see #toSet(String)
      * @since 1.8.2
      */
-    public static Set<CharSequence> toSet(CharSequence self) {
-        return new HashSet<CharSequence>(toList(self));
+    public static Set<String> toSet(CharSequence self) {
+        return new HashSet<String>(toList(self));
     }
 
     /**
-     * Converts the given String into a Set of unique strings of one character.
-     * <p>
-     * Example usage:
-     * <pre class="groovyTestCase">
-     * assert 'groovy'.toSet() == ['v', 'g', 'r', 'o', 'y'] as Set
-     * assert "abc".toSet().iterator()[0] instanceof String
-     * </pre>
-     *
-     * @param self a String
-     * @return a Set of unique character Strings (each a 1-character String)
-     * @since 1.8.0
+     * @deprecated Use the CharSequence version
+     * @see #toSet(CharSequence)
      */
+    @Deprecated
     public static Set<String> toSet(String self) {
-        return new HashSet<String>(toList(self));
+        return toSet((CharSequence) self);
     }
 
     /**
@@ -3671,42 +3485,25 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self a CharSequence
      * @return a Short
-     * @see #toShort(String)
      * @since 1.8.2
      */
     public static Short toShort(CharSequence self) {
-        return toShort(self.toString());
+        return Short.valueOf(self.toString().trim());
     }
 
     /**
-     * Parse a String into a Short
-     *
-     * @param self a String
-     * @return a Short
-     * @since 1.5.7
+     * @deprecated Use the CharSequence version
+     * @see #toShort(CharSequence)
      */
+    @Deprecated
     public static Short toShort(String self) {
-        return Short.valueOf(self.trim());
-    }
-
-    /**
-     * Translates a string by replacing characters from the sourceSet with characters from replacementSet.
-     *
-     * @param   self the CharSequence that is to be translated
-     * @param   sourceSet the set of characters to translate from
-     * @param   replacementSet the set of replacement characters
-     * @return  The resulting translated <tt>CharSequence</tt>
-     * @see #tr(String, String, String)
-     * @since 1.8.2
-     */
-    public static CharSequence tr(final CharSequence self, CharSequence sourceSet, CharSequence replacementSet) throws ClassNotFoundException {
-        return tr(self.toString(), sourceSet.toString(), replacementSet.toString());
+        return toShort((CharSequence) self);
     }
 
     /**
-     * Translates a string by replacing characters from the sourceSet with characters from replacementSet.
-     * If the first character from sourceSet appears in the string, it will be replaced with the first character from replacementSet.
-     * If the second character from sourceSet appears in the string, it will be replaced with the second character from replacementSet.
+     * Translates a CharSequence by replacing characters from the sourceSet with characters from replacementSet.
+     * If the first character from sourceSet appears in the CharSequence, it will be replaced with the first character from replacementSet.
+     * If the second character from sourceSet appears in the CharSequence, it will be replaced with the second character from replacementSet.
      * and so on for all provided replacement characters.
      * <p>
      * Here is an example which converts the vowels in a word from lower to uppercase:
@@ -3737,92 +3534,82 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      * The functionality provided by tr can be achieved using regular expressions but tr provides a much more compact
      * notation and efficient implementation for certain scenarios.
      *
-     * @param   self the string that is to be translated
+     * @param   self the CharSequence that is to be translated
      * @param   sourceSet the set of characters to translate from
      * @param   replacementSet the set of replacement characters
      * @return  The resulting translated <tt>String</tt>
      * @see org.codehaus.groovy.util.StringUtil#tr(String, String, String)
-     * @since 1.7.3
-     */
-    public static String tr(final String self, String sourceSet, String replacementSet) throws ClassNotFoundException {
-        return (String) InvokerHelper.invokeStaticMethod("org.codehaus.groovy.util.StringUtil", "tr", new Object[]{self, sourceSet, replacementSet});
-    }
-
-    /**
-     * Replaces sequences of whitespaces with tabs using tabStops of size 8.
-     *
-     * @param self A CharSequence to unexpand
-     * @return The unexpanded CharSequence
-     * @see #unexpand(String)
      * @since 1.8.2
      */
-    public static CharSequence unexpand(CharSequence self) {
-        return unexpand(self.toString());
+    public static String tr(final CharSequence self, CharSequence sourceSet, CharSequence replacementSet) throws ClassNotFoundException {
+        return (String) InvokerHelper.invokeStaticMethod("org.codehaus.groovy.util.StringUtil", "tr", new Object[]{self.toString(), sourceSet.toString(), replacementSet.toString()});
     }
 
     /**
-     * Replaces sequences of whitespaces with tabs.
-     *
-     * @param self A CharSequence to unexpand
-     * @param tabStop The number of spaces a tab represents
-     * @return The unexpanded CharSequence
-     * @see #unexpand(String, int)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #tr(CharSequence, CharSequence, CharSequence)
      */
-    public static CharSequence unexpand(CharSequence self, int tabStop) {
-        return unexpand(self.toString(), tabStop);
+    @Deprecated
+    public static String tr(final String self, String sourceSet, String replacementSet) throws ClassNotFoundException {
+        return tr((CharSequence) self, (CharSequence) sourceSet, (CharSequence) replacementSet);
     }
 
     /**
      * Replaces sequences of whitespaces with tabs using tabStops of size 8.
      *
-     * @param self A String to unexpand
-     * @return The unexpanded String
-     * @since 1.7.3
-     * @see #unexpand(String, int)
+     * @param self A CharSequence to unexpand
+     * @return an unexpanded String
+     * @see #unexpand(String)
+     * @since 1.8.2
      */
-    public static String unexpand(String self) {
+    public static String unexpand(CharSequence self) {
         return unexpand(self, 8);
     }
 
     /**
      * Replaces sequences of whitespaces with tabs.
      *
-     * @param self A String to unexpand
+     * @param self A CharSequence to unexpand
      * @param tabStop The number of spaces a tab represents
-     * @return The unexpanded String
-     * @since 1.7.3
+     * @return an unexpanded String
+     * @since 1.8.2
      */
-    public static String unexpand(String self, int tabStop) {
-        if (self.length() == 0) return self;
+    public static String unexpand(CharSequence self, int tabStop) {
+        String s = self.toString();
+        if (s.length() == 0) return s;
         try {
             StringBuilder builder = new StringBuilder();
-            for (String line : readLines(self)) {
+            for (String line : readLines((CharSequence) s)) {
                 builder.append(unexpandLine(line, tabStop));
                 builder.append("\n");
             }
             // remove the normalized ending line ending if it was not present
-            if (!self.endsWith("\n")) {
+            if (!s.endsWith("\n")) {
                 builder.deleteCharAt(builder.length() - 1);
             }
             return builder.toString();
         } catch (IOException e) {
             /* ignore */
         }
-        return self;
+        return s;
     }
 
     /**
-     * Replaces sequences of whitespaces with tabs within a line.
-     *
-     * @param self A line to unexpand
-     * @param tabStop The number of spaces a tab represents
-     * @return The unexpanded CharSequence
-     * @see #unexpandLine(String, int)
-     * @since 1.8.2
+     * @deprecated Use the CharSequence version
+     * @see #unexpand(CharSequence)
      */
-    public static CharSequence unexpandLine(CharSequence self, int tabStop) {
-        return unexpandLine(self.toString(), tabStop);
+    @Deprecated
+    public static String unexpand(String self) {
+        return unexpand((CharSequence) self);
+    }
+
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #unexpand(CharSequence, int)
+     */
+    @Deprecated
+    public static String unexpand(String self, int tabStop) {
+        return unexpand((CharSequence) self, tabStop);
     }
 
     /**
@@ -3830,11 +3617,11 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
      *
      * @param self A line to unexpand
      * @param tabStop The number of spaces a tab represents
-     * @return The unexpanded String
-     * @since 1.7.3
+     * @return an unexpanded String
+     * @since 1.8.2
      */
-    public static String unexpandLine(String self, int tabStop) {
-        StringBuilder builder = new StringBuilder(self);
+    public static String unexpandLine(CharSequence self, int tabStop) {
+        StringBuilder builder = new StringBuilder(self.toString());
         int index = 0;
         while (index + tabStop < builder.length()) {
             // cut original string in tabstop-length pieces
@@ -3854,4 +3641,13 @@ public class StringGroovyMethods extends DefaultGroovyMethodsSupport {
         return builder.toString();
     }
 
+    /**
+     * @deprecated Use the CharSequence version
+     * @see #tokenize(CharSequence)
+     */
+    @Deprecated
+    public static String unexpandLine(String self, int tabStop) {
+        return unexpandLine((CharSequence) self, tabStop);
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/runtime/callsite/AbstractCallSite.java b/src/main/org/codehaus/groovy/runtime/callsite/AbstractCallSite.java
index c4ad241..e7229d9 100644
--- a/src/main/org/codehaus/groovy/runtime/callsite/AbstractCallSite.java
+++ b/src/main/org/codehaus/groovy/runtime/callsite/AbstractCallSite.java
@@ -23,6 +23,8 @@ import org.codehaus.groovy.reflection.ParameterTypes;
 import org.codehaus.groovy.runtime.ArrayUtil;
 import org.codehaus.groovy.runtime.GroovyCategorySupport;
 import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.NullObject;
+import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
 import org.codehaus.groovy.runtime.wrappers.Wrapper;
 
 import java.lang.reflect.Method;
@@ -113,18 +115,34 @@ public class AbstractCallSite implements CallSite {
     }
 
     public Object call(Object receiver, Object arg1) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.call(receiver, arg1);
+        }
         return call(receiver, ArrayUtil.createArray(arg1));
     }
 
     public Object call(Object receiver, Object arg1, Object arg2) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.call(receiver, arg1, arg2);
+        }
         return call(receiver, ArrayUtil.createArray(arg1, arg2));
     }
 
     public Object call(Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.call(receiver, arg1, arg2, arg3);
+        }
         return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
     }
 
     public Object call(Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.call(receiver, arg1, arg2, arg3, arg4);
+        }
         return call(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
     }
 
@@ -138,18 +156,34 @@ public class AbstractCallSite implements CallSite {
     }
 
     public Object callCurrent(GroovyObject receiver, Object arg1) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callCurrent(receiver, arg1);
+        }
         return callCurrent(receiver, ArrayUtil.createArray(arg1));
     }
 
     public Object callCurrent(GroovyObject receiver, Object arg1, Object arg2) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callCurrent(receiver, arg1, arg2);
+        }
         return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2));
     }
 
     public Object callCurrent(GroovyObject receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callCurrent(receiver, arg1, arg2, arg3);
+        }
         return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
     }
 
     public Object callCurrent(GroovyObject receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callCurrent(receiver, arg1, arg2, arg3, arg4);
+        }
         return callCurrent(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
     }
 
@@ -162,18 +196,34 @@ public class AbstractCallSite implements CallSite {
     }
 
     public Object callStatic(Class receiver, Object arg1) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callStatic(receiver, arg1);
+        }
         return callStatic(receiver, ArrayUtil.createArray(arg1));
     }
 
     public Object callStatic(Class receiver, Object arg1, Object arg2) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callStatic(receiver, arg1, arg2);
+        }
         return callStatic(receiver, ArrayUtil.createArray(arg1, arg2));
     }
 
     public Object callStatic(Class receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callStatic(receiver, arg1, arg2, arg3);
+        }
         return callStatic(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
     }
 
     public Object callStatic(Class receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callStatic(receiver, arg1, arg2, arg3, arg4);
+        }
         return callStatic(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
     }
 
@@ -187,18 +237,34 @@ public class AbstractCallSite implements CallSite {
     }
 
     public Object callConstructor(Object receiver, Object arg1) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callConstructor(receiver, arg1);
+        }
         return callConstructor(receiver, ArrayUtil.createArray(arg1));
     }
 
     public Object callConstructor(Object receiver, Object arg1, Object arg2) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callConstructor(receiver, arg1, arg2);
+        }
         return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2));
     }
 
     public Object callConstructor(Object receiver, Object arg1, Object arg2, Object arg3) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callConstructor(receiver, arg1, arg2, arg3);
+        }
         return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2, arg3));
     }
 
     public Object callConstructor(Object receiver, Object arg1, Object arg2, Object arg3, Object arg4) throws Throwable {
+        CallSite stored = array.array[index];
+        if (stored!=this) {
+            return stored.callConstructor(receiver, arg1, arg2, arg3, arg4);
+        }
         return callConstructor(receiver, ArrayUtil.createArray(arg1, arg2, arg3, arg4));
     }
 
@@ -228,7 +294,15 @@ public class AbstractCallSite implements CallSite {
     }
 
     public Object callGroovyObjectGetProperty(Object receiver) throws Throwable {
-        return acceptGroovyObjectGetProperty(receiver).getProperty(receiver);
+        if (receiver == null) {
+            try {
+                return InvokerHelper.getProperty(NullObject.getNullObject(), name);
+            } catch (GroovyRuntimeException gre) {
+                throw ScriptBytecodeAdapter.unwrap(gre);
+            }
+        } else {
+            return acceptGroovyObjectGetProperty(receiver).getProperty(receiver);
+        }
     }
 
     public CallSite acceptGetProperty(Object receiver) {
@@ -305,7 +379,7 @@ public class AbstractCallSite implements CallSite {
         if (metaClass.getClass() != MetaClassImpl.class || GroovyCategorySupport.hasCategoryInCurrentThread()) {
             site = new PogoMetaClassGetPropertySite(this, metaClass);
         } else {
-            final MetaProperty effective = ((MetaClassImpl) metaClass).getEffectiveGetMetaProperty(metaClass.getClass(), receiver, name, false);
+            final MetaProperty effective = ((MetaClassImpl) metaClass).getEffectiveGetMetaProperty(this.array.owner, receiver, name, false);
             if (effective != null) {
                 if (effective instanceof CachedField)
                     site = new GetEffectivePogoFieldSite(this, metaClass, (CachedField) effective);
diff --git a/src/main/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java b/src/main/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
index 6c45e86..769acad 100644
--- a/src/main/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
+++ b/src/main/org/codehaus/groovy/runtime/callsite/CallSiteGenerator.java
@@ -16,9 +16,11 @@
 package org.codehaus.groovy.runtime.callsite;
 
 import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.reflection.CachedClass;
 import org.codehaus.groovy.reflection.CachedMethod;
+import org.codehaus.groovy.reflection.android.AndroidSupport;
 import org.objectweb.asm.ClassWriter;
 import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
@@ -242,7 +244,8 @@ public class CallSiteGenerator {
     }
 
     public static boolean isCompilable (CachedMethod method) {
-        return GroovySunClassLoader.sunVM != null || Modifier.isPublic(method.cachedClass.getModifiers()) && method.isPublic() && publicParams(method);
+        return (GroovySunClassLoader.sunVM != null || Modifier.isPublic(method.cachedClass.getModifiers()) && method.isPublic() && publicParams(method))
+                && !AndroidSupport.isRunningAndroid() && containsOnlyValidChars(method.getName());
     }
 
     private static boolean publicParams(CachedMethod method) {
@@ -253,4 +256,11 @@ public class CallSiteGenerator {
         return true;
     }
 
+    private static boolean containsOnlyValidChars(String name) {
+        // TODO: this might not do enough or too much
+        // But it is a good start without spreading logic everywhere
+        String encoded = GeneratorContext.encodeAsValidClassName(name);
+        return encoded.equals(name);
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/runtime/callsite/GetEffectivePojoPropertySite.java b/src/main/org/codehaus/groovy/runtime/callsite/GetEffectivePojoPropertySite.java
index b7d716e..da2eeba 100644
--- a/src/main/org/codehaus/groovy/runtime/callsite/GetEffectivePojoPropertySite.java
+++ b/src/main/org/codehaus/groovy/runtime/callsite/GetEffectivePojoPropertySite.java
@@ -48,7 +48,7 @@ public class GetEffectivePojoPropertySite extends AbstractCallSite {
 
     public final CallSite acceptGetProperty(Object receiver) {
 //        if (GroovyCategorySupport.hasCategoryInCurrentThread() || !(receiver instanceof GroovyObject) || ((GroovyObject)receiver).getMetaClass() != metaClass) {
-        if (GroovyCategorySupport.hasCategoryInCurrentThread() || receiver.getClass() != metaClass.getTheClass()
+        if (GroovyCategorySupport.hasCategoryInCurrentThread() || receiver==null || receiver.getClass() != metaClass.getTheClass()
             || version != metaClass.getVersion()) { // metaClass is invalid
             return createGetPropertySite(receiver);
         } else {
diff --git a/src/main/org/codehaus/groovy/runtime/callsite/PogoGetPropertySite.java b/src/main/org/codehaus/groovy/runtime/callsite/PogoGetPropertySite.java
index f015bdd..8d1f056 100644
--- a/src/main/org/codehaus/groovy/runtime/callsite/PogoGetPropertySite.java
+++ b/src/main/org/codehaus/groovy/runtime/callsite/PogoGetPropertySite.java
@@ -29,14 +29,14 @@ public class PogoGetPropertySite extends AbstractCallSite {
     }
 
     public CallSite acceptGetProperty(Object receiver) {
-        if (receiver.getClass() != aClass)
+        if (receiver== null || receiver.getClass() != aClass)
             return createGetPropertySite(receiver);
         else
           return this;
     }
 
     public CallSite acceptGroovyObjectGetProperty(Object receiver) {
-        if (receiver.getClass() != aClass)
+        if (receiver == null || receiver.getClass() != aClass)
             return createGroovyObjectGetPropertySite(receiver);
         else
           return this;
diff --git a/src/main/org/codehaus/groovy/runtime/m12n/ExtensionModule.java b/src/main/org/codehaus/groovy/runtime/m12n/ExtensionModule.java
index 2a17a34..e6d82c3 100644
--- a/src/main/org/codehaus/groovy/runtime/m12n/ExtensionModule.java
+++ b/src/main/org/codehaus/groovy/runtime/m12n/ExtensionModule.java
@@ -47,4 +47,12 @@ public abstract class ExtensionModule {
 
     public abstract List<MetaMethod> getMetaMethods();
 
+    @Override
+    public String toString() {
+        final StringBuilder sb = new StringBuilder("ExtensionModule{");
+        sb.append("name='").append(name).append('\'');
+        sb.append(", version='").append(version).append('\'');
+        sb.append('}');
+        return sb.toString();
+    }
 }
diff --git a/src/main/org/codehaus/groovy/runtime/memoize/Memoize.java b/src/main/org/codehaus/groovy/runtime/memoize/Memoize.java
index d9f7f99..918f3ab 100644
--- a/src/main/org/codehaus/groovy/runtime/memoize/Memoize.java
+++ b/src/main/org/codehaus/groovy/runtime/memoize/Memoize.java
@@ -22,6 +22,7 @@ import java.lang.ref.SoftReference;
 import java.util.Collections;
 
 import static java.util.Arrays.asList;
+import static java.util.Arrays.copyOf;
 
 /**
  * Implements memoize for Closures.
@@ -91,7 +92,8 @@ public abstract class Memoize {
      */
     private static Object generateKey(final Object[] args) {
         if (args == null) return Collections.emptyList();
-        return asList(args);
+        Object[] copyOfArgs = copyOf(args, args.length);
+        return asList(copyOfArgs);
     }
 
     /**
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java b/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
index 798ab15..2a128f6 100644
--- a/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaClass.java
@@ -57,15 +57,29 @@ public final class ClosureMetaClass extends MetaClassImpl {
     private MethodChooser chooser;
     private volatile boolean attributeInitDone = false;
 
-    private static final MetaClassImpl CLOSURE_METACLASS;
+    private static MetaClassImpl CLOSURE_METACLASS;
     private static MetaClassImpl classMetaClass;
     private static final Object[] EMPTY_ARGUMENTS = {};
     private static final String CLOSURE_CALL_METHOD = "call";
     private static final String CLOSURE_DO_CALL_METHOD = "doCall";
 
     static {
-        CLOSURE_METACLASS = new MetaClassImpl(Closure.class);
-        CLOSURE_METACLASS.initialize();
+        resetCachedMetaClasses();
+    }
+
+    public static void resetCachedMetaClasses() {
+        MetaClassImpl temp = new MetaClassImpl(Closure.class);
+        temp.initialize();
+        synchronized (ClosureMetaClass.class) {
+            CLOSURE_METACLASS = temp;
+        }
+        if (classMetaClass!=null) {
+            temp = new MetaClassImpl(Class.class);
+            temp.initialize();
+            synchronized (ClosureMetaClass.class) {
+                classMetaClass = temp;
+            }
+        }
     }
 
     private static synchronized MetaClass getStaticMetaClass() {
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaMethod.java b/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaMethod.java
index 861f730..11965af 100644
--- a/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaMethod.java
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/ClosureMetaMethod.java
@@ -38,6 +38,7 @@ import java.util.List;
  */
 public class ClosureMetaMethod extends MetaMethod implements ClosureInvokingMethod {
 
+    private static final Class[] EMPTY_CLASS_ARRAY = new Class[0];
     private final Closure callable;
     private final CachedMethod doCall;
     private final String name;
@@ -121,7 +122,7 @@ public class ClosureMetaMethod extends MetaMethod implements ClosureInvokingMeth
     
     private static MetaMethod adjustParamTypesForStdMethods(MetaMethod metaMethod, String methodName) {
         Class[] nativeParamTypes = metaMethod.getNativeParameterTypes();
-        nativeParamTypes = (nativeParamTypes != null) ? nativeParamTypes : new Class[0];
+        nativeParamTypes = (nativeParamTypes != null) ? nativeParamTypes : EMPTY_CLASS_ARRAY;
         // for methodMissing, first parameter should be String type - to allow overriding of this method without
         // type String explicitly specified for first parameter (missing method name) - GROOVY-2951
         if("methodMissing".equals(methodName) && nativeParamTypes.length == 2 && nativeParamTypes[0] != String.class) {
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/MetaClassRegistryImpl.java b/src/main/org/codehaus/groovy/runtime/metaclass/MetaClassRegistryImpl.java
index 80d66b6..7e74d06 100644
--- a/src/main/org/codehaus/groovy/runtime/metaclass/MetaClassRegistryImpl.java
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/MetaClassRegistryImpl.java
@@ -52,15 +52,15 @@ public class MetaClassRegistryImpl implements MetaClassRegistry{
      */
     public static final String MODULE_META_INF_FILE = "META-INF/services/org.codehaus.groovy.runtime.ExtensionModule";
 
-    private boolean useAccessible;
+    private final boolean useAccessible;
 
-    private FastArray instanceMethods = new FastArray();
-    private FastArray staticMethods = new FastArray();
+    private final FastArray instanceMethods = new FastArray();
+    private final FastArray staticMethods = new FastArray();
 
-    private LinkedList<MetaClassRegistryChangeEventListener> changeListenerList = new LinkedList();
-    private LinkedList<MetaClassRegistryChangeEventListener> nonRemoveableChangeListenerList = new LinkedList();
-    private ManagedLinkedList metaClassInfo = new ManagedLinkedList<MetaClass>(ReferenceBundle.getWeakBundle());
-    private ExtensionModuleRegistry moduleRegistry = new ExtensionModuleRegistry();
+    private final LinkedList<MetaClassRegistryChangeEventListener> changeListenerList = new LinkedList<MetaClassRegistryChangeEventListener>();
+    private final LinkedList<MetaClassRegistryChangeEventListener> nonRemoveableChangeListenerList = new LinkedList<MetaClassRegistryChangeEventListener>();
+    private final ManagedLinkedList metaClassInfo = new ManagedLinkedList<MetaClass>(ReferenceBundle.getWeakBundle());
+    private final ExtensionModuleRegistry moduleRegistry = new ExtensionModuleRegistry();
 
     public static final int LOAD_DEFAULT = 0;
     public static final int DONT_LOAD_DEFAULT = 1;
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/MixinInstanceMetaProperty.java b/src/main/org/codehaus/groovy/runtime/metaclass/MixinInstanceMetaProperty.java
index 6e42037..878f78f 100644
--- a/src/main/org/codehaus/groovy/runtime/metaclass/MixinInstanceMetaProperty.java
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/MixinInstanceMetaProperty.java
@@ -66,7 +66,7 @@ public class MixinInstanceMetaProperty extends MetaBeanProperty {
         return new MetaMethod() {
             final String name = getGetterName(property.getName(), property.getType());
             {
-                setParametersTypes (new CachedClass [0]);
+                setParametersTypes (CachedClass.EMPTY_ARRAY);
             }
 
             public int getModifiers() {
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/MultipleSetterProperty.java b/src/main/org/codehaus/groovy/runtime/metaclass/MultipleSetterProperty.java
new file mode 100644
index 0000000..73e169d
--- /dev/null
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/MultipleSetterProperty.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.runtime.metaclass;
+
+import groovy.lang.GroovyRuntimeException;
+import groovy.lang.MetaMethod;
+import groovy.lang.MetaProperty;
+import org.codehaus.groovy.reflection.CachedField;
+import org.codehaus.groovy.runtime.InvokerHelper;
+import org.codehaus.groovy.runtime.MetaClassHelper;
+
+/**
+ * This class represents a property with multiple setters. Unlike a MetaBeanProperty you cannot get the setter
+ * in this case. Instead invocation is done through the meta class of the property recevier.
+ */
+public class MultipleSetterProperty extends MetaProperty {
+    private MetaMethod getter;
+    private CachedField field;
+    private final String setterName;
+
+    public MultipleSetterProperty(String name) {
+        super(name, Object.class);
+        this.setterName = MetaProperty.getSetterName(name);
+    }
+
+    @Override
+    public Object getProperty(Object object) {
+        MetaMethod getter = getGetter();
+        if (getter == null) {
+            if (field != null) return field.getProperty(object);
+            throw new GroovyRuntimeException("Cannot read write-only property: " + name);
+        }
+        return getter.invoke(object, MetaClassHelper.EMPTY_ARRAY);
+    }
+
+    @Override
+    public void setProperty(Object object, Object newValue) {
+        InvokerHelper.getMetaClass(object).invokeMethod(object, setterName, new Object[]{newValue});
+    }
+
+    public void setField(CachedField f) {
+        this.field = f;
+    }
+
+    public CachedField getField() {
+        return field;
+    }
+
+    public void setGetter(MetaMethod getter) {
+        this.getter = getter;
+    }
+
+    public MetaMethod getGetter() {
+        return getter;
+    }
+
+    public MetaProperty createStaticVersion() {
+        boolean mf = field==null || field.isStatic();
+        boolean mg = getter==null || getter.isStatic();
+        if (mf && mg) return this;
+        if (mg) {
+            MultipleSetterProperty newMsp = new MultipleSetterProperty(name);
+            newMsp.setGetter(getter);
+            return newMsp;
+        } else if (mf) {
+            MultipleSetterProperty newMsp = new MultipleSetterProperty(name);
+            newMsp.setField(field);
+            return newMsp;
+        }
+        return null;
+    }
+}
diff --git a/src/main/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java b/src/main/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
index dc56972..7992987 100644
--- a/src/main/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
+++ b/src/main/org/codehaus/groovy/runtime/metaclass/ThreadManagedMetaBeanProperty.java
@@ -152,7 +152,7 @@ public class ThreadManagedMetaBeanProperty extends MetaBeanProperty {
 
 
         public ThreadBoundGetter(String name) {
-            setParametersTypes(new CachedClass[0]);
+            setParametersTypes(CachedClass.EMPTY_ARRAY);
             this.name = getGetterName(name, type);
         }
 
diff --git a/src/main/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java b/src/main/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
index d764620..e527cf5 100644
--- a/src/main/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
+++ b/src/main/org/codehaus/groovy/runtime/powerassert/AssertionRenderer.java
@@ -80,26 +80,27 @@ public final class AssertionRenderer {
 
     private void renderValues() {
         List<Value> values = recorder.getValues();
+        int valuesSize = values.size();
 
         nextValue:
-        for (int i = 0; i < values.size(); i++) {
-            Value value = values.get(i);
-            int startColumn = value.getColumn();
+        for (int i = 0; i < valuesSize; i++) {
+            final Value value = values.get(i);
+            final int startColumn = value.getColumn();
             if (startColumn < 1) continue; // skip values with unknown source position
 
             // if multiple values are associated with the same column, only
             // render the value which was recorded last (i.e. the value
             // corresponding to the outermost expression)
             // important for GROOVY-4344
-            Value next = i + 1 < values.size() ? values.get(i + 1) : null;
-            if (next != null && next.getColumn() == value.getColumn()) continue;
+            Value next = i + 1 < valuesSize ? values.get(i + 1) : null;
+            if (next != null && next.getColumn() == startColumn) continue;
 
             String str = valueToString(value.getValue());
             if (str == null) continue; // null signals the value shouldn't be rendered
 
             String[] strs = str.split("\r\n|\r|\n");
             int endColumn = strs.length == 1 ?
-                    value.getColumn() + str.length() : // exclusive
+                    startColumn + str.length() : // exclusive
                     Integer.MAX_VALUE; // multi-line strings are always placed on new lines
 
             for (int j = 1; j < lines.size(); j++)
diff --git a/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java b/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
index 11b15f4..2d004a9 100644
--- a/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
+++ b/src/main/org/codehaus/groovy/runtime/typehandling/DefaultTypeTransformation.java
@@ -30,6 +30,7 @@ import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
 import java.math.BigDecimal;
 import java.math.BigInteger;
+import java.text.MessageFormat;
 import java.util.*;
 
 /**
@@ -38,10 +39,11 @@ import java.util.*;
  * @author Guillaume Laforge
  */
 public class DefaultTypeTransformation {
-    
+
     protected static final Object[] EMPTY_ARGUMENTS = {};
     protected static final BigInteger ONE_NEG = new BigInteger("-1");
-    
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
     //  --------------------------------------------------------
     //                  unboxing methods
     //  --------------------------------------------------------       
@@ -266,40 +268,48 @@ public class DefaultTypeTransformation {
         if (Number.class.isAssignableFrom(type)) {
             Number n = castToNumber(object, type);
             if (type == Byte.class) {
-                return new Byte(n.byteValue());
-            } else if (type == Character.class) {
-                return new Character((char) n.intValue());
-            } else if (type == Short.class) {
-                return new Short(n.shortValue());
-            } else if (type == Integer.class) {
-                return Integer.valueOf(n.intValue());
-            } else if (type == Long.class) {
-                return new Long(n.longValue());
-            } else if (type == Float.class) {
-                return new Float(n.floatValue());
-            } else if (type == Double.class) {
-                Double answer = new Double(n.doubleValue());
+                return n.byteValue();
+            }
+            if (type == Character.class) {
+                return (char) n.intValue();
+            }
+            if (type == Short.class) {
+                return n.shortValue();
+            }
+            if (type == Integer.class) {
+                return n.intValue();
+            }
+            if (type == Long.class) {
+                return n.longValue();
+            }
+            if (type == Float.class) {
+                return n.floatValue();
+            }
+            if (type == Double.class) {
+                Double answer = n.doubleValue();
                 //throw a runtime exception if conversion would be out-of-range for the type.
-                if (!(n instanceof Double) && (answer.doubleValue() == Double.NEGATIVE_INFINITY
-                        || answer.doubleValue() == Double.POSITIVE_INFINITY)) {
+                if (!(n instanceof Double) && (answer == Double.NEGATIVE_INFINITY
+                        || answer == Double.POSITIVE_INFINITY)) {
                     throw new GroovyRuntimeException("Automatic coercion of " + n.getClass().getName()
                             + " value " + n + " to double failed.  Value is out of range.");
                 }
                 return answer;
-            } else if (type == BigDecimal.class) {
+            }
+            if (type == BigDecimal.class) {
                 if (n instanceof Float || n instanceof Double) {
                     return new BigDecimal(n.doubleValue());
                 }
                 return new BigDecimal(n.toString());
-            } else if (type == BigInteger.class) {
+            }
+            if (type == BigInteger.class) {
                 if (object instanceof Float || object instanceof Double) {
                     BigDecimal bd = new BigDecimal(n.doubleValue());
                     return bd.toBigInteger();
-                } else if (object instanceof BigDecimal) {
+                }
+                if (object instanceof BigDecimal) {
                     return ((BigDecimal) object).toBigInteger();
-                } else {
-                    return new BigInteger(n.toString());
                 }
+                return new BigInteger(n.toString());
             }
         }
 
@@ -452,7 +462,7 @@ public class DefaultTypeTransformation {
             }
         }
         else if (value instanceof Class && ((Class)value).isEnum()) {
-            Object[] values = (Object[])InvokerHelper.invokeMethod(value, "values", new Object[0]);
+            Object[] values = (Object[])InvokerHelper.invokeMethod(value, "values", EMPTY_OBJECT_ARRAY);
             return Arrays.asList(values);
         }
         else {
@@ -542,12 +552,12 @@ public class DefaultTypeTransformation {
         }
         if (left instanceof Comparable) {
             if (left instanceof Number) {
-                if (isValidCharacterString(right)) {
-                    return DefaultGroovyMethods.compareTo((Number) left, ShortTypeHandling.castToChar(right));
-                }
                 if (right instanceof Character || right instanceof Number) {
                     return DefaultGroovyMethods.compareTo((Number) left, castToNumber(right));
                 }
+                if (isValidCharacterString(right)) {
+                    return DefaultGroovyMethods.compareTo((Number) left, ShortTypeHandling.castToChar(right));
+                }
             }
             else if (left instanceof Character) {
                 if (isValidCharacterString(right)) {
@@ -579,8 +589,12 @@ public class DefaultTypeTransformation {
         if (equalityCheckOnly) {
             return -1; // anything other than 0
         }
-        throw new GroovyRuntimeException("Cannot compare " + left.getClass().getName() + " with value '" +
-                left + "' and " + right.getClass().getName() + " with value '" + right + "'");
+        throw new GroovyRuntimeException(
+                MessageFormat.format("Cannot compare {0} with value ''{1}'' and {2} with value ''{3}''",
+                        left.getClass().getName(),
+                        left,
+                        right.getClass().getName(),
+                        right));
     }
 
     public static boolean compareEqual(Object left, Object right) {
@@ -853,4 +867,17 @@ public class DefaultTypeTransformation {
         }
     }
 
+    public static Object castToVargsArray(Object[] origin, int firstVargsPos, Class<?> arrayType) {
+        Class<?> componentType = arrayType.getComponentType();
+        if (firstVargsPos>= origin.length) return Array.newInstance(componentType, 0);
+        int length = origin.length-firstVargsPos;
+        if (length==1 && arrayType.isInstance(origin[firstVargsPos])) return origin[firstVargsPos];
+        Object newArray = Array.newInstance(componentType, length);
+        for (int i=0; i<length; i++) {
+            Object convertedValue = castToType(origin[firstVargsPos+i],componentType);
+            Array.set(newArray, i, convertedValue);
+        }
+        return newArray;
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.java b/src/main/org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.java
index 7fd79ab..2079583 100644
--- a/src/main/org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.java
+++ b/src/main/org/codehaus/groovy/runtime/typehandling/ShortTypeHandling.java
@@ -58,7 +58,7 @@ public class ShortTypeHandling {
     public static Character castToChar(Object object) {
         if (object==null) return null;
         if (object instanceof Character) {
-            return ((Character) object).charValue();
+            return (Character) object;
         } else if (object instanceof Number) {
             Number value = (Number) object;
             return (char) value.intValue();
diff --git a/src/main/org/codehaus/groovy/tools/RootLoader.java b/src/main/org/codehaus/groovy/tools/RootLoader.java
index c067c29..a646713 100644
--- a/src/main/org/codehaus/groovy/tools/RootLoader.java
+++ b/src/main/org/codehaus/groovy/tools/RootLoader.java
@@ -72,6 +72,7 @@ import java.util.Map;
  */
 public class RootLoader extends URLClassLoader {
 
+    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
     private Map<String, Class> customClasses = new HashMap<String, Class>();
 
     /**
@@ -80,7 +81,7 @@ public class RootLoader extends URLClassLoader {
      * @param parent the parent Loader
      */
     private RootLoader(ClassLoader parent) {
-        this(new URL[0], parent);
+        this(EMPTY_URL_ARRAY, parent);
     }
 
     /**
diff --git a/src/main/org/codehaus/groovy/tools/StringHelper.java b/src/main/org/codehaus/groovy/tools/StringHelper.java
index 2a675ff..4b96f82 100644
--- a/src/main/org/codehaus/groovy/tools/StringHelper.java
+++ b/src/main/org/codehaus/groovy/tools/StringHelper.java
@@ -43,7 +43,7 @@ public class StringHelper {
             }
             first = last;
         }
-        return (String[])tokens.toArray(new String[0]);
+        return (String[])tokens.toArray(new String[tokens.size()]);
     }
 
     private static int scanToken(String s, int pos0) {
diff --git a/src/main/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java b/src/main/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
index 2ff9a7c..b0f07c6 100644
--- a/src/main/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
+++ b/src/main/org/codehaus/groovy/tools/javac/JavaAwareCompilationUnit.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.ModuleNode;
 import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.VariableScopeVisitor;
 import org.codehaus.groovy.control.*;
+import org.codehaus.groovy.transform.ASTTransformationCollectorCodeVisitor;
 
 import java.io.File;
 import java.io.FileNotFoundException;
@@ -56,7 +57,8 @@ public class JavaAwareCompilationUnit extends CompilationUnit {
         Map options = configuration.getJointCompilationOptions();
         generationGoal = (File) options.get("stubDir");
         boolean useJava5 = CompilerConfiguration.isPostJDK5(configuration.getTargetBytecode());
-        stubGenerator = new JavaStubGenerator(generationGoal, false, useJava5);
+		String encoding = configuration.getSourceEncoding();
+        stubGenerator = new JavaStubGenerator(generationGoal, false, useJava5, encoding);
         keepStubs = Boolean.TRUE.equals(options.get("keepStubs"));
 
         addPhaseOperation(new PrimaryClassNodeOperation() {
@@ -70,6 +72,13 @@ public class JavaAwareCompilationUnit extends CompilationUnit {
                 }
             }
         }, Phases.CONVERSION);
+        addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
+            public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
+                ASTTransformationCollectorCodeVisitor collector =
+                        new ASTTransformationCollectorCodeVisitor(source, JavaAwareCompilationUnit.this.getTransformLoader());
+                collector.visitClass(classNode);
+            }
+        }, Phases.CONVERSION);
 
         addPhaseOperation(new PrimaryClassNodeOperation() {
             public void call(SourceUnit source, GeneratorContext context, ClassNode classNode) throws CompilationFailedException {
diff --git a/src/main/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java b/src/main/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
index b557f32..813096e 100644
--- a/src/main/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
+++ b/src/main/org/codehaus/groovy/tools/javac/JavaStubCompilationUnit.java
@@ -53,7 +53,8 @@ public class JavaStubCompilationUnit extends CompilationUnit {
             destDir = (File) options.get("stubDir");
         }
         boolean useJava5 = CompilerConfiguration.isPostJDK5(configuration.getTargetBytecode());
-        stubGenerator = new JavaStubGenerator(destDir, false, useJava5);
+		String encoding = configuration.getSourceEncoding();
+        stubGenerator = new JavaStubGenerator(destDir, false, useJava5, encoding);
 
         addPhaseOperation(new PrimaryClassNodeOperation() {
             @Override
diff --git a/src/main/org/codehaus/groovy/tools/javac/JavaStubGenerator.java b/src/main/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
index d9a121c..5e108fa 100644
--- a/src/main/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
+++ b/src/main/org/codehaus/groovy/tools/javac/JavaStubGenerator.java
@@ -31,6 +31,7 @@ import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.control.ResolveVisitor;
 import org.codehaus.groovy.tools.Utilities;
+import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Opcodes;
 
 import java.io.File;
@@ -39,6 +40,8 @@ import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.PrintWriter;
 import java.io.StringWriter;
+import java.io.OutputStreamWriter;
+import java.nio.charset.Charset;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -48,6 +51,7 @@ import java.util.Map;
 
 public class JavaStubGenerator {
     private boolean java5 = false;
+	private String encoding;
     private boolean requireSuperResolved = false;
     private File outputPath;
     private List<String> toCompile = new ArrayList<String>();
@@ -56,15 +60,16 @@ public class JavaStubGenerator {
     private ArrayList<ConstructorNode> constructors = new ArrayList<ConstructorNode>();
     private ModuleNode currentModule;
 
-    public JavaStubGenerator(final File outputPath, final boolean requireSuperResolved, final boolean java5) {
+    public JavaStubGenerator(final File outputPath, final boolean requireSuperResolved, final boolean java5, String encoding) {
         this.outputPath = outputPath;
         this.requireSuperResolved = requireSuperResolved;
         this.java5 = java5;
+		this.encoding = encoding;
         outputPath.mkdirs();
     }
 
     public JavaStubGenerator(final File outputPath) {
-        this(outputPath, false, false);
+        this(outputPath, false, false, Charset.defaultCharset().name());
     }
 
     private void mkdirs(File parent, String relativeFile) {
@@ -93,7 +98,8 @@ public class JavaStubGenerator {
 
         File file = new File(outputPath, fileName + ".java");
         FileOutputStream fos = new FileOutputStream(file);
-        PrintWriter out = new PrintWriter(fos);
+        Charset charset = Charset.forName(encoding);
+        PrintWriter out = new PrintWriter(new OutputStreamWriter(fos, charset));
 
         try {
             String packageName = classNode.getPackageName();
@@ -185,7 +191,7 @@ public class JavaStubGenerator {
             verifier.visitClass(classNode);
             currentModule = classNode.getModule();
 
-            boolean isInterface = classNode.isInterface();
+            boolean isInterface = isInterfaceOrTrait(classNode);
             boolean isEnum = (classNode.getModifiers() & Opcodes.ACC_ENUM) != 0;
             boolean isAnnotationDefinition = classNode.isAnnotationDefinition();
             printAnnotations(out, classNode);
@@ -274,6 +280,45 @@ public class JavaStubGenerator {
             }
             printMethod(out, classNode, method);
         }
+
+        for (ClassNode node : classNode.getAllInterfaces()) {
+            if (Traits.isTrait(node)) {
+                List<MethodNode> traitMethods = node.getMethods();
+                for (MethodNode traitMethod : traitMethods) {
+                    MethodNode method = classNode.getMethod(traitMethod.getName(), traitMethod.getParameters());
+                    if (method == null) {
+                        for (MethodNode methodNode : propertyMethods) {
+                            if (methodNode.getName().equals(traitMethod.getName())) {
+                                boolean sameParams = sameParameterTypes(methodNode);
+                                if (sameParams) {
+                                    method = methodNode;
+                                    break;
+                                }
+                            }
+                        }
+                        if (method==null) {
+                            printMethod(out, classNode, traitMethod);
+                        }
+                    }
+                }
+            }
+        }
+
+    }
+
+    private static boolean sameParameterTypes(final MethodNode methodNode) {
+        Parameter[] a = methodNode.getParameters();
+        Parameter[] b = methodNode.getParameters();
+        boolean sameParams = a.length == b.length;
+        if (sameParams) {
+            for (int i = 0; i < a.length; i++) {
+                if (!a[i].getType().equals(b[i].getType())) {
+                    sameParams = false;
+                    break;
+                }
+            }
+        }
+        return sameParams;
     }
 
     private void printConstructors(PrintWriter out, ClassNode classNode) {
@@ -288,7 +333,7 @@ public class JavaStubGenerator {
     }
 
     private void printFields(PrintWriter out, ClassNode classNode) {
-        boolean isInterface = classNode.isInterface();
+        boolean isInterface = isInterfaceOrTrait(classNode);
         List<FieldNode> fields = classNode.getFields();
         if (fields == null) return;
         List<FieldNode> enumFields = new ArrayList<FieldNode>(fields.size());
@@ -544,7 +589,13 @@ public class JavaStubGenerator {
         if (methodNode.isSynthetic() && methodNode.getName().equals("$getStaticMetaClass")) return;
 
         printAnnotations(out, methodNode);
-        if (!clazz.isInterface()) printModifiers(out, methodNode.getModifiers());
+        if (!isInterfaceOrTrait(clazz)) {
+            int modifiers = methodNode.getModifiers();
+            if (isDefaultTraitImpl(methodNode)) {
+                modifiers ^= Opcodes.ACC_ABSTRACT;
+            }
+            printModifiers(out, modifiers);
+        }
 
         printGenericsBounds(out, methodNode.getGenericsTypes());
         out.print(" ");
@@ -565,7 +616,9 @@ public class JavaStubGenerator {
             printType(out, exception);
         }
 
-        if ((methodNode.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
+        if (Traits.isTrait(clazz)) {
+            out.println(";");
+        } else if (isAbstract(methodNode)) {
             if (clazz.isAnnotationDefinition() && methodNode.hasAnnotationDefault()) {
                 Statement fs = methodNode.getFirstStatement();
                 if (fs instanceof ExpressionStatement) {
@@ -598,6 +651,20 @@ public class JavaStubGenerator {
         }
     }
 
+    private boolean isAbstract(final MethodNode methodNode) {
+        if (isDefaultTraitImpl(methodNode)) {
+            return false;
+        }
+        if ((methodNode.getModifiers() & Opcodes.ACC_ABSTRACT) != 0) {
+            return true;
+        }
+        return false;
+    }
+
+    private boolean isDefaultTraitImpl(final MethodNode methodNode) {
+        return Traits.isTrait(methodNode.getDeclaringClass()) && Traits.hasDefaultImplementation(methodNode);
+    }
+
     private void printValue(PrintWriter out, Expression re, boolean assumeClass) {
         if (assumeClass) {
             if (re.getType().getName().equals("groovy.lang.Closure")) {
@@ -869,4 +936,8 @@ public class JavaStubGenerator {
     private static String escapeSpecialChars(String value) {
         return value.replace("\n", "\\n").replace("\r", "\\r").replace("\"", "\\\"");
     }
+
+    private static boolean isInterfaceOrTrait(ClassNode cn) {
+        return cn.isInterface() || Traits.isTrait(cn);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/tools/shell/IO.java b/src/main/org/codehaus/groovy/tools/shell/IO.java
index fc04859..994851a 100644
--- a/src/main/org/codehaus/groovy/tools/shell/IO.java
+++ b/src/main/org/codehaus/groovy/tools/shell/IO.java
@@ -16,6 +16,7 @@
 
 package org.codehaus.groovy.tools.shell;
 
+import java.io.Closeable;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InputStreamReader;
@@ -32,7 +33,7 @@ import org.fusesource.jansi.AnsiRenderWriter;
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
-public class IO
+public class IO implements Closeable
 {
     /** Raw input stream. */
     public final InputStream inputStream;
diff --git a/src/main/org/codehaus/groovy/transform/ASTTestTransformation.groovy b/src/main/org/codehaus/groovy/transform/ASTTestTransformation.groovy
index a65bd29..12f0714 100644
--- a/src/main/org/codehaus/groovy/transform/ASTTestTransformation.groovy
+++ b/src/main/org/codehaus/groovy/transform/ASTTestTransformation.groovy
@@ -34,7 +34,7 @@ class ASTTestTransformation extends AbstractASTTransformation implements Compila
     void visit(final ASTNode[] nodes, final SourceUnit source) {
         AnnotationNode annotationNode = nodes[0]
         def member = annotationNode.getMember('phase')
-        def phase = CompilePhase.SEMANTIC_ANALYSIS
+        def phase = null
         if (member) {
             if (member instanceof VariableExpression) {
                 phase = CompilePhase.valueOf(member.text)
@@ -56,9 +56,11 @@ class ASTTestTransformation extends AbstractASTTransformation implements Compila
 
         def pcallback = compilationUnit.progressCallback
         def callback = new CompilationUnit.ProgressCallback() {
+            Binding binding = new Binding([:].withDefault {null})
+
             @Override
             void call(final ProcessingUnit context, final int phaseRef) {
-                if (phaseRef == phase.phaseNumber) {
+                if (phase==null ||  phaseRef == phase.phaseNumber) {
                     ClosureExpression testClosure = nodes[0].getNodeMetaData(ASTTestTransformation)
                     StringBuilder sb = new StringBuilder()
                     for (int i = testClosure.lineNumber; i <= testClosure.lastLineNumber; i++) {
@@ -69,9 +71,11 @@ class ASTTestTransformation extends AbstractASTTransformation implements Compila
                     CompilerConfiguration config = new CompilerConfiguration()
                     def customizer = new ImportCustomizer()
                     config.addCompilationCustomizers(customizer)
-                    def binding = new Binding()
+                    binding['sourceUnit'] = source
                     binding['node'] = nodes[1]
                     binding['lookup'] = new MethodClosure(LabelFinder, "lookup").curry(nodes[1])
+                    binding['compilationUnit'] = compilationUnit
+                    binding['compilePhase'] = CompilePhase.fromPhaseNumber(phaseRef)
 
                     GroovyShell shell = new GroovyShell(binding, config)
 
diff --git a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
index da21646..058d2c3 100644
--- a/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AbstractASTTransformation.java
@@ -43,11 +43,29 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 
+import static groovy.transform.Undefined.isUndefined;
+
 public abstract class AbstractASTTransformation implements Opcodes, ASTTransformation {
     public static final ClassNode RETENTION_CLASSNODE = ClassHelper.makeWithoutCaching(Retention.class);
 
     protected SourceUnit sourceUnit;
 
+    /**
+     * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
+     * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
+     * <p>
+     * Annotations with {@link org.codehaus.groovy.runtime.GeneratedClosure} members are not supported for now.
+     */
+    protected List<AnnotationNode> copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode, String myTypeName) {
+        final ArrayList<AnnotationNode> copiedAnnotations = new ArrayList<AnnotationNode>();
+        final ArrayList<AnnotationNode> notCopied = new ArrayList<AnnotationNode>();
+        GeneralUtils.copyAnnotatedNodeAnnotations(annotatedNode, copiedAnnotations, notCopied);
+        for (AnnotationNode annotation : notCopied) {
+            addError(myTypeName + " does not support keeping Closure annotation members.", annotation);
+        }
+        return copiedAnnotations;
+    }
+
     protected void init(ASTNode[] nodes, SourceUnit sourceUnit) {
         if (nodes == null || nodes.length != 2 || !(nodes[0] instanceof AnnotationNode) || !(nodes[1] instanceof AnnotatedNode)) {
             throw new GroovyBugError("Internal error: expecting [AnnotationNode, AnnotatedNode] but got: " + (nodes == null ? null : Arrays.asList(nodes)));
@@ -66,16 +84,17 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform
         return null;
     }
 
-    public String getMemberStringValue(AnnotationNode node, String name, String defaultValue) {
+    public static String getMemberStringValue(AnnotationNode node, String name, String defaultValue) {
         final Expression member = node.getMember(name);
         if (member != null && member instanceof ConstantExpression) {
             Object result = ((ConstantExpression) member).getValue();
+            if (result != null && result instanceof String && isUndefined((String) result)) result = null;
             if (result != null) return result.toString();
         }
         return defaultValue;
     }
 
-    public String getMemberStringValue(AnnotationNode node, String name) {
+    public static String getMemberStringValue(AnnotationNode node, String name) {
         return getMemberStringValue(node, name, null);
     }
 
@@ -94,9 +113,9 @@ public abstract class AbstractASTTransformation implements Opcodes, ASTTransform
     public ClassNode getMemberClassValue(AnnotationNode node, String name, ClassNode defaultValue) {
         final Expression member = node.getMember(name);
         if (member != null) {
-            if (member instanceof ClassExpression)
-                return member.getType();
-            if (member instanceof VariableExpression) {
+            if (member instanceof ClassExpression) {
+                if (!isUndefined(member.getType())) return member.getType();
+            } else if (member instanceof VariableExpression) {
                 addError("Error expecting to find class value for '" + name + "' but found variable: " + member.getText() + ". Missing import?", node);
                 return null;
             } else if (member instanceof ConstantExpression) {
diff --git a/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java b/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
index b30fc1f..fd3ed14 100644
--- a/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/AutoCloneASTTransformation.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.VariableScope;
@@ -133,50 +134,66 @@ public class AutoCloneASTTransformation extends AbstractASTTransformation {
     }
 
     private void createCloneCopyConstructor(ClassNode cNode, List<FieldNode> list, List<String> excludes) {
-        BlockStatement initBody = new BlockStatement();
         if (cNode.getDeclaredConstructors().size() == 0) {
             // add no-arg constructor
-            initBody.addStatement(EmptyStatement.INSTANCE);
-            cNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, initBody);
-            initBody = new BlockStatement();
+            BlockStatement noArgBody = new BlockStatement();
+            noArgBody.addStatement(EmptyStatement.INSTANCE);
+            cNode.addConstructor(ACC_PUBLIC, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, noArgBody);
         }
-        Parameter initParam = param(GenericsUtils.nonGeneric(cNode), "other");
-        final Expression other = varX(initParam);
-        boolean hasParent = cNode.getSuperClass() != ClassHelper.OBJECT_TYPE;
-        if (hasParent) {
-            initBody.addStatement(stmt(ctorX(ClassNode.SUPER, other)));
+        boolean hasThisCons = false;
+        for (ConstructorNode consNode : cNode.getDeclaredConstructors()) {
+            Parameter[] parameters = consNode.getParameters();
+            if (parameters.length == 1 && parameters[0].getType().equals(cNode)) {
+                hasThisCons = true;
+            }
         }
-        for (FieldNode fieldNode : list) {
-            String name = fieldNode.getName();
-            if (excludes.contains(name)) continue;
-            ClassNode fieldType = fieldNode.getType();
-            Expression direct = propX(other, name);
-            Expression to = propX(varX("this"), name);
-            Statement assignDirect = assignS(to, direct);
-            Statement assignCloned = assignS(to, castX(fieldType, callX(direct, "clone")));
-            Statement assignClonedDynamic = assignS(to, castX(fieldType, callCloneDynamicX(direct)));
-            if (isOrImplements(fieldType, CLONEABLE_TYPE)) {
-                initBody.addStatement(assignCloned);
-            } else if (!possiblyCloneable(fieldType)) {
-                initBody.addStatement(assignDirect);
-            } else {
-                initBody.addStatement(ifElseS(isInstanceOfX(direct, CLONEABLE_TYPE), assignClonedDynamic, assignDirect));
+        if (!hasThisCons) {
+            BlockStatement initBody = new BlockStatement();
+            Parameter initParam = param(GenericsUtils.nonGeneric(cNode), "other");
+            final Expression other = varX(initParam);
+            boolean hasParent = cNode.getSuperClass() != ClassHelper.OBJECT_TYPE;
+            if (hasParent) {
+                initBody.addStatement(stmt(ctorX(ClassNode.SUPER, other)));
+            }
+            for (FieldNode fieldNode : list) {
+                String name = fieldNode.getName();
+                if (excludes.contains(name)) continue;
+                ClassNode fieldType = fieldNode.getType();
+                Expression direct = propX(other, name);
+                Expression to = propX(varX("this"), name);
+                Statement assignDirect = assignS(to, direct);
+                Statement assignCloned = assignS(to, castX(fieldType, callCloneDirectX(direct)));
+                Statement assignClonedDynamic = assignS(to, castX(fieldType, callCloneDynamicX(direct)));
+                if (isCloneableType(fieldType)) {
+                    initBody.addStatement(assignCloned);
+                } else if (!possiblyCloneable(fieldType)) {
+                    initBody.addStatement(assignDirect);
+                } else {
+                    initBody.addStatement(ifElseS(isInstanceOfX(direct, CLONEABLE_TYPE), assignClonedDynamic, assignDirect));
+                }
             }
+            cNode.addConstructor(ACC_PROTECTED, params(initParam), ClassNode.EMPTY_ARRAY, initBody);
         }
         ClassNode[] exceptions = {make(CloneNotSupportedException.class)};
-        cNode.addConstructor(ACC_PROTECTED, params(initParam), ClassNode.EMPTY_ARRAY, initBody);
-        cNode.addMethod("clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, block(
-                stmt(ctorX(cNode, args(varX("this"))))));
+        cNode.addMethod("clone", ACC_PUBLIC, GenericsUtils.nonGeneric(cNode), Parameter.EMPTY_ARRAY, exceptions, block(stmt(ctorX(cNode, args(varX("this"))))));
+    }
+
+    private boolean isCloneableType(ClassNode fieldType) {
+        return isOrImplements(fieldType, CLONEABLE_TYPE) || !fieldType.getAnnotations(MY_TYPE).isEmpty();
     }
 
     private boolean possiblyCloneable(ClassNode type) {
-        return !isPrimitiveType(type) && ((isOrImplements(type, CLONEABLE_TYPE) || (type.getModifiers() & ACC_FINAL) == 0));
+        return !isPrimitiveType(type) && ((isCloneableType(type) || (type.getModifiers() & ACC_FINAL) == 0));
     }
 
     private Expression callCloneDynamicX(Expression target) {
         return callX(INVOKER_TYPE, "invokeMethod", args(target, constX("clone"), ConstantExpression.NULL));
     }
 
+    private Expression callCloneDirectX(Expression direct) {
+        return ternaryX(equalsNullX(direct), ConstantExpression.NULL, callX(direct, "clone"));
+    }
+
     private void createSimpleClone(ClassNode cNode, List<FieldNode> fieldNodes, List<String> excludes) {
         if (cNode.getDeclaredConstructors().size() == 0) {
             // add no-arg constructor
@@ -206,9 +223,9 @@ public class AutoCloneASTTransformation extends AbstractASTTransformation {
             Expression direct = propX(varX("this"), name);
             Expression to = propX(other, name);
             Statement assignDirect = assignS(to, direct);
-            Statement assignCloned = assignS(to, castX(fieldType, callX(direct, "clone")));
+            Statement assignCloned = assignS(to, castX(fieldType, callCloneDirectX(direct)));
             Statement assignClonedDynamic = assignS(to, castX(fieldType, callCloneDynamicX(direct)));
-            if (isOrImplements(fieldType, CLONEABLE_TYPE)) {
+            if (isCloneableType(fieldType)) {
                 methodBody.addStatement(assignCloned);
             } else if (!possiblyCloneable(fieldType)) {
                 methodBody.addStatement(assignDirect);
@@ -229,9 +246,9 @@ public class AutoCloneASTTransformation extends AbstractASTTransformation {
             ClassNode fieldType = fieldNode.getType();
             Expression fieldExpr = varX(fieldNode);
             Expression to = propX(result, fieldNode.getName());
-            Statement doClone = assignS(to, castX(fieldType, callX(fieldExpr, "clone")));
+            Statement doClone = assignS(to, castX(fieldType, callCloneDirectX(fieldExpr)));
             Statement doCloneDynamic = assignS(to, castX(fieldType, callCloneDynamicX(fieldExpr)));
-            if (isOrImplements(fieldType, CLONEABLE_TYPE)) {
+            if (isCloneableType(fieldType)) {
                 body.addStatement(doClone);
             } else if (possiblyCloneable(fieldType)) {
                 body.addStatement(ifS(isInstanceOfX(fieldExpr, CLONEABLE_TYPE), doCloneDynamic));
diff --git a/src/main/org/codehaus/groovy/transform/BaseScriptASTTransformation.java b/src/main/org/codehaus/groovy/transform/BaseScriptASTTransformation.java
index 52d7798..cde24d4 100644
--- a/src/main/org/codehaus/groovy/transform/BaseScriptASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/BaseScriptASTTransformation.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.ImportNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.PackageNode;
@@ -50,6 +51,7 @@ public class BaseScriptASTTransformation extends AbstractASTTransformation {
     private static final Class<BaseScript> MY_CLASS = BaseScript.class;
     public static final ClassNode MY_TYPE = ClassHelper.make(MY_CLASS);
     private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
+    private static final Parameter[] CONTEXT_CTOR_PARAMETERS = {new Parameter(ClassHelper.BINDING_TYPE, "context")};
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         init(nodes, source);
@@ -144,6 +146,14 @@ public class BaseScriptASTTransformation extends AbstractASTTransformation {
                 cNode.addMethod(methodNode);
             }
         }
+
+        // If the new script base class does not have a contextual constructor (g.l.Binding), then we won't either.
+        // We have to do things this way (and rely on just default constructors) because the logic that generates
+        // the constructors for our script class have already run.
+        if (cNode.getSuperClass().getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS) == null) {
+            ConstructorNode orphanedConstructor = cNode.getDeclaredConstructor(CONTEXT_CTOR_PARAMETERS);
+            cNode.removeConstructor(orphanedConstructor);
+        }
     }
 
     private boolean isCustomScriptBodyMethod(MethodNode node) {
diff --git a/src/main/org/codehaus/groovy/transform/BuilderASTTransformation.java b/src/main/org/codehaus/groovy/transform/BuilderASTTransformation.java
index 9efa11d..e3d1a57 100644
--- a/src/main/org/codehaus/groovy/transform/BuilderASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/BuilderASTTransformation.java
@@ -35,6 +35,7 @@ import org.codehaus.groovy.control.SourceUnit;
 import java.util.ArrayList;
 import java.util.List;
 
+import static groovy.transform.Undefined.isUndefined;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstancePropertyFields;
 
 /**
@@ -94,8 +95,12 @@ public class BuilderASTTransformation extends AbstractASTTransformation implemen
 
         protected boolean unsupportedAttribute(BuilderASTTransformation transform, AnnotationNode anno, String memberName, String extraMessage) {
             Object memberValue = transform.getMemberValue(anno, memberName);
+            if (memberValue != null && memberValue instanceof String && isUndefined((String) memberValue)) return false;
             if (memberValue == null) {
                 memberValue = transform.getMemberClassValue(anno, memberName);
+                if (memberValue != null && isUndefined((ClassNode) memberValue)) {
+                    memberValue = null;
+                }
             }
             if (memberValue != null) {
                 String message = extraMessage.length() == 0 ? "" : " " + extraMessage;
diff --git a/src/main/org/codehaus/groovy/transform/CategoryASTTransformation.java b/src/main/org/codehaus/groovy/transform/CategoryASTTransformation.java
index e26fc75..87f4fdd 100644
--- a/src/main/org/codehaus/groovy/transform/CategoryASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/CategoryASTTransformation.java
@@ -210,7 +210,7 @@ public class CategoryASTTransformation implements ASTTransformation, Opcodes {
                     ce.getVariableScope().putReferencedLocalVariable((Parameter) parameter.get());
                     Parameter[] params = ce.getParameters();
                     if (params == null) {
-                        params = new Parameter[0];
+                        params = Parameter.EMPTY_ARRAY;
                     } else if (params.length == 0) {
                         params = new Parameter[]{
                                 new Parameter(ClassHelper.OBJECT_TYPE, "it")
diff --git a/src/main/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy b/src/main/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
index 58cf172..994dffe 100644
--- a/src/main/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
+++ b/src/main/org/codehaus/groovy/transform/ConditionalInterruptibleASTTransformation.groovy
@@ -18,6 +18,7 @@ package org.codehaus.groovy.transform
 import groovy.transform.ConditionalInterrupt
 import org.codehaus.groovy.ast.*
 import org.codehaus.groovy.ast.expr.*
+import org.codehaus.groovy.ast.tools.ClosureUtils
 import org.codehaus.groovy.control.CompilePhase
 
 /**
@@ -120,31 +121,11 @@ public class ConditionalInterruptibleASTTransformation extends AbstractInterrupt
    * @param expression a closure
    * @return the source the closure was created from
    */
-  // TODO should this be moved to ClosureExpression? It also appears in AstBuilderTransformation
   private String convertClosureToSource(ClosureExpression expression) {
-    if (expression == null) throw new IllegalArgumentException('Null: expression')
-
-    def lineRange = (expression.lineNumber..expression.lastLineNumber)
-
-    def source = lineRange.collect {
-      def line = source.source.getLine(it, null)
-      if (line == null) {
-        return "Error calculating source code for expression. Trying to read line $it from ${source.source.class}"
-      }
-      if (it == expression.lastLineNumber) {
-        line = line.substring(0, expression.lastColumnNumber - 1)
-      }
-      if (it == expression.lineNumber) {
-        line = line.substring(expression.columnNumber - 1)
-      }
-      return line
-    }?.join('\n')?.trim()   //restoring line breaks is important b/c of lack of semicolons
-
-    if (!source.startsWith('{')) {
-      return 'Error converting ClosureExpression into source code. ' +
-          "Closures must start with {. Found: $source"
+    try {
+        return ClosureUtils.convertClosureToSource(this.source.source, expression);
+    } catch(Exception e) {
+        return e.message
     }
-
-    return source
   }
 }
diff --git a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
index 2c58598..ca5dc3c 100644
--- a/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/DelegateASTTransformation.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2014 the original author or authors.
+ * Copyright 2008-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,25 +18,23 @@ package org.codehaus.groovy.transform;
 import groovy.lang.Delegate;
 import groovy.lang.GroovyObject;
 
+import groovy.lang.Lazy;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.PropertyNode;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
-import org.codehaus.groovy.ast.expr.ConstantExpression;
-import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
-import org.codehaus.groovy.ast.tools.GeneralUtils;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.classgen.Verifier;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
-import org.codehaus.groovy.runtime.GeneratedClosure;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -55,6 +53,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.propX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.returnS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.stmt;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.varX;
+import static org.codehaus.groovy.ast.tools.GenericsUtils.addMethodGenerics;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpec;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.correctToGenericsSpecRecurse;
 import static org.codehaus.groovy.ast.tools.GenericsUtils.createGenericsSpec;
@@ -76,6 +75,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
     private static final String MY_TYPE_NAME = "@" + MY_TYPE.getNameWithoutPackage();
     private static final ClassNode DEPRECATED_TYPE = make(Deprecated.class);
     private static final ClassNode GROOVYOBJECT_TYPE = make(GroovyObject.class);
+    private static final ClassNode LAZY_TYPE = make(Lazy.class);
 
     private static final String MEMBER_DEPRECATED = "deprecated";
     private static final String MEMBER_INTERFACES = "interfaces";
@@ -111,8 +111,8 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
                 fieldMethods.addAll(getAllMethods(next));
             }
 
-            final boolean skipInterfaces = hasBooleanValue(node.getMember(MEMBER_INTERFACES), false);
-            final boolean includeDeprecated = hasBooleanValue(node.getMember(MEMBER_DEPRECATED), true) || (type.isInterface() && !skipInterfaces);
+            final boolean skipInterfaces = memberHasValue(node, MEMBER_INTERFACES, false);
+            final boolean includeDeprecated = memberHasValue(node, MEMBER_DEPRECATED, true) || (type.isInterface() && !skipInterfaces);
             List<String> excludes = getMemberList(node, MEMBER_EXCLUDES);
             List<String> includes = getMemberList(node, MEMBER_INCLUDES);
             List<ClassNode> excludeTypes = getClassList(node, MEMBER_EXCLUDE_TYPES);
@@ -128,8 +128,8 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
                 if (prop.isStatic() || !prop.isPublic())
                     continue;
                 String name = prop.getName();
-                addGetterIfNeeded(fieldNode, owner, prop, name);
-                addSetterIfNeeded(fieldNode, owner, prop, name);
+                addGetterIfNeeded(fieldNode, owner, prop, name, includes, excludes);
+                addSetterIfNeeded(fieldNode, owner, prop, name, includes, excludes);
             }
 
             if (skipInterfaces) return;
@@ -152,13 +152,11 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
         }
     }
 
-    private boolean hasBooleanValue(Expression expression, boolean bool) {
-        return expression instanceof ConstantExpression && ((ConstantExpression) expression).getValue().equals(bool);
-    }
-
-    private void addSetterIfNeeded(FieldNode fieldNode, ClassNode owner, PropertyNode prop, String name) {
+    private void addSetterIfNeeded(FieldNode fieldNode, ClassNode owner, PropertyNode prop, String name, List<String> includes, List<String> excludes) {
         String setterName = "set" + Verifier.capitalize(name);
-        if ((prop.getModifiers() & ACC_FINAL) == 0 && owner.getSetterMethod(setterName) == null) {
+        if ((prop.getModifiers() & ACC_FINAL) == 0
+                && owner.getSetterMethod(setterName) == null
+                && !shouldSkipPropertyMethod(name, setterName, excludes, includes)) {
             owner.addMethod(setterName,
                     ACC_PUBLIC,
                     ClassHelper.VOID_TYPE,
@@ -169,9 +167,10 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
         }
     }
 
-    private void addGetterIfNeeded(FieldNode fieldNode, ClassNode owner, PropertyNode prop, String name) {
+    private void addGetterIfNeeded(FieldNode fieldNode, ClassNode owner, PropertyNode prop, String name, List<String> includes, List<String> excludes) {
         String getterName = "get" + Verifier.capitalize(name);
-        if (owner.getGetterMethod(getterName) == null) {
+        if (owner.getGetterMethod(getterName) == null
+                && !shouldSkipPropertyMethod(name, getterName, excludes, includes)) {
             owner.addMethod(getterName,
                     ACC_PUBLIC,
                     GenericsUtils.nonGeneric(prop.getType()),
@@ -180,6 +179,12 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
                     returnS(propX(varX(fieldNode), name)));
         }
     }
+    
+    private boolean shouldSkipPropertyMethod(String propertyName, String methodName, List<String> excludes, List<String> includes) {
+        return (deemedInternalName(propertyName)
+                    || excludes != null && (excludes.contains(propertyName) || excludes.contains(methodName)) 
+                    || (includes != null && !includes.isEmpty() && !includes.contains(propertyName) && !includes.contains(methodName)));
+    }
 
     private void addDelegateMethod(AnnotationNode node, FieldNode fieldNode, ClassNode owner, List<MethodNode> ownMethods, MethodNode candidate, boolean includeDeprecated, List<String> includes, List<String> excludes, List<ClassNode> includeTypes, List<ClassNode> excludeTypes) {
         if (!candidate.isPublic() || candidate.isStatic() || 0 != (candidate.getModifiers () & ACC_SYNTHETIC))
@@ -191,6 +196,7 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
         if (shouldSkip(candidate.getName(), excludes, includes)) return;
 
         Map<String,ClassNode> genericsSpec = createGenericsSpec(fieldNode.getDeclaringClass());
+        genericsSpec = addMethodGenerics(candidate, genericsSpec);
         extractSuperClassGenerics(fieldNode.getType(), candidate.getDeclaringClass(), genericsSpec);
 
         if (!excludeTypes.isEmpty() || !includeTypes.isEmpty()) {
@@ -224,27 +230,31 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
         }
         if (existingNode == null || existingNode.getCode() == null) {
 
-            final boolean includeParameterAnnotations = hasBooleanValue(node.getMember(MEMBER_PARAMETER_ANNOTATIONS), true);
-
             final ArgumentListExpression args = new ArgumentListExpression();
             final Parameter[] params = candidate.getParameters();
             final Parameter[] newParams = new Parameter[params.length];
+            List<String> currentMethodGenPlaceholders = genericPlaceholderNames(candidate);
             for (int i = 0; i < newParams.length; i++) {
-                Parameter newParam = new Parameter(correctToGenericsSpecRecurse(genericsSpec, params[i].getType()), getParamName(params, i, fieldNode.getName()));
+                ClassNode newParamType = correctToGenericsSpecRecurse(genericsSpec, params[i].getType(), currentMethodGenPlaceholders);
+                Parameter newParam = new Parameter(newParamType, getParamName(params, i, fieldNode.getName()));
                 newParam.setInitialExpression(params[i].getInitialExpression());
 
-                if (includeParameterAnnotations) newParam.addAnnotations(copyAnnotatedNodeAnnotations(params[i]));
+                if (memberHasValue(node, MEMBER_PARAMETER_ANNOTATIONS, true)) {
+                    newParam.addAnnotations(copyAnnotatedNodeAnnotations(params[i], MY_TYPE_NAME));
+                }
 
                 newParams[i] = newParam;
                 args.addExpression(varX(newParam));
             }
+            boolean alsoLazy = !fieldNode.getAnnotations(LAZY_TYPE).isEmpty();
             // addMethod will ignore attempts to override abstract or static methods with same signature on self
             MethodCallExpression mce = callX(
+                    alsoLazy ? propX(varX("this"), fieldNode.getName().substring(1)) :
                     varX(fieldNode.getName(), correctToGenericsSpecRecurse(genericsSpec, fieldNode.getType())),
                     candidate.getName(),
                     args);
             mce.setSourcePosition(fieldNode);
-            ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, candidate.getReturnType());
+            ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, candidate.getReturnType(), currentMethodGenPlaceholders);
             MethodNode newMethod = owner.addMethod(candidate.getName(),
                     candidate.getModifiers() & (~ACC_ABSTRACT) & (~ACC_NATIVE),
                     returnType,
@@ -253,12 +263,23 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
                     stmt(mce));
             newMethod.setGenericsTypes(candidate.getGenericsTypes());
 
-            if (hasBooleanValue(node.getMember(MEMBER_METHOD_ANNOTATIONS), true)) {
-                newMethod.addAnnotations(copyAnnotatedNodeAnnotations(candidate));
+            if (memberHasValue(node, MEMBER_METHOD_ANNOTATIONS, true)) {
+                newMethod.addAnnotations(copyAnnotatedNodeAnnotations(candidate, MY_TYPE_NAME));
             }
         }
     }
 
+    private List<String> genericPlaceholderNames(MethodNode candidate) {
+        GenericsType[] candidateGenericsTypes = candidate.getGenericsTypes();
+        List<String> names = new ArrayList<String>();
+        if (candidateGenericsTypes != null) {
+            for (GenericsType gt : candidateGenericsTypes) {
+                names.add(gt.getName());
+            }
+        }
+        return names;
+    }
+
     private String getParamName(Parameter[] params, int i, String fieldName) {
         String name = params[i].getName();
         while(name.equals(fieldName) || clashesWithOtherParams(name, params, i)) {
@@ -275,19 +296,4 @@ public class DelegateASTTransformation extends AbstractASTTransformation {
         return false;
     }
 
-    /**
-     * Copies all <tt>candidateAnnotations</tt> with retention policy {@link java.lang.annotation.RetentionPolicy#RUNTIME}
-     * and {@link java.lang.annotation.RetentionPolicy#CLASS}.
-     * <p>
-     * Annotations with {@link GeneratedClosure} members are not supported by now.
-     */
-    private List<AnnotationNode> copyAnnotatedNodeAnnotations(final AnnotatedNode annotatedNode) {
-        final ArrayList<AnnotationNode> delegateAnnotations = new ArrayList<AnnotationNode>();
-        final ArrayList<AnnotationNode> notCopied = new ArrayList<AnnotationNode>();
-        GeneralUtils.copyAnnotatedNodeAnnotations(annotatedNode, delegateAnnotations, notCopied);
-        for (AnnotationNode annotation : notCopied) {
-            addError(MY_TYPE_NAME + " does not support keeping Closure annotation members.", annotation);
-        }
-        return delegateAnnotations;
-    }
 }
diff --git a/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java b/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
index 02a2c9a..5df6081 100644
--- a/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/ImmutableASTTransformation.java
@@ -125,6 +125,7 @@ public class ImmutableASTTransformation extends AbstractASTTransformation {
     private static final ClassNode SORTEDMAP_CLASSNODE = make(SortedMap.class);
     private static final ClassNode SET_CLASSNODE = make(Set.class);
     private static final ClassNode MAP_CLASSNODE = make(Map.class);
+    public static final String IMMUTABLE_SAFE_FLAG = "Immutable.Safe";
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         init(nodes, source);
@@ -324,12 +325,12 @@ public class ImmutableASTTransformation extends AbstractASTTransformation {
 
     private void createConstructorMap(ClassNode cNode, List<PropertyNode> list, List<String> knownImmutableClasses, List<String> knownImmutables) {
         final BlockStatement body = new BlockStatement();
+        body.addStatement(ifS(equalsNullX(varX("args")), assignS(varX("args"), new MapExpression())));
         for (PropertyNode pNode : list) {
             body.addStatement(createConstructorStatement(cNode, pNode, knownImmutableClasses, knownImmutables));
         }
         // check for missing properties
         body.addStatement(stmt(callX(SELF_TYPE, "checkPropNames", args("this", "args"))));
-        body.addStatement(ifS(equalsNullX(varX("args")), assignS(varX("args"), new MapExpression())));
         createConstructorMapCommon(cNode, body);
         if (list.size() > 0) {
             createNoArgConstructor(cNode);
@@ -415,8 +416,9 @@ public class ImmutableASTTransformation extends AbstractASTTransformation {
     private boolean validateConstructors(ClassNode cNode) {
         List<ConstructorNode> declaredConstructors = cNode.getDeclaredConstructors();
         for (ConstructorNode constructorNode : declaredConstructors) {
-            // allow Synthetic constructors added by other transforms
-            if ((constructorNode.getModifiers() & ACC_SYNTHETIC) != 0) {
+            // allow constructors added by other transforms if flagged as safe
+            Object nodeMetaData = constructorNode.getNodeMetaData(IMMUTABLE_SAFE_FLAG);
+            if (nodeMetaData != null && ((Boolean)nodeMetaData)) {
                 continue;
             }
             // TODO: allow constructors which only call provided constructor?
diff --git a/src/main/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java b/src/main/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
index f9b0c7a..f715218 100644
--- a/src/main/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/InheritConstructorsASTTransformation.java
@@ -59,16 +59,18 @@ public class InheritConstructorsASTTransformation extends AbstractASTTransformat
         if (!MY_TYPE.equals(node.getClassNode())) return;
 
         if (parent instanceof ClassNode) {
-            processClass((ClassNode) parent);
+            processClass((ClassNode) parent, node);
         }
     }
 
-    private void processClass(ClassNode cNode) {
+    private void processClass(ClassNode cNode, AnnotationNode node) {
         if (cNode.isInterface()) {
             addError("Error processing interface '" + cNode.getName() +
                     "'. " + MY_TYPE_NAME + " only allowed for classes.", cNode);
             return;
         }
+        boolean copyConstructorAnnotations = memberHasValue(node, "constructorAnnotations", true);
+        boolean copyParameterAnnotations = memberHasValue(node, "parameterAnnotations", true);
         ClassNode sNode = cNode.getSuperClass();
         List<AnnotationNode> superAnnotations = sNode.getAnnotations(MY_TYPE);
         if (superAnnotations.size() == 1) {
@@ -76,28 +78,39 @@ public class InheritConstructorsASTTransformation extends AbstractASTTransformat
             // so force that order here. The transformation is benign on an already
             // processed node so processing twice in any order won't matter bar
             // a very small time penalty.
-            processClass(sNode);
+            processClass(sNode, node);
         }
         for (ConstructorNode cn : sNode.getDeclaredConstructors()) {
-            addConstructorUnlessAlreadyExisting(cNode, cn);
+            addConstructorUnlessAlreadyExisting(cNode, cn, copyConstructorAnnotations, copyParameterAnnotations);
         }
     }
 
-    private void addConstructorUnlessAlreadyExisting(ClassNode classNode, ConstructorNode consNode) {
+    private void addConstructorUnlessAlreadyExisting(ClassNode classNode, ConstructorNode consNode, boolean copyConstructorAnnotations, boolean copyParameterAnnotations) {
         Parameter[] origParams = consNode.getParameters();
         if (consNode.isPrivate()) return;
         Parameter[] params = new Parameter[origParams.length];
-        List<Expression> theArgs = new ArrayList<Expression>();
         Map<String, ClassNode> genericsSpec = createGenericsSpec(classNode);
         extractSuperClassGenerics(classNode, classNode.getSuperClass(), genericsSpec);
+        List<Expression> theArgs = buildParams(origParams, params, genericsSpec, copyParameterAnnotations);
+        if (isExisting(classNode, params)) return;
+        ConstructorNode added = classNode.addConstructor(consNode.getModifiers(), params, consNode.getExceptions(), block(ctorSuperS(args(theArgs))));
+        if (copyConstructorAnnotations) {
+            added.addAnnotations(copyAnnotatedNodeAnnotations(consNode, MY_TYPE_NAME));
+        }
+    }
+
+    private List<Expression> buildParams(Parameter[] origParams, Parameter[] params, Map<String, ClassNode> genericsSpec, boolean copyParameterAnnotations) {
+        List<Expression> theArgs = new ArrayList<Expression>();
         for (int i = 0; i < origParams.length; i++) {
             Parameter p = origParams[i];
             ClassNode newType = correctToGenericsSpecRecurse(genericsSpec, p.getType());
             params[i] = p.hasInitialExpression() ? param(newType, p.getName(), p.getInitialExpression()) : param(newType, p.getName());
+            if (copyParameterAnnotations) {
+                params[i].addAnnotations(copyAnnotatedNodeAnnotations(origParams[i], MY_TYPE_NAME));
+            }
             theArgs.add(varX(p.getName(), newType));
         }
-        if (isExisting(classNode, params)) return;
-        classNode.addConstructor(consNode.getModifiers(), params, consNode.getExceptions(), block(ctorSuperS(args(theArgs))));
+        return theArgs;
     }
 
     private boolean isExisting(ClassNode classNode, Parameter[] params) {
diff --git a/src/main/org/codehaus/groovy/transform/MemoizedASTTransformation.java b/src/main/org/codehaus/groovy/transform/MemoizedASTTransformation.java
index 077e1c4..b2a43f1 100644
--- a/src/main/org/codehaus/groovy/transform/MemoizedASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/MemoizedASTTransformation.java
@@ -165,7 +165,7 @@ public class MemoizedASTTransformation extends AbstractASTTransformation {
         StringBuilder nameBuilder = new StringBuilder("memoizedMethod" + ident + "$").append(methodNode.getName());
         if (methodNode.getParameters() != null) {
             for (Parameter parameter : methodNode.getParameters()) {
-                nameBuilder.append(parameter.getType().getNameWithoutPackage());
+                nameBuilder.append(buildTypeName(parameter.getType()));
             }
         }
         while (owner.getField(nameBuilder.toString()) != null) {
@@ -175,4 +175,11 @@ public class MemoizedASTTransformation extends AbstractASTTransformation {
         return nameBuilder.toString();
     }
 
+    private static String buildTypeName(ClassNode type) {
+        if (type.isArray()) {
+            return String.format("%sArray", buildTypeName(type.getComponentType()));
+        }
+        return type.getNameWithoutPackage();
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/transform/NewifyASTTransformation.java b/src/main/org/codehaus/groovy/transform/NewifyASTTransformation.java
index 30a6584..3215905 100644
--- a/src/main/org/codehaus/groovy/transform/NewifyASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/NewifyASTTransformation.java
@@ -169,6 +169,11 @@ public class NewifyASTTransformation extends ClassCodeExpressionTransformer impl
         } else if (expr instanceof ClosureExpression) {
             ClosureExpression ce = (ClosureExpression) expr;
             ce.getCode().visit(this);
+        } else if (expr instanceof ConstructorCallExpression) {
+            ConstructorCallExpression cce = (ConstructorCallExpression) expr;
+            if (cce.isUsingAnonymousInnerClass()) {
+                cce.getType().visitContents(this);
+            }
         } else if (expr instanceof DeclarationExpression) {
             DeclarationExpression de = (DeclarationExpression) expr;
             if (de == candidate || auto) {
diff --git a/src/main/org/codehaus/groovy/transform/PackageScopeASTTransformation.java b/src/main/org/codehaus/groovy/transform/PackageScopeASTTransformation.java
index 20148ec..8e7e1db 100644
--- a/src/main/org/codehaus/groovy/transform/PackageScopeASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/PackageScopeASTTransformation.java
@@ -24,6 +24,7 @@ import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.ConstructorNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.PropertyNode;
@@ -105,6 +106,12 @@ public class PackageScopeASTTransformation extends AbstractASTTransformation {
                 if (mNode.isSyntheticPublic()) revertVisibility(mNode);
             }
         }
+        if (value.contains(groovy.transform.PackageScopeTarget.CONSTRUCTORS)) {
+            final List<ConstructorNode> cList = cNode.getDeclaredConstructors();
+            for (MethodNode mNode : cList) {
+                if (mNode.isSyntheticPublic()) revertVisibility(mNode);
+            }
+        }
         if (value.contains(PackageScopeTarget.FIELDS)) {
             final List<PropertyNode> pList = cNode.getProperties();
             List<PropertyNode> foundProps = new ArrayList<PropertyNode>();
diff --git a/src/main/org/codehaus/groovy/transform/SynchronizedASTTransformation.java b/src/main/org/codehaus/groovy/transform/SynchronizedASTTransformation.java
index ecffec0..bd9870f 100644
--- a/src/main/org/codehaus/groovy/transform/SynchronizedASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/SynchronizedASTTransformation.java
@@ -50,7 +50,6 @@ public class SynchronizedASTTransformation extends AbstractASTTransformation {
 
     public void visit(ASTNode[] nodes, SourceUnit source) {
         init(nodes, source);
-        init(nodes, source);
         AnnotatedNode parent = (AnnotatedNode) nodes[1];
         AnnotationNode node = (AnnotationNode) nodes[0];
         if (!MY_TYPE.equals(node.getClassNode())) return;
@@ -58,8 +57,13 @@ public class SynchronizedASTTransformation extends AbstractASTTransformation {
 
         if (parent instanceof MethodNode) {
             MethodNode mNode = (MethodNode) parent;
+            if (mNode.isAbstract()) {
+                addError("Error during " + MY_TYPE_NAME + " processing: annotation not allowed on abstract method '" + mNode.getName() + "'", mNode);
+                return;
+            }
             ClassNode cNode = mNode.getDeclaringClass();
             String lockExpr = determineLock(value, cNode, mNode);
+            if (lockExpr == null) return;
             Statement origCode = mNode.getCode();
             Statement newCode = new SynchronizedStatement(varX(lockExpr), origCode);
             mNode.setCode(newCode);
@@ -71,10 +75,12 @@ public class SynchronizedASTTransformation extends AbstractASTTransformation {
         if (value != null && value.length() > 0 && !value.equalsIgnoreCase("$lock")) {
             if (cNode.getDeclaredField(value) == null) {
                 addError("Error during " + MY_TYPE_NAME + " processing: lock field with name '" + value + "' not found in class " + cNode.getName(), mNode);
+                return null;
             }
             FieldNode field = cNode.getDeclaredField(value);
-            if (field.isStatic() != isStatic) {
-                addError("Error during " + MY_TYPE_NAME + " processing: lock field with name '" + value + "' should " + (isStatic ? "" : "not ") + "be static", field);
+            if (isStatic && !field.isStatic()) {
+                addError("Error during " + MY_TYPE_NAME + " processing: lock field with name '" + value + "' must be static for static method '" + mNode.getName() + "'", field);
+                return null;
             }
             return value;
         }
diff --git a/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java b/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
index 9fb2753..6b4a82b 100644
--- a/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/ToStringASTTransformation.java
@@ -36,6 +36,7 @@ import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.InvokerHelper;
 
 import java.util.ArrayList;
+import java.util.Iterator;
 import java.util.List;
 
 import static org.codehaus.groovy.ast.ClassHelper.make;
@@ -47,6 +48,7 @@ import static org.codehaus.groovy.ast.tools.GeneralUtils.constX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.ctorX;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.declS;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.equalsNullX;
+import static org.codehaus.groovy.ast.tools.GeneralUtils.getAllProperties;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceNonPropertyFields;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.getInstanceProperties;
 import static org.codehaus.groovy.ast.tools.GeneralUtils.hasDeclaredMethod;
@@ -83,6 +85,7 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
             ClassNode cNode = (ClassNode) parent;
             if (!checkNotInterface(cNode, MY_TYPE_NAME)) return;
             boolean includeSuper = memberHasValue(anno, "includeSuper", true);
+            boolean includeSuperProperties = memberHasValue(anno, "includeSuperProperties", true);
             boolean cacheToString = memberHasValue(anno, "cache", true);
             if (includeSuper && cNode.getSuperClass().getName().equals("java.lang.Object")) {
                 addError("Error during " + MY_TYPE_NAME + " processing: includeSuper=true but '" + cNode.getName() + "' has no super class.", anno);
@@ -100,7 +103,7 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
                 if (includes == null || includes.isEmpty()) includes = getMemberList(canonical, "includes");
             }
             if (!checkIncludeExclude(anno, excludes, includes, MY_TYPE_NAME)) return;
-            createToString(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, cacheToString);
+            createToString(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, cacheToString, includeSuperProperties);
         }
     }
 
@@ -117,6 +120,10 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
     }
 
     public static void createToString(ClassNode cNode, boolean includeSuper, boolean includeFields, List<String> excludes, List<String> includes, boolean includeNames, boolean ignoreNulls, boolean includePackage, boolean cache) {
+        createToString(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, false, false);
+    }
+
+    public static void createToString(ClassNode cNode, boolean includeSuper, boolean includeFields, List<String> excludes, List<String> includes, boolean includeNames, boolean ignoreNulls, boolean includePackage, boolean cache, boolean includeSuperProperties) {
         // make a public method if none exists otherwise try a private method with leading underscore
         boolean hasExistingToString = hasDeclaredMethod(cNode, "toString", 0);
         if (hasExistingToString && hasDeclaredMethod(cNode, "_toString", 0)) return;
@@ -128,11 +135,11 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
             final Expression savedToString = varX(cacheField);
             body.addStatement(ifS(
                     equalsNullX(savedToString),
-                    assignS(savedToString, calculateToStringStatements(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, body))
+                    assignS(savedToString, calculateToStringStatements(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, includeSuperProperties, body))
             ));
             tempToString = savedToString;
         } else {
-            tempToString = calculateToStringStatements(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, body);
+            tempToString = calculateToStringStatements(cNode, includeSuper, includeFields, excludes, includes, includeNames, ignoreNulls, includePackage, includeSuperProperties, body);
         }
         body.addStatement(returnS(tempToString));
 
@@ -140,7 +147,7 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
                 ClassHelper.STRING_TYPE, Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, body));
     }
 
-    private static Expression calculateToStringStatements(ClassNode cNode, boolean includeSuper, boolean includeFields, List<String> excludes, List<String> includes, boolean includeNames, boolean ignoreNulls, boolean includePackage, BlockStatement body) {
+    private static Expression calculateToStringStatements(ClassNode cNode, boolean includeSuper, boolean includeFields, List<String> excludes, List<String> includes, boolean includeNames, boolean ignoreNulls, boolean includePackage, boolean includeSuperProperties, BlockStatement body) {
         // def _result = new StringBuilder()
         final Expression result = varX("_result");
         body.addStatement(declS(result, ctorX(STRINGBUILDER_TYPE)));
@@ -154,7 +161,18 @@ public class ToStringASTTransformation extends AbstractASTTransformation {
         body.addStatement(appendS(result, constX(className + "(")));
 
         // append properties
-        List<PropertyNode> pList = getInstanceProperties(cNode);
+        List<PropertyNode> pList;
+        if (includeSuperProperties) {
+            pList = getAllProperties(cNode);
+            Iterator<PropertyNode> pIterator = pList.iterator();
+            while (pIterator.hasNext()) {
+                if (pIterator.next().isStatic()) {
+                    pIterator.remove();
+                }
+            }
+        } else {
+            pList = getInstanceProperties(cNode);
+        }
         for (PropertyNode pNode : pList) {
             if (shouldSkip(pNode.getName(), excludes, includes)) continue;
             Expression getter = callX(INVOKER_TYPE, "getProperty", args(varX("this"), constX(pNode.getName())));
diff --git a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
index 99a7211..70ed8af 100644
--- a/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/sc/StaticCompilationVisitor.java
@@ -25,6 +25,7 @@ import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.ForStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.classgen.asm.*;
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationMopWriter;
 import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
@@ -34,6 +35,7 @@ import org.objectweb.asm.Opcodes;
 
 import java.util.*;
 
+import static org.codehaus.groovy.ast.tools.GenericsUtils.*;
 import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.*;
 import static org.codehaus.groovy.transform.stc.StaticTypesMarker.DIRECT_METHOD_CALL_TARGET;
 import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
@@ -99,19 +101,33 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
     @Override
     public void visitClass(final ClassNode node) {
         boolean skip = shouldSkipClassNode(node);
+        if (!skip && !anyMethodSkip(node)) {
+            node.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
+        }
         ClassNode oldCN = classNode;
         classNode = node;
         Iterator<InnerClassNode> innerClasses = classNode.getInnerClasses();
         while (innerClasses.hasNext()) {
             InnerClassNode innerClassNode = innerClasses.next();
-            innerClassNode.putNodeMetaData(STATIC_COMPILE_NODE, !(skip || isSkippedInnerClass(innerClassNode)));
+            boolean innerStaticCompile = !(skip || isSkippedInnerClass(innerClassNode));
+            innerClassNode.putNodeMetaData(STATIC_COMPILE_NODE, innerStaticCompile);
             innerClassNode.putNodeMetaData(WriterControllerFactory.class, node.getNodeMetaData(WriterControllerFactory.class));
+            if (innerStaticCompile && !anyMethodSkip(innerClassNode)) {
+                innerClassNode.putNodeMetaData(MopWriter.Factory.class, StaticCompilationMopWriter.FACTORY);
+            }
         }
         super.visitClass(node);
         addPrivateFieldAndMethodAccessors(node);
         classNode = oldCN;
     }
 
+    private boolean anyMethodSkip(final ClassNode node) {
+        for (MethodNode methodNode : node.getMethods()) {
+            if (isSkipMode(methodNode)) return true;
+        }
+        return false;
+    }
+
     /**
      * If we are in a constructor, that is static compiled, but in a class, that
      * is not, it may happen that init code from object initializers, fields
@@ -188,7 +204,7 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
     private void addPrivateBridgeMethods(final ClassNode node) {
         Set<ASTNode> accessedMethods = (Set<ASTNode>) node.getNodeMetaData(StaticTypesMarker.PV_METHODS_ACCESS);
         if (accessedMethods==null) return;
-        List<MethodNode> methods = new ArrayList<MethodNode>(node.getMethods());
+        List<MethodNode> methods = new ArrayList<MethodNode>(node.getAllDeclaredMethods());
         Map<MethodNode, MethodNode> privateBridgeMethods = (Map<MethodNode, MethodNode>) node.getNodeMetaData(PRIVATE_BRIDGE_METHODS);
         if (privateBridgeMethods!=null) {
             // private bridge methods already added
@@ -199,10 +215,21 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
         final int access = Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC;
         for (MethodNode method : methods) {
             if (accessedMethods.contains(method)) {
+                List<String> methodSpecificGenerics = methodSpecificGenerics(method);
                 i++;
+                ClassNode declaringClass = method.getDeclaringClass();
+                Map<String,ClassNode> genericsSpec = createGenericsSpec(node);
+                genericsSpec = addMethodGenerics(method, genericsSpec);
+                extractSuperClassGenerics(node, declaringClass, genericsSpec);
                 Parameter[] methodParameters = method.getParameters();
                 Parameter[] newParams = new Parameter[methodParameters.length+1];
-                System.arraycopy(methodParameters, 0, newParams, 1, methodParameters.length);
+                for (int j = 1; j < newParams.length; j++) {
+                    Parameter orig = methodParameters[j-1];
+                    newParams[j] = new Parameter(
+                            correctToGenericsSpecRecurse(genericsSpec, orig.getOriginType(), methodSpecificGenerics),
+                            orig.getName()
+                    );
+                }
                 newParams[0] = new Parameter(node.getPlainNodeReference(), "$that");
                 Expression arguments;
                 if (method.getParameters()==null || method.getParameters().length==0) {
@@ -219,12 +246,34 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
                 mce.setMethodTarget(method);
 
                 ExpressionStatement returnStatement = new ExpressionStatement(mce);
-                MethodNode bridge = node.addMethod("access$"+i, access, method.getReturnType(), newParams, method.getExceptions(), returnStatement);
+                MethodNode bridge = node.addMethod(
+                        "access$"+i, access,
+                        correctToGenericsSpecRecurse(genericsSpec, method.getReturnType(), methodSpecificGenerics),
+                        newParams,
+                        method.getExceptions(),
+                        returnStatement);
+                GenericsType[] origGenericsTypes = method.getGenericsTypes();
+                if (origGenericsTypes !=null) {
+                    bridge.setGenericsTypes(applyGenericsContextToPlaceHolders(genericsSpec,origGenericsTypes));
+                }
                 privateBridgeMethods.put(method, bridge);
                 bridge.addAnnotation(new AnnotationNode(COMPILESTATIC_CLASSNODE));
             }
         }
-        node.setNodeMetaData(PRIVATE_BRIDGE_METHODS, privateBridgeMethods);
+        if (!privateBridgeMethods.isEmpty()) {
+            node.setNodeMetaData(PRIVATE_BRIDGE_METHODS, privateBridgeMethods);
+        }
+    }
+
+    private static List<String> methodSpecificGenerics(final MethodNode method) {
+        List<String> genericTypeTokens = new ArrayList<String>();
+        GenericsType[] candidateGenericsTypes = method.getGenericsTypes();
+        if (candidateGenericsTypes != null) {
+            for (GenericsType gt : candidateGenericsTypes) {
+                genericTypeTokens.add(gt.getName());
+            }
+        }
+        return genericTypeTokens;
     }
 
     private void memorizeInitialExpressions(final MethodNode node) {
@@ -317,20 +366,54 @@ public class StaticCompilationVisitor extends StaticTypeCheckingVisitor {
             public void visitField(final FieldNode node) {
                 if (visitor!=null) visitor.visitField(node);
                 ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass!=null) rType.set(declaringClass);
+                if (declaringClass!=null) {
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, ClassHelper.LIST_TYPE)) {
+                        boolean spread = declaringClass.getDeclaredField(node.getName()) != node;
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
             }
 
             public void visitMethod(final MethodNode node) {
                 if (visitor!=null) visitor.visitMethod(node);
                 ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass!=null) rType.set(declaringClass);
+                if (declaringClass!=null){
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, ClassHelper.LIST_TYPE)) {
+                        List<MethodNode> properties = declaringClass.getDeclaredMethods(node.getName());
+                        boolean spread = true;
+                        for (MethodNode mn : properties) {
+                            if (node==mn) {
+                                spread = false;
+                                break;
+                            }
+                        }
+                        // it's no real property but a property of the component
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
             }
 
             @Override
             public void visitProperty(final PropertyNode node) {
                 if (visitor!=null) visitor.visitProperty(node);
                 ClassNode declaringClass = node.getDeclaringClass();
-                if (declaringClass!=null) rType.set(declaringClass);
+                if (declaringClass!=null) {
+                    if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(declaringClass, ClassHelper.LIST_TYPE)) {
+                        List<PropertyNode> properties = declaringClass.getProperties();
+                        boolean spread = true;
+                        for (PropertyNode propertyNode : properties) {
+                            if (propertyNode==node) {
+                                spread = false;
+                                break;
+                            }
+                        }
+                        // it's no real property but a property of the component
+                        pexp.setSpreadSafe(spread);
+                    }
+                    rType.set(declaringClass);
+                }
             }
         };
         boolean exists = super.existsProperty(pexp, checkForReadOnly, receiverMemoizer);
diff --git a/src/main/org/codehaus/groovy/transform/sc/StaticCompileTransformation.java b/src/main/org/codehaus/groovy/transform/sc/StaticCompileTransformation.java
index d805c82..d9767d0 100644
--- a/src/main/org/codehaus/groovy/transform/sc/StaticCompileTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/sc/StaticCompileTransformation.java
@@ -44,7 +44,6 @@ public class StaticCompileTransformation extends StaticTypesTransformation {
 
     @Override
     public void visit(final ASTNode[] nodes, final SourceUnit source) {
-        StaticCompilationTransformer transformer = new StaticCompilationTransformer(source);
         AnnotationNode annotationInformation = (AnnotationNode) nodes[0];
         AnnotatedNode node = (AnnotatedNode) nodes[1];
         StaticTypeCheckingVisitor visitor = null;
@@ -79,6 +78,7 @@ public class StaticCompileTransformation extends StaticTypesTransformation {
         if (visitor != null) {
             visitor.performSecondPass();
         }
+        StaticCompilationTransformer transformer = new StaticCompilationTransformer(source, visitor);
         if (node instanceof ClassNode) {
             transformer.visitClass((ClassNode) node);
         } else if (node instanceof MethodNode) {
@@ -90,5 +90,4 @@ public class StaticCompileTransformation extends StaticTypesTransformation {
     protected StaticTypeCheckingVisitor newVisitor(final SourceUnit unit, final ClassNode node) {
         return new StaticCompilationVisitor(unit, node);
     }
-
 }
diff --git a/src/main/org/codehaus/groovy/transform/sc/TemporaryVariableExpression.java b/src/main/org/codehaus/groovy/transform/sc/TemporaryVariableExpression.java
new file mode 100644
index 0000000..3b528d9
--- /dev/null
+++ b/src/main/org/codehaus/groovy/transform/sc/TemporaryVariableExpression.java
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.transform.sc;
+
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.GroovyCodeVisitor;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ExpressionTransformer;
+import org.codehaus.groovy.classgen.AsmClassGenerator;
+import org.codehaus.groovy.classgen.asm.ExpressionAsVariableSlot;
+import org.codehaus.groovy.classgen.asm.WriterController;
+
+/**
+ * A front-end class for {@link org.codehaus.groovy.classgen.asm.ExpressionAsVariableSlot} which
+ * allows defining temporary variables loaded from variable slots directly at the AST level,
+ * without any knowledge of {@link org.codehaus.groovy.classgen.AsmClassGenerator}.
+ *
+ * @author Cédric Champeau
+ * @since 2.4.0
+ */
+public class TemporaryVariableExpression extends Expression {
+
+    private Expression expression;
+
+    private ExpressionAsVariableSlot variable;
+
+    public TemporaryVariableExpression(final Expression expression) {
+        this.expression = expression;
+    }
+
+    @Override
+    public Expression transformExpression(final ExpressionTransformer transformer) {
+        TemporaryVariableExpression result = new TemporaryVariableExpression(expression.transformExpression(transformer));
+        result.copyNodeMetaData(this);
+        return result;
+    }
+
+    @Override
+    public void visit(final GroovyCodeVisitor visitor) {
+        if (visitor instanceof AsmClassGenerator) {
+            if (variable==null) {
+                AsmClassGenerator acg = (AsmClassGenerator) visitor;
+                WriterController controller = acg.getController();
+                variable = new ExpressionAsVariableSlot(controller, expression);
+            }
+            variable.visit(visitor);
+        } else {
+            expression.visit(visitor);
+        }
+    }
+
+    public void remove(WriterController controller) {
+        controller.getCompileStack().removeVar(variable.getIndex());
+        variable = null;
+    }
+
+    @Override
+    public ClassNode getType() {
+        return expression.getType();
+    }
+}
diff --git a/src/main/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java b/src/main/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
index 2bcfdfe..01a99f9 100644
--- a/src/main/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/sc/transformers/BinaryExpressionTransformer.java
@@ -27,21 +27,30 @@ import org.codehaus.groovy.ast.expr.DeclarationExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.TernaryExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.tools.WideningCategories;
+import org.codehaus.groovy.classgen.asm.sc.StaticPropertyAccessHelper;
 import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
+import org.codehaus.groovy.runtime.DefaultGroovyMethods;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.sc.ListOfExpressionsExpression;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
+import java.math.BigDecimal;
+import java.math.BigInteger;
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
 
+import static org.codehaus.groovy.syntax.Types.COMPARE_EQUAL;
+import static org.codehaus.groovy.syntax.Types.COMPARE_NOT_EQUAL;
 import static org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys.BINARY_EXP_TARGET;
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isCompareToBoolean;
 
 public class BinaryExpressionTransformer {
     private static final MethodNode COMPARE_TO_METHOD = ClassHelper.COMPARABLE_TYPE.getMethods("compareTo").get(0);
@@ -65,40 +74,52 @@ public class BinaryExpressionTransformer {
     }
 
     Expression transformBinaryExpression(final BinaryExpression bin) {
-        Object[] list = (Object[]) bin.getNodeMetaData(BINARY_EXP_TARGET);
+        if (bin instanceof DeclarationExpression) {
+            Expression optimized = transformDeclarationExpression(bin);
+            if (optimized!=null) {
+                return optimized;
+            }
+        }
+        Object[] list = bin.getNodeMetaData(BINARY_EXP_TARGET);
         Token operation = bin.getOperation();
         int operationType = operation.getType();
         Expression rightExpression = bin.getRightExpression();
         Expression leftExpression = bin.getLeftExpression();
-        if (operationType==Types.COMPARE_EQUAL || operationType == Types.COMPARE_NOT_EQUAL) {
+        if (bin instanceof DeclarationExpression && leftExpression instanceof VariableExpression) {
+            ClassNode declarationType = ((VariableExpression) leftExpression).getOriginType();
+            if (rightExpression instanceof ConstantExpression) {
+                ClassNode unwrapper = ClassHelper.getUnwrapper(declarationType);
+                ClassNode wrapper = ClassHelper.getWrapper(declarationType);
+                if (!rightExpression.getType().equals(declarationType)
+                        && wrapper.isDerivedFrom(ClassHelper.Number_TYPE)
+                        && WideningCategories.isDoubleCategory(unwrapper)) {
+                    ConstantExpression constant = (ConstantExpression) rightExpression;
+                    if (constant.getValue()!=null) {
+                        return optimizeConstantInitialization(bin, operation, constant, leftExpression, declarationType);
+                    }
+                }
+            }
+        }
+        if (operationType == Types.EQUAL && leftExpression instanceof PropertyExpression) {
+            MethodNode directMCT = leftExpression.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+            if (directMCT != null) {
+                return transformPropertyAssignmentToSetterCall((PropertyExpression) leftExpression, rightExpression, directMCT);
+            }
+        }
+        if (operationType == Types.COMPARE_EQUAL || operationType == Types.COMPARE_NOT_EQUAL) {
             // let's check if one of the operands is the null constant
             CompareToNullExpression compareToNullExpression = null;
             if (isNullConstant(leftExpression)) {
-                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(rightExpression), operationType==Types.COMPARE_EQUAL);
+                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(rightExpression), operationType == Types.COMPARE_EQUAL);
             } else if (isNullConstant(rightExpression)) {
-                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(leftExpression), operationType==Types.COMPARE_EQUAL);
+                compareToNullExpression = new CompareToNullExpression(staticCompilationTransformer.transform(leftExpression), operationType == Types.COMPARE_EQUAL);
             }
             if (compareToNullExpression != null) {
                 compareToNullExpression.setSourcePosition(bin);
                 return compareToNullExpression;
             }
-        } else if (operationType==Types.KEYWORD_IN) {
-            MethodCallExpression call = new MethodCallExpression(
-                    rightExpression,
-                    "isCase",
-                    leftExpression
-            );
-            call.setMethodTarget((MethodNode) bin.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
-            call.setSourcePosition(bin);
-            call.copyNodeMetaData(bin);
-            TernaryExpression tExp = new TernaryExpression(
-                    new BooleanExpression(
-                            new BinaryExpression(rightExpression, Token.newSymbol("==",-1,-1), new ConstantExpression(null))
-                    ),
-                    new BinaryExpression(leftExpression, Token.newSymbol("==", -1, -1), new ConstantExpression(null)),
-                    call
-            );
-            return staticCompilationTransformer.transform(tExp);
+        } else if (operationType == Types.KEYWORD_IN) {
+            return convertInOperatorToTernary(bin, rightExpression, leftExpression);
         }
         if (list != null) {
             if (operationType == Types.COMPARE_TO) {
@@ -146,6 +167,11 @@ public class BinaryExpressionTransformer {
             String name = (String) list[1];
             Expression left = staticCompilationTransformer.transform(leftExpression);
             Expression right = staticCompilationTransformer.transform(rightExpression);
+            BinaryExpression optimized = tryOptimizeCharComparison(left, right, bin);
+            if (optimized!=null) {
+                optimized.removeNodeMetaData(BINARY_EXP_TARGET);
+                return transformBinaryExpression(optimized);
+            }
             call = new MethodCallExpression(
                     left,
                     name,
@@ -177,15 +203,15 @@ public class BinaryExpressionTransformer {
             Iterator<Expression> leftIt = leftExpressions.iterator();
             Iterator<Expression> rightIt = rightExpressions.iterator();
             if (isDeclaration) {
-            while (leftIt.hasNext()) {
-                Expression left = leftIt.next();
-                if (rightIt.hasNext()) {
-                    Expression right = rightIt.next();
-                    BinaryExpression bexp = new DeclarationExpression(left, bin.getOperation(), right);
-                    bexp.setSourcePosition(right);
-                    cle.addExpression(bexp);
+                while (leftIt.hasNext()) {
+                    Expression left = leftIt.next();
+                    if (rightIt.hasNext()) {
+                        Expression right = rightIt.next();
+                        BinaryExpression bexp = new DeclarationExpression(left, bin.getOperation(), right);
+                        bexp.setSourcePosition(right);
+                        cle.addExpression(bexp);
+                    }
                 }
-            }
             } else {
                 // (next, result) = [ result, next+result ]
                 // -->
@@ -196,10 +222,10 @@ public class BinaryExpressionTransformer {
                 int size = rightExpressions.size();
                 List<Expression> tmpAssignments = new ArrayList<Expression>(size);
                 List<Expression> finalAssignments = new ArrayList<Expression>(size);
-                for (int i=0; i<Math.min(size, leftExpressions.size());i++ ) {
+                for (int i = 0; i < Math.min(size, leftExpressions.size()); i++) {
                     Expression left = leftIt.next();
                     Expression right = rightIt.next();
-                    VariableExpression tmpVar = new VariableExpression("$tmpVar$"+tmpVarCounter++);
+                    VariableExpression tmpVar = new VariableExpression("$tmpVar$" + tmpVarCounter++);
                     BinaryExpression bexp = new DeclarationExpression(tmpVar, bin.getOperation(), right);
                     bexp.setSourcePosition(right);
                     tmpAssignments.add(bexp);
@@ -219,8 +245,144 @@ public class BinaryExpressionTransformer {
         return staticCompilationTransformer.superTransform(bin);
     }
 
+    private BinaryExpression tryOptimizeCharComparison(final Expression left, final Expression right, final BinaryExpression bin) {
+        int op = bin.getOperation().getType();
+        if (isCompareToBoolean(op) || op == COMPARE_EQUAL || op == COMPARE_NOT_EQUAL) {
+            Character cLeft = tryCharConstant(left);
+            Character cRight = tryCharConstant(right);
+            if (cLeft != null || cRight != null) {
+                Expression oLeft = cLeft == null ? left : new ConstantExpression(cLeft, true);
+                oLeft.setSourcePosition(left);
+                Expression oRight = cRight == null ? right : new ConstantExpression(cRight, true);
+                oRight.setSourcePosition(right);
+                bin.setLeftExpression(oLeft);
+                bin.setRightExpression(oRight);
+                return bin;
+            }
+        }
+        return null;
+    }
+
+    private Character tryCharConstant(final Expression expr) {
+        if (expr instanceof ConstantExpression) {
+            ConstantExpression ce = (ConstantExpression) expr;
+            if (ClassHelper.STRING_TYPE.equals(ce.getType())) {
+                String val = (String) ce.getValue();
+                if (val!=null && val.length()==1) {
+                    return val.charAt(0);
+                }
+            }
+        }
+        return null;
+    }
+
+    private Expression transformDeclarationExpression(final BinaryExpression bin) {
+        Expression leftExpression = bin.getLeftExpression();
+        if (leftExpression instanceof VariableExpression) {
+            if (ClassHelper.char_TYPE.equals(((VariableExpression) leftExpression).getOriginType())) {
+                Expression rightExpression = bin.getRightExpression();
+                if (rightExpression instanceof ConstantExpression && ClassHelper.STRING_TYPE.equals(rightExpression.getType())) {
+                    String text = (String) ((ConstantExpression) rightExpression).getValue();
+                    if (text.length() == 1) {
+                        // optimize char initialization
+                        ConstantExpression ce = new ConstantExpression(
+                                text.charAt(0),
+                                true
+                        );
+                        ce.setSourcePosition(rightExpression);
+                        bin.setRightExpression(ce);
+                        return bin;
+                    }
+                }
+            }
+        }
+        return null;
+    }
+
+    private Expression convertInOperatorToTernary(final BinaryExpression bin, final Expression rightExpression, final Expression leftExpression) {
+        MethodCallExpression call = new MethodCallExpression(
+                rightExpression,
+                "isCase",
+                leftExpression
+        );
+        call.setMethodTarget((MethodNode) bin.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET));
+        call.setSourcePosition(bin);
+        call.copyNodeMetaData(bin);
+        TernaryExpression tExp = new TernaryExpression(
+                new BooleanExpression(
+                        new BinaryExpression(rightExpression, Token.newSymbol("==", -1, -1), new ConstantExpression(null))
+                ),
+                new BinaryExpression(leftExpression, Token.newSymbol("==", -1, -1), new ConstantExpression(null)),
+                call
+        );
+        return staticCompilationTransformer.transform(tExp);
+    }
+
+    private DeclarationExpression optimizeConstantInitialization(
+            final BinaryExpression originalDeclaration,
+            final Token operation,
+            final ConstantExpression constant,
+            final Expression leftExpression,
+            final ClassNode declarationType) {
+        ConstantExpression cexp = new ConstantExpression(
+                convertConstant((Number) constant.getValue(), ClassHelper.getWrapper(declarationType)), true);
+        cexp.setType(declarationType);
+        cexp.setSourcePosition(constant);
+        DeclarationExpression result = new DeclarationExpression(
+                leftExpression,
+                operation,
+                cexp
+        );
+        result.setSourcePosition(originalDeclaration);
+        result.copyNodeMetaData(originalDeclaration);
+        return result;
+    }
+
+    private static Object convertConstant(Number source, ClassNode target) {
+        if (ClassHelper.Byte_TYPE.equals(target)) {
+            return source.byteValue();
+        }
+        if (ClassHelper.Short_TYPE.equals(target)) {
+            return source.shortValue();
+        }
+        if (ClassHelper.Integer_TYPE.equals(target)) {
+            return source.intValue();
+        }
+        if (ClassHelper.Long_TYPE.equals(target)) {
+            return source.longValue();
+        }
+        if (ClassHelper.Float_TYPE.equals(target)) {
+            return source.floatValue();
+        }
+        if (ClassHelper.Double_TYPE.equals(target)) {
+            return source.doubleValue();
+        }
+        if (ClassHelper.BigInteger_TYPE.equals(target)) {
+            return DefaultGroovyMethods.asType(source, BigInteger.class);
+        }
+        if (ClassHelper.BigDecimal_TYPE.equals(target)) {
+            return DefaultGroovyMethods.asType(source, BigDecimal.class);
+        }
+        throw new IllegalArgumentException("Unsupported conversion");
+    }
+
+    private Expression transformPropertyAssignmentToSetterCall(final PropertyExpression leftExpression, final Expression rightExpression, final MethodNode directMCT) {
+        // transform "a.x = b" into "def tmp = b; a.setX(tmp); tmp"
+        Expression arg = staticCompilationTransformer.transform(rightExpression);
+        return StaticPropertyAccessHelper.transformToSetterCall(
+                leftExpression.getObjectExpression(),
+                directMCT,
+                arg,
+                false,
+                false,
+                false,
+                true, // to be replaced with a proper test whether a return value should be used or not
+                leftExpression
+        );
+    }
+
     protected static boolean isNullConstant(final Expression expression) {
-        return expression instanceof ConstantExpression && ((ConstantExpression) expression).getValue()==null;
+        return expression instanceof ConstantExpression && ((ConstantExpression) expression).getValue() == null;
     }
 
 }
\ No newline at end of file
diff --git a/src/main/org/codehaus/groovy/transform/sc/transformers/CastExpressionOptimizer.java b/src/main/org/codehaus/groovy/transform/sc/transformers/CastExpressionOptimizer.java
new file mode 100644
index 0000000..b2de8ae
--- /dev/null
+++ b/src/main/org/codehaus/groovy/transform/sc/transformers/CastExpressionOptimizer.java
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.transform.sc.transformers;
+
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.expr.ArrayExpression;
+import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
+
+public class CastExpressionOptimizer {
+    private final StaticCompilationTransformer transformer;
+
+    public CastExpressionOptimizer(StaticCompilationTransformer staticCompilationTransformer) {
+        transformer = staticCompilationTransformer;
+    }
+
+    public Expression transformCastExpression(final CastExpression cast) {
+        if (cast.isCoerce()) {
+            Expression expression = cast.getExpression();
+            ClassNode exprInferredType = transformer.getTypeChooser().resolveType(expression, transformer.getClassNode());
+            ClassNode castType = cast.getType();
+            if (castType.isArray() && expression instanceof ListExpression) {
+                ArrayExpression arrayExpression = new ArrayExpression(castType.getComponentType(), ((ListExpression) expression).getExpressions());
+                arrayExpression.setSourcePosition(cast);
+                return transformer.transform(arrayExpression);
+            }
+            if (isOptimizable(exprInferredType, castType)) {
+                // coerce is not needed
+                CastExpression trn = new CastExpression(castType, transformer.transform(expression));
+                trn.setSourcePosition(cast);
+                trn.copyNodeMetaData(cast);
+                return trn;
+            }
+        } else if (ClassHelper.char_TYPE.equals(cast.getType())) {
+            Expression expression = cast.getExpression();
+            if (expression instanceof ConstantExpression) {
+                ConstantExpression ce = (ConstantExpression) expression;
+                if (ClassHelper.STRING_TYPE.equals(ce.getType())) {
+                    String val = (String) ce.getValue();
+                    if (val!=null && val.length()==1) {
+                        ConstantExpression result = new ConstantExpression(val.charAt(0),true);
+                        result.setSourcePosition(cast);
+                        return result;
+                    }
+                }
+            }
+        }
+        return transformer.superTransform(cast);
+    }
+
+    private boolean isOptimizable(final ClassNode exprInferredType, final ClassNode castType) {
+        if (StaticTypeCheckingSupport.implementsInterfaceOrIsSubclassOf(exprInferredType, castType)) {
+            return true;
+        }
+        if (ClassHelper.isPrimitiveType(exprInferredType) && ClassHelper.isPrimitiveType(castType)) {
+            return true;
+        }
+        return false;
+    }
+}
diff --git a/src/main/org/codehaus/groovy/transform/sc/transformers/MethodCallExpressionTransformer.java b/src/main/org/codehaus/groovy/transform/sc/transformers/MethodCallExpressionTransformer.java
index 7a18563..1e8f00b 100644
--- a/src/main/org/codehaus/groovy/transform/sc/transformers/MethodCallExpressionTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/sc/transformers/MethodCallExpressionTransformer.java
@@ -18,17 +18,23 @@ package org.codehaus.groovy.transform.sc.transformers;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
+import org.codehaus.groovy.classgen.asm.MopWriter;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
 import java.util.List;
 
+import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
+import static org.objectweb.asm.Opcodes.ACC_SYNTHETIC;
+
 public class MethodCallExpressionTransformer {
     private final StaticCompilationTransformer staticCompilationTransformer;
 
@@ -37,6 +43,10 @@ public class MethodCallExpressionTransformer {
     }
 
     Expression transformMethodCallExpression(final MethodCallExpression expr) {
+        ClassNode superCallReceiver = expr.getNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED);
+        if (superCallReceiver!=null) {
+            return transformMethodCallExpression(transformToMopSuperCall(superCallReceiver, expr));
+        }
         Expression objectExpression = expr.getObjectExpression();
         ClassNode type = staticCompilationTransformer.getTypeChooser().resolveType(objectExpression, staticCompilationTransformer.getClassNode());
         if (isCallOnClosure(expr)) {
@@ -111,6 +121,31 @@ public class MethodCallExpressionTransformer {
         return staticCompilationTransformer.superTransform(expr);
     }
 
+    private MethodCallExpression transformToMopSuperCall(final ClassNode superCallReceiver, final MethodCallExpression expr) {
+        MethodNode mn = expr.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        String mopName = MopWriter.getMopMethodName(mn, false);
+        MethodNode direct = new MethodNode(
+                mopName,
+                ACC_PUBLIC | ACC_SYNTHETIC,
+                mn.getReturnType(),
+                mn.getParameters(),
+                mn.getExceptions(),
+                EmptyStatement.INSTANCE
+        );
+        direct.setDeclaringClass(superCallReceiver);
+        MethodCallExpression result = new MethodCallExpression(
+                new VariableExpression("this"),
+                mopName,
+                expr.getArguments()
+        );
+        result.setImplicitThis(true);
+        result.setSpreadSafe(false);
+        result.setSafe(false);
+        result.setSourcePosition(expr);
+        result.setMethodTarget(direct);
+        return result;
+    }
+
     private boolean isCallOnClosure(final MethodCallExpression expr) {
         return expr.isImplicitThis()
                 && expr.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET) == StaticTypeCheckingVisitor.CLOSURE_CALL_VARGS
diff --git a/src/main/org/codehaus/groovy/transform/sc/transformers/StaticCompilationTransformer.java b/src/main/org/codehaus/groovy/transform/sc/transformers/StaticCompilationTransformer.java
index 1711bf7..4c0ff35 100644
--- a/src/main/org/codehaus/groovy/transform/sc/transformers/StaticCompilationTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/sc/transformers/StaticCompilationTransformer.java
@@ -22,6 +22,8 @@ import org.codehaus.groovy.classgen.asm.sc.StaticTypesTypeChooser;
 import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.runtime.ScriptBytecodeAdapter;
 import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
 
 import java.util.*;
 
@@ -51,6 +53,7 @@ public class StaticCompilationTransformer extends ClassCodeExpressionTransformer
     private final SourceUnit unit;
 
     private final StaticTypesTypeChooser typeChooser = new StaticTypesTypeChooser();
+    private final StaticTypeCheckingVisitor staticCompilationVisitor;
 
     // various helpers in order to avoid a potential very big class
     private final StaticMethodCallExpressionTransformer staticMethodCallExpressionTransformer = new StaticMethodCallExpressionTransformer(this);
@@ -62,9 +65,11 @@ public class StaticCompilationTransformer extends ClassCodeExpressionTransformer
     private final VariableExpressionTransformer variableExpressionTransformer = new VariableExpressionTransformer();
     private final RangeExpressionTransformer rangeExpressionTransformer = new RangeExpressionTransformer(this);
     private final ListExpressionTransformer listExpressionTransformer = new ListExpressionTransformer(this);
+    private final CastExpressionOptimizer castExpressionTransformer = new CastExpressionOptimizer(this);
 
-    public StaticCompilationTransformer(final SourceUnit unit) {
+    public StaticCompilationTransformer(final SourceUnit unit, final StaticTypeCheckingVisitor visitor) {
         this.unit = unit;
+        this.staticCompilationVisitor = visitor;
     }
 
     @Override
@@ -114,6 +119,9 @@ public class StaticCompilationTransformer extends ClassCodeExpressionTransformer
         if (expr instanceof ListExpression) {
             return listExpressionTransformer.transformListExpression((ListExpression) expr);
         }
+        if (expr instanceof CastExpression) {
+            return castExpressionTransformer.transformCastExpression(((CastExpression)expr));
+        }
         return super.transform(expr);
     }
 
@@ -136,4 +144,13 @@ public class StaticCompilationTransformer extends ClassCodeExpressionTransformer
         }
         classNode = prec;
     }
+
+    @Override
+    protected void visitConstructorOrMethod(final MethodNode node, final boolean isConstructor) {
+        if (staticCompilationVisitor.isSkipMode(node)) {
+            // method has already been visited by a static type checking visitor
+            return;
+        }
+        super.visitConstructorOrMethod(node, isConstructor);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java b/src/main/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
index 21b4da8..c465cba 100644
--- a/src/main/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/sc/transformers/VariableExpressionTransformer.java
@@ -16,37 +16,68 @@
 package org.codehaus.groovy.transform.sc.transformers;
 
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.transform.sc.StaticCompilationMetadataKeys;
-import org.codehaus.groovy.transform.sc.StaticCompilationVisitor;
-import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
 import org.codehaus.groovy.transform.stc.StaticTypesMarker;
 
 /**
  * Transformer for VariableExpression the bytecode backend wouldn't be able to
- * handle otherwise. 
+ * handle otherwise.
  * @author <a href="mailto:blackdrag at gmx.org">Jochen "blackdrag" Theodorou</a>
  */
 public class VariableExpressionTransformer {
 
     public Expression transformVariableExpression(VariableExpression expr) {
+        Expression trn = tryTransformPrivateFieldAccess(expr);
+        if (trn != null) {
+            return trn;
+        }
+        trn = tryTransformDelegateToProperty(expr);
+        if (trn != null) {
+            return trn;
+        }
+        return expr;
+    }
+
+    private Expression tryTransformDelegateToProperty(VariableExpression expr) {
         // we need to transform variable expressions that go to a delegate
         // to a property expression, as ACG would loose the information
         // in processClassVariable before it reaches any makeCall, that could
         // handle it
         Object val = expr.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
-        if (val==null) return expr;
+        if (val == null) return null;
         VariableExpression implicitThis = new VariableExpression("this");
         PropertyExpression pexp = new PropertyExpression(implicitThis, expr.getName());
         pexp.copyNodeMetaData(expr);
         pexp.setImplicitThis(true);
         ClassNode owner = expr.getNodeMetaData(StaticCompilationMetadataKeys.PROPERTY_OWNER);
-        if (owner!=null) {
+        if (owner != null) {
             implicitThis.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, owner);
             implicitThis.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, val);
         }
         return pexp;
     }
+
+    private Expression tryTransformPrivateFieldAccess(VariableExpression expr) {
+        FieldNode field = expr.getNodeMetaData(StaticTypesMarker.PV_FIELDS_ACCESS);
+        if (field != null) {
+            // access to a private field from a section of code that normally doesn't have access to it, like a
+            // closure or an inner class
+            VariableExpression receiver = new VariableExpression("this");
+            PropertyExpression pexp = new PropertyExpression(
+                    receiver,
+                    expr.getName()
+            );
+            pexp.setImplicitThis(true);
+            // put the receiver inferred type so that the class writer knows that it will have to call a bridge method
+            receiver.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getDeclaringClass());
+            // add inferred type information
+            pexp.putNodeMetaData(StaticTypesMarker.INFERRED_TYPE, field.getOriginType());
+            return pexp;
+        }
+        return null;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/transform/stc/AbstractTypeCheckingExtension.java b/src/main/org/codehaus/groovy/transform/stc/AbstractTypeCheckingExtension.java
index 712884f..2c1b449 100644
--- a/src/main/org/codehaus/groovy/transform/stc/AbstractTypeCheckingExtension.java
+++ b/src/main/org/codehaus/groovy/transform/stc/AbstractTypeCheckingExtension.java
@@ -404,6 +404,10 @@ public class AbstractTypeCheckingExtension extends TypeCheckingExtension {
         context.pushEnclosingMethod(methodNode);
     }
 
+    public Set<MethodNode> getGeneratedMethods() {
+        return generatedMethods;
+    }
+
     public List<BinaryExpression> getEnclosingBinaryExpressionStack() {
         return context.getEnclosingBinaryExpressionStack();
     }
diff --git a/src/main/org/codehaus/groovy/transform/stc/DefaultTypeCheckingExtension.java b/src/main/org/codehaus/groovy/transform/stc/DefaultTypeCheckingExtension.java
index 11d4713..b2e5edd 100644
--- a/src/main/org/codehaus/groovy/transform/stc/DefaultTypeCheckingExtension.java
+++ b/src/main/org/codehaus/groovy/transform/stc/DefaultTypeCheckingExtension.java
@@ -22,6 +22,7 @@ import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.expr.*;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
 
+import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.LinkedList;
 import java.util.List;
@@ -170,7 +171,9 @@ public class DefaultTypeCheckingExtension extends TypeCheckingExtension {
 
     @Override
     public void setup() {
-        for (TypeCheckingExtension handler : handlers) {
+        ArrayList<TypeCheckingExtension> copy = new ArrayList<TypeCheckingExtension>(handlers);
+        // we're using a copy here because new extensions can be added during the "setup" phase
+        for (TypeCheckingExtension handler : copy) {
             handler.setup();
         }
     }
diff --git a/src/main/org/codehaus/groovy/transform/stc/GroovyTypeCheckingExtensionSupport.java b/src/main/org/codehaus/groovy/transform/stc/GroovyTypeCheckingExtensionSupport.java
index fffbdc5..58ae6c1 100644
--- a/src/main/org/codehaus/groovy/transform/stc/GroovyTypeCheckingExtensionSupport.java
+++ b/src/main/org/codehaus/groovy/transform/stc/GroovyTypeCheckingExtensionSupport.java
@@ -41,6 +41,8 @@ import org.codehaus.groovy.runtime.InvokerHelper;
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.UnsupportedEncodingException;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
 import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
@@ -124,17 +126,33 @@ public class GroovyTypeCheckingExtensionSupport extends AbstractTypeCheckingExte
             Class<?> clazz = transformLoader.loadClass(scriptPath, false, true);
             if (TypeCheckingDSL.class.isAssignableFrom(clazz)) {
                 script = (TypeCheckingDSL) clazz.newInstance();
+            } else if (TypeCheckingExtension.class.isAssignableFrom(clazz)) {
+                // since 2.4, we can also register precompiled type checking extensions which are not scripts
+                try {
+                    Constructor<?> declaredConstructor = clazz.getDeclaredConstructor(StaticTypeCheckingVisitor.class);
+                    TypeCheckingExtension extension = (TypeCheckingExtension) declaredConstructor.newInstance(typeCheckingVisitor);
+                    typeCheckingVisitor.addTypeCheckingExtension(extension);
+                    extension.setup();
+                    return;
+                } catch (InstantiationException e) {
+                    addLoadingError(config);
+                } catch (IllegalAccessException e) {
+                    addLoadingError(config);
+                } catch (NoSuchMethodException e) {
+                    context.getErrorCollector().addFatalError(
+                            new SimpleMessage("Static type checking extension '" + scriptPath + "' could not be loaded because it doesn't have a constructor accepting StaticTypeCheckingVisitor.",
+                                    config.getDebug(), typeCheckingVisitor.getSourceUnit())
+                    );
+                } catch (InvocationTargetException e) {
+                    addLoadingError(config);
+                }
             }
         } catch (ClassNotFoundException e) {
             // silent
         } catch (InstantiationException e) {
-            context.getErrorCollector().addFatalError(
-                    new SimpleMessage("Static type checking extension '" + scriptPath + "' could not be loaded.",
-                            config.getDebug(), typeCheckingVisitor.getSourceUnit()));
+            addLoadingError(config);
         } catch (IllegalAccessException e) {
-            context.getErrorCollector().addFatalError(
-                    new SimpleMessage("Static type checking extension '" + scriptPath + "' could not be loaded.",
-                            config.getDebug(), typeCheckingVisitor.getSourceUnit()));
+            addLoadingError(config);
         }
         if (script==null) {
             ClassLoader cl = typeCheckingVisitor.getSourceUnit().getClassLoader();
@@ -178,6 +196,13 @@ public class GroovyTypeCheckingExtensionSupport extends AbstractTypeCheckingExte
         }
     }
 
+    private void addLoadingError(final CompilerConfiguration config) {
+        context.getErrorCollector().addFatalError(
+                new SimpleMessage("Static type checking extension '" + scriptPath + "' could not be loaded.",
+                        config.getDebug(), typeCheckingVisitor.getSourceUnit())
+        );
+    }
+
     @Override
     public void finish() {
         List<Closure> list = eventHandlers.get("finish");
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
index 831415b..37594dd 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingSupport.java
@@ -32,6 +32,7 @@ import org.codehaus.groovy.runtime.m12n.ExtensionModuleScanner;
 import org.codehaus.groovy.runtime.m12n.MetaInfExtensionModule;
 import org.codehaus.groovy.runtime.metaclass.MetaClassRegistryImpl;
 import org.codehaus.groovy.tools.GroovyClass;
+import org.codehaus.groovy.transform.trait.Traits;
 import org.objectweb.asm.Opcodes;
 
 import java.lang.ref.WeakReference;
@@ -379,7 +380,7 @@ public abstract class StaticTypeCheckingSupport {
         return false;
     }
 
-    static boolean isCompareToBoolean(int op) {
+    public static boolean isCompareToBoolean(int op) {
         return op == COMPARE_GREATER_THAN ||
                 op == COMPARE_GREATER_THAN_EQUAL ||
                 op == COMPARE_LESS_THAN ||
@@ -558,7 +559,7 @@ public abstract class StaticTypeCheckingSupport {
         if (leftRedirect==rightRedirect) return true;
 
         if (leftRedirect.isArray() && rightRedirect.isArray()) {
-            return checkCompatibleAssignmentTypes(leftRedirect.getComponentType(), rightRedirect.getComponentType(), rightExpression, allowConstructorCoercion);
+            return checkCompatibleAssignmentTypes(leftRedirect.getComponentType(), rightRedirect.getComponentType(), rightExpression, false);
         }
 
         if (right==VOID_TYPE||right==void_WRAPPER_TYPE) {
@@ -608,11 +609,7 @@ public abstract class StaticTypeCheckingSupport {
 
         // if right is array, map or collection we try invoking the
         // constructor
-        if (allowConstructorCoercion && (rightRedirect.implementsInterface(MAP_TYPE) ||
-                rightRedirect.implementsInterface(Collection_TYPE) ||
-                rightRedirect.equals(MAP_TYPE) ||
-                rightRedirect.equals(Collection_TYPE) ||
-                rightRedirect.isArray())) {
+        if (allowConstructorCoercion && isGroovyConstructorCompatible(rightExpression)) {
             //TODO: in case of the array we could maybe make a partial check
             if (leftRedirect.isArray() && rightRedirect.isArray()) {
                 return checkCompatibleAssignmentTypes(leftRedirect.getComponentType(), rightRedirect.getComponentType());
@@ -638,7 +635,24 @@ public abstract class StaticTypeCheckingSupport {
             return true;
         }
 
-        return false;
+        if (left.isGenericsPlaceHolder()) {
+            // GROOVY-7307
+            GenericsType[] genericsTypes = left.getGenericsTypes();
+            if (genericsTypes!=null && genericsTypes.length==1) {
+                // should always be the case, but safe guard is better
+                return genericsTypes[0].isCompatibleWith(right);
+            }
+        }
+
+        // GROOVY-7316 : it is an apparently legal thing to allow this. It's not type safe,
+        // but it is allowed...
+        return right.isGenericsPlaceHolder();
+    }
+
+    private static boolean isGroovyConstructorCompatible(final Expression rightExpression) {
+        return rightExpression instanceof ListExpression
+                || rightExpression instanceof MapExpression
+                || rightExpression instanceof ArrayExpression;
     }
 
     /**
@@ -727,7 +741,7 @@ public abstract class StaticTypeCheckingSupport {
                     return false; // no possible loose here
             }
         }
-        return true; // possible loose of precision
+        return true; // possible loss of precision
     }
 
     static String toMethodParametersString(String methodName, ClassNode... parameters) {
@@ -1465,7 +1479,11 @@ public abstract class StaticTypeCheckingSupport {
             compareNode = getCombinedBoundType(resolved);
             compareNode = compareNode.redirect().getPlainNodeReference();
         } else {
-            compareNode = resolved.getType().getPlainNodeReference();
+            if (!resolved.isPlaceholder()) {
+                compareNode = resolved.getType().getPlainNodeReference();
+            } else {
+                return true;
+            }
         }
         return gt.isCompatibleWith(compareNode);
     }
@@ -1881,9 +1899,15 @@ public abstract class StaticTypeCheckingSupport {
             Collections.addAll(instanceExtClasses, DefaultGroovyMethods.additionals);
             staticExtClasses.add(DefaultGroovyStaticMethods.class);
             instanceExtClasses.add(ObjectArrayStaticTypesHelper.class);
-            List<Class> allClasses = new ArrayList<Class>(instanceExtClasses.size()+staticExtClasses.size());
-            allClasses.addAll(instanceExtClasses);
-            allClasses.addAll(staticExtClasses);
+
+            scanClassesForDGMMethods(methods, staticExtClasses, true);
+            scanClassesForDGMMethods(methods, instanceExtClasses, false);
+            
+            return methods;
+        }
+
+        private static void scanClassesForDGMMethods(Map<String, List<MethodNode>> accumulator,
+                                                    Iterable<Class> allClasses, boolean isStatic) {
             for (Class dgmLikeClass : allClasses) {
                 ClassNode cn = ClassHelper.makeWithoutCaching(dgmLikeClass, true);
                 for (MethodNode metaMethod : cn.getMethods()) {
@@ -1899,22 +1923,21 @@ public abstract class StaticTypeCheckingSupport {
                                 metaMethod.getReturnType(),
                                 parameters,
                                 ClassNode.EMPTY_ARRAY, null,
-                                staticExtClasses.contains(dgmLikeClass));
+                                isStatic);
                         node.setGenericsTypes(metaMethod.getGenericsTypes());
                         ClassNode declaringClass = types[0].getType();
                         String declaringClassName = declaringClass.getName();
                         node.setDeclaringClass(declaringClass);
 
-                        List<MethodNode> nodes = methods.get(declaringClassName);
+                        List<MethodNode> nodes = accumulator.get(declaringClassName);
                         if (nodes == null) {
                             nodes = new LinkedList<MethodNode>();
-                            methods.put(declaringClassName, nodes);
+                            accumulator.put(declaringClassName, nodes);
                         }
                         nodes.add(node);
                     }
                 }
             }
-            return methods;
         }
 
     }
@@ -2049,4 +2072,38 @@ public abstract class StaticTypeCheckingSupport {
                 && !genericsTypes[0].isPlaceholder()
                 && !genericsTypes[0].isWildcard();
     }
+
+    public static List<MethodNode> findSetters(ClassNode cn, String setterName, boolean voidOnly) {
+        List<MethodNode> result = null;
+        for (MethodNode method : cn.getDeclaredMethods(setterName)) {
+            if (setterName.equals(method.getName())
+                    && (!voidOnly || ClassHelper.VOID_TYPE==method.getReturnType())
+                    && method.getParameters().length == 1) {
+                if (result==null) {
+                    result = new LinkedList<MethodNode>();
+                }
+                result.add(method);
+            }
+        }
+        if (result==null) {
+            ClassNode parent = cn.getSuperClass();
+            if (parent != null) {
+                return findSetters(parent, setterName, voidOnly);
+            }
+            return Collections.emptyList();
+        }
+        return result;
+    }
+
+    public static ClassNode isTraitSelf(VariableExpression vexp) {
+        if (Traits.THIS_OBJECT.equals(vexp.getName())) {
+            Variable accessedVariable = vexp.getAccessedVariable();
+            ClassNode type = accessedVariable!=null?accessedVariable.getType():null;
+            if (accessedVariable instanceof Parameter
+                    && Traits.isTrait(type)) {
+                return type;
+            }
+        }
+        return null;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
index 424c5e1..0004424 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypeCheckingVisitor.java
@@ -19,6 +19,7 @@ import groovy.lang.Closure;
 import groovy.lang.DelegatesTo;
 import groovy.lang.IntRange;
 import groovy.lang.Range;
+import groovy.transform.SelfType;
 import groovy.transform.TypeChecked;
 import groovy.transform.TypeCheckingMode;
 import groovy.transform.stc.ClosureParams;
@@ -63,6 +64,7 @@ import org.codehaus.groovy.runtime.MetaClassHelper;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.transform.StaticTypesTransformation;
+import org.codehaus.groovy.transform.trait.Traits;
 import org.codehaus.groovy.util.ListHashMap;
 import org.objectweb.asm.Opcodes;
 
@@ -71,6 +73,7 @@ import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.HashSet;
 import java.util.Iterator;
@@ -80,6 +83,7 @@ import java.util.LinkedList;
 import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
 import java.util.concurrent.atomic.AtomicReference;
 
 import static org.codehaus.groovy.ast.ClassHelper.*;
@@ -122,6 +126,7 @@ import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.*;
 public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     private static final boolean DEBUG_GENERATED_CODE = Boolean.valueOf(System.getProperty("groovy.stc.debug", "false"));
+    private static final AtomicLong UNIQUE_LONG = new AtomicLong();
 
     protected static final Object ERROR_COLLECTOR = ErrorCollector.class;
     protected static final ClassNode ITERABLE_TYPE = ClassHelper.make(Iterable.class);
@@ -139,8 +144,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     protected static final ClassNode DELEGATES_TO_TARGET = ClassHelper.make(DelegatesTo.Target.class);
     protected static final ClassNode LINKEDHASHMAP_CLASSNODE = make(LinkedHashMap.class);
     protected static final ClassNode CLOSUREPARAMS_CLASSNODE = make(ClosureParams.class);
-
-
+    protected static final ClassNode MAP_ENTRY_TYPE = make(Map.Entry.class);
+    protected static final ClassNode ENUMERATION_TYPE = make(Enumeration.class);
 
     public static final Statement GENERATED_EMPTY_STATEMENT = new EmptyStatement();
 
@@ -159,6 +164,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         });
     }
 
+    private static final String[] EMPTY_STRING_ARRAY = new String[0];
+
     protected final ReturnAdder.ReturnStatementListener returnListener = new ReturnAdder.ReturnStatementListener() {
         public void returnStatementAdded(final ReturnStatement returnStatement) {
             ClassNode returnType = checkReturnType(returnStatement);
@@ -321,34 +328,66 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     @SuppressWarnings("unchecked")
-    private void addPrivateFieldOrMethodAccess(ClassNode cn, StaticTypesMarker type, ASTNode accessedMember) {
+    private void addPrivateFieldOrMethodAccess(Expression source, ClassNode cn, StaticTypesMarker type, ASTNode accessedMember) {
         Set<ASTNode> set = (Set<ASTNode>) cn.getNodeMetaData(type);
         if (set==null) {
             set = new LinkedHashSet<ASTNode>();
             cn.putNodeMetaData(type, set);
         }
         set.add(accessedMember);
+        source.putNodeMetaData(type, accessedMember);
     }
 
     /**
      * Given a field node, checks if we are calling a private field from an inner class.
      */
-    private void checkOrMarkPrivateAccess(FieldNode fn) {
+    private void checkOrMarkPrivateAccess(Expression source, FieldNode fn) {
         if (fn!=null && Modifier.isPrivate(fn.getModifiers()) &&
             (fn.getDeclaringClass() != typeCheckingContext.getEnclosingClassNode() || typeCheckingContext.getEnclosingClosure()!=null) &&
             fn.getDeclaringClass().getModule() == typeCheckingContext.getEnclosingClassNode().getModule()) {
-            addPrivateFieldOrMethodAccess(fn.getDeclaringClass(), StaticTypesMarker.PV_FIELDS_ACCESS, fn);
+            addPrivateFieldOrMethodAccess(source, fn.getDeclaringClass(), StaticTypesMarker.PV_FIELDS_ACCESS, fn);
         }
     }
 
     /**
      * Given a method node, checks if we are calling a private method from an inner class.
      */
-    private void checkOrMarkPrivateAccess(MethodNode mn) {
-        if (mn!=null && Modifier.isPrivate(mn.getModifiers()) &&
-            (mn.getDeclaringClass() != typeCheckingContext.getEnclosingClassNode() || typeCheckingContext.getEnclosingClosure()!=null) &&
-            mn.getDeclaringClass().getModule() == typeCheckingContext.getEnclosingClassNode().getModule()) {
-            addPrivateFieldOrMethodAccess(mn.getDeclaringClass(), StaticTypesMarker.PV_METHODS_ACCESS, mn);
+    private void checkOrMarkPrivateAccess(Expression source, MethodNode mn) {
+        if (mn==null) {
+            return;
+        }
+        ClassNode declaringClass = mn.getDeclaringClass();
+        ClassNode enclosingClassNode = typeCheckingContext.getEnclosingClassNode();
+        if (declaringClass != enclosingClassNode || typeCheckingContext.getEnclosingClosure() != null) {
+            int mods = mn.getModifiers();
+            boolean sameModule = declaringClass.getModule() == enclosingClassNode.getModule();
+            String packageName = declaringClass.getPackageName();
+            if (packageName==null) {
+                packageName = "";
+            }
+            if ((Modifier.isPrivate(mods) && sameModule)
+                    || (Modifier.isProtected(mods) && !packageName.equals(enclosingClassNode.getPackageName()))) {
+                addPrivateFieldOrMethodAccess(source, sameModule? declaringClass : enclosingClassNode, StaticTypesMarker.PV_METHODS_ACCESS, mn);
+            }
+        }
+    }
+
+    private void checkSuperCallFromClosure(Expression call, MethodNode directCallTarget) {
+        if (call instanceof MethodCallExpression && typeCheckingContext.getEnclosingClosure() != null) {
+            Expression objectExpression = ((MethodCallExpression)call).getObjectExpression();
+            if (objectExpression instanceof VariableExpression) {
+                VariableExpression var = (VariableExpression) objectExpression;
+                if (var.isSuperExpression()) {
+                    ClassNode current = typeCheckingContext.getEnclosingClassNode();
+                    LinkedList<MethodNode> list = current.getNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED);
+                    if (list == null) {
+                        list = new LinkedList<MethodNode>();
+                        current.putNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED, list);
+                    }
+                    list.add(directCallTarget);
+                    call.putNodeMetaData(StaticTypesMarker.SUPER_MOP_METHOD_REQUIRED, current);
+                }
+            }
         }
     }
 
@@ -387,6 +426,25 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         if (storeTypeForThis(vexp)) return;
         if (storeTypeForSuper(vexp)) return;
+        if (vexp.getAccessedVariable() instanceof PropertyNode) {
+            // we must be careful, because the property node may be of a wrong type:
+            // if a class contains a getter and a setter of different types or
+            // overloaded setters, the type of the property node is arbitrary!
+            if (tryVariableExpressionAsProperty(vexp, vexp.getName())) {
+                BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
+                if (enclosingBinaryExpression != null) {
+                    Expression leftExpression = enclosingBinaryExpression.getLeftExpression();
+                    Expression rightExpression = enclosingBinaryExpression.getRightExpression();
+                    SetterInfo setterInfo = removeSetterInfo(leftExpression);
+                    if (setterInfo != null) {
+                        if (!ensureValidSetter(vexp, leftExpression, rightExpression, setterInfo)) {
+                            return;
+                        }
+
+                    }
+                }
+            }
+        }
 
         TypeCheckingContext.EnclosingClosure enclosingClosure = typeCheckingContext.getEnclosingClosure();
         if (enclosingClosure != null) {
@@ -410,6 +468,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         DynamicVariable dyn = (DynamicVariable) vexp.getAccessedVariable();
         // first, we must check the 'with' context
         String dynName = dyn.getName();
+        if (tryVariableExpressionAsProperty(vexp, dynName)) return;
+
+        if (!extension.handleUnresolvedVariableExpression(vexp)) {
+            addStaticTypeError("The variable [" + vexp.getName() + "] is undeclared.", vexp);
+        }
+    }
+
+    private boolean tryVariableExpressionAsProperty(final VariableExpression vexp, final String dynName) {
         VariableExpression implicitThis = new VariableExpression("this");
         PropertyExpression pe = new PropertyExpression(implicitThis, dynName);
         pe.setImplicitThis(true);
@@ -422,12 +488,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             if (val!=null) vexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY,val);
             val = pe.getNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER);
             if (val!=null) vexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER,val);
-            return;
-        }
-
-        if (!extension.handleUnresolvedVariableExpression(vexp)) {
-            addStaticTypeError("The variable [" + vexp.getName() + "] is undeclared.", vexp);
+            return true;
         }
+        return false;
     }
 
     private boolean visitPropertyExpressionSilent(PropertyExpression pe, Expression lhsPart) {
@@ -482,26 +545,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             final Expression leftExpression = expression.getLeftExpression();
             final Expression rightExpression = expression.getRightExpression();
             int op = expression.getOperation().getType();
-            if (rightExpression instanceof ClosureExpression) {
-                leftExpression.visit(this);
-                SetterInfo setterInfo = removeSetterInfo(leftExpression);
-                if (setterInfo != null) {
-                    // for expressions like foo = { ... }
-                    // we know that the RHS type is a closure
-                    // but we must check if the binary expression is an assignment
-                    // because we need to check if a setter uses @DelegatesTo
-                    VariableExpression ve = new VariableExpression("%", setterInfo.receiverType);
-                    MethodCallExpression call = new MethodCallExpression(
-                            ve,
-                            setterInfo.setter.getName(),
-                            rightExpression
-                    );
-                    visitMethodCallExpression(call);
-                } else {
-                    rightExpression.visit(this);
+            leftExpression.visit(this);
+            SetterInfo setterInfo = removeSetterInfo(leftExpression);
+            if (setterInfo != null) {
+                if (ensureValidSetter(expression, leftExpression, rightExpression, setterInfo)) {
+                    return;
                 }
+
             } else {
-                leftExpression.visit(this);
                 rightExpression.visit(this);
             }
             ClassNode lType = getType(leftExpression);
@@ -638,9 +689,72 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
+    /**
+     * Given a binary expression corresponding to an assignment, will check that the type of the RHS matches one
+     * of the possible setters and if not, throw a type checking error.
+     * @param expression the assignment expression
+     * @param leftExpression left expression of the assignment
+     * @param rightExpression right expression of the assignment
+     * @param setterInfo possible setters
+     * @return true if type checking passed
+     */
+    private boolean ensureValidSetter(final Expression expression, final Expression leftExpression, final Expression rightExpression, final SetterInfo setterInfo) {
+        // for expressions like foo = { ... }
+        // we know that the RHS type is a closure
+        // but we must check if the binary expression is an assignment
+        // because we need to check if a setter uses @DelegatesTo
+        VariableExpression ve = new VariableExpression("%", setterInfo.receiverType);
+        MethodCallExpression call = new MethodCallExpression(
+                ve,
+                setterInfo.name,
+                rightExpression
+        );
+        call.setImplicitThis(false);
+        visitMethodCallExpression(call);
+        MethodNode directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+        if (directSetterCandidate==null) {
+            // this may happen if there's a setter of type boolean/String/Class, and that we are using the property
+            // notation AND that the RHS is not a boolean/String/Class
+            for (MethodNode setter : setterInfo.setters) {
+                ClassNode type = getWrapper(setter.getParameters()[0].getOriginType());
+                if (Boolean_TYPE.equals(type) || STRING_TYPE.equals(type) || CLASS_Type.equals(type)) {
+                    call = new MethodCallExpression(
+                            ve,
+                            setterInfo.name,
+                            new CastExpression(type,rightExpression)
+                    );
+                    call.setImplicitThis(false);
+                    visitMethodCallExpression(call);
+                    directSetterCandidate = call.getNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET);
+                    if (directSetterCandidate!=null) {
+                        break;
+                    }
+                }
+            }
+        }
+        if (directSetterCandidate != null) {
+            for (MethodNode setter : setterInfo.setters) {
+                if (setter == directSetterCandidate) {
+                    leftExpression.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directSetterCandidate);
+                    storeType(leftExpression, getType(rightExpression));
+                    break;
+                }
+            }
+        } else {
+            ClassNode firstSetterType = setterInfo.setters.iterator().next().getParameters()[0].getOriginType();
+            addAssignmentError(firstSetterType, getType(rightExpression), expression);
+            return true;
+        }
+        return false;
+    }
+
     protected ClassNode getOriginalDeclarationType(Expression lhs) {
         if (lhs instanceof VariableExpression) {
             Variable var = findTargetVariable((VariableExpression) lhs);
+            if (var instanceof PropertyNode) {
+                // Do NOT trust the type of the property node!
+                return getType(lhs);
+            }
             if (var instanceof DynamicVariable) return getType(lhs);
             return var.getOriginType();
         }
@@ -716,7 +830,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         potentialTypes.add(typeExpression.getType());
     }
-    
+
     private boolean typeCheckMultipleAssignmentAndContinue(Expression leftExpression, Expression rightExpression) {
         // multiple assignment check
         if (!(leftExpression instanceof TupleExpression)) return true;
@@ -760,7 +874,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         return wrappedRHS;
     }
-    
+
     private boolean addedReadOnlyPropertyError(Expression expr) {
         // if expr is of READONLY_PROPERTY_RETURN type, then it means we are on a missing property
         if (expr.getNodeMetaData(StaticTypesMarker.READONLY_PROPERTY) == null) return false;
@@ -773,11 +887,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         addStaticTypeError("Cannot set read-only property: " + name, expr);
         return true;
     }
-    
+
     private void addPrecisionErrors(ClassNode leftRedirect, ClassNode lhsType, ClassNode inferredrhsType, Expression rightExpression) {
         if (isNumberType(leftRedirect) && isNumberType(inferredrhsType)) {
             if (checkPossibleLooseOfPrecision(leftRedirect, inferredrhsType, rightExpression)) {
-                addStaticTypeError("Possible loose of precision from " + inferredrhsType + " to " + leftRedirect, rightExpression);
+                addStaticTypeError("Possible loss of precision from " + inferredrhsType + " to " + leftRedirect, rightExpression);
                 return;
             }
         }
@@ -800,11 +914,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             }
         }
     }
-    
+
     private void addListAssignmentConstructorErrors(
-            ClassNode leftRedirect, ClassNode leftExpressionType, 
-            ClassNode inferredRightExpressionType, Expression rightExpression, 
-            Expression assignmentExpression) 
+            ClassNode leftRedirect, ClassNode leftExpressionType,
+            ClassNode inferredRightExpressionType, Expression rightExpression,
+            Expression assignmentExpression)
     {
         // if left type is not a list but right type is a list, then we're in the case of a groovy
         // constructor type : Dimension d = [100,200]
@@ -824,7 +938,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
         }
     }
-    
+
     private void addMapAssignmentConstructorErrors(ClassNode leftRedirect, Expression leftExpression, Expression rightExpression) {
         // if left type is not a list but right type is a map, then we're in the case of a groovy
         // constructor type : A a = [x:2, y:3]
@@ -850,14 +964,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
         GenericsType gt = GenericsUtils.buildWildcardType(leftExpressionType);
         if (    UNKNOWN_PARAMETER_TYPE.equals(wrappedRHS) ||
-                gt.isCompatibleWith(wrappedRHS) || 
+                gt.isCompatibleWith(wrappedRHS) ||
                 isNullConstant(rightExpression)) return;
 
         addStaticTypeError("Incompatible generic argument types. Cannot assign "
                 + wrappedRHS.toString(false)
                 + " to: " + leftExpressionType.toString(false), rightExpression);
     }
-    
+
     private boolean hasGStringStringError(ClassNode leftExpressionType, ClassNode wrappedRHS, Expression rightExpression) {
         if (isParameterizedWithString(leftExpressionType) && isParameterizedWithGStringOrGStringString(wrappedRHS)) {
             addStaticTypeError("You are trying to use a GString in place of a String in a type which explicitly declares accepting String. " +
@@ -866,13 +980,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         return false;
     }
-    
+
     protected void typeCheckAssignment(
             final BinaryExpression assignmentExpression,
             final Expression leftExpression,
             final ClassNode leftExpressionType,
             final Expression rightExpression,
-            final ClassNode inferredRightExpressionType) 
+            final ClassNode inferredRightExpressionType)
     {
 
         if (!typeCheckMultipleAssignmentAndContinue(leftExpression, rightExpression)) return;
@@ -901,6 +1015,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     protected void checkGroovyConstructorMap(final Expression receiver, final ClassNode receiverType, final MapExpression mapExpression) {
+        // workaround for map-style checks putting setter info on wrong AST nodes
+        typeCheckingContext.pushEnclosingBinaryExpression(null);
         for (MapEntryExpression entryExpression : mapExpression.getMapEntryExpressions()) {
             Expression keyExpr = entryExpression.getKeyExpression();
             if (!(keyExpr instanceof ConstantExpression)) {
@@ -922,6 +1038,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 }
             }
         }
+        typeCheckingContext.popEnclosingBinaryExpression();
     }
 
     protected static boolean hasRHSIncompleteGenericTypeInfo(final ClassNode inferredRightExpressionType) {
@@ -1069,108 +1186,119 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         HashSet<ClassNode> handledNodes = new HashSet<ClassNode>();
         for (Receiver<String> receiver : receivers) {
             ClassNode testClass = receiver.getType();
-                LinkedList<ClassNode> queue = new LinkedList<ClassNode>();
-                queue.add(testClass);
-                while (!queue.isEmpty()) {
-                    ClassNode current = queue.removeFirst();
-                    if (handledNodes.contains(current)) continue;
-                    handledNodes.add(current);
-                    Set<ClassNode> allInterfaces = current.getAllInterfaces();
-                    for (ClassNode intf : allInterfaces) {
-                        //TODO: apply right generics here!
-                        queue.add(GenericsUtils.parameterizeType(current, intf));
-                    }
+            LinkedList<ClassNode> queue = new LinkedList<ClassNode>();
+            queue.add(testClass);
+            if (isPrimitiveType(testClass)) {
+                queue.add(getWrapper(testClass));
+            }
+            while (!queue.isEmpty()) {
+                ClassNode current = queue.removeFirst();
+                if (handledNodes.contains(current)) continue;
+                handledNodes.add(current);
+                Set<ClassNode> allInterfaces = current.getAllInterfaces();
+                for (ClassNode intf : allInterfaces) {
+                    //TODO: apply right generics here!
+                    queue.add(GenericsUtils.parameterizeType(current, intf));
+                }
 
-                    // in case of a lookup on Class we look for instance methods on Class
-                    // as well, since in case of a static property access we have the class
-                    // itself in the list of receivers already;
-                    boolean staticOnly;
-                    if (isClassClassNodeWrappingConcreteType(current)) {
-                        staticOnly = false;
-                    } else {
-                        staticOnly = staticOnlyAccess;
-                    }
+                // in case of a lookup on Class we look for instance methods on Class
+                // as well, since in case of a static property access we have the class
+                // itself in the list of receivers already;
+                boolean staticOnly;
+                if (isClassClassNodeWrappingConcreteType(current)) {
+                    staticOnly = false;
+                } else {
+                    staticOnly = staticOnlyAccess;
+                }
 
-                    FieldNode field = current.getDeclaredField(propertyName);
-                    field  = allowStaticAccessToMember(field, staticOnly);
-                    if (storeField(field, isAttributeExpression, pexp, current, visitor, receiver.getData())) return true;
-
-                    PropertyNode propertyNode = current.getProperty(propertyName);
-                    propertyNode = allowStaticAccessToMember(propertyNode, staticOnly);
-                    if (storeProperty(propertyNode, pexp, current, visitor, receiver.getData())) return true;
-
-                    boolean isThisExpression = objectExpression instanceof VariableExpression && 
-                                                ((VariableExpression)objectExpression).isThisExpression();
-                    if (storeField(field, isThisExpression, pexp, receiver.getType(), visitor, receiver.getData())) return true;
-
-                    MethodNode getter = current.getGetterMethod("get" + capName);
-                    getter = allowStaticAccessToMember(getter, staticOnly);
-                    if (getter == null) getter = current.getGetterMethod("is" + capName);
-                    getter = allowStaticAccessToMember(getter, staticOnly);
-                    MethodNode setter = current.getSetterMethod("set" + capName, false);
-                    setter = allowStaticAccessToMember(setter, staticOnly);
-
-                    // TODO: remove this visit
-                    // need to visit even if we only look for a setter for compatibility
-                    if (visitor != null && getter!=null) visitor.visitMethod(getter);
-
-                    if (readMode) {
-                        if (getter!=null) {
-                            ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
-                            storeInferredTypeForPropertyExpression(pexp, cn);
-                            pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
-                            String delegationData = receiver.getData();
-                            if (delegationData!=null) pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
-                            return true;
-                        }
-                    } else {
-                        if (setter != null) {
-                            if (visitor != null) {
-                                if (field!=null) {
-                                    visitor.visitField(field);
-                                } else {
+                FieldNode field = current.getDeclaredField(propertyName);
+                field = allowStaticAccessToMember(field, staticOnly);
+                if (storeField(field, isAttributeExpression, pexp, current, visitor, receiver.getData())) return true;
+
+                PropertyNode propertyNode = current.getProperty(propertyName);
+                propertyNode = allowStaticAccessToMember(propertyNode, staticOnly);
+                if (storeProperty(propertyNode, pexp, current, visitor, receiver.getData())) return true;
+
+                boolean isThisExpression = objectExpression instanceof VariableExpression &&
+                        ((VariableExpression) objectExpression).isThisExpression();
+                if (storeField(field, isThisExpression, pexp, receiver.getType(), visitor, receiver.getData()))
+                    return true;
+
+                MethodNode getter = current.getGetterMethod("get" + capName);
+                getter = allowStaticAccessToMember(getter, staticOnly);
+                if (getter == null) getter = current.getGetterMethod("is" + capName);
+                getter = allowStaticAccessToMember(getter, staticOnly);
+                final String setterName = "set" + capName;
+                List<MethodNode> setters = findSetters(current, setterName, false);
+                setters = allowStaticAccessToMember(setters, staticOnly);
+
+                // TODO: remove this visit
+                // need to visit even if we only look for a setters for compatibility
+                if (visitor != null && getter != null) visitor.visitMethod(getter);
+
+                if (readMode) {
+                    if (getter != null) {
+                        ClassNode cn = inferReturnTypeGenerics(current, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
+                        storeInferredTypeForPropertyExpression(pexp, cn);
+                        pexp.removeNodeMetaData(StaticTypesMarker.READONLY_PROPERTY);
+                        String delegationData = receiver.getData();
+                        if (delegationData != null)
+                            pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
+                        return true;
+                    }
+                } else {
+                    if (!setters.isEmpty()) {
+                        if (visitor != null) {
+                            if (field != null) {
+                                visitor.visitField(field);
+                            } else {
+                                for (MethodNode setter : setters) {
                                     ClassNode setterType = setter.getParameters()[0].getOriginType();
                                     FieldNode virtual = new FieldNode(propertyName, 0, setterType, current, EmptyExpression.INSTANCE);
                                     visitor.visitField(virtual);
                                 }
                             }
-
-                            //TODO: apply generics on parameter[0]? 
-                            storeType(pexp, setter.getParameters()[0].getType());
-                            SetterInfo info = new SetterInfo(current, setter);
-                            BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
-                            if (enclosingBinaryExpression!=null) putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
-                            String delegationData = receiver.getData();
-                            if (delegationData!=null) pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
-                            return true;
-                        } else if (getter!=null) {
-                            pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, true);
                         }
-                    }
-                    foundGetterOrSetter = foundGetterOrSetter || setter!=null || getter!=null;
-
-                    if (storeField(field, true, pexp, current, visitor, receiver.getData())) return true;
-                    // if the property expression is an attribute expression (o. at attr), then
-                    // we stop now, otherwise we must check the parent class
-                    if (/*!isAttributeExpression && */current.getSuperClass() != null) {
-                        queue.add(current.getUnresolvedSuperClass());
+                        //TODO: apply generics on parameter[0]?
+//                                storeType(pexp, setter.getParameters()[0].getType());
+                        SetterInfo info = new SetterInfo(current, setterName, setters);
+                        BinaryExpression enclosingBinaryExpression = typeCheckingContext.getEnclosingBinaryExpression();
+                        if (enclosingBinaryExpression != null) {
+                            putSetterInfo(enclosingBinaryExpression.getLeftExpression(), info);
+                        }
+                        String delegationData = receiver.getData();
+                        if (delegationData != null) {
+                            pexp.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
+                        }
+                        return true;
+                    } else if (getter != null) {
+                        pexp.putNodeMetaData(StaticTypesMarker.READONLY_PROPERTY, true);
                     }
                 }
-                // GROOVY-5568, the property may be defined by DGM
-                List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "get" + capName, ClassNode.EMPTY_ARRAY);
-                if (!methods.isEmpty()) {
-                    List<MethodNode> methodNodes = chooseBestMethod(testClass, methods, ClassNode.EMPTY_ARRAY);
-                    if (methodNodes.size() == 1) {
-                        MethodNode getter = methodNodes.get(0);
-                        if (visitor != null) {
-                            visitor.visitMethod(getter);
-                        }
-                        ClassNode cn = inferReturnTypeGenerics(testClass, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
-                        storeInferredTypeForPropertyExpression(pexp, cn);
+                foundGetterOrSetter = foundGetterOrSetter || !setters.isEmpty() || getter != null;
 
-                        return true;
+                if (storeField(field, true, pexp, current, visitor, receiver.getData())) return true;
+                // if the property expression is an attribute expression (o. at attr), then
+                // we stop now, otherwise we must check the parent class
+                if (/*!isAttributeExpression && */current.getSuperClass() != null) {
+                    queue.add(current.getUnresolvedSuperClass());
+                }
+            }
+            // GROOVY-5568, the property may be defined by DGM
+            List<MethodNode> methods = findDGMMethodsByNameAndArguments(getTransformLoader(), testClass, "get" + capName, ClassNode.EMPTY_ARRAY);
+            if (!methods.isEmpty()) {
+                List<MethodNode> methodNodes = chooseBestMethod(testClass, methods, ClassNode.EMPTY_ARRAY);
+                if (methodNodes.size() == 1) {
+                    MethodNode getter = methodNodes.get(0);
+                    if (visitor != null) {
+                        visitor.visitMethod(getter);
                     }
+                    ClassNode cn = inferReturnTypeGenerics(testClass, getter, ArgumentListExpression.EMPTY_ARGUMENTS);
+                    storeInferredTypeForPropertyExpression(pexp, cn);
+
+                    return true;
                 }
+            }
         }
 
         for (Receiver<String> receiver : receivers) {
@@ -1226,7 +1354,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         AtomicReference<ClassNode> result = new AtomicReference<ClassNode>();
         if (existsProperty(subExp, true, new PropertyLookupVisitor(result))) {
             intf = LIST_TYPE.getPlainNodeReference();
-            intf.setGenericsTypes(new GenericsType[] { new GenericsType(getWrapper(result.get()))});
+            ClassNode itemType = result.get();
+            intf.setGenericsTypes(new GenericsType[] { new GenericsType(wrapTypeIfNecessary(itemType))});
             return intf;
         }
         return null;
@@ -1266,13 +1395,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     /**
      * This method is used to filter search results in which null means "no match",
-     * to filter out illegal access to instance members from a static context. 
-     * 
+     * to filter out illegal access to instance members from a static context.
+     *
      * Return null if the given member is not static, but we want to access in
      * a static way (staticOnly=true). If we want to access in a non-static way
-     * we always return the member, since then access to static members and 
-     * non-static members is allowed. 
+     * we always return the member, since then access to static members and
+     * non-static members is allowed.
      */
+    @SuppressWarnings("unchecked")
     private <T> T allowStaticAccessToMember(T member, boolean staticOnly) {
         if (member == null) return null;
         if (!staticOnly) return member;
@@ -1280,6 +1410,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (member instanceof Variable) {
             Variable v = (Variable) member;
             isStatic = Modifier.isStatic(v.getModifiers());
+        } else if (member instanceof List)  {
+            List<MethodNode> list = (List<MethodNode>) member;
+            if (list.size()==1) {
+                return (T) Arrays.asList(allowStaticAccessToMember(list.get(0), staticOnly));
+            }
+            return (T) Collections.emptyList();
         } else {
             MethodNode mn = (MethodNode) member;
             isStatic = mn.isStatic();
@@ -1302,7 +1438,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (field==null || !returnTrueIfFieldExists) return false;
         if (visitor != null) visitor.visitField(field);
         storeWithResolve(field.getOriginType(), receiver, field.getDeclaringClass(), field.isStatic(), expressionToStoreOn);
-        checkOrMarkPrivateAccess(field);
+        checkOrMarkPrivateAccess(expressionToStoreOn, field);
         if (delegationData!=null) {
             expressionToStoreOn.putNodeMetaData(StaticTypesMarker.IMPLICIT_RECEIVER, delegationData);
         }
@@ -1356,10 +1492,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 ClassNode current = queue.removeFirst();
                 current = current.redirect();
                 // check that a setter also exists
-                MethodNode setterMethod = current.getSetterMethod("set" + capName, false);
-                if (setterMethod != null) {
-                    storeType(pexp, setterMethod.getParameters()[0].getType());
-                    return new SetterInfo(current, setterMethod);
+                String setterName = "set" + capName;
+                List<MethodNode> setterMethods = findSetters(current, setterName, false);
+                if (!setterMethods.isEmpty()) {
+//                    storeType(pexp, setterMethod.getParameters()[0].getType());
+                    return new SetterInfo(current, setterName, setterMethods);
                 }
                 if (!isAttributeExpression && current.getSuperClass() != null) {
                     queue.add(current.getSuperClass());
@@ -1454,12 +1591,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     public static ClassNode inferLoopElementType(final ClassNode collectionType) {
         ClassNode componentType = collectionType.getComponentType();
         if (componentType == null) {
-            if (collectionType.implementsInterface(ITERABLE_TYPE)) {
+            if (implementsInterfaceOrIsSubclassOf(collectionType, ITERABLE_TYPE)) {
                 ClassNode intf = GenericsUtils.parameterizeType(collectionType, ITERABLE_TYPE);
                 GenericsType[] genericsTypes = intf.getGenericsTypes();
                 componentType = genericsTypes[0].getType();
-            } else if (collectionType == ClassHelper.STRING_TYPE) {
+            } else if (implementsInterfaceOrIsSubclassOf(collectionType, MAP_TYPE)) {
+                // GROOVY-6240
+                ClassNode intf = GenericsUtils.parameterizeType(collectionType, MAP_TYPE);
+                GenericsType[] genericsTypes = intf.getGenericsTypes();
+                componentType = MAP_ENTRY_TYPE.getPlainNodeReference();
+                componentType.setGenericsTypes(genericsTypes);
+            } else if (STRING_TYPE.equals(collectionType)) {
                 componentType = ClassHelper.Character_TYPE;
+            } else if (ENUMERATION_TYPE.equals(collectionType)) {
+                // GROOVY-6123
+                ClassNode intf = GenericsUtils.parameterizeType(collectionType, ENUMERATION_TYPE);
+                GenericsType[] genericsTypes = intf.getGenericsTypes();
+                componentType = genericsTypes[0].getType();
             } else {
                 componentType = ClassHelper.OBJECT_TYPE;
             }
@@ -1764,7 +1912,21 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                         ArrayList<ClassNode> arr = new ArrayList<ClassNode>(classNodes.size() + 1);
                         arr.add(ret[i]);
                         arr.addAll(classNodes);
-                        ret[i] = new UnionTypeClassNode(arr.toArray(new ClassNode[arr.size()]));
+                        // GROOVY-7333: filter out Object
+                        Iterator<ClassNode> iterator = arr.iterator();
+                        while (iterator.hasNext()) {
+                            ClassNode next = iterator.next();
+                            if (ClassHelper.OBJECT_TYPE.equals(next)) {
+                                iterator.remove();
+                            }
+                        }
+                        if (arr.isEmpty()) {
+                            ret[i] = ClassHelper.OBJECT_TYPE.getPlainNodeReference();
+                        } else if (arr.size()==1) {
+                            ret[i] = arr.get(0);
+                        } else {
+                            ret[i] = new UnionTypeClassNode(arr.toArray(new ClassNode[arr.size()]));
+                        }
                     }
                 }
             }
@@ -2107,7 +2269,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     || !visitClosures && !(expression instanceof ClosureExpression)) {
                 if (i<params.length && visitClosures) {
                     Parameter param = params[i];
-                    checkClosureWithDelegatesTo(newArgs,params , expression, param);
+                    checkClosureWithDelegatesTo(receiver, selectedMethod, newArgs,params , expression, param);
                     if (selectedMethod instanceof ExtensionMethodNode) {
                         if (i>0) {
                             inferClosureParameterTypes(receiver, arguments, (ClosureExpression)expression, param, selectedMethod);
@@ -2153,7 +2315,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
-    
+
     private void inferSAMType(Parameter param, ClassNode receiver, MethodNode methodWithSAMParameter, ArgumentListExpression originalMethodCallArguments, ClosureExpression openBlock) {
         // In a method call with SAM coercion the inference is to be
         // understood as a two phase process. We have the normal method call
@@ -2245,7 +2407,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private void doInferClosureParameterTypes(final ClassNode receiver, final Expression arguments, final ClosureExpression expression, final MethodNode selectedMethod, final Expression hintClass, final Expression options) {
-        List<ClassNode[]> closureSignatures = getSignaturesFromHint(expression,selectedMethod,hintClass,options);
+        List<ClassNode[]> closureSignatures = getSignaturesFromHint(expression, selectedMethod, hintClass, options);
         List<ClassNode[]> candidates = new LinkedList<ClassNode[]>();
         for (ClassNode[] signature : closureSignatures) {
             // in order to compute the inferred types of the closure parameters, we're using the following trick:
@@ -2254,46 +2416,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             // 3. fetch inferred types from the result of inferReturnTypeGenerics
             // In practice, it could be done differently but it has the main advantage of reusing
             // existing code, hence reducing the amount of code to debug in case of failure.
-            final int id = System.identityHashCode(expression);
-            ClassNode dummyResultNode = new ClassNode("cl$" + id, 0, OBJECT_TYPE).getPlainNodeReference();
-            final GenericsType[] genericTypes = new GenericsType[signature.length];
-            for (int i = 0; i < signature.length; i++) {
-                genericTypes[i] = new GenericsType(signature[i]);
-            }
-            dummyResultNode.setGenericsTypes(genericTypes);
-            MethodNode dummyMN = selectedMethod instanceof ExtensionMethodNode ? ((ExtensionMethodNode) selectedMethod).getExtensionMethodNode() : selectedMethod;
-            dummyMN = new MethodNode(
-                    dummyMN.getName(),
-                    dummyMN.getModifiers(),
-                    dummyResultNode,
-                    dummyMN.getParameters(),
-                    dummyMN.getExceptions(),
-                    EmptyStatement.INSTANCE
-                    );
-            dummyMN.setDeclaringClass(selectedMethod.getDeclaringClass());
-            dummyMN.setGenericsTypes(selectedMethod.getGenericsTypes());
-            if (selectedMethod instanceof ExtensionMethodNode) {
-                ExtensionMethodNode orig = (ExtensionMethodNode) selectedMethod;
-                dummyMN = new ExtensionMethodNode(
-                        dummyMN,
-                        dummyMN.getName(),
-                        dummyMN.getModifiers(),
-                        dummyResultNode,
-                        orig.getParameters(),
-                        orig.getExceptions(),
-                        EmptyStatement.INSTANCE,
-                        orig.isStaticExtension()
-                        );
-                dummyMN.setDeclaringClass(orig.getDeclaringClass());
-                dummyMN.setGenericsTypes(orig.getGenericsTypes());
-            }
-            ClassNode classNode = inferReturnTypeGenerics(receiver, dummyMN, arguments);
-            ClassNode[] inferred = new ClassNode[classNode.getGenericsTypes().length];
-            for (int i = 0; i < classNode.getGenericsTypes().length; i++) {
-                GenericsType genericsType = classNode.getGenericsTypes()[i];
-                ClassNode value = createUsableClassNodeFromGenericsType(genericsType);
-                inferred[i] = value;
-            }
+            ClassNode[] inferred = resolveGenericsFromTypeHint(receiver, arguments, selectedMethod, signature);
             Parameter[] closureParams = expression.getParameters();
             if (signature.length == closureParams.length // same number of arguments
                     || (signature.length == 1 && closureParams.length == 0) // implicit it
@@ -2365,6 +2488,49 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
     }
 
+    private ClassNode[] resolveGenericsFromTypeHint(final ClassNode receiver, final Expression arguments, final MethodNode selectedMethod, final ClassNode[] signature) {
+        ClassNode dummyResultNode = new ClassNode("ClForInference$" + UNIQUE_LONG.incrementAndGet(), 0, OBJECT_TYPE).getPlainNodeReference();
+        final GenericsType[] genericTypes = new GenericsType[signature.length];
+        for (int i = 0; i < signature.length; i++) {
+            genericTypes[i] = new GenericsType(signature[i]);
+        }
+        dummyResultNode.setGenericsTypes(genericTypes);
+        MethodNode dummyMN = selectedMethod instanceof ExtensionMethodNode ? ((ExtensionMethodNode) selectedMethod).getExtensionMethodNode() : selectedMethod;
+        dummyMN = new MethodNode(
+                dummyMN.getName(),
+                dummyMN.getModifiers(),
+                dummyResultNode,
+                dummyMN.getParameters(),
+                dummyMN.getExceptions(),
+                EmptyStatement.INSTANCE
+                );
+        dummyMN.setDeclaringClass(selectedMethod.getDeclaringClass());
+        dummyMN.setGenericsTypes(selectedMethod.getGenericsTypes());
+        if (selectedMethod instanceof ExtensionMethodNode) {
+            ExtensionMethodNode orig = (ExtensionMethodNode) selectedMethod;
+            dummyMN = new ExtensionMethodNode(
+                    dummyMN,
+                    dummyMN.getName(),
+                    dummyMN.getModifiers(),
+                    dummyResultNode,
+                    orig.getParameters(),
+                    orig.getExceptions(),
+                    EmptyStatement.INSTANCE,
+                    orig.isStaticExtension()
+                    );
+            dummyMN.setDeclaringClass(orig.getDeclaringClass());
+            dummyMN.setGenericsTypes(orig.getGenericsTypes());
+        }
+        ClassNode classNode = inferReturnTypeGenerics(receiver, dummyMN, arguments);
+        ClassNode[] inferred = new ClassNode[classNode.getGenericsTypes().length];
+        for (int i = 0; i < classNode.getGenericsTypes().length; i++) {
+            GenericsType genericsType = classNode.getGenericsTypes()[i];
+            ClassNode value = createUsableClassNodeFromGenericsType(genericsType);
+            inferred[i] = value;
+        }
+        return inferred;
+    }
+
     /**
      * Given a GenericsType instance, returns a ClassNode which can be used as an inferred type.
      * @param genericsType a {@link org.codehaus.groovy.ast.GenericsType} representing either a type, a placeholder or a wildcard
@@ -2389,7 +2555,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     private static String[] convertToStringArray(final Expression options) {
         if (options==null) {
-            return new String[0];
+            return EMPTY_STRING_ARRAY;
         }
         if (options instanceof ConstantExpression) {
             return new String[] { options.getText() };
@@ -2405,7 +2571,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         throw new IllegalArgumentException("Unexpected options for @ClosureParams:"+options);
     }
 
-    private void checkClosureWithDelegatesTo(final ArgumentListExpression arguments, final Parameter[] params, final Expression expression, final Parameter param) {
+    private void checkClosureWithDelegatesTo(final ClassNode receiver,
+                                             final MethodNode mn,
+                                             final ArgumentListExpression arguments,
+                                             final Parameter[] params,
+                                             final Expression expression,
+                                             final Parameter param) {
         List<AnnotationNode> annotations = param.getAnnotations(DELEGATES_TO);
         if (annotations!=null && !annotations.isEmpty()) {
             for (AnnotationNode annotation : annotations) {
@@ -2413,6 +2584,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                 Expression value = annotation.getMember("value");
                 Expression strategy = annotation.getMember("strategy");
                 Expression genericTypeIndex = annotation.getMember("genericTypeIndex");
+                Expression type = annotation.getMember("type");
                 Integer stInt = Closure.OWNER_FIRST;
                 if (strategy!=null) {
                     stInt = (Integer) evaluateExpression(new CastExpression(ClassHelper.Integer_TYPE,strategy), typeCheckingContext.source.getConfiguration());
@@ -2424,6 +2596,23 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     }
                     // temporarily store the delegation strategy and the delegate type
                     expression.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata(value.getType(), stInt, typeCheckingContext.delegationMetadata));
+                } else if (type!=null && !"".equals(type.getText()) && type instanceof ConstantExpression) {
+                    String typeString = type.getText();
+                    ClassNode[] resolved = GenericsUtils.parseClassNodesFromString(
+                            typeString,
+                            getSourceUnit(),
+                            typeCheckingContext.compilationUnit,
+                            mn,
+                            type
+                    );
+                    if (resolved!=null) {
+                        if (resolved.length==1) {
+                            resolved = resolveGenericsFromTypeHint(receiver, arguments, mn, resolved );
+                            expression.putNodeMetaData(StaticTypesMarker.DELEGATION_METADATA, new DelegationMetadata(resolved[0], stInt, typeCheckingContext.delegationMetadata));
+                        } else {
+                            addStaticTypeError("Incorrect type hint found in method " + (mn), type);
+                        }
+                    }
                 } else {
                     final List<Expression> expressions = arguments.getExpressions();
                     final int expressionsSize = expressions.size();
@@ -2442,7 +2631,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                                     Expression actualArgument = expressions.get(j);
                                     ClassNode actualType = getType(actualArgument);
                                     if (genericTypeIndex!=null && genericTypeIndex instanceof ConstantExpression) {
-                                        int gti = Integer.valueOf(genericTypeIndex.getText());
+                                        int gti = Integer.parseInt(genericTypeIndex.getText());
                                         ClassNode paramType = methodParam.getType(); // type annotated with @DelegatesTo.Target
                                         GenericsType[] genericsTypes = paramType.getGenericsTypes();
                                         if (genericsTypes==null) {
@@ -2719,7 +2908,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
                         if (isUsingGenericsOrIsArrayUsingGenerics(returnType)) {
                             visitMethodCallArguments(chosenReceiver.getType(), argumentList, true, directMethodCallCandidate);
-                            ClassNode irtg = inferReturnTypeGenerics(chosenReceiver.getType(), directMethodCallCandidate, callArguments);
+                            ClassNode irtg = inferReturnTypeGenerics(
+                                    chosenReceiver.getType(),
+                                    directMethodCallCandidate,
+                                    callArguments,
+                                    call.getGenericsTypes());
                             returnType = irtg != null && implementsInterfaceOrIsSubclassOf(irtg, returnType) ? irtg : returnType;
                             callArgsVisited = true;
                         }
@@ -2822,7 +3015,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     private void addArrayMethods(List<MethodNode> methods, ClassNode receiver, String name, ClassNode[] args) {
         if (args.length!=1) return;
         if (!receiver.isArray()) return;
-        if (!isIntCategory(args[0])) return;
+        if (!isIntCategory(getUnwrapper(args[0]))) return;
         if ("getAt".equals(name)) {
             MethodNode node = new MethodNode(name, Opcodes.ACC_PUBLIC, receiver.getComponentType(), new Parameter[]{new Parameter(args[0],"arg")}, null, null);
             node.setDeclaringClass(receiver.redirect());
@@ -2873,6 +3066,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             // GROOVY-xxxx
             owners.add(Receiver.<String>make(OBJECT_TYPE));
         }
+        addSelfTypes(receiver, owners);
         if (!typeCheckingContext.temporaryIfBranchTypeInformation.empty()) {
             List<ClassNode> potentialReceiverType = getTemporaryTypesForExpression(objectExpression);
             if (potentialReceiverType != null) {
@@ -2889,6 +3083,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return owners;
     }
 
+    private void addSelfTypes(final ClassNode receiver, final List<Receiver<String>> owners) {
+        LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
+        for (ClassNode selfType : Traits.collectSelfTypes(receiver, selfTypes)) {
+            owners.add(Receiver.<String>make(selfType));
+        }
+    }
+
     protected void checkForbiddenSpreadArgument(ArgumentListExpression argumentList) {
         for (Expression arg : argumentList.getExpressions()) {
             if (arg instanceof SpreadExpression) {
@@ -2910,7 +3111,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
     protected void storeTargetMethod(final Expression call, final MethodNode directMethodCallCandidate) {
         call.putNodeMetaData(StaticTypesMarker.DIRECT_METHOD_CALL_TARGET, directMethodCallCandidate);
-        checkOrMarkPrivateAccess(directMethodCallCandidate);
+        checkOrMarkPrivateAccess(call, directMethodCallCandidate);
+        checkSuperCallFromClosure(call, directMethodCallCandidate);
         extension.onMethodSelection(call, directMethodCallCandidate);
     }
 
@@ -3204,7 +3406,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             if (rightRedirect.isDerivedFrom(CLOSURE_TYPE) && isSAMType(leftRedirect) && rightExpression instanceof ClosureExpression) {
                 return inferSAMTypeGenericsInAssignment(left, findSAM(left),right,(ClosureExpression) rightExpression);
             }
-            
+
             if (leftExpression instanceof VariableExpression) {
                 ClassNode initialType = getOriginalDeclarationType(leftExpression).redirect();
                 if (isPrimitiveType(right) && initialType.isDerivedFrom(Number_TYPE)) {
@@ -3261,6 +3463,10 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             } else if (isCompareToBoolean(op) || op == COMPARE_EQUAL || op == COMPARE_NOT_EQUAL) {
                 return boolean_TYPE;
             }
+        } else if (char_TYPE.equals(leftRedirect) && char_TYPE.equals(rightRedirect)) {
+            if (isCompareToBoolean(op) || op == COMPARE_EQUAL || op == COMPARE_NOT_EQUAL) {
+                return boolean_TYPE;
+            }
         }
 
 
@@ -3516,6 +3722,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                             method.getExceptions(),
                             GENERATED_EMPTY_STATEMENT
                     );
+                    stubbed.setGenericsTypes(method.getGenericsTypes());
                 }
                 stubbed.setDeclaringClass(receiver);
                 result.add(stubbed);
@@ -3690,9 +3897,12 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             VariableExpression vexp = (VariableExpression) exp;
             if (vexp == VariableExpression.THIS_EXPRESSION) return makeThis();
             if (vexp == VariableExpression.SUPER_EXPRESSION) return makeSuper();
+            ClassNode selfTrait = isTraitSelf(vexp);
+            if (selfTrait!=null) return makeSelf(selfTrait);
             final Variable variable = vexp.getAccessedVariable();
             if (variable instanceof FieldNode) {
-                checkOrMarkPrivateAccess((FieldNode) variable);
+                checkOrMarkPrivateAccess(vexp, (FieldNode) variable);
+                return getType((FieldNode) variable);
             }
             if (variable != null && variable != vexp && variable instanceof VariableExpression) {
                 return getType((Expression) variable);
@@ -3774,14 +3984,32 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
             return ((Parameter) exp).getOriginType();
         }
         if (exp instanceof FieldNode) {
-            return ((FieldNode) exp).getOriginType();
+            FieldNode fn = (FieldNode) exp;
+            return getGenericsResolvedTypeOfFieldOrProperty(fn, fn.getOriginType());
         }
         if (exp instanceof PropertyNode) {
-            return ((PropertyNode) exp).getOriginType();
+            PropertyNode pn = (PropertyNode) exp;
+            return getGenericsResolvedTypeOfFieldOrProperty(pn, pn.getOriginType());
         }
         return exp instanceof VariableExpression ? ((VariableExpression) exp).getOriginType() : ((Expression) exp).getType();
     }
 
+    /**
+     * resolves a Field or Property node generics by using the current class and
+     * the declaring class to extract the right meaning of the generics symbols
+     * @param an a FieldNode or PropertyNode
+     * @param type the origin type
+     * @return the new ClassNode with corrected generics
+     */
+    private ClassNode getGenericsResolvedTypeOfFieldOrProperty(AnnotatedNode an, ClassNode type) {
+        if (!type.isUsingGenerics()) return type;
+        Map<String, GenericsType> connections = new HashMap();
+        //TODO: inner classes mean a different this-type. This is ignored here!
+        extractGenericsConnections(connections, typeCheckingContext.getEnclosingClassNode(), an.getDeclaringClass());
+        type= applyGenericsContext(connections, type);
+        return type;
+    }
+
     private ClassNode makeSuper() {
         ClassNode ret = typeCheckingContext.getEnclosingClassNode().getSuperClass();
         if (typeCheckingContext.isInStaticContext) {
@@ -3794,7 +4022,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private ClassNode makeThis() {
-        ClassNode ret = typeCheckingContext.getEnclosingClassNode(); 
+        ClassNode ret = typeCheckingContext.getEnclosingClassNode();
         if (typeCheckingContext.isInStaticContext) {
             ClassNode staticRet = CLASS_Type.getPlainNodeReference();
             GenericsType gt = new GenericsType(ret);
@@ -3804,6 +4032,17 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return ret;
     }
 
+    private ClassNode makeSelf(ClassNode trait) {
+        ClassNode ret = trait;
+        LinkedHashSet<ClassNode> selfTypes = new LinkedHashSet<ClassNode>();
+        Traits.collectSelfTypes(ret, selfTypes);
+        if (!selfTypes.isEmpty()) {
+            selfTypes.add(ret);
+            ret = new UnionTypeClassNode(selfTypes.toArray(new ClassNode[selfTypes.size()]));
+        }
+        return ret;
+    }
+
     /**
      * Stores the inferred return type of a closure or a method. We are using a separate key to store
      * inferred return type because the inferred type of a closure is {@link Closure}, which is different
@@ -3893,7 +4132,21 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     }
 
     private static class ExtensionMethodDeclaringClass{}
-    
+
+    /**
+     * If a method call returns a parameterized type, then we can perform additional inference on the
+     * return type, so that the type gets actual type parameters. For example, the method
+     * Arrays.asList(T...) is generified with type T which can be deduced from actual type
+     * arguments.
+     *
+     * @param method    the method node
+     * @param arguments the method call arguments
+     * @return parameterized, infered, class node
+     */
+    protected ClassNode inferReturnTypeGenerics(ClassNode receiver, MethodNode method, Expression arguments) {
+        return inferReturnTypeGenerics(receiver, method, arguments, null);
+    }
+
     /**
      * If a method call returns a parameterized type, then we can perform additional inference on the
      * return type, so that the type gets actual type parameters. For example, the method
@@ -3902,9 +4155,14 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
      *
      * @param method    the method node
      * @param arguments the method call arguments
+     * @param explicitTypeHints explicit type hints as found for example in Collections.<String>emptyList()
      * @return parameterized, infered, class node
      */
-    protected ClassNode inferReturnTypeGenerics(final ClassNode receiver, final MethodNode method, final Expression arguments) {
+    protected ClassNode inferReturnTypeGenerics(
+            ClassNode receiver,
+            MethodNode method,
+            Expression arguments,
+            GenericsType[] explicitTypeHints) {
         ClassNode returnType = method.getReturnType();
         if (method instanceof ExtensionMethodNode
                 && (isUsingGenericsOrIsArrayUsingGenerics(returnType))) {
@@ -3928,8 +4186,9 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         if (!isUsingGenericsOrIsArrayUsingGenerics(returnType)) return returnType;
         if (getGenericsWithoutArray(returnType)==null) return returnType;
-
         Map<String, GenericsType> resolvedPlaceholders = resolvePlaceHoldersFromDeclaration(receiver, getDeclaringClass(method, arguments), method, method.isStatic());
+        GenericsUtils.extractPlaceholders(receiver, resolvedPlaceholders);
+        resolvePlaceholdersFromExplicitTypeHints(method, explicitTypeHints, resolvedPlaceholders);
         if (resolvedPlaceholders.isEmpty()) return returnType;
         Map<String, GenericsType> placeholdersFromContext = extractGenericsParameterMapOfThis(typeCheckingContext.getEnclosingMethod());
         applyGenericsConnections(placeholdersFromContext,resolvedPlaceholders);
@@ -3950,7 +4209,8 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
                     actualType = actualType.getComponentType();
                 }
                 if (isUsingGenericsOrIsArrayUsingGenerics(type)) {
-                    if (implementsInterfaceOrIsSubclassOf(actualType, CLOSURE_TYPE) && !implementsInterfaceOrIsSubclassOf(type, CLOSURE_TYPE)) {
+                    if (implementsInterfaceOrIsSubclassOf(actualType, CLOSURE_TYPE) &&
+                            isSAMType(type)) {
                         // implicit closure coercion in action!
                         Map<String,GenericsType> pholders = applyGenericsContextToParameterClass(resolvedPlaceholders, type);
                         actualType = convertClosureTypeToSAMType(expressions.get(i), actualType, type, pholders);
@@ -3965,6 +4225,7 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
 
                     Map<String, GenericsType> connections  = new HashMap<String, GenericsType>();
                     extractGenericsConnections(connections, actualType,type);
+                    extractGenericsConnectionsForSuperClassAndInterfaces(resolvedPlaceholders, connections);
                     applyGenericsConnections(connections, resolvedPlaceholders);
                 }
             }
@@ -3973,6 +4234,62 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         return applyGenericsContext(resolvedPlaceholders, returnType);
     }
 
+    private void resolvePlaceholdersFromExplicitTypeHints(final MethodNode method, final GenericsType[] explicitTypeHints, final Map<String, GenericsType> resolvedPlaceholders) {
+        if (explicitTypeHints!=null) {
+            GenericsType[] methodGenericTypes = method.getGenericsTypes();
+            if (methodGenericTypes!=null && methodGenericTypes.length==explicitTypeHints.length) {
+                for (int i = 0; i < explicitTypeHints.length; i++) {
+                    GenericsType methodGenericType = methodGenericTypes[i];
+                    GenericsType explicitTypeHint = explicitTypeHints[i];
+                    resolvedPlaceholders.put(methodGenericType.getName(), explicitTypeHint);
+                }
+                for (GenericsType typeHint : explicitTypeHints) {
+                    System.err.println("Type hint = " + typeHint);
+                }
+            }
+        }
+    }
+
+    private void extractGenericsConnectionsForSuperClassAndInterfaces(final Map<String, GenericsType> resolvedPlaceholders, final Map<String, GenericsType> connections) {
+        for (GenericsType value : new HashSet<GenericsType>(connections.values())) {
+            if (!value.isPlaceholder() && !value.isWildcard()) {
+                ClassNode valueType = value.getType();
+                List<ClassNode> deepNodes = new LinkedList<ClassNode>();
+                ClassNode unresolvedSuperClass = valueType.getUnresolvedSuperClass();
+                if (unresolvedSuperClass!=null && unresolvedSuperClass.isUsingGenerics()) {
+                    deepNodes.add(unresolvedSuperClass);
+                }
+                for (ClassNode node : valueType.getUnresolvedInterfaces()) {
+                    if (node.isUsingGenerics()) {
+                        deepNodes.add(node);
+                    }
+                }
+                if (!deepNodes.isEmpty()) {
+                    for (GenericsType genericsType : resolvedPlaceholders.values()) {
+                        ClassNode lowerBound = genericsType.getLowerBound();
+                        if (lowerBound != null) {
+                            for (ClassNode deepNode : deepNodes) {
+                                if (lowerBound.equals(deepNode)) {
+                                    extractGenericsConnections(connections, deepNode, lowerBound);
+                                }
+                            }
+                        }
+                        ClassNode[] upperBounds = genericsType.getUpperBounds();
+                        if (upperBounds != null) {
+                            for (ClassNode upperBound : upperBounds) {
+                                for (ClassNode deepNode : deepNodes) {
+                                    if (upperBound.equals(deepNode)) {
+                                        extractGenericsConnections(connections, deepNode, upperBound);
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+    }
+
     /**
      * This method will convert a closure type to the appropriate SAM type, which will be used
      * to infer return type generics.
@@ -4067,11 +4384,11 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         }
         return declaringClass;
     }
-    
+
     private Map<String, GenericsType> resolvePlaceHoldersFromDeclaration(ClassNode receiver, ClassNode declaration, MethodNode method, boolean isStaticTarget) {
         Map<String, GenericsType> resolvedPlaceholders;
-        if (    isStaticTarget && CLASS_Type.equals(receiver) && 
-                receiver.isUsingGenerics() && 
+        if (    isStaticTarget && CLASS_Type.equals(receiver) &&
+                receiver.isUsingGenerics() &&
                 receiver.getGenericsTypes().length>0 &&
                 !OBJECT_TYPE.equals(receiver.getGenericsTypes()[0].getType()))
         {
@@ -4099,51 +4416,59 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
         if (isPrimitiveType(receiver) && !isPrimitiveType(declaringClass)) {
             receiver = getWrapper(receiver);
         }
-        ClassNode current = receiver;
-        while (true) {
-            boolean continueLoop = true;
-            //extract the place holders
-            Map<String, GenericsType> currentPlaceHolders = new HashMap<String, GenericsType>();
-            if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
-                extractGenericsConnections(currentPlaceHolders, current, declaringClass);
-                if (method!=null) addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
-                continueLoop = false;
-            } else {
-                GenericsUtils.extractPlaceholders(current, currentPlaceHolders);
-            }
-
-            if (resolvedPlaceholders!=null) {
-                // merge maps 
-                Set<Map.Entry<String,GenericsType>> entries = currentPlaceHolders.entrySet();
-                for (Map.Entry<String,GenericsType> entry : entries) {
-                    GenericsType gt = entry.getValue();
-                    if (!gt.isPlaceholder()) continue;
-                    GenericsType referenced = resolvedPlaceholders.get(gt.getName());
-                    if (referenced==null) continue;
-                    entry.setValue(referenced);
+        final List<ClassNode> queue;
+        if (receiver instanceof UnionTypeClassNode) {
+            queue = Arrays.asList(((UnionTypeClassNode) receiver).getDelegates());
+        } else {
+            queue = Collections.singletonList(receiver);
+        }
+        for (ClassNode item : queue) {
+            ClassNode current = item;
+            while (current!=null) {
+                boolean continueLoop = true;
+                //extract the place holders
+                Map<String, GenericsType> currentPlaceHolders = new HashMap<String, GenericsType>();
+                if (isGenericsPlaceHolderOrArrayOf(declaringClass) || declaringClass.equals(current)) {
+                    extractGenericsConnections(currentPlaceHolders, current, declaringClass);
+                    if (method!=null) addMethodLevelDeclaredGenerics(method, currentPlaceHolders);
+                    continueLoop = false;
+                } else {
+                    GenericsUtils.extractPlaceholders(current, currentPlaceHolders);
                 }
-            }
-            resolvedPlaceholders = currentPlaceHolders;
 
-            // we are done if we are now in the declaring class
-            if (!continueLoop) break;
+                if (resolvedPlaceholders!=null) {
+                    // merge maps
+                    Set<Map.Entry<String,GenericsType>> entries = currentPlaceHolders.entrySet();
+                    for (Map.Entry<String,GenericsType> entry : entries) {
+                        GenericsType gt = entry.getValue();
+                        if (!gt.isPlaceholder()) continue;
+                        GenericsType referenced = resolvedPlaceholders.get(gt.getName());
+                        if (referenced==null) continue;
+                        entry.setValue(referenced);
+                    }
+                }
+                resolvedPlaceholders = currentPlaceHolders;
 
-            current = getNextSuperClass(current, declaringClass);
-            if (current==null && CLASS_Type.equals(declaringClass)) {
-                // this can happen if the receiver is Class<Foo>, then
-                // the actual receiver is Foo and declaringClass is Class
-                current = declaringClass;
-            }
-            if (current==null) {
-                String descriptor = "<>";
-                if (method!=null) descriptor = method.getTypeDescriptor();
-                throw new GroovyBugError(
-                        "Declaring class for method call to '" +
-                        descriptor + "' declared in " + declaringClass.getName() +
-                        " was not matched with found receiver "+ receiver.getName() + "." +
-                        " This should not have happened!");
+                // we are done if we are now in the declaring class
+                if (!continueLoop) break;
+
+                current = getNextSuperClass(current, declaringClass);
+                if (current==null && CLASS_Type.equals(declaringClass)) {
+                    // this can happen if the receiver is Class<Foo>, then
+                    // the actual receiver is Foo and declaringClass is Class
+                    current = declaringClass;
+                }
             }
         }
+        if (resolvedPlaceholders==null) {
+            String descriptor = "<>";
+            if (method!=null) descriptor = method.getTypeDescriptor();
+            throw new GroovyBugError(
+                    "Declaring class for method call to '" +
+                            descriptor + "' declared in " + declaringClass.getName() +
+                            " was not matched with found receiver "+ receiver.getName() + "." +
+                            " This should not have happened!");
+        }
         return resolvedPlaceholders;
     }
 
@@ -4393,11 +4718,13 @@ public class StaticTypeCheckingVisitor extends ClassCodeVisitorSupport {
     // a.x = foo or x=foo is found and that it corresponds to a setter call
     private static class SetterInfo {
         final ClassNode receiverType;
-        final MethodNode setter;
+        final String name;
+        final List<MethodNode> setters;
 
-        private SetterInfo(final ClassNode receiverType, final MethodNode setter) {
+        private SetterInfo(final ClassNode receiverType, final String name, final List<MethodNode> setters) {
             this.receiverType = receiverType;
-            this.setter = setter;
+            this.setters = setters;
+            this.name = name;
         }
     }
 
diff --git a/src/main/org/codehaus/groovy/transform/stc/StaticTypesMarker.java b/src/main/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
index a7a7559..cfc51a2 100644
--- a/src/main/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
+++ b/src/main/org/codehaus/groovy/transform/stc/StaticTypesMarker.java
@@ -32,5 +32,6 @@ public enum StaticTypesMarker {
     IMPLICIT_RECEIVER, // if the receiver is implicit but not "this", store the name of the receiver (delegate or owner)
     PV_FIELDS_ACCESS, // set of private fields that are accessed from closures or inner classes
     PV_METHODS_ACCESS, // set of private methods that are accessed from closures or inner classes
-    DYNAMIC_RESOLUTION // call recognized by a type checking extension as a dynamic method call
+    DYNAMIC_RESOLUTION, // call recognized by a type checking extension as a dynamic method call
+    SUPER_MOP_METHOD_REQUIRED // used to store the list of MOP methods that still have to be generated
 }
diff --git a/src/main/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java b/src/main/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
index 92be29f..76a0bf6 100644
--- a/src/main/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
+++ b/src/main/org/codehaus/groovy/transform/stc/TraitTypeCheckingExtension.java
@@ -18,8 +18,12 @@ package org.codehaus.groovy.transform.stc;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.MethodCall;
+import org.codehaus.groovy.ast.expr.MethodCallExpression;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.transform.trait.TraitASTTransformation;
 import org.codehaus.groovy.transform.trait.Traits;
 
 import java.util.Arrays;
@@ -27,6 +31,8 @@ import java.util.Collections;
 import java.util.LinkedHashSet;
 import java.util.List;
 
+import static org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport.isClassClassNodeWrappingConcreteType;
+
 /**
  * A type checking extension that will take care of handling errors which are specific to traits. In particular, it will
  * hanldle the "super" method calls within a trait.
@@ -56,9 +62,49 @@ public class TraitTypeCheckingExtension extends AbstractTypeCheckingExtension {
         if (decomposed != null) {
             return convertToDynamicCall(call, receiver, decomposed, argumentTypes);
         }
+        if (call instanceof MethodCallExpression) {
+            MethodCallExpression mce = (MethodCallExpression) call;
+            if (mce.getReceiver() instanceof VariableExpression) {
+                VariableExpression var = (VariableExpression) mce.getReceiver();
+
+                // GROOVY-7322
+                // static method call in trait?
+                ClassNode type = null;
+                if (isStaticTraitReceiver(receiver, var)) {
+                    type = receiver.getGenericsTypes()[0].getType();
+                } else if (isThisTraitReceiver(var)) {
+                    type = receiver;
+                }
+                if (type != null && Traits.isTrait(type)) {
+                    ClassNode helper = Traits.findHelper(type);
+                    Parameter[] params = new Parameter[argumentTypes.length + 1];
+                    params[0] = new Parameter(ClassHelper.CLASS_Type.getPlainNodeReference(), "staticSelf");
+                    for (int i = 1; i < params.length; i++) {
+                        params[i] = new Parameter(argumentTypes[i-1], "p" + i);
+                    }
+                    MethodNode method = helper.getDeclaredMethod(name, params);
+                    if (method != null) {
+                        return Collections.singletonList(makeDynamic(call, method.getReturnType()));
+                    }
+                }
+            }
+
+            ClassNode dynamic = mce.getNodeMetaData(TraitASTTransformation.DO_DYNAMIC);
+            if (dynamic!=null) {
+                return Collections.singletonList(makeDynamic(call, dynamic));
+            }
+        }
         return NOTFOUND;
     }
 
+    private boolean isStaticTraitReceiver(final ClassNode receiver, final VariableExpression var) {
+        return Traits.STATIC_THIS_OBJECT.equals(var.getName()) && isClassClassNodeWrappingConcreteType(receiver);
+    }
+
+    private boolean isThisTraitReceiver(final VariableExpression var) {
+        return Traits.THIS_OBJECT.equals(var.getName());
+    }
+
     private List<MethodNode> convertToDynamicCall(MethodCall call, ClassNode receiver, String[] decomposed, ClassNode[] argumentTypes) {
         String traitName = decomposed[0];
         String name = decomposed[1];
diff --git a/src/main/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java b/src/main/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
index c6b39dc..149b3fa 100644
--- a/src/main/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
+++ b/src/main/org/codehaus/groovy/transform/stc/UnionTypeClassNode.java
@@ -39,7 +39,7 @@ class UnionTypeClassNode extends ClassNode {
     
     public UnionTypeClassNode(ClassNode... classNodes) {
         super("<UnionType"+asArrayDescriptor(classNodes)+">", 0, ClassHelper.OBJECT_TYPE);
-        delegates = classNodes==null?new ClassNode[0] : classNodes;
+        delegates = classNodes==null ? ClassNode.EMPTY_ARRAY : classNodes;
     }
     
     private static String asArrayDescriptor(ClassNode... nodes) {
diff --git a/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java b/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
index 1a5193a..f96591d 100644
--- a/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/SuperCallTraitTransformer.java
@@ -15,9 +15,13 @@
  */
 package org.codehaus.groovy.transform.trait;
 
+import groovy.lang.MetaProperty;
 import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
 import org.codehaus.groovy.ast.ClassNode;
+import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
+import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.ClassExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
@@ -25,6 +29,8 @@ import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.TupleExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.syntax.Types;
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingSupport;
 
 import java.util.List;
 
@@ -54,9 +60,49 @@ class SuperCallTraitTransformer extends ClassCodeExpressionTransformer {
         if (exp instanceof MethodCallExpression) {
             return transformMethodCallExpression((MethodCallExpression)exp);
         }
+        if (exp instanceof BinaryExpression) {
+            return transformBinaryExpression((BinaryExpression) exp);
+        }
         return super.transform(exp);
     }
 
+    private Expression transformBinaryExpression(final BinaryExpression exp) {
+        Expression trn = super.transform(exp);
+        if (trn instanceof BinaryExpression) {
+            BinaryExpression bin = (BinaryExpression) trn;
+            Expression leftExpression = bin.getLeftExpression();
+            if (bin.getOperation().getType() == Types.EQUAL && leftExpression instanceof PropertyExpression) {
+                ClassNode traitReceiver = ((PropertyExpression) leftExpression).getObjectExpression().getNodeMetaData(SuperCallTraitTransformer.class);
+                if (traitReceiver!=null) {
+                    // A.super.foo = ...
+                    TraitHelpersTuple helpers = Traits.findHelpers(traitReceiver);
+                    ClassNode helper = helpers.getHelper();
+                    String setterName = MetaProperty.getSetterName(((PropertyExpression) leftExpression).getPropertyAsString());
+                    List<MethodNode> methods = helper.getMethods(setterName);
+                    for (MethodNode method : methods) {
+                        Parameter[] parameters = method.getParameters();
+                        if (parameters.length==2 && parameters[0].getType().equals(traitReceiver)) {
+                            ArgumentListExpression args = new ArgumentListExpression(
+                                    new VariableExpression("this"),
+                                    transform(exp.getRightExpression())
+                            );
+                            MethodCallExpression setterCall = new MethodCallExpression(
+                                    new ClassExpression(helper),
+                                    setterName,
+                                    args
+                            );
+                            setterCall.setMethodTarget(method);
+                            setterCall.setImplicitThis(false);
+                            return setterCall;
+                        }
+                    }
+                    return bin;
+                }
+            }
+        }
+        return trn;
+    }
+
     private Expression transformMethodCallExpression(final MethodCallExpression exp) {
         Expression objectExpression = transform(exp.getObjectExpression());
         ClassNode traitReceiver = objectExpression.getNodeMetaData(SuperCallTraitTransformer.class);
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
index 33e5031..44d944d 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitASTTransformation.java
@@ -19,6 +19,7 @@ import groovy.transform.CompilationUnitAware;
 import org.codehaus.groovy.ast.ASTNode;
 import org.codehaus.groovy.ast.AnnotatedNode;
 import org.codehaus.groovy.ast.AnnotationNode;
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
@@ -27,8 +28,11 @@ import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.PropertyNode;
+import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
 import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.Expression;
 import org.codehaus.groovy.ast.expr.FieldExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
@@ -37,17 +41,21 @@ import org.codehaus.groovy.ast.stmt.BlockStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.Statement;
 import org.codehaus.groovy.ast.tools.GeneralUtils;
+import org.codehaus.groovy.classgen.GeneratorContext;
 import org.codehaus.groovy.classgen.VariableScopeVisitor;
 import org.codehaus.groovy.classgen.Verifier;
+import org.codehaus.groovy.control.CompilationFailedException;
 import org.codehaus.groovy.control.CompilationUnit;
 import org.codehaus.groovy.control.CompilePhase;
 import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.ASTTransformationCollectorCodeVisitor;
 import org.codehaus.groovy.transform.AbstractASTTransformation;
 import org.codehaus.groovy.transform.GroovyASTTransformation;
+import org.codehaus.groovy.transform.sc.StaticCompileTransformation;
 
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -68,6 +76,13 @@ import java.util.Set;
 @GroovyASTTransformation(phase = CompilePhase.SEMANTIC_ANALYSIS)
 public class TraitASTTransformation extends AbstractASTTransformation implements CompilationUnitAware {
 
+    public static final String DO_DYNAMIC = TraitReceiverTransformer.class+".doDynamic";
+    public static final String POST_TYPECHECKING_REPLACEMENT = TraitReceiverTransformer.class+".replacement";
+
+    private static final ClassNode INVOKERHELPER_CLASSNODE = ClassHelper.make(InvokerHelper.class);
+
+    private static final ClassNode OVERRIDE_CLASSNODE = ClassHelper.make(Override.class);
+
     private SourceUnit unit;
     private CompilationUnit compilationUnit;
 
@@ -82,11 +97,17 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
             if (!checkNotInterface(cNode, Traits.TRAIT_TYPE_NAME)) return;
             checkNoConstructor(cNode);
             checkExtendsClause(cNode);
+            generateMethodsWithDefaultArgs(cNode);
             replaceExtendsByImplements(cNode);
             createHelperClass(cNode);
         }
     }
 
+    private void generateMethodsWithDefaultArgs(final ClassNode cNode) {
+        DefaultArgsMethodsAdder adder = new DefaultArgsMethodsAdder();
+        adder.addDefaultParameterMethods(cNode);
+    }
+
     private void checkExtendsClause(final ClassNode cNode) {
         ClassNode superClass = cNode.getSuperClass();
         if (superClass.isInterface() && !Traits.isTrait(superClass)) {
@@ -118,11 +139,6 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
         }
     }
 
-    private static void fixGenerics(MethodNode mn, ClassNode cNode) {
-        if (!cNode.isUsingGenerics()) return;
-        mn.setGenericsTypes(cNode.getGenericsTypes());
-    }
-
     private void createHelperClass(final ClassNode cNode) {
         ClassNode helper = new InnerClassNode(
                 cNode,
@@ -207,6 +223,12 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
         if (fieldHelper != null) {
             unit.getAST().addClass(fieldHelper);
         }
+
+        // resolve scope (for closures)
+        resolveScope(helper);
+        if (fieldHelper!=null) {
+            resolveScope(fieldHelper);
+        }
     }
 
     private MethodNode createInitMethod(final boolean isStatic, final ClassNode cNode, final ClassNode helper) {
@@ -218,8 +240,13 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
                 ClassNode.EMPTY_ARRAY,
                 new BlockStatement()
         );
-        fixGenerics(initializer, cNode);
         helper.addMethod(initializer);
+
+        // Cannot add static compilation of init method because of GROOVY-7217, see example 2 of test case
+        //AnnotationNode an = new AnnotationNode(TraitComposer.COMPILESTATIC_CLASSNODE);
+        //initializer.addAnnotation(an);
+        //cNode.addTransform(StaticCompileTransformation.class, an);
+
         return initializer;
     }
 
@@ -228,6 +255,16 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
                 unit, compilationUnit.getTransformLoader()
         );
         collector.visitClass(helper);
+        // Perform an additional phase which has to be done *after* type checking
+        compilationUnit.addPhaseOperation(new CompilationUnit.PrimaryClassNodeOperation() {
+            @Override
+            public void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode) throws CompilationFailedException {
+                if (classNode==helper) {
+                    PostTypeCheckingExpressionReplacer replacer = new PostTypeCheckingExpressionReplacer(source);
+                    replacer.visitClass(helper);
+                }
+            }
+        }, CompilePhase.INSTRUCTION_SELECTION.getPhaseNumber());
     }
 
     /**
@@ -314,7 +351,6 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
             MethodNode getter =
                     new MethodNode(getterName, propNodeModifiers, node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
             getter.setSynthetic(true);
-            fixGenerics(getter, cNode);
             cNode.addMethod(getter);
 
             if (ClassHelper.boolean_TYPE == node.getType() || ClassHelper.Boolean_TYPE == node.getType()) {
@@ -322,7 +358,6 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
                 MethodNode secondGetter =
                         new MethodNode(secondGetterName, propNodeModifiers, node.getType(), Parameter.EMPTY_ARRAY, ClassNode.EMPTY_ARRAY, getterBlock);
                 secondGetter.setSynthetic(true);
-                fixGenerics(secondGetter, cNode);
                 cNode.addMethod(secondGetter);
             }
         }
@@ -333,7 +368,6 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
             MethodNode setter =
                     new MethodNode(setterName, propNodeModifiers, ClassHelper.VOID_TYPE, setterParameterTypes, ClassNode.EMPTY_ARRAY, setterBlock);
             setter.setSynthetic(true);
-            fixGenerics(setter, cNode);
             cNode.addMethod(setter);
         }
     }
@@ -357,11 +391,24 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
             ExpressionStatement initCode = new ExpressionStatement(initialExpression);
             processBody(thisObject, selectedMethod, initCode, trait, fieldHelper, knownFields);
             BlockStatement code = (BlockStatement) selectedMethod.getCode();
-            MethodCallExpression mce = new MethodCallExpression(
-                    new CastExpression(createReceiverType(field.isStatic(), fieldHelper), thisObject),
-                    Traits.helperSetterName(field),
-                    initCode.getExpression()
-            );
+            MethodCallExpression mce;
+            if (field.isStatic()) {
+                mce = new MethodCallExpression(
+                        new ClassExpression(INVOKERHELPER_CLASSNODE),
+                        "invokeStaticMethod",
+                        new ArgumentListExpression(
+                                thisObject,
+                                new ConstantExpression(Traits.helperSetterName(field)),
+                                initCode.getExpression()
+                        )
+                );
+            } else {
+                mce = new MethodCallExpression(
+                        new CastExpression(createReceiverType(field.isStatic(), fieldHelper), thisObject),
+                        Traits.helperSetterName(field),
+                        new CastExpression(field.getOriginType(),initCode.getExpression())
+                );
+            }
             mce.setImplicitThis(false);
             mce.setSourcePosition(initialExpression);
             code.addStatement(new ExpressionStatement(mce));
@@ -370,7 +417,7 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
         fieldHelper.addMethod(
                 Traits.helperSetterName(field),
                 ACC_PUBLIC | ACC_ABSTRACT,
-                ClassHelper.VOID_TYPE,
+                field.getOriginType(),
                 new Parameter[]{new Parameter(field.getOriginType(), "val")},
                 ClassNode.EMPTY_ARRAY,
                 null
@@ -419,7 +466,8 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
                 processBody(new VariableExpression(newParams[0]), methodNode, methodNode.getCode(), traitClass, fieldHelper, knownFields)
         );
         mNode.setSourcePosition(methodNode);
-        mNode.addAnnotations(methodNode.getAnnotations());
+        mNode.addAnnotations(filterAnnotations(methodNode.getAnnotations()));
+        mNode.setGenericsTypes(methodNode.getGenericsTypes());
         if (methodNode.isAbstract()) {
             mNode.setModifiers(ACC_PUBLIC | ACC_ABSTRACT);
         } else {
@@ -433,6 +481,17 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
         return mNode;
     }
 
+    private static List<AnnotationNode> filterAnnotations(List<AnnotationNode> annotations) {
+        List<AnnotationNode> result = new ArrayList<AnnotationNode>(annotations.size());
+        for (AnnotationNode annotation : annotations) {
+            if (!OVERRIDE_CLASSNODE.equals(annotation.getClassNode())) {
+                result.add(annotation);
+            }
+        }
+
+        return result;
+    }
+
     private Parameter createSelfParameter(final ClassNode traitClass, boolean isStatic) {
         final ClassNode rawType = traitClass.getPlainNodeReference();
         ClassNode type = createReceiverType(isStatic, rawType);
@@ -468,4 +527,36 @@ public class TraitASTTransformation extends AbstractASTTransformation implements
     public void setCompilationUnit(final CompilationUnit unit) {
         this.compilationUnit = unit;
     }
+
+    private static class DefaultArgsMethodsAdder extends Verifier {
+
+        @Override
+        public void addDefaultParameterMethods(final ClassNode node) {
+            setClassNode(node);
+            super.addDefaultParameterMethods(node);
+        }
+    }
+
+    private static class PostTypeCheckingExpressionReplacer extends ClassCodeExpressionTransformer {
+        private final SourceUnit sourceUnit;
+
+        private PostTypeCheckingExpressionReplacer(final SourceUnit sourceUnit) {
+            this.sourceUnit = sourceUnit;
+        }
+
+        @Override
+        protected SourceUnit getSourceUnit() {
+            return sourceUnit;
+        }
+
+        @Override
+        public Expression transform(final Expression exp) {
+            Expression replacement = exp.getNodeMetaData(TraitASTTransformation.POST_TYPECHECKING_REPLACEMENT);
+            if (replacement!=null) {
+                return replacement;
+            }
+            return super.transform(exp);
+        }
+    }
+
 }
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
index dc740bb..540cd2d 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitComposer.java
@@ -20,6 +20,7 @@ import org.codehaus.groovy.ast.AnnotationNode;
 import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.Parameter;
 import org.codehaus.groovy.ast.PropertyNode;
@@ -35,6 +36,7 @@ import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.ast.stmt.BlockStatement;
+import org.codehaus.groovy.ast.stmt.EmptyStatement;
 import org.codehaus.groovy.ast.stmt.ExpressionStatement;
 import org.codehaus.groovy.ast.stmt.IfStatement;
 import org.codehaus.groovy.ast.stmt.ReturnStatement;
@@ -50,11 +52,16 @@ import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
 import org.codehaus.groovy.syntax.Types;
 import org.codehaus.groovy.transform.ASTTransformationCollectorCodeVisitor;
+import org.codehaus.groovy.transform.sc.StaticCompileTransformation;
 import org.objectweb.asm.Opcodes;
 
+import java.lang.reflect.Modifier;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
 import java.util.LinkedHashSet;
 import java.util.LinkedList;
 import java.util.List;
@@ -134,7 +141,7 @@ public abstract class TraitComposer {
     private static void applyTrait(final ClassNode trait, final ClassNode cNode, final TraitHelpersTuple helpers) {
         ClassNode helperClassNode = helpers.getHelper();
         ClassNode fieldHelperClassNode = helpers.getFieldHelper();
-        Map genericsSpec = GenericsUtils.createGenericsSpec(cNode);
+        Map<String,ClassNode> genericsSpec = GenericsUtils.createGenericsSpec(cNode);
         genericsSpec = GenericsUtils.createGenericsSpec(trait, genericsSpec);
 
         for (MethodNode methodNode : helperClassNode.getAllDeclaredMethods()) {
@@ -146,10 +153,17 @@ public abstract class TraitComposer {
                 argList.addExpression(new VariableExpression("this"));
                 Parameter[] origParams = new Parameter[helperMethodParams.length - 1];
                 Parameter[] params = new Parameter[helperMethodParams.length - 1];
+                System.arraycopy(methodNode.getParameters(), 1, params, 0, params.length);
+                Map<String,ClassNode> methodGenericsSpec = new LinkedHashMap<String, ClassNode>(genericsSpec);
+                MethodNode originalMethod = trait.getMethod(name, params);
+                // Original method may be null in case of a private method
+                if (originalMethod!=null) {
+                    methodGenericsSpec = GenericsUtils.addMethodGenerics(originalMethod, methodGenericsSpec);
+                }
                 for (int i = 1; i < helperMethodParams.length; i++) {
                     Parameter parameter = helperMethodParams[i];
                     ClassNode originType = parameter.getOriginType();
-                    ClassNode fixedType = correctToGenericsSpecRecurse(genericsSpec, originType);
+                    ClassNode fixedType = correctToGenericsSpecRecurse(methodGenericsSpec, originType);
                     Parameter newParam = new Parameter(fixedType, "arg" + i);
                     List<AnnotationNode> copied = new LinkedList<AnnotationNode>();
                     List<AnnotationNode> notCopied = new LinkedList<AnnotationNode>();
@@ -159,7 +173,7 @@ public abstract class TraitComposer {
                     origParams[i-1] = parameter;
                     argList.addExpression(new VariableExpression(params[i - 1]));
                 }
-                createForwarderMethod(trait, cNode, methodNode, helperClassNode, genericsSpec, helperMethodParams, origParams, params, argList);
+                createForwarderMethod(trait, cNode, methodNode, originalMethod, helperClassNode, methodGenericsSpec, helperMethodParams, origParams, params, argList);
             }
         }
         cNode.addObjectInitializerStatements(new ExpressionStatement(
@@ -168,13 +182,19 @@ public abstract class TraitComposer {
                         Traits.INIT_METHOD,
                         new ArgumentListExpression(new VariableExpression("this")))
         ));
+        MethodCallExpression staticInitCall = new MethodCallExpression(
+                new ClassExpression(helperClassNode),
+                Traits.STATIC_INIT_METHOD,
+                new ArgumentListExpression(new ClassExpression(cNode)));
+        MethodNode staticInitMethod = new MethodNode(
+                Traits.STATIC_INIT_METHOD, Opcodes.ACC_STATIC | Opcodes.ACC_PUBLIC, ClassHelper.VOID_TYPE,
+                new Parameter[] {new Parameter(ClassHelper.CLASS_Type,"clazz")}, ClassNode.EMPTY_ARRAY, EmptyStatement.INSTANCE);
+        staticInitMethod.setDeclaringClass(helperClassNode);
+        staticInitCall.setMethodTarget(staticInitMethod);
         cNode.addStaticInitializerStatements(Collections.<Statement>singletonList(new ExpressionStatement(
-                new MethodCallExpression(
-                        new ClassExpression(helperClassNode),
-                        Traits.STATIC_INIT_METHOD,
-                        new ArgumentListExpression(new VariableExpression("this")))
+                staticInitCall
         )), false);
-        if (fieldHelperClassNode != null) {
+        if (fieldHelperClassNode != null && !cNode.declaresInterface(fieldHelperClassNode)) {
             // we should implement the field helper interface too
             cNode.addInterface(fieldHelperClassNode);
             // implementation of methods
@@ -242,7 +262,9 @@ public abstract class TraitComposer {
                             ClassNode.EMPTY_ARRAY,
                             body
                     );
-                    impl.addAnnotation(new AnnotationNode(COMPILESTATIC_CLASSNODE));
+                    AnnotationNode an = new AnnotationNode(COMPILESTATIC_CLASSNODE);
+                    impl.addAnnotation(an);
+                    cNode.addTransform(StaticCompileTransformation.class, an);
                     cNode.addMethod(impl);
                 }
             }
@@ -253,25 +275,35 @@ public abstract class TraitComposer {
             ClassNode trait,
             ClassNode targetNode,
             MethodNode helperMethod,
+            MethodNode originalMethod,
             ClassNode helperClassNode,
-            Map genericsSpec,
+            Map<String,ClassNode> genericsSpec,
             Parameter[] helperMethodParams,
             Parameter[] traitMethodParams,
             Parameter[] forwarderParams,
             ArgumentListExpression helperMethodArgList) {
-        ClassNode[] exceptionNodes = copyExceptions(helperMethod.getExceptions());
         MethodCallExpression mce = new MethodCallExpression(
                 new ClassExpression(helperClassNode),
                 helperMethod.getName(),
                 helperMethodArgList
         );
         mce.setImplicitThis(false);
+
+        genericsSpec = GenericsUtils.addMethodGenerics(helperMethod,genericsSpec);
+
+        ClassNode[] exceptionNodes = correctToGenericsSpecRecurse(genericsSpec, copyExceptions(helperMethod.getExceptions()));
         ClassNode fixedReturnType = correctToGenericsSpecRecurse(genericsSpec, helperMethod.getReturnType());
         Expression forwardExpression = genericsSpec.isEmpty()?mce:new CastExpression(fixedReturnType,mce);
         int access = helperMethod.getModifiers();
-        if (!helperMethodParams[0].getOriginType().equals(ClassHelper.CLASS_Type)) {
-            // we could rely on the first parameter name ($static$self) but that information is not
-            // guaranteed to be always present
+        // we could rely on the first parameter name ($static$self) but that information is not
+        // guaranteed to be always present
+        boolean isHelperForStaticMethod = helperMethodParams[0].getOriginType().equals(ClassHelper.CLASS_Type);
+        if (Modifier.isPrivate(access) && !isHelperForStaticMethod) {
+            // do not create forwarder for private methods
+            // see GROOVY-7213
+            return;
+        }
+        if (!isHelperForStaticMethod) {
             access = access ^ Opcodes.ACC_STATIC;
         }
         MethodNode forwarder = new MethodNode(
@@ -288,7 +320,11 @@ public abstract class TraitComposer {
         if (!copied.isEmpty()) {
             forwarder.addAnnotations(copied);
         }
-
+        if (originalMethod!=null) {
+            GenericsType[] newGt = GenericsUtils.applyGenericsContextToPlaceHolders(genericsSpec, originalMethod.getGenericsTypes());
+            newGt = removeNonPlaceHolders(newGt);
+            forwarder.setGenericsTypes(newGt);
+        }
         // add a helper annotation indicating that it is a bridge method
         AnnotationNode bridgeAnnotation = new AnnotationNode(Traits.TRAITBRIDGE_CLASSNODE);
         bridgeAnnotation.addMember("traitClass", new ClassExpression(trait));
@@ -304,12 +340,29 @@ public abstract class TraitComposer {
         createSuperForwarder(targetNode, forwarder, genericsSpec);
     }
 
+    private static GenericsType[] removeNonPlaceHolders(GenericsType[] oldTypes) {
+        if (oldTypes==null || oldTypes.length==0) return oldTypes;
+        ArrayList<GenericsType> l = new ArrayList<GenericsType>(Arrays.asList(oldTypes));
+        Iterator<GenericsType> it = l.iterator();
+        boolean modified = false;
+        while (it.hasNext()) {
+            GenericsType gt = it.next();
+            if (!gt.isPlaceholder()) {
+                it.remove();
+                modified = true;
+            }
+        }
+        if (!modified) return oldTypes;
+        if (l.size()==0) return null;
+        return l.toArray(new GenericsType[l.size()]);
+    }
+
     /**
      * Creates, if necessary, a super forwarder method, for stackable traits.
      * @param forwarder a forwarder method
      * @param genericsSpec
      */
-    private static void createSuperForwarder(ClassNode targetNode, MethodNode forwarder, final Map genericsSpec) {
+    private static void createSuperForwarder(ClassNode targetNode, MethodNode forwarder, final Map<String,ClassNode> genericsSpec) {
         List<ClassNode> interfaces = new ArrayList<ClassNode>(Traits.collectAllInterfacesReverseOrder(targetNode, new LinkedHashSet<ClassNode>()));
         String name = forwarder.getName();
         Parameter[] forwarderParameters = forwarder.getParameters();
@@ -344,7 +397,7 @@ public abstract class TraitComposer {
      * @param interfacesToGenerateForwarderFor
      * @param genericsSpec
      */
-    private static void doCreateSuperForwarder(ClassNode targetNode, MethodNode forwarderMethod, ClassNode[] interfacesToGenerateForwarderFor, Map genericsSpec) {
+    private static void doCreateSuperForwarder(ClassNode targetNode, MethodNode forwarderMethod, ClassNode[] interfacesToGenerateForwarderFor, Map<String,ClassNode> genericsSpec) {
         Parameter[] parameters = forwarderMethod.getParameters();
         Parameter[] superForwarderParams = new Parameter[parameters.length];
         for (int i = 0; i < parameters.length; i++) {
@@ -354,12 +407,13 @@ public abstract class TraitComposer {
         }
         for (int i = 0; i < interfacesToGenerateForwarderFor.length; i++) {
             final ClassNode current = interfacesToGenerateForwarderFor[i];
-            final ClassNode next = i<interfacesToGenerateForwarderFor.length-1?interfacesToGenerateForwarderFor[i+1]:null;
+            final ClassNode next = i < interfacesToGenerateForwarderFor.length - 1 ? interfacesToGenerateForwarderFor[i + 1] : null;
             String forwarderName = Traits.getSuperTraitMethodName(current, forwarderMethod.getName());
-            if (targetNode.getDeclaredMethod(forwarderName, superForwarderParams)==null) {
-            ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, forwarderMethod.getReturnType());
-            Statement delegate = next==null?createSuperFallback(forwarderMethod, returnType):createDelegatingForwarder(forwarderMethod, next);
-            targetNode.addMethod(forwarderName, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, returnType, superForwarderParams, ClassNode.EMPTY_ARRAY, delegate);
+            if (targetNode.getDeclaredMethod(forwarderName, superForwarderParams) == null) {
+                ClassNode returnType = correctToGenericsSpecRecurse(genericsSpec, forwarderMethod.getReturnType());
+                Statement delegate = next == null ? createSuperFallback(forwarderMethod, returnType) : createDelegatingForwarder(forwarderMethod, next);
+                MethodNode methodNode = targetNode.addMethod(forwarderName, Opcodes.ACC_PUBLIC | Opcodes.ACC_SYNTHETIC, returnType, superForwarderParams, ClassNode.EMPTY_ARRAY, delegate);
+                methodNode.setGenericsTypes(forwarderMethod.getGenericsTypes());
             }
         }
     }
diff --git a/src/main/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java b/src/main/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
index 4f36514..cf44293 100644
--- a/src/main/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
+++ b/src/main/org/codehaus/groovy/transform/trait/TraitReceiverTransformer.java
@@ -21,12 +21,15 @@ import org.codehaus.groovy.ast.ClassHelper;
 import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.DynamicVariable;
 import org.codehaus.groovy.ast.FieldNode;
+import org.codehaus.groovy.ast.GenericsType;
 import org.codehaus.groovy.ast.MethodNode;
 import org.codehaus.groovy.ast.PropertyNode;
 import org.codehaus.groovy.ast.Variable;
 import org.codehaus.groovy.ast.expr.ArgumentListExpression;
 import org.codehaus.groovy.ast.expr.BinaryExpression;
+import org.codehaus.groovy.ast.expr.BooleanExpression;
 import org.codehaus.groovy.ast.expr.CastExpression;
+import org.codehaus.groovy.ast.expr.ClassExpression;
 import org.codehaus.groovy.ast.expr.ClosureExpression;
 import org.codehaus.groovy.ast.expr.ConstantExpression;
 import org.codehaus.groovy.ast.expr.DeclarationExpression;
@@ -35,10 +38,13 @@ import org.codehaus.groovy.ast.expr.FieldExpression;
 import org.codehaus.groovy.ast.expr.MethodCallExpression;
 import org.codehaus.groovy.ast.expr.PropertyExpression;
 import org.codehaus.groovy.ast.expr.StaticMethodCallExpression;
+import org.codehaus.groovy.ast.expr.TernaryExpression;
 import org.codehaus.groovy.ast.expr.VariableExpression;
 import org.codehaus.groovy.control.SourceUnit;
+import org.codehaus.groovy.runtime.InvokerHelper;
 import org.codehaus.groovy.syntax.SyntaxException;
 import org.codehaus.groovy.syntax.Token;
+import org.codehaus.groovy.syntax.Types;
 
 import java.util.Collection;
 import java.util.List;
@@ -57,6 +63,8 @@ import java.util.List;
  */
 class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
 
+    private static final ClassNode INVOKERHELPER_CLASSNODE = ClassHelper.make(InvokerHelper.class);
+
     private final VariableExpression weaved;
     private final SourceUnit unit;
     private final ClassNode traitClass;
@@ -80,50 +88,7 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
     public Expression transform(final Expression exp) {
         ClassNode weavedType = weaved.getOriginType();
         if (exp instanceof BinaryExpression) {
-            Expression leftExpression = ((BinaryExpression) exp).getLeftExpression();
-            Expression rightExpression = ((BinaryExpression) exp).getRightExpression();
-            Token operation = ((BinaryExpression) exp).getOperation();
-            if (operation.getText().equals("=")) {
-                String leftFieldName = null;
-                // it's an assignment
-                if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).getAccessedVariable() instanceof FieldNode) {
-                    leftFieldName = ((VariableExpression) leftExpression).getAccessedVariable().getName();
-                } else if (leftExpression instanceof FieldExpression) {
-                    leftFieldName = ((FieldExpression) leftExpression).getFieldName();
-                } else if (leftExpression instanceof PropertyExpression
-                        && (((PropertyExpression) leftExpression).isImplicitThis() || "this".equals(((PropertyExpression) leftExpression).getObjectExpression().getText()))) {
-                    leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
-                }
-                if (leftFieldName!=null) {
-                    FieldNode fn = weavedType.getDeclaredField(leftFieldName);
-                    if (fn==null) {
-                        fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
-                    }
-                    Expression receiver = createFieldHelperReceiver();
-                    if (fn.isStatic()) {
-                        receiver = new PropertyExpression(receiver, "class");
-                    }
-                    String method = Traits.helperSetterName(fn);
-                    MethodCallExpression mce = new MethodCallExpression(
-                            receiver,
-                            method,
-                            new ArgumentListExpression(super.transform(rightExpression))
-                    );
-                    mce.setSourcePosition(exp);
-                    mce.setImplicitThis(false);
-                    return mce;
-                }
-            }
-            Expression leftTransform = transform(leftExpression);
-            Expression rightTransform = transform(rightExpression);
-            Expression ret =
-                    exp instanceof DeclarationExpression ?new DeclarationExpression(
-                            leftTransform, operation, rightTransform
-                    ):
-                    new BinaryExpression(leftTransform, operation, rightTransform);
-            ret.setSourcePosition(exp);
-            ret.copyNodeMetaData(exp);
-            return ret;
+            return transformBinaryExpression((BinaryExpression)exp, weavedType);
         } else if (exp instanceof StaticMethodCallExpression) {
             StaticMethodCallExpression call = (StaticMethodCallExpression) exp;
             ClassNode ownerType = call.getOwnerType();
@@ -148,31 +113,26 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
                 return transformSuperMethodCall(call);
             }
         } else if (exp instanceof FieldExpression) {
-            FieldNode field = ((FieldExpression) exp).getField();
-            MethodCallExpression mce = new MethodCallExpression(
-                    createFieldHelperReceiver(),
-                    Traits.helperGetterName(field),
-                    ArgumentListExpression.EMPTY_ARGUMENTS
-            );
-            mce.setSourcePosition(exp);
-            mce.setImplicitThis(false);
-            return mce;
+            return transformFieldExpression((FieldExpression)exp);
         } else if (exp instanceof VariableExpression) {
             VariableExpression vexp = (VariableExpression) exp;
             Variable accessedVariable = vexp.getAccessedVariable();
             if (accessedVariable instanceof FieldNode) {
                 FieldNode fn = (FieldNode) accessedVariable;
                 Expression receiver = createFieldHelperReceiver();
-                if (fn.isStatic()) {
-                    receiver = new PropertyExpression(createFieldHelperReceiver(), "class");
+                MethodCallExpression mce;
+                boolean isStatic = fn.isStatic();
+                if (isStatic) {
+                    receiver = createStaticReceiver(receiver);
                 }
-                MethodCallExpression mce = new MethodCallExpression(
-                        receiver,
-                        Traits.helperGetterName((FieldNode) accessedVariable),
-                        ArgumentListExpression.EMPTY_ARGUMENTS
+                mce = new MethodCallExpression(
+                            receiver,
+                            Traits.helperGetterName(fn),
+                            ArgumentListExpression.EMPTY_ARGUMENTS
                 );
                 mce.setSourcePosition(exp);
                 mce.setImplicitThis(false);
+                markDynamicCall(mce, fn, isStatic);
                 return mce;
             } else if (accessedVariable instanceof PropertyNode) {
                 String propName = accessedVariable.getName();
@@ -235,13 +195,125 @@ class TraitReceiverTransformer extends ClassCodeExpressionTransformer {
             );
             mce.setImplicitThis(false);
             mce.setSourcePosition(exp);
-            return mce;
+            ((ClosureExpression) exp).getCode().visit(this);
+            // The rewrite we do is causing some troubles with type checking, which will
+            // not be able to perform closure parameter type inference
+            // so we store the replacement, which will be done *after* type checking.
+            exp.putNodeMetaData(TraitASTTransformation.POST_TYPECHECKING_REPLACEMENT, mce);
+            return exp;
         }
 
         // todo: unary expressions (field++, field+=, ...)
         return super.transform(exp);
     }
 
+    private Expression transformFieldExpression(final FieldExpression exp) {
+        FieldNode field = exp.getField();
+        MethodCallExpression mce = new MethodCallExpression(
+                createFieldHelperReceiver(),
+                Traits.helperGetterName(field),
+                ArgumentListExpression.EMPTY_ARGUMENTS
+        );
+        mce.setSourcePosition(exp);
+        mce.setImplicitThis(false);
+        markDynamicCall(mce, field, field.isStatic());
+        return mce;
+    }
+
+    private Expression transformBinaryExpression(final BinaryExpression exp, final ClassNode weavedType) {
+        Expression leftExpression = exp.getLeftExpression();
+        Expression rightExpression = exp.getRightExpression();
+        Token operation = exp.getOperation();
+        if (operation.getText().equals("=")) {
+            String leftFieldName = null;
+            // it's an assignment
+            if (leftExpression instanceof VariableExpression && ((VariableExpression) leftExpression).getAccessedVariable() instanceof FieldNode) {
+                leftFieldName = ((VariableExpression) leftExpression).getAccessedVariable().getName();
+            } else if (leftExpression instanceof FieldExpression) {
+                leftFieldName = ((FieldExpression) leftExpression).getFieldName();
+            } else if (leftExpression instanceof PropertyExpression
+                    && (((PropertyExpression) leftExpression).isImplicitThis() || "this".equals(((PropertyExpression) leftExpression).getObjectExpression().getText()))) {
+                leftFieldName = ((PropertyExpression) leftExpression).getPropertyAsString();
+                FieldNode fn = tryGetFieldNode(weavedType, leftFieldName);
+                if (fieldHelper == null || fn==null && !fieldHelper.hasPossibleMethod(Traits.helperSetterName(new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null)), rightExpression)) {
+                    return createAssignmentToField(rightExpression, operation, leftFieldName);
+                }
+            }
+            if (leftFieldName!=null) {
+                FieldNode fn = weavedType.getDeclaredField(leftFieldName);
+                FieldNode staticField = tryGetFieldNode(weavedType, leftFieldName);
+                if (fn==null) {
+                    fn = new FieldNode(leftFieldName, 0, ClassHelper.OBJECT_TYPE, weavedType, null);
+                }
+                Expression receiver = createFieldHelperReceiver();
+                boolean isStatic = staticField!=null && staticField.isStatic();
+                if (fn.isStatic()) { // DO NOT USE isStatic variable here!
+                    receiver = new PropertyExpression(receiver, "class");
+                }
+                String method = Traits.helperSetterName(fn);
+                MethodCallExpression mce = new MethodCallExpression(
+                        receiver,
+                        method,
+                        new ArgumentListExpression(super.transform(rightExpression))
+                );
+                mce.setSourcePosition(exp);
+                mce.setImplicitThis(false);
+                markDynamicCall(mce, staticField, isStatic);
+                return mce;
+            }
+        }
+        Expression leftTransform = transform(leftExpression);
+        Expression rightTransform = transform(rightExpression);
+        Expression ret =
+                exp instanceof DeclarationExpression ?new DeclarationExpression(
+                        leftTransform, operation, rightTransform
+                ):
+                new BinaryExpression(leftTransform, operation, rightTransform);
+        ret.setSourcePosition(exp);
+        ret.copyNodeMetaData(exp);
+        return ret;
+    }
+
+    private void markDynamicCall(final MethodCallExpression mce, final FieldNode fn, final boolean isStatic) {
+        if (isStatic) {
+            mce.putNodeMetaData(TraitASTTransformation.DO_DYNAMIC, fn.getOriginType());
+        }
+    }
+
+    private TernaryExpression createStaticReceiver(final Expression receiver) {
+        return new TernaryExpression(
+                new BooleanExpression(new BinaryExpression(
+                        receiver,
+                        Token.newSymbol(Types.KEYWORD_INSTANCEOF, -1, -1),
+                        new ClassExpression(ClassHelper.CLASS_Type)
+                )),
+                receiver,
+                new MethodCallExpression(createFieldHelperReceiver(), "getClass", ArgumentListExpression.EMPTY_ARGUMENTS)
+        );
+    }
+
+    private BinaryExpression createAssignmentToField(final Expression rightExpression, final Token operation, final String fieldName) {
+        return new BinaryExpression(
+                new PropertyExpression(
+                        new VariableExpression(weaved),
+                        fieldName
+                ),
+                operation,
+                transform(rightExpression));
+    }
+
+    private FieldNode tryGetFieldNode(final ClassNode weavedType, final String fieldName) {
+        FieldNode fn = weavedType.getDeclaredField(fieldName);
+        if (fn==null && ClassHelper.CLASS_Type.equals(weavedType)) {
+            GenericsType[] genericsTypes = weavedType.getGenericsTypes();
+            if (genericsTypes !=null && genericsTypes.length==1) {
+                // for static properties
+                fn = genericsTypes[0].getType().getDeclaredField(fieldName);
+            }
+        }
+        return fn;
+    }
+
     private void throwSuperError(final ASTNode node) {
         unit.addError(new SyntaxException("Call to super is not allowed in a trait", node.getLineNumber(), node.getColumnNumber()));
     }
diff --git a/src/main/org/codehaus/groovy/transform/trait/Traits.java b/src/main/org/codehaus/groovy/transform/trait/Traits.java
index b9cc17d..8fef09b 100644
--- a/src/main/org/codehaus/groovy/transform/trait/Traits.java
+++ b/src/main/org/codehaus/groovy/transform/trait/Traits.java
@@ -16,6 +16,7 @@
 package org.codehaus.groovy.transform.trait;
 
 import groovy.lang.GeneratedGroovyProxy;
+import groovy.transform.SelfType;
 import groovy.transform.Trait;
 import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.ast.AnnotationNode;
@@ -24,9 +25,13 @@ import org.codehaus.groovy.ast.ClassNode;
 import org.codehaus.groovy.ast.FieldNode;
 import org.codehaus.groovy.ast.InnerClassNode;
 import org.codehaus.groovy.ast.MethodNode;
+import org.codehaus.groovy.ast.expr.ClassExpression;
+import org.codehaus.groovy.ast.expr.Expression;
+import org.codehaus.groovy.ast.expr.ListExpression;
 import org.codehaus.groovy.ast.tools.GenericsUtils;
 import org.codehaus.groovy.classgen.asm.BytecodeHelper;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.transform.stc.Receiver;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -49,6 +54,7 @@ public abstract class Traits {
     public static final Class TRAIT_CLASS = Trait.class;
     public static final ClassNode TRAIT_CLASSNODE = ClassHelper.make(TRAIT_CLASS);
     public static final ClassNode GENERATED_PROXY_CLASSNODE = ClassHelper.make(GeneratedGroovyProxy.class);
+    public static final ClassNode SELFTYPE_CLASSNODE = ClassHelper.make(SelfType.class);
 
     static final String TRAIT_TYPE_NAME = "@" + TRAIT_CLASSNODE.getNameWithoutPackage();
     static final String TRAIT_HELPER = "$Trait$Helper";
@@ -57,8 +63,8 @@ public abstract class Traits {
     static final String DIRECT_GETTER_SUFFIX = "$get";
     static final String INIT_METHOD = "$init$";
     static final String STATIC_INIT_METHOD = "$static$init$";
-    static final String THIS_OBJECT = "$self";
-    static final String STATIC_THIS_OBJECT = "$static$self";
+    public static final String THIS_OBJECT = "$self";
+    public static final String STATIC_THIS_OBJECT = "$static$self";
     static final String STATIC_FIELD_PREFIX = "$static";
     static final String FIELD_PREFIX = "$ins";
     static final String PUBLIC_FIELD_PREFIX = "$0";
@@ -92,6 +98,14 @@ public abstract class Traits {
         return owner;
     }
 
+    public static ClassNode findHelper(final ClassNode trait) {
+        return findHelpers(trait).getHelper();
+    }
+
+    public static ClassNode findFieldHelper(final ClassNode trait) {
+        return findHelpers(trait).getFieldHelper();
+    }
+
     static TraitHelpersTuple findHelpers(final ClassNode trait) {
         ClassNode helperClassNode = null;
         ClassNode fieldHelperClassNode = null;
@@ -261,6 +275,67 @@ public abstract class Traits {
         return interfaces;
     }
 
+    /**
+     * Collects all the self types that a type should extend or implement, given
+     * the traits is implements. Collects from interfaces and superclasses too.
+     * @param receiver a class node that may implement a trait
+     * @param selfTypes a collection where the list of self types will be written
+     * @return the selfTypes collection itself
+     * @since 2.4.0
+     */
+    public static LinkedHashSet<ClassNode> collectSelfTypes(
+            ClassNode receiver,
+            LinkedHashSet<ClassNode> selfTypes) {
+        return collectSelfTypes(receiver, selfTypes, true, true);
+    }
+
+    /**
+     * Collects all the self types that a type should extend or implement, given
+     * the traits is implements.
+     * @param receiver a class node that may implement a trait
+     * @param selfTypes a collection where the list of self types will be written
+     * @param checkInterfaces should the interfaces that the node implements be collected too
+     * @param checkSuper should we collect from the superclass too
+     * @return the selfTypes collection itself
+     * @since 2.4.0
+     */
+    public static LinkedHashSet<ClassNode> collectSelfTypes(
+            ClassNode receiver,
+            LinkedHashSet<ClassNode> selfTypes,
+            boolean checkInterfaces,
+            boolean checkSuper) {
+        if (Traits.isTrait(receiver)) {
+            List<AnnotationNode> annotations = receiver.getAnnotations(SELFTYPE_CLASSNODE);
+            for (AnnotationNode annotation : annotations) {
+                Expression value = annotation.getMember("value");
+                if (value instanceof ClassExpression) {
+                    selfTypes.add(value.getType());
+                } else if (value instanceof ListExpression) {
+                    List<Expression> expressions = ((ListExpression) value).getExpressions();
+                    for (Expression expression : expressions) {
+                        if (expression instanceof ClassExpression) {
+                            selfTypes.add(expression.getType());
+                        }
+                    }
+                }
+            }
+        }
+        if (checkInterfaces) {
+            ClassNode[] interfaces = receiver.getInterfaces();
+            for (ClassNode anInterface : interfaces) {
+                collectSelfTypes(anInterface, selfTypes, true, checkSuper);
+            }
+        }
+
+        if (checkSuper) {
+            ClassNode superClass = receiver.getSuperClass();
+            if (superClass != null) {
+                collectSelfTypes(superClass, selfTypes, checkInterfaces, true);
+            }
+        }
+        return selfTypes;
+    }
+
     static String getSuperTraitMethodName(ClassNode trait, String method) {
         return trait.getName().replace("_","__").replace('.','_')+SUPER_TRAIT_METHOD_PREFIX+method;
     }
diff --git a/src/main/org/codehaus/groovy/util/FastArray.java b/src/main/org/codehaus/groovy/util/FastArray.java
index a82f57b..f585c49 100644
--- a/src/main/org/codehaus/groovy/util/FastArray.java
+++ b/src/main/org/codehaus/groovy/util/FastArray.java
@@ -17,6 +17,7 @@ package org.codehaus.groovy.util;
 
 import java.util.AbstractList;
 import java.util.Collection;
+import java.util.Collections;
 import java.util.List;
 
 public class FastArray implements Cloneable {
@@ -107,6 +108,11 @@ public class FastArray implements Cloneable {
     }
 
     public List toList () {
+        if (size==0) {
+            return Collections.emptyList();
+        } else if (size==1) {
+            return Collections.singletonList(data[0]);
+        }
         return new AbstractList() {
 
             public Object get(int index) {
diff --git a/src/main/org/codehaus/groovy/vmplugin/VMPlugin.java b/src/main/org/codehaus/groovy/vmplugin/VMPlugin.java
index 7b71da8..37e8dcd 100644
--- a/src/main/org/codehaus/groovy/vmplugin/VMPlugin.java
+++ b/src/main/org/codehaus/groovy/vmplugin/VMPlugin.java
@@ -17,6 +17,8 @@ package org.codehaus.groovy.vmplugin;
 
 import org.codehaus.groovy.ast.*;
 
+import java.lang.reflect.Method;
+
 /**
  * Interface to access VM version based actions.
  * This interface is for internal use only!
@@ -30,4 +32,28 @@ public interface VMPlugin {
     void configureAnnotation(AnnotationNode an);
     void configureClassNode(CompileUnit compileUnit, ClassNode classNode);
     void invalidateCallSites();
+    /**
+     * Returns a handle with bound receiver to invokeSpecial the given method.
+     * This method will require at least Java 7, but since the source has to compile
+     * on older Java versions as well it is not marked to return a MethodHandle and
+     * uses Object instead
+     * @return  null in case of jdk<7, otherwise a handel that takes the method call
+     *          arguments for the invokespecial call
+     */
+    Object getInvokeSpecialHandle(Method m, Object receiver);
+
+    /**
+     * Invokes a handle produced by #getInvokeSpecialdHandle
+     * @param handle the handle
+     * @param args arguments for the method call, can be empty but not null
+     * @return the result of the method call
+     */
+    Object invokeHandle(Object handle, Object[] args) throws Throwable;
+
+    /**
+     * Gives the version the plguin is made for
+     * @return 5 for jdk5, 6 for jdk6, 7 for jdk7 or higher
+     */
+    int getVersion();
+
 }
diff --git a/src/main/org/codehaus/groovy/vmplugin/VMPluginFactory.java b/src/main/org/codehaus/groovy/vmplugin/VMPluginFactory.java
index 06f77af..af4b1ca 100644
--- a/src/main/org/codehaus/groovy/vmplugin/VMPluginFactory.java
+++ b/src/main/org/codehaus/groovy/vmplugin/VMPluginFactory.java
@@ -54,7 +54,7 @@ public class VMPluginFactory {
             ClassLoader loader = VMPluginFactory.class.getClassLoader();
             loader.loadClass(classNameCheck);
             return (VMPlugin) loader.loadClass(pluginName).newInstance();
-        } catch (Exception ex) {
+        } catch (Throwable ex) {
             return null;
         }
     }
diff --git a/src/main/org/codehaus/groovy/vmplugin/v5/Java5.java b/src/main/org/codehaus/groovy/vmplugin/v5/Java5.java
index 7c8dcb2..6c94505 100644
--- a/src/main/org/codehaus/groovy/vmplugin/v5/Java5.java
+++ b/src/main/org/codehaus/groovy/vmplugin/v5/Java5.java
@@ -452,5 +452,20 @@ public class Java5 implements VMPlugin {
     }
 
     public void invalidateCallSites() {}
+
+    @Override
+    public Object getInvokeSpecialHandle(Method m, Object receiver){
+        throw new GroovyBugError("getInvokeSpecialHandle requires at least JDK 7 wot private access to Lookup");
+    }
+
+    @Override
+    public int getVersion() {
+        return 5;
+    }
+
+    @Override
+    public Object invokeHandle(Object handle, Object[] args) throws Throwable {
+        throw new GroovyBugError("invokeHandle requires at least JDK 7");
+    }
 }
 
diff --git a/src/main/org/codehaus/groovy/vmplugin/v6/Java6.java b/src/main/org/codehaus/groovy/vmplugin/v6/Java6.java
index 52fb8c8..3471bb2 100644
--- a/src/main/org/codehaus/groovy/vmplugin/v6/Java6.java
+++ b/src/main/org/codehaus/groovy/vmplugin/v6/Java6.java
@@ -23,4 +23,9 @@ import org.codehaus.groovy.vmplugin.v5.Java5;
  * @author Jochen Theodorou
  */
 public class Java6 extends Java5 {
+
+    @Override
+    public int getVersion() {
+        return 6;
+    }
 }
diff --git a/src/main/org/codehaus/groovy/vmplugin/v7/Java7.java b/src/main/org/codehaus/groovy/vmplugin/v7/Java7.java
index 21b6349..8d40709 100644
--- a/src/main/org/codehaus/groovy/vmplugin/v7/Java7.java
+++ b/src/main/org/codehaus/groovy/vmplugin/v7/Java7.java
@@ -16,8 +16,17 @@
 
 package org.codehaus.groovy.vmplugin.v7;
 
+import org.codehaus.groovy.GroovyBugError;
 import org.codehaus.groovy.vmplugin.v6.Java6;
 
+import java.lang.invoke.MethodHandle;
+import java.lang.invoke.MethodHandles;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
 /**
  * Java 7 based functions. Currently just a stub but you can
  * add your own methods to your own version and place it on the classpath
@@ -26,8 +35,69 @@ import org.codehaus.groovy.vmplugin.v6.Java6;
  * @author Jochen Theodorou
  */
 public class Java7 extends Java6 {
+    private final static Constructor<MethodHandles.Lookup> LOOKUP_Constructor;
+    static {
+        Constructor<MethodHandles.Lookup> con = null;
+        try {
+            con = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
+        } catch (NoSuchMethodException e) {
+            throw new GroovyBugError(e);
+        }
+        try {
+            if (!con.isAccessible()) {
+                final Constructor tmp = con;
+                AccessController.doPrivileged(new PrivilegedAction() {
+                    @Override
+                    public Object run() {
+                        tmp.setAccessible(true);
+                        return null;
+                    }
+                });
+            }
+        } catch (SecurityException se) {
+            con = null;
+        }
+        LOOKUP_Constructor = con;
+    }
+
     @Override
     public void invalidateCallSites() {
     	IndyInterface.invalidateSwitchPoints();
     }
+
+    @Override
+    public int getVersion() {
+        return 7;
+    }
+
+    @Override
+    public Object getInvokeSpecialHandle(final Method method, final Object receiver) {
+        if (LOOKUP_Constructor==null) {
+            return super.getInvokeSpecialHandle(method, receiver);
+        }
+        if (!method.isAccessible()) {
+            AccessController.doPrivileged(new PrivilegedAction() {
+                @Override
+                public Object run() {
+                    method.setAccessible(true);
+                    return null;
+                }
+            });
+        }
+        Class declaringClass = method.getDeclaringClass();
+        try {
+            return LOOKUP_Constructor.
+                    newInstance(declaringClass, MethodHandles.Lookup.PRIVATE).
+                    unreflectSpecial(method, declaringClass).
+                    bindTo(receiver);
+        } catch (ReflectiveOperationException e) {
+            throw new GroovyBugError(e);
+        }
+    }
+
+    @Override
+    public Object invokeHandle(Object handle, Object[] args) throws Throwable {
+        MethodHandle mh = (MethodHandle) handle;
+        return mh.invokeWithArguments(args);
+    }
 }
diff --git a/src/main/org/codehaus/groovy/vmplugin/v7/Selector.java b/src/main/org/codehaus/groovy/vmplugin/v7/Selector.java
index 0447967..b2a0609 100644
--- a/src/main/org/codehaus/groovy/vmplugin/v7/Selector.java
+++ b/src/main/org/codehaus/groovy/vmplugin/v7/Selector.java
@@ -35,6 +35,7 @@ import org.codehaus.groovy.reflection.ClassInfo;
 import org.codehaus.groovy.reflection.GeneratedMetaMethod;
 import org.codehaus.groovy.reflection.stdclasses.CachedSAMClass;
 import org.codehaus.groovy.runtime.GeneratedClosure;
+import org.codehaus.groovy.runtime.GroovyCategorySupport;
 import org.codehaus.groovy.runtime.GroovyCategorySupport.CategoryMethod;
 import org.codehaus.groovy.runtime.NullObject;
 import org.codehaus.groovy.runtime.dgmimpl.NumberNumberMetaMethod;
@@ -282,7 +283,11 @@ public abstract class Selector {
             }
 
             if (method!=null || mci==null) return;
-            MetaProperty res = mci.getEffectiveGetMetaProperty(mci.getTheClass(), receiver, name, false);
+            Class chosenSender = this.sender;
+            if (mci.getTheClass()!= chosenSender && GroovyCategorySupport.hasCategoryInCurrentThread()) {
+                chosenSender = mci.getTheClass();
+            }
+            MetaProperty res = mci.getEffectiveGetMetaProperty(chosenSender, receiver, name, false);
             if (res instanceof MethodMetaProperty) {
                 MethodMetaProperty mmp = (MethodMetaProperty) res;
                 method = mmp.getMetaMethod();
diff --git a/src/resources/groovy/grape/defaultGrapeConfig.xml b/src/resources/groovy/grape/defaultGrapeConfig.xml
index b05c54b..0d3e60f 100644
--- a/src/resources/groovy/grape/defaultGrapeConfig.xml
+++ b/src/resources/groovy/grape/defaultGrapeConfig.xml
@@ -23,7 +23,7 @@
       </filesystem>
       <ibiblio name="localm2" root="file:${user.home}/.m2/repository/" checkmodified="true" changingPattern=".*" changingMatcher="regexp" m2compatible="true"/>
       <!-- todo add 'endorsed groovy extensions' resolver here -->
-      <ibiblio name="jcenter" root="http://jcenter.bintray.com/" m2compatible="true"/>
+      <ibiblio name="jcenter" root="https://jcenter.bintray.com/" m2compatible="true"/>
       <ibiblio name="codehaus" root="http://repository.codehaus.org/" m2compatible="true"/>
       <ibiblio name="ibiblio" m2compatible="true"/>
       <ibiblio name="java.net2" root="http://download.java.net/maven/2/" m2compatible="true"/>
diff --git a/src/spec/assets/img/console1.png b/src/spec/assets/img/console1.png
new file mode 100644
index 0000000..4433eba
Binary files /dev/null and b/src/spec/assets/img/console1.png differ
diff --git a/src/spec/assets/img/console2.png b/src/spec/assets/img/console2.png
new file mode 100644
index 0000000..8f81229
Binary files /dev/null and b/src/spec/assets/img/console2.png differ
diff --git a/src/spec/assets/img/console3.png b/src/spec/assets/img/console3.png
new file mode 100644
index 0000000..e9641bd
Binary files /dev/null and b/src/spec/assets/img/console3.png differ
diff --git a/src/spec/assets/img/console5.png b/src/spec/assets/img/console5.png
new file mode 100644
index 0000000..591e2c0
Binary files /dev/null and b/src/spec/assets/img/console5.png differ
diff --git a/src/spec/assets/img/console6.png b/src/spec/assets/img/console6.png
new file mode 100644
index 0000000..aa74313
Binary files /dev/null and b/src/spec/assets/img/console6.png differ
diff --git a/src/spec/assets/img/console7.png b/src/spec/assets/img/console7.png
new file mode 100644
index 0000000..39f31d8
Binary files /dev/null and b/src/spec/assets/img/console7.png differ
diff --git a/src/spec/assets/img/example1.png b/src/spec/assets/img/example1.png
new file mode 100644
index 0000000..f8a4c7d
Binary files /dev/null and b/src/spec/assets/img/example1.png differ
diff --git a/src/spec/assets/img/example10.png b/src/spec/assets/img/example10.png
new file mode 100644
index 0000000..0cf1132
Binary files /dev/null and b/src/spec/assets/img/example10.png differ
diff --git a/src/spec/assets/img/example11.png b/src/spec/assets/img/example11.png
new file mode 100644
index 0000000..11cf05e
Binary files /dev/null and b/src/spec/assets/img/example11.png differ
diff --git a/src/spec/assets/img/example12.png b/src/spec/assets/img/example12.png
new file mode 100644
index 0000000..1f6867e
Binary files /dev/null and b/src/spec/assets/img/example12.png differ
diff --git a/src/spec/assets/img/example13.png b/src/spec/assets/img/example13.png
new file mode 100644
index 0000000..19bd985
Binary files /dev/null and b/src/spec/assets/img/example13.png differ
diff --git a/src/spec/assets/img/example14.png b/src/spec/assets/img/example14.png
new file mode 100644
index 0000000..7d442da
Binary files /dev/null and b/src/spec/assets/img/example14.png differ
diff --git a/src/spec/assets/img/example15.png b/src/spec/assets/img/example15.png
new file mode 100644
index 0000000..155c461
Binary files /dev/null and b/src/spec/assets/img/example15.png differ
diff --git a/src/spec/assets/img/example16.png b/src/spec/assets/img/example16.png
new file mode 100644
index 0000000..161e2a1
Binary files /dev/null and b/src/spec/assets/img/example16.png differ
diff --git a/src/spec/assets/img/example17.png b/src/spec/assets/img/example17.png
new file mode 100644
index 0000000..b25e629
Binary files /dev/null and b/src/spec/assets/img/example17.png differ
diff --git a/src/spec/assets/img/example18.png b/src/spec/assets/img/example18.png
new file mode 100644
index 0000000..14eed4e
Binary files /dev/null and b/src/spec/assets/img/example18.png differ
diff --git a/src/spec/assets/img/example19.png b/src/spec/assets/img/example19.png
new file mode 100644
index 0000000..7ba2f16
Binary files /dev/null and b/src/spec/assets/img/example19.png differ
diff --git a/src/spec/assets/img/example2.png b/src/spec/assets/img/example2.png
new file mode 100644
index 0000000..a6550b6
Binary files /dev/null and b/src/spec/assets/img/example2.png differ
diff --git a/src/spec/assets/img/example4.png b/src/spec/assets/img/example4.png
new file mode 100644
index 0000000..2f4e2ba
Binary files /dev/null and b/src/spec/assets/img/example4.png differ
diff --git a/src/spec/assets/img/example5.png b/src/spec/assets/img/example5.png
new file mode 100644
index 0000000..44e0303
Binary files /dev/null and b/src/spec/assets/img/example5.png differ
diff --git a/src/spec/assets/img/example7.png b/src/spec/assets/img/example7.png
new file mode 100644
index 0000000..ad8b97d
Binary files /dev/null and b/src/spec/assets/img/example7.png differ
diff --git a/src/spec/assets/img/example8.png b/src/spec/assets/img/example8.png
new file mode 100644
index 0000000..972c4f3
Binary files /dev/null and b/src/spec/assets/img/example8.png differ
diff --git a/src/spec/assets/img/example9.png b/src/spec/assets/img/example9.png
new file mode 100644
index 0000000..8366341
Binary files /dev/null and b/src/spec/assets/img/example9.png differ
diff --git a/src/spec/assets/img/github1.png b/src/spec/assets/img/github1.png
new file mode 100644
index 0000000..d853794
Binary files /dev/null and b/src/spec/assets/img/github1.png differ
diff --git a/src/spec/assets/img/github2.png b/src/spec/assets/img/github2.png
new file mode 100644
index 0000000..c2e34be
Binary files /dev/null and b/src/spec/assets/img/github2.png differ
diff --git a/src/spec/assets/img/github3.png b/src/spec/assets/img/github3.png
new file mode 100644
index 0000000..d8e9c11
Binary files /dev/null and b/src/spec/assets/img/github3.png differ
diff --git a/src/spec/assets/img/github4.png b/src/spec/assets/img/github4.png
new file mode 100644
index 0000000..4836fd5
Binary files /dev/null and b/src/spec/assets/img/github4.png differ
diff --git a/src/spec/assets/img/github5.png b/src/spec/assets/img/github5.png
new file mode 100644
index 0000000..c9c7e39
Binary files /dev/null and b/src/spec/assets/img/github5.png differ
diff --git a/src/spec/assets/img/github6.png b/src/spec/assets/img/github6.png
new file mode 100644
index 0000000..0277749
Binary files /dev/null and b/src/spec/assets/img/github6.png differ
diff --git a/src/spec/assets/img/githubfork.png b/src/spec/assets/img/githubfork.png
new file mode 100644
index 0000000..d3e7181
Binary files /dev/null and b/src/spec/assets/img/githubfork.png differ
diff --git a/src/spec/assets/img/githubhomepanel.png b/src/spec/assets/img/githubhomepanel.png
new file mode 100644
index 0000000..3fbcbb0
Binary files /dev/null and b/src/spec/assets/img/githubhomepanel.png differ
diff --git a/src/spec/assets/img/githubsearch.png b/src/spec/assets/img/githubsearch.png
new file mode 100644
index 0000000..bd85cf3
Binary files /dev/null and b/src/spec/assets/img/githubsearch.png differ
diff --git a/src/spec/assets/img/groovy.png b/src/spec/assets/img/groovy.png
new file mode 100644
index 0000000..85d0593
Binary files /dev/null and b/src/spec/assets/img/groovy.png differ
diff --git a/src/spec/assets/img/groovy1.png b/src/spec/assets/img/groovy1.png
new file mode 100644
index 0000000..ccc482d
Binary files /dev/null and b/src/spec/assets/img/groovy1.png differ
diff --git a/src/spec/assets/img/repolist.png b/src/spec/assets/img/repolist.png
new file mode 100644
index 0000000..49cd88c
Binary files /dev/null and b/src/spec/assets/img/repolist.png differ
diff --git a/src/spec/assets/img/teamcity.png b/src/spec/assets/img/teamcity.png
new file mode 100644
index 0000000..d1e9943
Binary files /dev/null and b/src/spec/assets/img/teamcity.png differ
diff --git a/src/spec/doc/assets/img/gconsole-toolbar.png b/src/spec/doc/assets/img/gconsole-toolbar.png
new file mode 100644
index 0000000..c6a0cc3
Binary files /dev/null and b/src/spec/doc/assets/img/gconsole-toolbar.png differ
diff --git a/src/spec/doc/assets/img/groovysh2.jpg b/src/spec/doc/assets/img/groovysh2.jpg
deleted file mode 100644
index 3beba75..0000000
Binary files a/src/spec/doc/assets/img/groovysh2.jpg and /dev/null differ
diff --git a/src/spec/doc/assets/img/groovysh3.jpg b/src/spec/doc/assets/img/groovysh3.jpg
deleted file mode 100644
index 2486ba1..0000000
Binary files a/src/spec/doc/assets/img/groovysh3.jpg and /dev/null differ
diff --git a/src/spec/doc/assets/img/groovysh4.jpg b/src/spec/doc/assets/img/groovysh4.jpg
deleted file mode 100644
index c6d2724..0000000
Binary files a/src/spec/doc/assets/img/groovysh4.jpg and /dev/null differ
diff --git a/src/spec/doc/contributors.adoc b/src/spec/doc/contributors.adoc
new file mode 100644
index 0000000..bcd203b
--- /dev/null
+++ b/src/spec/doc/contributors.adoc
@@ -0,0 +1,29 @@
+= Contributors
+
+The Groovy team would like to thank the contributors of this documentation (by alphabetical order):
+
+* https://github.com/mojavelinux[Dan Allen]
+* http://hamletdarcy.blogspot.fr/[Hamlet D'Arcy]
+* https://github.com/bura[Andrey Bloschetsov]
+* https://github.com/JBrownVisualSpection[J Brown]
+* https://github.com/jeffbrown[Jeff Scott Brown]
+* http://twitter.com/CedricChampeau[Cédric Champeau]
+* https://github.com/tobia[Tobia Conforto]
+* https://github.com/ddimtirov[Dimitar Dimitrov]
+* http://twitter.com/werdnagreb[Andrew Eisenberg]
+* https://github.com/christoph-frick[Christoph Frick]
+* http://twitter.com/marioggar[Mario García]
+* https://github.com/davidmichaelkarr[David Michael Karr]
+* http://twitter.com/paulk_asert[Paul King]
+* http://twitter.com/glaforge[Guillaume Laforge]
+* http://twitter.com/pledbrook[Peter Ledbrook]
+* http://grantmcconnaughey.github.io/[Grant McConnaughey]
+* https://github.com/dnahodil[David Nahodil]
+* https://github.com/jnorthr[James Northrop]
+* https://github.com/marcpa00[Marc Paquette]
+* https://github.com/michaelss[Michael Schuenck]
+* https://github.com/PascalSchumacher[Pascal Schumacher]
+* https://twitter.com/asteingr[André Steingreß]
+* https://github.com/keeganwitt[Keegan Witt]
+
+If you can offer time to improve groovy or our documentation, link:groovy-contributions.html[read this tutorial].
diff --git a/src/spec/doc/core-closures.adoc b/src/spec/doc/core-closures.adoc
index 6558656..9fa2c07 100644
--- a/src/spec/doc/core-closures.adoc
+++ b/src/spec/doc/core-closures.adoc
@@ -1,29 +1,547 @@
-= Closures (TBD)
+= Closures
 
-This chapter covers Groovy Closures.
+:lambdas: http://docs.oracle.com/javase/tutorial/java/javaOO/lambdaexpressions.html[lambda expressions in Java 8]
 
-== Syntax (TBD)
+This chapter covers Groovy Closures. A closure in Groovy is an open, anonymous, block of code that can take arguments,
+return a value and be assigned to a variable. A closure may reference variables declared in its surrounding scope. In
+opposition to the formal definition of a closure, `Closure` in the Groovy language can also contain free variables which
+are defined outside of its surrounding scope. While breaking the formal concept of a closure, it offers a variety of
+advantages which are described in this chapter.
 
-== Parameters (TBD)
+== Syntax
+=== Defining a closure
 
-=== Normal parameters (TBD)
-=== Implicit parameter (TBD)
-=== Default parameter (TBD)
-=== Varargs (TBD)
+A closure definition follows this syntax:
 
-== Delegation strategy (TBD)
+[source,groovy]
+-----------------------------------
+{ [closureParameters -> ] statements }
+-----------------------------------
 
-== Closures in GStrings (TBD)
+Where `+[closureParameters->]+` is an optional comma-delimited list of
+parameters, and statements are 0 or more Groovy statements. The parameters
+look similar to a method parameter list, and these parameters may be
+typed or untyped.
 
-== Functional programming (TBD)
+When a parameter list is specified, the `+->+` character
+is required and serves to separate the arguments from the closure body.
+The _statements_ portion consists of 0, 1, or many Groovy statements.
 
-=== Currying (TBD)
-==== Left currying (TBD)
-==== Right currying (TBD)
-==== Index based currying (TBD)
+Some examples of valid closure definitions:
 
-=== Memoization (TBD)
+[source,groovy]
+-----------------------------------------------------------
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_1,indent=0]
 
-=== Composition (TBD)
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_1bis,indent=0]
 
-=== Trampoline (TBD)
\ No newline at end of file
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_2,indent=0]
+
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_3,indent=0]
+
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_4,indent=0]
+
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_5,indent=0]
+
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_syntax_6,indent=0]
+-----------------------------------------------------------
+<1> A closure referencing a variable named `item`
+<2> It is possible to explicitly separate closure parameters from code by adding an arrow (`+->+`)
+<3> A closure using an implicit parameter (`it`)
+<4> An alternative version where `it` is this time an explicit parameter
+<5> In that case it is often better to use an explicit name for the parameter
+<6> A closure accepting two typed parameters
+<7> A closure can contain multiple statements
+
+[[closure-as-object]]
+=== Closures as an object
+
+A closure is an instance of the `groovy.lang.Closure` class, making it assignable to a variable or a field as any
+other variable, despite being a block of code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_is_an_instance_of_Closure,indent=0]
+----
+<1> You can assign a closure to a variable, and it is an instance of `groovy.lang.Closure`
+<2> If not using `def`, you can assign a closure to a variable of type `groovy.lang.Closure`
+<3> Optionally, you can specify the return type of the closure by using the generic type of `groovy.lang.Closure`
+
+=== Calling a closure
+
+A closure, as an anonymous block of code, can be called like any other method. If you define a closure which takes
+no argument like this:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1,indent=0]
+----
+
+Then the code inside the closure will only be executed when you _call_ the closure, which can be done by using the
+variable as if it was a regular method:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1_direct,indent=0]
+----
+
+Alternatively, you can be explicit and use the `call` method:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_1_explicit,indent=0]
+----
+
+The principle is the same if the closure accepts arguments:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_call_2,indent=0]
+----
+<1> define a closure which accepts an `int` as a parameter
+<2> it can be called directly
+<3> or using the `call` method
+<4> same goes for a closure with an implicit argument (`it`)
+<5> which can be called directly using `(arg)`
+<6> or using `call`
+
+Unlike a method, a closure *always* returns a value when called. The next section discusses how to declare closure arguments, when to use them and what is the <<implicit-it,implicit
+"it" parameter>>.
+
+== Parameters
+
+=== Normal parameters
+
+Parameters of closures follow the same principle as parameters of regular methods:
+
+* an optional type
+* a name
+* an optional default value
+
+Parameters are separated with commas:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_param_declaration,indent=0]
+----
+
+[[implicit-it]]
+=== Implicit parameter
+
+When a closure does not explicitly define a parameter list (using `+->+`), a closure *always* defines an implicit
+parameter, named `it`. This means that this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=implicit_it,indent=0]
+----
+
+is stricly equivalent to this one:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=implicit_it_equiv,indent=0]
+----
+
+If you want to declare a closure which accepts no argument and must be restricted to calls without arguments,
+then you *must* declare it with an explicit empty argument list:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_no_arg_def,indent=0]
+
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_no_arg_fail,indent=0]
+----
+
+=== Varargs
+
+It is possible for a closure to declare variable arguments like any other method. _Vargs_ methods are methods that
+can accept a variable number of arguments if the last parameter is of variable length (or an array) like in the next
+examples:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_vargs,indent=0]
+----
+<1> A closure accepting a variable number of strings as first parameter
+<2> It may be called using any number of arguments *without* having to explicitly wrap them into an array
+<3> The same behavior is directly available if the _args_ parameter is declared as an array
+<4> As long as the *last* parameter is an array of an explicit vargs type
+
+== Delegation strategy
+
+=== Groovy closures vs lambda expressions
+
+Groovy defines closures as <<closure-as-object, instances of the Closure class>>. It makes it very different from
+{lambdas}. Delegation is a
+key concept in Groovy closures which has no equivalent in lambdas. The ability to _change the delegate_ or _change the
+delegation strategy_ of closures make it possible to design beautiful domain specific languages (DSLs) in Groovy.
+
+[[closure-owner]]
+=== Owner, delegate and this
+
+To understand the concept of delegate, we must first explain the meaning of `this` inside a closure. A closure actually
+defines 3 distinct things:
+
+- `this` corresponds to the _enclosing class_ where the closure is defined
+- `owner` corresponds to the _enclosing object_ where the closure is defined, which may be either a class or a closure
+- `delegate` corresponds to a third party object where methods calls or properties are resolved whenever the receiver of
+the message is not defined
+
+[[closure-this]]
+==== The meaning of this
+
+In a closure, calling `getThisObject` will return the enclosing class where the closure is defined. It is equivalent to
+using an explicit `this`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_this,indent=0]
+----
+<1> a closure is defined inside the `Enclosing` class, and returns `getThisObject`
+<2> calling the closure will return the instance of `Enclosing` where the the closure is defined
+<3> in general, you will just want to use the shortcut `this` notation
+<4> and it returns *exactly* the same object
+<5> if the closure is defined in a inner class
+<6> `this` in the closure *will* return the inner class, not the top-level one
+<7> in case of nested closures, like here `cl` being defined inside the scope of `nestedClosures`
+<8> then `this` corresponds to the closest outer class, not the enclosing closure!
+
+It is of course possible to call methods from the enclosing class this way:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_this_call,indent=0]
+----
+<1> the closure calls `toString` on `this`, which will actually call the `toString` method on the enclosing object,
+that is to say the `Person` instance
+
+==== Owner of a closure
+
+The owner of a closure is very similar to the definition of <<closure-this,this in a closure>> with a subtle difference:
+it will return the direct enclosing object, be it a closure or a class:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_owner,indent=0]
+----
+<1> a closure is defined inside the `Enclosing` class, and returns `getOwner`
+<2> calling the closure will return the instance of `Enclosing` where the the closure is defined
+<3> in general, you will just want to use the shortcut `owner` notation
+<4> and it returns *exactly* the same object
+<5> if the closure is defined in a inner class
+<6> `owner` in the closure *will* return the inner class, not the top-level one
+<7> but in case of nested closures, like here `cl` being defined inside the scope of `nestedClosures`
+<8> then `owner` corresponds to the enclosing closure, hence a different object from `this`!
+
+==== Delegate of a closure
+
+The delegate of a closure can be accessed by using the `delegate` property or calling the `getDelegate` method. It is a
+powerful concept for building domain specific languages in Groovy. While <<this,closure-this>> and <<owner,closure-owner>>
+refer to the lexical scope of a closure, the delegate is a user defined object that a closure will use. By default, the
+delegate is set to `owner`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_is_owner,indent=0]
+----
+<1> you can get the delegate of a closure calling the `getDelegate` method
+<2> or using the `delegate` property
+<3> both return the same object
+<4> which is the enclosing class or closure
+<5> in particular in case of nested closures
+<6> `delegate` will correspond to the `owner`
+
+The delegate of a closure can be changed to *any object*. Let's illustrate this by creating two classes which are not
+subclasses of each other but both define a property called `name`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_classes,indent=0]
+----
+
+Then let's define a closure which fetches the `name` property on the delegate:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_closure,indent=0]
+----
+
+Then by changing the delegate of the closure, you can see that the target object will change:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=change_delegate_asserts,indent=0]
+----
+
+At this point, the behavior is not different from having a `variable defined in the lexical scope of the closure:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_alernative,indent=0]
+----
+
+However there is are major differences:
+
+* in the last example, _target_ is a local variable referenced from within the closure
+* the delegate can be used transparently, that is to say without prefixing method calls with `delegate.` as explained
+in the next paragraph.
+
+==== Delegation strategy
+
+Whenever, in a closure, a property is accessed without explicitly setting a receiver object, then a delegation strategy
+is involved:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegation_strategy_intro,indent=0]
+----
+<1> `name` is not referencing a variable in the lexical scope of the closure
+<2> we can change the delegate of the closure to be an instance of `Person`
+<3> and the method call will succeed
+
+The reason this code works is that the `name` property will be resolved transparently on the `delegate` object! This is
+a very powerful way to resolve properties or method calls inside closures. There's no need to set an explicit `delegate.`
+receiver: the call will be made because the default delegation strategy of the closure makes it so. A closure actually
+defines multiple resolution strategies that you can choose:
+
+* `Closure.OWNER_FIRST` is the *default strategy*. If a property/method exists on the *owner*, then it will be called on
+the owner. If not, then the *delegate* is used.
+* `Closure.DELEGATE_FIRST` reverses the logic: the *delegate* is used first, then the *owner*
+* `Closure.OWNER_ONLY` will only resolve the property/method lookup on the owner: the delegate will be ignored.
+* `Closure.DELEGATE_ONLY` will only resolve the property/method lookup on the delegate: the owner will be ignored.
+* `Closure.TO_SELF` can be used by developers who need advanced meta-programming techniques and wish to implement a
+ custom resolution strategy: the resolution will not be made on the owner or the delegate but only on the closure class
+ itself. It makes only sense to use this if you implement your own subclass of `Closure`.
+
+Let's illustrate the default "owner first" strategy with this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_owner_first,indent=0]
+----
+<1> for the illustration, we define a closure member which references "name"
+<2> both the `Person` and the `Thing` class define a `name` property
+<3> Using the default strategy, the `name` property is resolved on the owner first
+<4> so if we change the `delegate` to `t` which is an instance of `Thing`
+<5> there is no change in the result: `name` is first resolved on the `owner` of the closure
+
+However, it is possible to change the resolution strategy of the closure:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_delegate_first,indent=0]
+----
+
+By changing the `resolveStrategy`, we are modifying the way Groovy will resolve the "implicit this" references: in this
+case, `name` will first be looked in the delegate, then if not found, on the owner. Since `name` is defined in the
+delegate, an instance of `Thing`, then this value is used.
+
+The difference between "delegate first" and "delegate only" or "owner first" and "owner only" can be illustrated if one
+of the delegate (resp. owner) does *not* have such a method or property:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=delegate_only,indent=0]
+----
+
+In this example, we define two classes which both have a `name` property but only the `Person` class declares an `age`.
+The `Person` class also declares a closure which references `age`. We can change the default resolution strategy from
+"owner first" to "delegate only". Since the owner of the closure is the `Person` class, then we can check that if the
+delegate is an instance of `Person`, calling the closure is successful, but if we call it with a delegate being an
+instance of `Thing`, it fails with a `groovy.lang.MissingPropertyException`. Despite the closure being defined inside
+the `Person` class, the owner is not used.
+
+NOTE: A comprehensive explanation about how to use this feature to develop DSLs can be found in a
+link:core-domain-specific-languages.html[dedicated section of the manual].
+
+== Closures in GStrings
+
+Take the following code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_eager_intro,indent=0]
+----
+
+The code behaves as you would expect, but what happens if you add:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_eager_outro,indent=0]
+----
+
+You will see that the assert fails! There are two reasons for this:
+
+* a GString only evaluates lazily the `toString` representation of values
+* the syntax `${x}` in a GString does *not* represent a closure but an *expression* to `$x`, evaluated when the GString
+is created.
+
+In our example, the `GString` is created with an expression referencing `x`. When the `GString` is created, the *value*
+of `x` is 1, so the `GString` is created with a value of 1. When the assert is triggered, the `GString` is evaluated
+and 1 is converted to a `String` using `toString`. When we change `x` to 2, we did change the value of `x`, but it is
+a different object, and the `GString` still references the old one.
+
+TIP: A `GString` will only change its `toString` representation if the values it references are mutating. If the references
+change, nothing will happen.
+
+If you need a real closure in a GString and for example enforce lazy evaluation of variables, you need to use the
+alternate syntax `${-> x}` like in the fixed example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_lazy,indent=0]
+----
+
+And let's illustrate how it differs from mutation with this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_mutation,indent=0]
+----
+<1> the `Person` class has a `toString` method returning the `name` property
+<2> we create a first `Person` named _Sam_
+<3> we create another `Person` named _Lucy_
+<4> the `p` variable is set to `Sam`
+<5> and a closure is created, referencing the value of `p`, that is to say _Sam_
+<6> so when we evaluate the string, it returns _Sam_
+<7> if we change `p` to _Lucy_
+<8> the string still evaluates to _Sam_ because it was the *value* of `p` when the `GString` was created
+<9> so if we mutate _Sam_ to change his name to _Lucy_
+<10> this time the `GString` is correctly mutated
+
+So if you don't want to rely on mutating objects or wrapping objects, you *must* use closures in `GString` by explicitly
+declaring an empty argument list:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=gstring_no_mutation,indent=0]
+----
+
+== Closure coercion
+
+Closures can be converted into interfaces or single-abstract method types. Please refer to
+link:core-semantics.html#closure-coercion[this section of the manual] for a complete description.
+
+== Functional programming
+
+Closures, like {lambdas} are at the core of the functional programming paradigm in Groovy. Some functional programming
+operations on functions are available directly on the `Closure` class, like illustrated in this section.
+
+=== Currying
+
+In Groovy, currying refers to the concept of partial application. It does *not* correspond to the real concept of currying
+in functional programming because of the different scoping rules that Groovy applies on closures. Currying in Groovy will
+let you set the value of one parameter of a closure, and it will return a new closure accepting one less argument.
+
+==== Left currying
+
+Left currying is the fact of setting the left-most parameter of a closure, like in this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=left_curry,indent=0]
+----
+<1> the `nCopies` closure defines two parameters
+<2> `curry` will set the first parameter to `2`, creating a new closure (function) which accepts a single `String`
+<3> so the new function call be called with only a `String`
+<4> and it is equivalent to calling `nCopies` with two parameters
+
+==== Right currying
+
+Similarily to left currying, it is possible to set the right-most parameter of a closure:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=right_curry,indent=0]
+----
+<1> the `nCopies` closure defines two parameters
+<2> `rcurry` will set the last parameter to `bla`, creating a new closure (function) which accepts a single `int`
+<3> so the new function call be called with only an `int`
+<4> and it is equivalent to calling `nCopies` with two parameters
+
+==== Index based currying
+
+In case a closure accepts more than 2 parameters, it is possible to set an arbitrary parameter using `ncurry`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=ncurry,indent=0]
+----
+<1> the `volume` function defines 3 parameters
+<2> `ncurry` will set the second parameter (index = 1) to `2d`, creating a new volume function which accepts length and height
+<3> that function is equivalent to calling `volume` omitting the width
+<4> it is also possible to set multiple parameters, starting from the specified index
+<5> the resulting function accepts as many parameters as the initial one minus the number of parameters set by `ncurry`
+
+=== Memoization
+
+Memoization allows the result of the call of a closure to be cached. It is interesting if the computation done by a
+function (closure) is slow, but you know that this function is going to be called often with the same arguments. A
+typical example is the Fibonacci suite. A naive implementation may look like this:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=naive_fib,indent=0]
+----
+
+It is a naive implementation because 'fib' is often called recursively with the same arguments, leading to an exponential
+algorithm:
+
+- computing `fib(15)` requires the result of `fib(14)` and `fib(13)`
+- computing `fib(14)` requires the result of `fib(13)` and `fib(12)`
+
+Since calls are recursive, you call already see that we will compute the same values again and again, although they could
+be cached. This naive implementation can be "fixed" by caching the result of calls using `memoize`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=memoized_fib,indent=0]
+----
+
+WARNING: The cache works *using the actual values of the arguments*. This means that you should be very careful if you use
+memoization with something else than primitive or boxed primitive types.
+
+The behavior of the cache can be tweaked using alternate methods:
+
+* `memoizeAtMost` will generate a new closure which caches *at most* _n_ values
+* `memoizeAtLeast` will generate a new closure which caches *at least* _n_ values
+* `memoizeBetween` will generate a new closure which caches *at least* _n_ values and *at most* _n_ values
+
+The cache used in all memoize variants is a LRU cache.
+
+=== Composition
+
+Closure composition corresponds to the concept of function composition, that is to say creating a new function by
+composing two or more functions (chaining calls), as illustrated in this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=closure_composition,indent=0]
+----
+
+=== Trampoline
+
+Recursive algorithms are often restricted by a physical limit: the maximum stack height. For example, if you call a method
+that recursively calls itself too deep, you will eventually receive a `StackOverflowException`.
+
+An approach that helps in those situations is by using `Closure` and its trampoline capability.
+
+Closures are wrapped in a `TrampolineClosure`. Upon calling, a trampolined `Closure` will call the original `Closure` waiting
+for its result. If the outcome of the call is another instance of a `TrampolineClosure`, created perhaps as a result
+to a call to the `trampoline()` method, the `Closure` will again be invoked. This repetitive invocation of returned
+trampolined Closures instances will continue until a value other than a trampolined `Closure` is returned. That value
+will become the final result of the trampoline. That way, calls are made serially, rather than filling the stack.
+
+Here’s an example of the use of `trampoline()` to implement the factorial function:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClosuresSpecTest.groovy[tags=trampoline,indent=0]
+----
+
+=== Method pointers
+
+It is often practical to be able to use a regular method as a closure. For example, you might want to use the currying
+abilities of a closure, but those are not available to normal methods. In Groovy, you can obtain a closure from any
+method with the link:core-operators.html#method-pointer-operator[method pointer operator].
diff --git a/src/spec/doc/core-differences-java.adoc b/src/spec/doc/core-differences-java.adoc
index 983b400..18da776 100644
--- a/src/spec/doc/core-differences-java.adoc
+++ b/src/spec/doc/core-differences-java.adoc
@@ -198,3 +198,59 @@ instead:
 Runnable run = { println 'run' }
 list.each { println it } // or list.each(this.&println)
 ----
+
+
+== GStrings
+
+As double-quoted string literals are interpreted as `GString` values, Groovy may fail
+with compile error or produce subtly different code if a class with `String` literal
+containing a dollar character is compiled with Groovy and Java compiler.
+
+While typically, Groovy will auto-cast between `GString` and `String` if an API declares
+the type of a parameter, beware of Java APIs that accept an `Object` parameter and then
+check the actual type.
+
+== String and Character literals
+
+Singly-quoted literals in Groovy are used for `String`, and double-quoted result in
+`String` or `GString`, depending whether there is interpolation in the literal.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=type_depends_on_quoting_AND_whether_we_actually_interpolate,indent=0]
+----
+
+Groovy will automatically cast a single-character `String` to `char` when assigning to
+a variable of type `char`. When calling methods with arguments of type `char` we need
+to either cast explicitly or make sure the value has been cast in advance.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=single_char_strings_are_autocasted,indent=0]
+----
+
+Groovy supports two styles of casting and in the case of casting to `char` there
+are subtle differences when casting a multi-char strings. The Groovy style cast is
+more lenient and will take the first character, while the C-style cast will fail
+with exception.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DifferencesFromJavaTest.groovy[tags=chars_c_vs_groovy_cast,indent=0]
+----
+
+== Behaviour of `==`
+
+In Java `==` means equality of primitive types or identity for objects.  In
+Groovy `==` translates to `a.compareTo(b)==0`, iff they are `Comparable`, and
+`a.equals(b)` otherwise.  To check for identity, there is `is`.  E.g.
+`a.is(b)`.
+
+
+== Different keywords
+
+There are a few more keywords in Groovy than in Java.  Don't use them for
+variable names etc.
+
+* `in` 
+* `trait` 
diff --git a/src/spec/doc/core-domain-specific-languages.adoc b/src/spec/doc/core-domain-specific-languages.adoc
index e29e393..b35ea2a 100644
--- a/src/spec/doc/core-domain-specific-languages.adoc
+++ b/src/spec/doc/core-domain-specific-languages.adoc
@@ -3,7 +3,7 @@
 == Command chains
 
 Groovy lets you omit parentheses around the arguments of a
-method call for top-level statements. ``command chain'' feature extends this by allowing us to chain such
+method call for top-level statements. "command chain" feature extends this by allowing us to chain such
 parentheses-free method calls, requiring neither parentheses around arguments, nor dots between the chained calls.
 The general idea is that a call like `a b c d` will actually be equivalent to `a(b).c(d)`. This
 also works with multiple arguments, closure arguments, and even named arguments. Furthermore, such command chains can
@@ -91,9 +91,158 @@ include::{projectdir}/src/spec/test/CommandChainsTest.groovy[tags=commandchain_i
 -----------------------------------------------------
 
 
-== Operator overloading (TBD)
-== Script base classes (TBD)
-== Adding properties to numbers (TBD)
+== Operator overloading
+
+Various operators in Groovy are mapped onto regular method calls on objects.
+
+This allows you to provide your own Java or Groovy objects which can take advantage of operator overloading. The following table describes the operators supported in Groovy and the methods they map to.
+
+[options="header"]
+|======================
+|Operator | Method 
+| `a + b` | a.plus(b)
+| `a - b` | a.minus(b)
+| `a * b` | a.multiply(b)
+| `a ** b` | a.power(b)
+| `a / b` | a.div(b)
+| `a % b` | a.mod(b)
+| `a \| b` | a.or(b)
+| `a & b` | a.and(b)
+| `a ^ b` | a.xor(b)
+| `pass:[a++]` or `pass:[++a]` | a.next()
+| `a--` or `--a` | a.previous()
+| `a[b]` | a.getAt(b)
+| `a[b] = c` | a.putAt(b, c)
+| `a << b` | a.leftShift(b)
+| `a >> b` | a.rightShift(b)
+| `a >>> b` | a.rightShiftUnsigned(b)
+| `switch(a) { case(b) : }` | b.isCase(a)
+| `if(a)` | a.asBoolean()
+| `~a` | a.bitwiseNegate()
+| `-a` | a.negative()
+| `+a` | a.positive()
+| `a as b` | a.asType(b)
+| `a == b` | a.equals(b)
+| `a != b` | ! a.equals(b)
+| `a pass:[<=>] b` | a.compareTo(b)
+| `a > b` | a.compareTo(b) > 0
+| `a >= b` | a.compareTo(b) >= 0
+| `a < b` | a.compareTo(b) < 0
+| `a \<= b` | a.compareTo(b) \<= 0
+|======================
+
+== Script base classes
+=== The Script class
+Groovy scripts are always compiled to classes. For example, a script as simple as:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=simple_script,indent=0]
+----
+
+is compiled to a class extending the abstract gapi:groovy.lang.Script[] class. This class contains a single abstract
+method called _run_. When a script is compiled, then its body will become the _run_ method, while the other methods
+found in the script are found in the implementing class. The `Script` class provides base support for integration
+with your application through the `Binding` object, as illustrated in this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=integ_binding,indent=0]
+----
+<1> a binding is used to share data between the script and the calling class
+<2> a `GroovyShell` can be used with this binding
+<3> input variables are set from the calling class inside the binding
+<4> then the script is evaluated
+<5> and the `z` variable has been "exported" into the binding
+
+This is a very practical way to share data between the caller and the script, however it may be insufficient or not
+practical in some cases. For that purpose, Groovy allows you to set your own base script class. A base script class
+has to extend gapi:groovy.lang.Script[] and be a single abstract method type:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=baseclass_def,indent=0]
+----
+
+Then the custom script base class can be declared in the compiler configuration, for example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=use_custom_conf,indent=0]
+----
+<1> create a custom compiler configuration
+<2> set the base script class to our custom base script class
+<3> then create a `GroovyShell` using that configuration
+<4> the script will then extend the base script class, giving direct access to the `name` property and `greet` method
+
+=== The @BaseScript annotation
+
+As an alternative, it is also possible to use the `@BaseScript` annotation directly into a script:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=use_basescript,indent=0]
+----
+
+where `@BaseScript` should annotate a variable which type is the class of the base script. Alternatively, you can set
+the base script class as a member of the `@BaseScript` annotation itself:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=use_basescript_alt,indent=0]
+----
+
+=== Alternate abstract method
+
+We have seen that the base script class is a single abstract method type that needs to implement the `run` method. The
+`run` method is executed by the script engine automatically. In some circumstances it may be interesting to have a base
+class which implements the `run` method, but provides an alternative abstract method to be used for the script body.
+For example, the base script `run` method might perform some initialization before the `run` method is executed. This
+is possible by doing this:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=custom_run_method,indent=0]
+----
+<1> the base script class should define one (and only one) abstract method
+<2> the `run` method can be overriden and perform a task before executing the script body
+<3> `run` calls the abstract `scriptBody` method which will delegate to the user script
+<4> then it can return something else than the value from the script
+
+If you execute this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=custom_run_eval,indent=0]
+----
+
+Then you will see that the script is executed, but the result of the evaluation is `1` as returned by the `run`
+method of the base class. It is even clearer if you use `parse` instead of `evaluate`, because it would allow you to
+execute the `run` method several times on the same script instance:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/BaseScriptSpecTest.groovy[tags=custom_run_parse,indent=0]
+----
+
+== Adding properties to numbers
+
+In Groovy number types are considered equal to any other types. As such, it is possible to enhance numbers by adding
+properties or methods to them. This can be very handy when dealing with measurable quantities for example. Details about
+how existing classes can be enhanced in Groovy are found in the link:core-metaprogramming.html#_extension_modules[extension
+modules] section or the link:core-metaprogramming.html#categories[categories] section.
+
+An illustration of this can be found in Groovy using the `TimeCategory`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/CategoryTest.groovy[tags=time_category,indent=0]
+----
+<1> using the `TimeCategory`, a property `minute` is added to the `Integer` class
+<2> similarily, the `months` method returns a `groovy.time.DatumDependentDuration` which can be used in calculus
+
+Categories are lexically bound, making them a great fit for internal DSLs.
+
 [[section-delegatesto]]
 == @DelegatesTo
 
@@ -207,7 +356,7 @@ include::{projectdir}/src/spec/test/DelegatesToSpecTest.groovy[tags=email_method
 What we’ve done here is telling the compiler (or the IDE) that when the
 method will be called with a closure, the delegate of this closure will
 be set to an object of type `email`. But there is still a problem: the
-defaut delegation strategy is not the one which is used in our method.
+default delegation strategy is not the one which is used in our method.
 So we will give more information and tell the compiler (or the IDE) that
 the delegation strategy is also changed:
 
@@ -308,7 +457,7 @@ with `@DelegatesTo`. However, to make the IDE aware of the delegate
 type, or the *type checker* aware of it, we need to add `@DelegatesTo`.
 And in this case, it will now that the `Greeter` variable is of
 type `Greeter`, so it will not report errors on the _sayHello_
-method *even if the exec method doesn’t explicitely define the target as
+method *even if the exec method doesn’t explicitly define the target as
 of type Greeter*. This is a very powerful feature, because it prevents
 you from writing multiple versions of the same `exec` method for
 different receiver types!
@@ -386,6 +535,49 @@ the example above, that means that the delegate type is resolved against `List<T
 
 NOTE: We're using a `genericTypeIndex` instead of a placeholder (`T`) because of JVM limitations.
 
+==== Delegating to an arbitrary type
+
+It is possible that none of the options above can represent the type you want to delegate to. For example, let's define
+a mapper class which is parametrized with an object and defines a map method which returns an object of another type:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DelegatesToSpecTest.groovy[tags=delegatestotype_mapper,indent=0]
+----
+<1> The mapper class takes two generic type arguments: the source type and the target type
+<2> The source object is stored in a final field
+<3> The `map` method asks to convert the source object to a target object
+
+As you can see, the method signature from `map` does not give any information about what object will
+be manipulated by the closure. Reading the method body, we know that it will be the `value` which is
+of type `T`, but `T` is not found in the method signature, so we are facing a case where none of the
+available options for `@DelegatesTo` is suitable. For example, if we try to statically compile this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DelegatesToSpecTest.groovy[tags=delegatestotype_mapper_test,indent=0]
+----
+
+Then the compiler will fail with:
+
+----
+Static type checking] - Cannot find matching method TestScript0#length()
+----
+
+In that case, you can use the `type` member of the `@DelegatesTo` annotation to reference `T` as a type token:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/DelegatesToSpecTest.groovy[tags=delegatestotype_mapper_fixed,indent=0]
+----
+<1> The `@DelegatesTo` annotation references a generic type which is not found in the method signature
+
+Note that you are not limited to generic type tokens. The `type` member can be used to represent complex types, such
+as `List<T>` or `Map<T,List<U>>`. The reason why you should use that in last resort is that the type is only checked
+when the type checker finds usage of `@DelegatesTo`, not when the annotated method itself is compiled. This means that
+type safety is only ensured at the call site. Additionally, compilation will be slower (though probably unnoticeable for
+most cases).
+
 [[compilation-customizers]]
 == Compilation customizers
 === Introduction
@@ -437,7 +629,7 @@ import org.codehaus.groovy.control.customizers.ImportCustomizer
 include::{projectdir}/src/spec/test/CustomizersTest.groovy[tags=import_cz,indent=0]
 -----------------------------------------------------------------------------------------------------
 
-A detailed description of all shortcuts can be found in gapi::org.codehaus.groovy.control.customizers.ImportCustomizer
+A detailed description of all shortcuts can be found in gapi:org.codehaus.groovy.control.customizers.ImportCustomizer[]
 
 === AST transformation customizer
 
@@ -488,7 +680,7 @@ give it a `ClosureExpression`, like in the following example:
 include::{projectdir}/src/spec/test/CustomizersTest.groovy[tags=ast_cz_closure,indent=0]
 --------------------------------------------------------------------------------------------------------------
 
-For a complete list of options, please refer to gapi::org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+For a complete list of options, please refer to gapi:org.codehaus.groovy.control.customizers.ASTTransformationCustomizer[]
 
 === Secure AST customizer
 
@@ -527,7 +719,7 @@ import static org.codehaus.groovy.syntax.Types.* <1>
 
 include::{projectdir}/src/spec/test/CustomizersTest.groovy[tags=secure_cz,indent=0]
 -------------------------------------------------------------------------------------
-<1> use for token types from gapi::org.codehaus.groovy.syntax.Types
+<1> use for token types from gapi:org.codehaus.groovy.syntax.Types[]
 <2> you can use class literals here
 
 If what the secure AST customizer provides out of the box isn’t enough
@@ -563,8 +755,8 @@ include::{projectdir}/src/spec/test/CustomizersTest.groovy[tags=secure_cz_custom
 ----
 <1> will fail compilation
 
-Statements can be checked using gapi::org.codehaus.groovy.control.customizers.SecureASTCustomizer.StatementChecker
-Expressions can be checked using gapi::org.codehaus.groovy.control.customizers.SecureASTCustomizer.ExpressionChecker
+Statements can be checked using gapi:org.codehaus.groovy.control.customizers.SecureASTCustomizer.StatementChecker[]
+Expressions can be checked using gapi:org.codehaus.groovy.control.customizers.SecureASTCustomizer.ExpressionChecker[]
 
 === Source aware customizer
 
@@ -783,25 +975,177 @@ exposed in the script. Then, compile your files using the following command line
 groovyc -configscript src/conf/config.groovy src/main/groovy/MyClass.groovy
 ---------------------------------------------------------------------------
 
-We strongly recommand you to separate configuration files from classes,
+We strongly recommend you to separate configuration files from classes,
 hence why we suggest using the `src/main` and `src/conf` directories above.
 
-=== AST transformations (TBD)
-== Custom type checking extensions (TBD)
-== Builders (TBD)
-=== Creating a builder (TBD)
-==== BuilderSupport (TBD)
-==== FactoryBuilderSupport (TBD)
-=== Existing builders (TBD)
-==== MarkupBuilder (TBD)
-==== StreamingMarkupBuilder (TBD)
-==== SaxBuilder (TBD)
-==== StaxBuilder (TBD)
-==== DomBuilder (TBD)
-==== NodeBuilder (TBD)
-==== JsonBuilder (TBD)
-==== StreamingJsonBuilder (TBD)
-==== SwingBuilder (TBD)
-==== AntBuilder (TBD)
-==== CliBuilder (TBD)
-==== ObjectGraphBuilder (TBD)
+=== AST transformations
+
+If:
+
+* runtime metaprogramming doesn't allow you do do what you want
+* you need to improve the performance of the execution of your DSLs
+* you want to leverage the same syntax as Groovy but with different semantics
+* you want to improve support for type checking in your DSLs
+
+Then AST transformations are the way to go. Unlike the techniques used so far, AST transformations are meant to
+change or generate code before it is compiled to bytecode. AST transformations are capable of adding new methods at
+compile time for example, or totally changing the body of a method based on your needs. They are a very powerful tool
+but also come at the price of not being easy to write. For more information about AST transformations, please take
+a look at the http://docs.groovy-lang.org/latest/html/documentation/index.html#_compile_time_metaprogramming[compile-time
+metaprogramming] section of this manual.
+
+== Custom type checking extensions
+
+It may be interesting, in some circumstances, to provide feedback about wrong code to the user as soon as possible,
+that is to say when the DSL script is compiled, rather than having to wait for the execution of the script. However,
+this is not often possible with dynamic code. Groovy actually provides a practical answer to this known as
+link:type-checking-extensions.html[type checking extensions].
+
+== Builders
+
+(TBD)
+
+=== Creating a builder
+
+(TBD)
+
+==== BuilderSupport
+
+(TBD)
+
+==== FactoryBuilderSupport
+
+(TBD)
+
+=== Existing builders
+
+(TBD)
+
+==== MarkupBuilder
+
+See <<_markupbuilder,Creating Xml - MarkupBuilder>>.
+
+==== StreamingMarkupBuilder
+
+See <<_streamingmarkupbuilder,Creating Xml - StreamingMarkupBuilder>>.
+
+==== SaxBuilder
+
+(TBD)
+
+==== StaxBuilder
+
+(TBD)
+
+==== DomBuilder
+
+(TBD)
+
+==== NodeBuilder
+
+(TBD)
+
+
+include::{projectdir}/subprojects/groovy-json/{specfolder}/json-builder.adoc[leveloffset=+3]
+
+include::{projectdir}/subprojects/groovy-json/{specfolder}/streaming-jason-builder.adoc[leveloffset=+3]
+
+include::{projectdir}/subprojects/groovy-swing/{specfolder}/swing-builder.adoc[leveloffset=+3]
+
+include::{projectdir}/subprojects/groovy-ant/{specfolder}/ant-builder.adoc[leveloffset=+3]
+
+==== CliBuilder
+
+(TBD)
+
+
+==== ObjectGraphBuilder
+
+`ObjectGraphBuilder` is a builder for an arbitrary graph of beans that
+follow the JavaBean convention. It is in particular useful for creating test data.
+
+Let's start with a list of classes that belong to your domain:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=domain_classes,indent=0]
+----
+
+Then using `ObjectGraphBuilder` building a `Company` with three employees is as
+easy as:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=builder_example,indent=0]
+----
+<1> creates a new object graph builder
+<2> sets the classloader where the classes will be resolved
+<3> sets the base package name for classes to be resolved
+<4> creates a `Company` instance
+<5> with 3 `Employee` instances
+<6> each of them having a distinct `Address`
+
+Behind the scenes, the object graph builder:
+
+* will try to match a node name into a `Class`, using a default `ClassNameResolver` strategy that requires a package name
+* then will create an instance of the appropriate class using a default `NewInstanceResolver` strategy that calls a no-arg constructor
+* resolves the parent/child relationship for nested nodes, involving two other strategies:
+** `RelationNameResolver` will yield the name of the child property in the parent, and the name of the parent property
+in the child (if any, in this case, `Employee` has a parent property aptly named `company`)
+** `ChildPropertySetter` will insert the child into the parent taking into account if the child belongs to a `Collection`
+ or not (in this case `employees` should be a list of `Employee` instances in `Company`).
+
+All 4 strategies have a default implementation that work as expected if
+the code follows the usual conventions for writing JavaBeans. In case any of your beans or objects do not follow the convention
+you may plug your own implementation of each strategy. For example imagine that you need to build a class which is
+immutable:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=immutable_class,indent=0]
+----
+
+Then if you try to create a `Person` with the builder:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=immutable_fail_runtime,indent=0]
+----
+
+It will fail at runtime with:
+
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=expected_error_immutable,indent=0]
+----
+
+Fixing this can be done by changing the new instance strategy:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=newinstanceresolver,indent=0]
+----
+
+`ObjectGraphBuilder` supports ids per node, meaning
+that you can store a reference to a node in the builder. This is
+useful when multiple objects reference the same instance. Because a
+property named `id` may be of business meaning in some domain models
+`ObjectGraphBuilder` has a strategy named `IdentifierResolver` that you
+may configure to change the default name value. The same may
+happen with the property used for referencing a previously saved
+instance, a strategy named `ReferenceResolver` will yield the
+appropriate value (default is `refId'):
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/builder/ObjectGraphBuilderTest.groovy[tags=test_id,indent=0]
+----
+<1> an address can be created with an `id`
+<2> an employee can reference the address directly with its id
+<3> or use the `refId` attribute corresponding to the `id` of the corresponding address
+
+Its worth mentioning that you cannot modify the properties of a
+referenced bean.
+
+==== JmxBuilder
+
+See <<jmx_jmxbuilder,Working with JMX - JmxBuilder>> for details.
\ No newline at end of file
diff --git a/src/spec/doc/core-gdk.adoc b/src/spec/doc/core-gdk.adoc
index bd87ea2..465ce6f 100644
--- a/src/spec/doc/core-gdk.adoc
+++ b/src/spec/doc/core-gdk.adoc
@@ -1,8 +1,8 @@
-= Groovy Development Kit (TBD)
+= Groovy Development Kit
 
-== Working with IO (TBD)
+include::{projectdir}/src/spec/doc/working-with-io.adoc[leveloffset=+1]
 
-== Working with collections (TBD)
+include::{projectdir}/src/spec/doc/working-with-collections.adoc[leveloffset=+1]
 
 == Handy utilities
 
@@ -90,7 +90,7 @@ include::{projectdir}/src/spec/test/gdk/ExpandoTest.groovy[tags=expando_method,i
 === Observable list, map and set
 
 Groovy comes with observable lists, maps and sets. Each of these collections trigger `java.beans.PropertyChangeEvent` events when elements
-are added, removed or changed. Note that a `PropertyChangeEvent` is not only signaling that a certain event has
+are added, removed or changed. Note that a `PropertyChangeEvent` is not only signalling that a certain event has
  occurred, moreover, it holds information on the property name and the old/new value a certain property has been changed to.
 
 Depending on the type of change that has happened, observable collections might fire more specialized `PropertyChangeEvent`
diff --git a/src/spec/doc/core-getting-started.adoc b/src/spec/doc/core-getting-started.adoc
index 418b4b7..3b8c8b7 100644
--- a/src/spec/doc/core-getting-started.adoc
+++ b/src/spec/doc/core-getting-started.adoc
@@ -8,21 +8,21 @@ For a quick and effortless start on Mac OSX, Linux or Cygwin, you can use http:/
 
 === Stable
 
-- **Download zip**: http://dist.groovy.codehaus.org/distributions/groovy-binary-{groovy-full-version}.zip[**Binary Release**] | http://dist.groovy.codehaus.org/distributions/groovy-src-{groovy-full-version}.zip[Source Release]
-- **Download documentation**: http://dist.groovy.codehaus.org/distributions/groovy-docs-{groovy-full-version}.zip[**JavaDoc and zipped online documentation**]
-- **Combined binary / source / documentation bundle**: http://dist.groovy.codehaus.org/distributions/groovy-sdk-{groovy-full-version}.zip[**Distribution bundle**]
+- **Download zip**: https://bintray.com/artifact/download/groovy/maven/groovy-binary-{groovy-full-version}.zip[**Binary Release**] | https://bintray.com/artifact/download/groovy/maven/groovy-src-{groovy-full-version}.zip[Source Release]
+- **Download documentation**: https://bintray.com/artifact/download/groovy/maven/groovy-docs-{groovy-full-version}.zip[**JavaDoc and zipped online documentation**]
+- **Combined binary / source / documentation bundle**: https://bintray.com/artifact/download/groovy/maven/groovy-sdk-{groovy-full-version}.zip[**Distribution bundle**]
 
-You can learn more about this version in the http://groovy.codehaus.org/Groovy+{groovy-short-version}+release+notes[release notes] or in the http://jira.codehaus.org/secure/ReleaseNote.jspa?projectId=10242&version=19074[JIRA release notes].
+You can learn more about this version in the http://groovy-lang.org/releasenotes/groovy-{groovy-short-version}.html[release notes] or in the http://groovy-lang.org/changelogs/changelog-{groovy-full-version}.html[changelog].
 
 If you plan on using invokedynamic support, link:invokedynamic-support.html[read those notes].
 
 === Snapshots
 
-For those who want to test the very latest versions of Groovy and live on the bleeding edge, you can use our http://snapshots.repository.codehaus.org/org/codehaus/groovy/groovy-all/[snapshot builds]. As soon as a build succeeds on our continuous integration server a snapshot is deployed to Codehaus' snapshot repository.
+For those who want to test the very latest versions of Groovy and live on the bleeding edge, you can use our https://oss.jfrog.org/oss-snapshot-local/org/codehaus/groovy[snapshot builds]. As soon as a build succeeds on our continuous integration server a snapshot is deployed to Artifactory's OSS snapshot repository.
 
 == Maven Repository
 
-If you wish to embed Groovy in your application, you may just prefer to point to your favourite maven repositories or the http://repository.codehaus.org/org/codehaus/groovy[codehaus maven repository].
+If you wish to embed Groovy in your application, you may just prefer to point to your favourite maven repositories or the https://oss.jfrog.org/oss-release-local/org/codehaus/groovy[JCenter maven repository].
 
 === Stable Release
 
@@ -32,30 +32,26 @@ If you wish to embed Groovy in your application, you may just prefer to point to
 |Maven
 |Explanation
 
-|\'org.codehaus.groovy:groovy:{groovy-full-version}'
+|'org.codehaus.groovy:groovy:{groovy-full-version}'
 |<groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy</artifactId> 
 <version>{groovy-full-version}</version>
-|Just the core of groovy without the modules (see below). Treats Antlr, ASM, etc. as standard dependencies. Only useful if you happen to also use the same versions of these jars yourself as it will save you having two copies of these jars.
+|Just the core of groovy without the modules (see below).
 
-|\'org.codehaus.groovy:groovy-$module:{groovy-full-version}'
+|'org.codehaus.groovy:groovy-$module:{groovy-full-version}'
 |<groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy-$module</artifactId>
 <version>{groovy-full-version}</version>
 |"$module" stands for the different optional groovy modules "ant", "bsf", "console", "docgenerator", "groovydoc", "groovysh", "jmx", "json", "jsr223", "servlet", "sql", "swing", "test", "testng" and "xml". Example: <artifactId>groovy-sql</artifactId>
 
-|\'org.codehaus.groovy:groovy-all:{groovy-full-version}'
+|'org.codehaus.groovy:groovy-all:{groovy-full-version}'
 |<groupId>org.codehaus.groovy</groupId>
 <artifactId>groovy-all</artifactId>
 <version>{groovy-full-version}</version>
-|The core plus all the modules. Also includes jar versions of Antlr, ASM, Commons-CLI and Retrotranslator runtime. Allows you or your other dependencies (e.g. Hibernate) to use other versions of these jars. Optional dependencies are marked as optional. You may need to include some of the optional dependencies to use some features of Groovy, e.g. AntBuilder, GroovyMBeans, etc.
+|The core plus all the modules. Optional dependencies are marked as optional. You may need to include some of the optional dependencies to use some features of Groovy, e.g. AntBuilder, GroovyMBeans, etc.
 |===
 
-To use the link:invokedynamic-support.html[InvokeDynamic] version of the jars just append \':indy' for Gradle or <classifier>indy</classifier> for Maven.
-
-=== Snapshot Releases
-
-In addition to the stable and milestone releases you can find intermediate SNAPSHOT releases at the http://snapshots.repository.codehaus.org/org/codehaus/groovy[codehaus snapshot maven repository].
+To use the link:invokedynamic-support.html[InvokeDynamic] version of the jars just append ':indy' for Gradle or <classifier>indy</classifier> for Maven.
 
 == GVM (the Groovy enVironment Manager)
 
@@ -121,7 +117,7 @@ If you're on Windows, you can also use the link:TODO-Windows+NSIS-Installer[NSIS
 
 === Other Distributions
 
-You may download other distributions of Groovy from http://dist.codehaus.org/groovy/distributions/[this site].
+You may download other distributions of Groovy from https://bintray.com/groovy/maven[this site].
 
 === Source Code
 
@@ -129,16 +125,16 @@ If you prefer to live on the bleeding edge, you can also grab the https://github
 
 === IDE plugin
 
-If you are an IDE user, you can just grab the latest link:tools/tools-ide.html[IDE plugin] and follow the plugin installation instructions.
+If you are an IDE user, you can just grab the latest link:tools-ide.html[IDE plugin] and follow the plugin installation instructions.
 
 == Install Binary
 
 These instructions describe how to install a binary distribution of **Groovy**.
 
 * First, <<download-groovy,Download>> a binary distribution of Groovy and unpack it into some file on your local file system.
-* Set your ++GROOVY_HOME++ environment variable to the directory you unpacked the distribution.
-* Add ++GROOVY_HOME/bin++ to your ++PATH++ environment variable.
-* Set your ++JAVA_HOME++ environment variable to point to your JDK. On OS X this is ++/Library/Java/Home++, on other unixes its often ++/usr/java++ etc. If you've already installed tools like Ant or Maven you've probably already done this step.
+* Set your `GROOVY_HOME` environment variable to the directory you unpacked the distribution.
+* Add `GROOVY_HOME/bin` to your `PATH` environment variable.
+* Set your `JAVA_HOME` environment variable to point to your JDK. On OS X this is `/Library/Java/Home`, on other unixes its often `/usr/java` etc. If you've already installed tools like Ant or Maven you've probably already done this step.
 
 You should now have Groovy installed properly. You can test this by typing the following in a command shell:
 
@@ -147,7 +143,7 @@ You should now have Groovy installed properly. You can test this by typing the f
 groovysh
 ----
 
-Which should create an interactive groovy shell where you can type Groovy statements. Or to run the link:tools/tools-groovyconsole.html[Swing interactive console] type:
+Which should create an interactive groovy shell where you can type Groovy statements. Or to run the link:tools-groovyconsole.html[Swing interactive console] type:
 
 [source,shell]
 ----
diff --git a/src/spec/doc/core-metaprogramming.adoc b/src/spec/doc/core-metaprogramming.adoc
index 371be84..b2d2a61 100644
--- a/src/spec/doc/core-metaprogramming.adoc
+++ b/src/spec/doc/core-metaprogramming.adoc
@@ -4,14 +4,29 @@ The Groovy language supports two flavors of metaprogramming: runtime metaprogram
 The first one allows altering the class model and the behavior of a program at runtime, while the second only occurs
 at compile-time. Both have pros and cons, that we will detail in this section.
 
-== Runtime metaprogramming (TBD)
+== Runtime metaprogramming
 
-=== GroovyObject interface (TBD)
-==== invokeMethod (TBD)
-==== get/setProperty (TBD)
-==== get/setMetaClass (TBD)
+(TBD)
+
+
+=== GroovyObject interface (MaksymStavytskyi)
+==== invokeMethod
+
+(TBD)
+
+==== get/setProperty
+
+(TBD)
+
+==== get/setMetaClass
+
+(TBD)
+
+
+=== get/setAttribute
+
+(TBD)
 
-=== get/setAttribute (TBD)
 
 === methodMissing
 
@@ -78,8 +93,12 @@ performance.
 `methodMissing` and `propertyMissing` that deal with static methods and properties can be added via
 the <<core-metaprogramming.adoc#metaprogramming_emc,ExpandoMetaClass>>.
 
-=== GroovyInterceptable (TBD)
+=== GroovyInterceptable
+
+(TBD)
 
+
+[[categories]]
 === Categories
 
 There are situations where it is useful if a class _not_ under control had additional methods. In order to enable this
@@ -91,9 +110,9 @@ pre-defined rules for defining extension methods.
 There are a few categories that are included in the system for adding functionality to classes that make them more
 usable within the Groovy environment:
 
-* http://groovy.codehaus.org/api/groovy/time/TimeCategory.html[groovy.time.TimeCategory]
-* http://groovy.codehaus.org/api/groovy/servlet/ServletCategory.html[groovy.servlet.ServletCategory]
-* http://groovy.codehaus.org/api/groovy/xml/dom/DOMCategory.html[groovy.xml.dom.DOMCategory]
+* gapi:groovy.time.TimeCategory[]
+* gapi:groovy.servlet.ServletCategory[]
+* gapi:groovy.xml.dom.DOMCategory[]
 
 Category classes aren't enabled by default. To use the methods defined in a category class it is necessary to apply
 the scoped `use` method that is provided by the GDK and available from inside every Groovy object instance:
@@ -193,11 +212,26 @@ first parameter. The target type class is given as an argument to the annotation
 [NOTE]
 There is a distinct section on `@Category` in the <<core-metaprogramming.adoc#xform-Category,compile-time metaprogramming section>>.
 
-=== Metaclasses (TBD)
-==== Custom metaclasses (TBD)
-===== Delegating metaclass (TBD)
-===== Magic package (TBD)
-==== Per instance metaclass (TBD)
+=== Metaclasses
+
+(TBD)
+
+==== Custom metaclasses
+
+(TBD)
+
+===== Delegating metaclass
+
+(TBD)
+
+===== Magic package
+
+(TBD)
+
+==== Per instance metaclass
+
+(TBD)
+
 
 [[metaprogramming_emc]]
 ==== ExpandoMetaClass
@@ -514,7 +548,7 @@ your extension helper classes. You must create a file named
 
 .org.codehaus.groovy.runtime.ExtensionModule
 --------------------------------------------------------
-include::{projectdir}/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule[tags=extension_descriptor,indent=0]
+include::{projectdir}/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModuleSpec[tags=extension_descriptor,indent=0]
 --------------------------------------------------------
 
 The module descriptor requires 4 keys:
@@ -603,7 +637,7 @@ include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=tostring_simple,indent=0]
 ----
 
-With this definition, then the following assertion passes, meaning that a `toString` method taking the field valuess from
+With this definition, then the following assertion passes, meaning that a `toString` method taking the field values from
 the class and printing them out has been generated:
 
 [source,groovy]
@@ -636,6 +670,11 @@ include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=
 ----
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=tostring_example_includeSuper,indent=0]
 ----
+|includeSuperProperties|False|Should super properties be included in toString|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=tostring_example_includeSuperProperties,indent=0]
+----
 |includeFields|False|Should fields be included in toString, in addition to properties|
 [source,groovy]
 ----
@@ -763,7 +802,7 @@ include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=tupleconstructor_example_callSuper,indent=0]
 ----
 |force|False|By default, the transformation will do nothing if a constructor is already defined. Setting this property
-to true, the constructor will be generated and it's your responsability to ensure that no duplicate constructor
+to true, the constructor will be generated and it's your responsibility to ensure that no duplicate constructor
 is defined|See javadocs
 |=======================================================================
 
@@ -801,13 +840,30 @@ include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=
 ===== @groovy.transform.InheritConstructors
 
 The `@InheritConstructor` AST transformation aims at generating constructors matching super constructors for you. This
-is in particular useful when overridding exception classes:
+is in particular useful when overriding exception classes:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=inheritconstructors_simple,indent=0]
 ----
 
+The `@InheritConstructor` AST transformation supports the following configuration options:
+
+[cols="1,1,2,3a",options="header"]
+|=======================================================================
+|Attribute|Default value|Description|Example
+|constructorAnnotations|False|Whether to carry over annotations from the constructor during copying|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=inheritconstructors_constructor_annotations,indent=0]
+----
+|parameterAnnotations|False|Whether to carry over annotations from the constructor parameters when copying the constructor|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=inheritconstructors_parameter_annotations,indent=0]
+----
+|=======================================================================
+
 [[xform-Category]]
 ===== @groovy.lang.Category
 
@@ -819,7 +875,7 @@ written like this:
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=oldstyle_category,indent=0]
 ----
 
-The `@Category` transformation lets you write the same using an instance-style class, rather that a static class style.
+The `@Category` transformation lets you write the same using an instance-style class, rather than a static class style.
 This removes the need for having the first argument of each method being the receiver. The category can be written like
 this:
 
@@ -1132,6 +1188,14 @@ from `@Canonical` will be re-used for `@Builder`. Here is an example using `@Bui
 include::{projectdir}/src/spec/test/CodeGenerationASTTransformsTest.groovy[tags=builder_initializer_immutable,indent=0]
 ----
 
+This strategy also supports annotating static methods and constructors. In this case, the static method or constructor
+parameters become the properties to use for building purposes and in the case of static methods, the return type
+of the method becomes the target class being built. If you have more than one `@Builder` annotation used within
+a class (at either the class, method or constructor positions) then it is up to you to ensure that the generated
+helper classes and factory methods have unique names (i.e. no more than one can use the default name values).
+For an example of method and constructor usage but using the `DefaultStrategy` strategy, consult that strategy's
+documentation.
+
 The annotation attribute `forClass` is not supported for this strategy.
 
 ==== Class design annotations
@@ -1494,8 +1558,8 @@ include::{projectdir}/src/spec/test/DeclarativeConcurrencyASTTransformsTest.groo
 
 For details
 
-* See Javadoc for gapi::groovy.transform.WithReadLock
-* See Javadoc for gapi::groovy.transform.WithWriteLock
+* See Javadoc for gapi:groovy.transform.WithReadLock[]
+* See Javadoc for gapi:groovy.transform.WithWriteLock[]
 
 ==== Easier cloning and externalizing
 
@@ -1512,7 +1576,7 @@ The `@AutoClone` annotation is aimed at implementing the `@java.lang.Cloneable`
 * the `AutoCloneStyle.COPY_CONSTRUCTOR` strategy creates and uses a copy constructor
 * the `AutoCloneStyle.SERIALIZATION` strategy uses serialization (or externalization) to clone the object
 
-Each of those strategies have pros and cons which are discussed in the Javadoc for gapi::groovy.transform.AutoClone and gapi::groovy.transform.AutoCloneStyle .
+Each of those strategies have pros and cons which are discussed in the Javadoc for gapi:groovy.transform.AutoClone[] and gapi:groovy.transform.AutoCloneStyle[] .
 
 For example, the following example:
 
@@ -1536,7 +1600,7 @@ In addition to cloning styles, `@AutoClone` supports multiple options:
 |=======================================================================
 |Attribute|Default value|Description|Example
 |excludes|Empty list|A list of property or field names that need to be excluded from cloning. A string consisting of a comma-separated field/property names is also allowed.
-See gapi::groovy.transform.AutoClone#excludes for details|
+See gapi:groovy.transform.AutoClone#excludes[] for details|
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CloningASTTransformsTest.groovy[tags=example_autoclone_excludes,indent=0]
@@ -1573,7 +1637,7 @@ The `@AutoExternalize` annotation supports two parameters which will let you sli
 |=======================================================================
 |Attribute|Default value|Description|Example
 |excludes|Empty list|A list of property or field names that need to be excluded from externalizing. A string consisting of a comma-separated field/property names is also allowed.
-See gapi::groovy.transform.AutoExternalize#excludes for details|
+See gapi:groovy.transform.AutoExternalize#excludes[] for details|
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CloningASTTransformsTest.groovy[tags=example_autoext_excludes,indent=0]
@@ -1588,7 +1652,7 @@ include::{projectdir}/src/spec/test/CloningASTTransformsTest.groovy[tags=example
 
 ==== Safer scripting
 
-The Groovy language makes it easy to execute user scripts at runtime (for example using gapi::groovy.lang.GroovyShell),
+The Groovy language makes it easy to execute user scripts at runtime (for example using gapi:groovy.lang.GroovyShell[]),
 but how do you make sure that a script won't eat all CPU (infinite loops) or that concurrent scripts won't slowly consume
 all available threads of a thread pool? Groovy provides several annotations which are aimed towards safer scripting,
 generating code which will for example allow you to interrupt execution automatically.
@@ -1599,7 +1663,7 @@ generating code which will for example allow you to interrupt execution automati
 One complicated situation in the JVM world is when a thread can't be stopped. The `Thread#stop` method exists but is
 deprecated (and isn't reliable) so your only chance relies in `Thread#interrupt`. Calling the latter will set the
 `interrupt` flag on the thread, but it will *not* stop the execution of the thread. This is problematic because it's the
-responsability of the code executing in the thread to check the interrupt flag and properly exit. This makes sense when
+responsibility of the code executing in the thread to check the interrupt flag and properly exit. This makes sense when
 you, as a developer, know that the code you are executing is meant to be run in an independent thread, but in general,
 you don't know it. It's even worse with user scripts, who might not even know what a thread is (think of DSLs).
 
@@ -1620,7 +1684,7 @@ This is an obvious infinite loop. If this code executes in its own thread, inter
 the thread, then the calling code would be able to continue, but the thread would still be alive, running in background
 without any ability for you to stop it, slowly causing thread starvation.
 
-One possibility to work around this is to setup your shell this way:
+One possibility to work around this is to set up your shell this way:
 
 [source,groovy]
 ----
@@ -1655,19 +1719,19 @@ exception will be thrown, interrupting the execution of the thread.
 ----
 include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=threadinterrupt_thrown,indent=0]
 ----
-|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi::groovy.transform.ThreadInterrupt for details.|
+|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi:groovy.transform.ThreadInterrupt[] for details.|
 [source,groovy]
 ----
 @ThreadInterrupt(checkOnMethodStart=false)
 ----
-|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi::groovy.transform.ThreadInterrupt for details.|
+|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi:groovy.transform.ThreadInterrupt[] for details.|
 [source,groovy]
 ----
 @ThreadInterrupt(applyToAllClasses=false)
 class A { ... } // interrupt checks added
 class B { ... } // no interrupt checks
 ----
-|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi::groovy.transform.ThreadInterrupt for details.|
+|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi:groovy.transform.ThreadInterrupt[] for details.|
 [source,groovy]
 ----
 class A {
@@ -1734,19 +1798,19 @@ include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=
 ----
 include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=timedinterrupt_thrown,indent=0]
 ----
-|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi::groovy.transform.TimedInterrupt for details.|
+|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi:groovy.transform.TimedInterrupt[] for details.|
 [source,groovy]
 ----
 @TimedInterrupt(checkOnMethodStart=false)
 ----
-|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi::groovy.transform.TimedInterrupt for details.|
+|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi:groovy.transform.TimedInterrupt[] for details.|
 [source,groovy]
 ----
 @TimedInterrupt(applyToAllClasses=false)
 class A { ... } // interrupt checks added
 class B { ... } // no interrupt checks
 ----
-|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi::groovy.transform.TimedInterrupt for details.|
+|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi:groovy.transform.TimedInterrupt[] for details.|
 [source,groovy]
 ----
 class A {
@@ -1786,7 +1850,7 @@ include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=
 ----
 
 Of course, in practice, it is unlikely that `@ConditionalInterrupt` will be itself added by hand on user code. It can be injected in a similar manner as the example shown in the
-<<xform-ThreadInterrupt,ThreadInterrupt>> section, using the gapi::org.codehaus.groovy.control.customizers.ASTTransformationCustomizer :
+<<xform-ThreadInterrupt,ThreadInterrupt>> section, using the gapi:org.codehaus.groovy.control.customizers.ASTTransformationCustomizer[] :
 
 [source,groovy]
 ----
@@ -1808,19 +1872,19 @@ include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=
 ----
 include::{projectdir}/src/spec/test/SaferScriptingASTTransformsTest.groovy[tags=conditionalinterrupt_thrown,indent=0]
 ----
-|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi::groovy.transform.ConditionalInterrupt for details.|
+|checkOnMethodStart|true|Should an interruption check be inserted at the beginning of each method body. See gapi:groovy.transform.ConditionalInterrupt[] for details.|
 [source,groovy]
 ----
 @ConditionalInterrupt(checkOnMethodStart=false)
 ----
-|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi::groovy.transform.ConditionalInterrupt for details.|
+|applyToAllClasses|true|Should the transformation be applied on all classes of the same source unit (in the same source file). See gapi:groovy.transform.ConditionalInterrupt[] for details.|
 [source,groovy]
 ----
 @ConditionalInterrupt(applyToAllClasses=false)
 class A { ... } // interrupt checks added
 class B { ... } // no interrupt checks
 ----
-|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi::groovy.transform.ConditionalInterrupt for details.|
+|applyToAllMembers|true|Should the transformation be applied on all members of class. See gapi:groovy.transform.ConditionalInterrupt[] for details.|
 [source,groovy]
 ----
 class A {
@@ -1857,7 +1921,7 @@ equivalent to this:
 include::{projectdir}/src/spec/test/CompilerDirectivesASTTransformsTest.groovy[tags=field_missing_property_equiv,indent=0]
 ----
 
-So `def x` is effectiveley interpreted as a local variable, outside of the scope of the `line` method. The `@Field` AST transformation aims at fixing this
+So `def x` is effectively interpreted as a local variable, outside of the scope of the `line` method. The `@Field` AST transformation aims at fixing this
 by changing the scope of the variable to a field of the enclosing script:
 
 [source,groovy]
@@ -1889,6 +1953,20 @@ Should you want to create a package private field instead of a property (private
 include::{projectdir}/src/spec/test/CompilerDirectivesASTTransformsTest.groovy[tags=packagescope_property_javalike,indent=0]
 ----
 
+The `@PackageScope` annotation can also be used for classes, methods and constructors. In addition, by specifying a list
+of `PackageScopeTarget` values as the annotation attribute at the class level, all members within that class that don't
+have an explicit modifier and match the provided `PackageScopeTarget` will remain package protected. For example to apply
+to fields within a class use the following annotation:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/CompilerDirectivesASTTransformsTest.groovy[tags=packagescope_property_usingtarget,indent=0]
+----
+
+The `@PackageScope` annotation is seldom used as part of normal Groovy conventions but is sometimes useful
+for factory methods that should be visible internally within a package or for methods or constructors provided
+for testing purposes, or when integrating with third-party libraries which require such visibility conventions.
+
 [[xform-AnnotationCollector]]
 ===== @groovy.transform.AnnotationCollector
 
@@ -1913,7 +1991,7 @@ include::{projectdir}/src/spec/test/CompilerDirectivesASTTransformsTest.groovy[t
 ===== @groovy.lang.DelegatesTo
 
 `@DelegatesTo` is not, technically speaking, an AST transformation. It is aimed at documenting code and helping the compiler in case you are
-using <<xform-TypeChecked,type checking>> or <<xform-CompileStatic, static compilation>>. The annotation is described throughfully in the
+using <<xform-TypeChecked,type checking>> or <<xform-CompileStatic, static compilation>>. The annotation is described thoroughly in the
 <<section-delegatesto,DSL section>> of this guide.
 
 ==== Swing patterns
@@ -2027,7 +2105,7 @@ placed on any annotable node and requires two parameters:
 * _phase_: sets at which phase at which `@ASTTest` will be triggered. The test code will work on the AST tree at the end of this phase.
 * _value_: the code which will be executed once the phase is reached, on the annotated node
 
-TIP: Compile phase has to be chosen from one of gapi::org.codehaus.groovy.control.CompilePhase . However, since it is not possible to annotate a node twice with the same annotation, you will
+TIP: Compile phase has to be chosen from one of gapi:org.codehaus.groovy.control.CompilePhase[] . However, since it is not possible to annotate a node twice with the same annotation, you will
 not be able to use `@ASTTest` on the same node at two distinct compile phases.
 
 `value` is a closure expression which has access to a special variable `node` corresponding to the annotated node, and a helper `lookup` method which will be discussed <<asttest-lookup,here>>.
@@ -2043,7 +2121,7 @@ include::{projectdir}/src/spec/test/TestingASTTransformsTest.groovy[tags=asttest
 
 One interesting feature of `@ASTTest` is that if an assertion fails, then *compilation will fail*. Now imagine that we want to check the behavior of an AST transformation at compile time.
 We will take `@PackageScope` here, and we will want to verify that a property annotated with `@PackageScope` becomes a package private field. For this, we have to know at which phase the
-transform runs, which can be found in gapi::org.codehaus.groovy.transform.PackageScopeASTTransformation : semantic analysis. Then a test can be written like this:
+transform runs, which can be found in gapi:org.codehaus.groovy.transform.PackageScopeASTTransformation[] : semantic analysis. Then a test can be written like this:
 
 [source,groovy]
 ----
@@ -2069,6 +2147,33 @@ Imagine, for example, that you want to test the declared type of a for loop vari
 include::{projectdir}/src/spec/test/TestingASTTransformsTest.groovy[tags=asttest_forloop,indent=0]
 ----
 
+`@ASTTest` also exposes those variables inside the test closure:
+
+* `node` corresponds to the annotated node, as usual
+* `compilationUnit` gives access to the current `org.codehaus.groovy.control.CompilationUnit`
+* `compilePhase` returns the current compile phase (`org.codehaus.groovy.control.CompilePhase`)
+
+The latter is interesting if you don't specify the `phase` attribute. In that case, the closure will be executed after
+each compile phase after (and including) `SEMANTIC_ANALYSIS`. The context of the transformation is kept after each phase,
+giving you a chance to check what changed between two phases.
+
+As an example, here is how you could dump the list of AST transformations registered on a class node:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TestingASTTransformsTest.groovy[tags=dump_ast_xforms,indent=0]
+----
+
+And here is how you can memorize variables for testing between two phases:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TestingASTTransformsTest.groovy[tags=memorize_in_binding,indent=0]
+----
+<1> if the current compile phase is instruction selection
+<2> then we want to make sure `toString` was added at `CANONICALIZATION`
+<3> otherwise, if `toString` exists and that the variable from the context, `added` is null
+<4> then it means that this compile phase is the one where `toString` was added
 
 ==== Grape handling
 [[xform-Grab]]
@@ -2083,12 +2188,322 @@ include::{projectdir}/src/spec/test/TestingASTTransformsTest.groovy[tags=asttest
 ===== @groovy.lang.Grapes
 
 `Grape` is a dependency management engine embedded into Groovy, relying on several annotations which are described
-throughfully in this <<section-grape,section of the guide>>.
+thoroughly in this <<section-grape,section of the guide>>.
 
 [[developing-ast-xforms]]
-=== Developing AST transformations (TBD)
-==== Compilation phases guide (TBD)
-==== Local transformations (TBD)
-==== Global transformations (TBD)
-==== AST API guide (TBD)
-==== Testing AST transformations (TBD)
+=== Developing AST transformations
+
+There are two kinds of transformations: global and local transformations.
+
+* <<transforms-global,Global transformations>> are applied to by the compiler on the code being compiled,
+wherever the transformation apply. Compiled classes that implement global transformations
+are in a JAR added to the classpath of the compiler and contain service locator file
+`META-INF/services/org.codehaus.groovy.transform.ASTTransformation` with a line with the name of the
+transformation class. The transformation class must have a no-args constructor and implement the
+`org.codehaus.groovy.transform.ASTTransformation` interface.
+It will be run against *every source in the compilation*, so be sure to not create transformations which
+scan all the AST in an expansive and time-consuming manner, to keep the compiler fast.
+* <<transforms-local,Local transformations>> are transformations applied locally by annotating code elements you want to
+transform. For this, we reuse the annotation notation, and those annotations should implement
+`org.codehaus.groovy.transform.ASTTransformation`. The compiler will discover them and apply the
+transformation on these code elements.
+
+==== Compilation phases guide
+
+Groovy AST transformations must be performed in one of the nine defined
+compilation phases (gapi:org.codehaus.groovy.control.CompilePhase[]).
+
+Global transformations may be applied in any phase, but local
+transformations may only be applied in the semantic analysis phase or
+later. Briefly, the compiler phases are:
+
+* _Initialization_: source files are opened and environment configured
+* _Parsing_: the grammar is used to to produce tree of tokens representing
+the source code
+* _Conversion_: An abstract syntax tree (AST) is created from token trees.
+* _Semantic Analysis_: Performs consistency and validity checks that the
+grammar can’t check for, and resolves classes.
+* _Canonicalization_: Complete building the AST
+* _Instruction Selection_: instruction set is chosen, for example Java 6 or Java 7 bytecode level
+* _Class Generation_: creates the bytecode of the class in memory
+* _Output_: write the binary output to the file system
+* _Finalization_: Perform any last cleanup
+
+Generally speaking, there is more type information available later in
+the phases. If your transformation is concerned with reading the AST,
+then a later phase where information is more plentiful might be a good
+choice. If your transformation is concerned with writing AST, then an
+earlier phase where the tree is more sparse might be more convenient.
+
+[[transforms-local]]
+==== Local transformations
+
+Local AST transformations are relative to the context they are applied to. In
+most cases, the context is defined by an annotation that will define the scope
+of the transform. For example, annotating a field would mean that the transformation
+_applies to_ the field, while annotating the class would mean that the transformation
+_applies to_ the whole class.
+
+As a naive and simple example, consider wanting to write a `@WithLogging`
+transformation that would add console messages at the start and end of a
+method invocation. So the following "Hello World" example would
+actually print "Hello World" along with a start and stop message:
+
+[source,groovy]
+.Poor man's aspect oriented programming
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_example,indent=0]
+----
+
+A local AST transformation is an easy way to do this. It requires two things:
+
+* a definition of the `@WithLogging` annotation
+* an implementation of gapi:org.codehaus.groovy.transform.ASTTransformation[] that adds the logging
+expressions to the method
+
+An `ASTTransformation` is a callback that gives you access to the
+gapi:org.codehaus.groovy.control.SourceUnit[],
+through which you can get a reference to the
+gapi:org.codehaus.groovy.ast.ModuleNode[] (AST).
+
+The AST (Abstract Syntax Tree) is a tree structure consisting mostly of
+gapi:org.codehaus.groovy.ast.expr.Expression[] (expressions) or
+gapi:org.codehaus.groovy.ast.expr.Statement[] (statements). An easy way to
+learn about the AST is to explore it in a debugger. Once you have the AST,
+you can analyze it to find out information about the code or rewrite it to add
+new functionality.
+
+The local transformation annotation is the simple part. Here is the
+`@WithLogging` one:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_ann,indent=0]
+----
+
+The annotation retention can be `SOURCE` because you won’t need the annotation
+past that. The element type here is `METHOD`, the `@WithLogging` because the annotation
+applies to methods.
+
+But the most important part is the
+`@GroovyASTTransformationClass` annotation. This links the `@WithLogging`
+annotation to the `ASTTransformation` class you will write.
+`gep.WithLoggingASTTransformation` is the fully qualified class name of the
+`ASTTransformation` we are going to write. This line wires the annotation to the transformation.
+
+With this in place, the Groovy compiler is going to invoke
+`gep.WithLoggingASTTransformation` every time an `@WithLogging` is found in a
+source unit. Any breakpoint set within `LoggingASTTransformation` will now
+be hit within the IDE when running the sample script.
+
+The `ASTTransformation` class is a little more complex. Here is the
+very simple, and very naive, transformation to add a method start and
+stop message for `@WithLogging`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_xform,indent=0]
+----
+<1> even if not mandatory, if you write an AST transformation in Groovy, it is highly recommended to use `CompileStatic`
+because it will improve performance of the compiler.
+<2> annotate with gapi:org.codehaus.groovy.transform.GroovyASTTransformation[] to tell at which compilation phase the
+transform needs to run. Here, it's at the _semantic analysis_ phase.
+<3> implement the `ASTTransformation` interface
+<4> which only has a single `visit` method
+<5> the `nodes` parameter is a 2 AST node array, for which the first one is the annotation node (`@WithLogging`) and
+the second one is the annotated node (the method node)
+<6> create a statement that will print a message when we enter the method
+<7> create a statement that will print a message when we exit the method
+<8> get the method body, which in this case is a `BlockStatement`
+<9> add the enter method message before the first statement of existing code
+<10> append the exit method message after the last statement of existing code
+<11> creates an `ExpressionStatement` wrapping a `MethodCallExpression` corresponding to `this.println("message")`
+
+It is important to notice that for the brevity of this example, we didn't make the necessary checks, such as checking
+that the annotated node is really a `MethodNode`, or that the method body is an instance of `BlockStatement`. This
+exercise is left to the reader.
+
+Note the creation of the new println statements in the
+`createPrintlnAst(String)` method. Creating AST for code is not always
+simple. In this case we need to construct a new method call, passing in
+the receiver/variable, the name of the method, and an argument list.
+When creating AST, it might be helpful to write the code you’re trying
+to create in a Groovy file and then inspect the AST of that code in the
+debugger to learn what to create. Then write a function like
+`createPrintlnAst` using what you learned through the debugger.
+
+In the end:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_example,indent=0]
+----
+
+Produces:
+
+--------------
+Starting greet
+Hello World
+Ending greet
+--------------
+
+NOTE: It is important to note that an AST transformation participates directly in the compilation process. A common
+error by beginners is to have the AST transformation code in the same source tree as a class that uses the transformation.
+Being in the same source tree in general means that they are compiled at the same time. Since the transformation itself
+is going to be compiled in phases and that each compile phase processes all files of the same source unit before going
+to the next one, there's a direct consequence: the transformation will not be compiled before the class that uses it! In
+conclusion, AST transformations need to be precompiled before you can use them. In general, it is as easy as having them
+in a separate source tree.
+
+[[transforms-global]]
+==== Global transformations
+
+Global AST transformation are similar to local one with a major difference: they do not need an annotation, meaning that
+they are applied _globally_, that is to say on each class being compiled. It is therefore very important to limit their
+use to last resort, because it can have a significant impact on the compiler performance.
+
+Following the example of the <<transform-local, local AST transformation>>, imagine that we would like to trace all
+methods, and not only those which are annotated with `@WithLogging`. Basically, we need this code to behave the same
+as the one annotated with `@WithLogging` before:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_example_global,indent=0]
+----
+
+To make this work, there are two steps:
+
+. create the `org.codehaus.groovy.transform.ASTTransformation` descriptor inside the `META-INF/services` directory
+. create the `ASTTransformation` implementation
+
+The descriptor file is required and must be found on classpath. It will contain a single line:
+
+[source,groovy]
+.META-INF/services/org.codehaus.groovy.transform.ASTTransformation
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=xform_descriptor_file,indent=0]
+----
+
+The code for the transformation looks similar to the local case, but instead of using the `ASTNode[]` parameter, we need
+to use the `SourceUnit` instead:
+
+[source,groovy]
+.gep/WithLoggingASTTransformation.groovy
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=withlogging_xform_global,indent=0]
+----
+<1> even if not mandatory, if you write an AST transformation in Groovy, it is highly recommended to use `CompileStatic`
+because it will improve performance of the compiler.
+<2> annotate with gapi:org.codehaus.groovy.transform.GroovyASTTransformation[] to tell at which compilation phase the
+transform needs to run. Here, it's at the _semantic analysis_ phase.
+<3> implement the `ASTTransformation` interface
+<4> which only has a single `visit` method
+<5> the `sourceUnit` parameter gives access to the source being compiled, so we get the AST of the current source
+and retrieve the list of methods from this file
+<6> we iterate on each method from the source file
+<7> create a statement that will print a message when we enter the method
+<8> create a statement that will print a message when we exit the method
+<9> get the method body, which in this case is a `BlockStatement`
+<10> add the enter method message before the first statement of existing code
+<11> append the exit method message after the last statement of existing code
+<12> creates an `ExpressionStatement` wrapping a `MethodCallExpression` corresponding to `this.println("message")`
+
+==== AST API guide
+===== AbstractASTTransformation
+
+While you have seen that you can directly implement the `ASTTransformation` interface, in almost all cases you will not
+do this but extend the gapi:org.codehaus.groovy.transform.AbstractASTTransformation[] class. This class provides several
+utility methods that make AST transformations easier to write. Almost all AST transformations included in Groovy
+extend this class.
+
+===== ClassCodeExpressionTransformer
+
+It is a common use case to be able to transform an expression into another. Groovy provides a class which makes it
+very easy to do this: gapi:org.codehaus.groovy.ast.ClassCodeExpressionTransformer[]
+
+To illustrate this, let's create a `@Shout` transformation that will transform all `String` constants in method call
+arguments into their uppercase version. For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=shout_example,indent=0]
+----
+
+should print:
+
+----
+HELLO WORLD
+----
+
+Then the code for the transformation can use the `ClassCodeExpressionTransformer` to make this easier:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=shout_xform,indent=0]
+----
+<1> Internally the transformation creates a `ClassCodeExpressionTransformer`
+<2> The transformer needs to return the source unit
+<3> if a constant expression of type string is detected inside an argument list, transform it into its upper case version
+<4> call the transformer on the method being annotated
+
+===== AST Nodes
+
+WARNING: Writing an AST transformation requires a deep knowledge of the internal Groovy API. In particular it requires
+knowledge about the AST classes. Since those classes are internal, there are chances that the API will change in the
+future, meaning that your transformations _could_ break. Despite that warning, the AST has been very stable over time
+and such a thing rarely happens.
+
+Classes of the Abstract Syntax Tree belong to the `org.codehaus.groovy.ast` package. It is recommended to the reader
+to use the Groovy Console, in particular the AST browser tool, to gain knowledge about those classes. However, a good
+resource for learning is the https://github.com/groovy/groovy-core/tree/master/src/test/org/codehaus/groovy/ast/builder[AST Builder]
+test suite.
+
+==== Testing AST transformations
+===== Separating source trees
+
+This section is about good practices with regards to testing AST transformations. Previous sections highlighted the fact
+that to be able to execute an AST transformation, it has to be precompiled. It might sound obvious but a lot of people
+get caught on this, trying to use an AST transformation in the same source tree as where it is defined.
+
+The first tip for testing AST transformation is therefore to separate test sources from the sources of the transform.
+Again, this is nothing but best practices, but you must make sure that your build too does actually compile them separately.
+This is the case by default with both http://maven.apache.org[Apache Maven] and http://gradle.org[Gradle].
+
+===== Debugging AST transformations
+
+It is very handy to be able to put a breakpoint in an AST transformation, so that you can debug your code in the IDE.
+However, you might be surprised to see that your IDE doesn't stop on the breakpoint. The reason is actually simple: if
+your IDE uses the Groovy compiler to compile the unit tests for your AST transformation, then the compilation is triggered
+from the IDE, but the process which will compile the files doesn't have debugging options. It's only when the test case
+is executed that the debugging options are set on the virtual machine. In short: it is too late, the class has been compiled
+already, and your transformation is already applied.
+
+A very easy workaround is to use the `GroovyTestCase` class which provides an `assertScript` method. This means that
+instead of writing this in a test case:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=breakpoint_missed,indent=0]
+----
+
+You should write:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy[tags=breakpoint_hit,indent=0]
+----
+
+The difference is that when you use `assertScript`, the code in the `assertScript` block is compiled *when the
+unit test is executed*. That is to say that this time, the `Subject` class will be compiled with debugging active, and
+the breakpoint is going to be hit.
+
+===== ASTTest
+
+Last but not least, testing an AST transformation is also about testing the state of the AST *during compilation*. Groovy
+provides a tool named `@ASTTest` for this: it is an annotation that will let you add assertions on an abstract syntax
+tree. Please check the <<xform-ASTTest,documentation for ASTTest>> for more details.
+
+==== External references
+
+If you are interested in a step-by-step tutorial about writing AST transformations, you can follow
+http://melix.github.io/ast-workshop/[this workshop].
\ No newline at end of file
diff --git a/src/spec/doc/core-object-orientation.adoc b/src/spec/doc/core-object-orientation.adoc
index bc43008..46498b8 100644
--- a/src/spec/doc/core-object-orientation.adoc
+++ b/src/spec/doc/core-object-orientation.adoc
@@ -1,49 +1,759 @@
 = Object orientation
+:jls: http://docs.oracle.com/javase/specs/jls/se8/html/
 
 This chapter covers the object orientation of the Groovy programming language.
 
-== Types (TBD)
+== Types
 
-=== Primitive types (TBD)
+=== Primitive types
 
-=== Class (TBD)
-==== Normal class (TBD)
-==== Static class (TBD)
-==== Inner class (TBD)
-===== Anonymous inner class (TBD)
-==== Abstract class (TBD)
+Groovy supports the same primitive types as those defined by the {jls}[Java Language Specification]:
 
-=== Interface (TBD)
+* integral types: `byte` (8 bit), `short` (16 bit), `int` (32 bit) and `long` (64 bit)
+* floating-point types: `float` (32 bit) and `double` (64 bit)
+* `boolean` type (exactly `true` or `false`)
+* `char` type (16 bit, usable as a numeric type, representing an UTF-16 code)
 
-=== Annotation (TBD)
+=== Class
 
-==== Closure annotation parameters (TBD)
-==== Meta-annotations (TBD)
-==== Annotation placement (TBD)
+Groovy classes are very similar to Java classes, being compatible to those ones at JVM level. They may have methods and fields/properties, which can have the same modifiers (public, protected, private, static, etc) as Java classes.
 
-=== Constructors (TBD)
+Here are key aspects of Groovy classes, that are different from their Java counterparts:
 
-==== Named argument constructor (TBD)
+* Public fields are turned into properties automatically, which results in less verbose code,
+without so many getter and setter methods. More on this aspect will be covered in the <<fields,fields and properties section>>.
+* Their declarations and any property or method without an access modifier are public.
+* Classes do not need to have the same name of the files where they are defined.
+* One file may contain one or more classes (but if a file contains no classes, it is considered a script).
 
-=== Methods (TBD)
+The following code presents an example class.
 
-==== Method definition (TBD)
-==== Named arguments (TBD)
-==== Default arguments (TBD)
-==== Varargs (TBD)
-==== Method selection algorithm (TBD)
-==== Exception declaration (TBD)
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=class_definition,indent=0]
+----
+<1> class beginning, with the name `Person`
+<2> string field and property named `name`
+<3> method definition
 
-=== Fields and properties (TBD)
 
-==== Fields (TBD)
-==== Properties (TBD)
+==== Normal class
+
+Normal classes refer to classes which are top level and concrete. This means they can be instantiated without restrictions from any other classes or scripts. This way, they can only be public (even though the `public` keyword may be supressed). Classes are instantiated by calling their constructors, using the `new` keyword, as in the following snippet.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=class_instantiation,indent=0]
+----
+
+
+==== Inner class
+
+Inner classes are defined within another classes. The enclosing class can use the inner class as usual. On the other side, a inner class can access members of its enclosing class, even if they are private. Classes other than the enclosing class are not allowed to access inner classes. Here is an example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=inner_class,indent=0]
+----
+<1> the inner class is instantiated and its method gets called
+<2> inner class definition, inside its enclosing class
+<3> even being private, a field of the enclosing class is accessed by the inner class
+
+There are some reasons for using inner classes:
+
+ * They increase encapsulation by hiding the inner class from other classes, which do not need to know about it. This also leads to cleaner packages and workspaces.
+ * They provide a good organization, by grouping classes that are used by only one class.
+ * They lead to more maintainable codes, since inner classes are near the classes that use them.
+
+In several cases, inner classes are implementation of interfaces whose methods are needed by the outer class. The code below illustrates this with the usage of threads, which are very common.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=inner_class2,indent=0]
+----
+
+Note that the class `Inner2` is defined only to provide an implementation of the method `run` to class `Outer2`. Anonymous inner classes help to eliminate verbosity in this case.
+
+
+===== Anonymous inner class
+
+The last example of inner class can be simplified with an anonymous inner class. The same functionality can be achieved with the following code.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=anonymous_inner_class,indent=0]
+----
+<1> comparing with the last example of previous section, the `new Inner2()` was replaced by `new Runnable()` along with all its implementation
+<2> the method `start` is invoked normally
+
+Thus, there was no need to define a new class to be used just once.
+
+
+==== Abstract class
+
+Abstract classes represent generic concepts, thus, they cannot be instantiated, being created to be subclassed. Their members include fields/properties and abstract or concrete methods. Abstract methods do not have implementation, and must be implemented by concrete subclasses.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=abstract_class,indent=0]
+----
+<1> abstract classes must be declared with `abstract` keyword
+<2> abstract methods must also be declared with `abstract` keyword
+
+Abstract classes are commonly compared to interfaces. But there are at least two important differences of choosing one or another. First, while abstract classes may contain fields/properties and concrete methods, interfaces may contain only abstract methods (method signatures). Moreover, one class can implement several interfaces, whereas it can extend just one class, abstract or not. 
+
+=== Interface
+
+An interface defines a contract that a class needs to conform to. An interface only defines a list of methods that need
+to be implemented, but does not define the methods implementation.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=interface_def_1,indent=0]
+----
+<1> an interface needs to be declared using the `interface` keyword
+<2> an interface only defines method signatures
+
+Methods of an interface are always *public*. It is an error to use `protected` or `private` methods in interfaces:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=protected_forbidden,indent=0]
+----
+<1> Using `protected` is a compile-time error
+
+A class _implements_ an interface if it defines the interface in its `implements` list or if any of its superclasses
+does:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=class_implements,indent=0]
+----
+<1> The `SystemGreeter` declares the `Greeter` interface using the `implements` keyword
+<2> Then implements the required `greet` method
+<3> Any instance of `SystemGreeter` is also an instance of the `Greeter` interface
+
+An interface can extend another interface:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=class_implements,indent=0]
+----
+<1> the `ExtendedGreeter` interface extends the `Greeter` interface using the `extends` keyword
+
+It is worth noting that for a class to be an instance of an interface, it has to be explicit. For example, the following
+class defines the `greet` method as it is declared in the `Greeter` interface, but does not declare `Greeter` in its
+interfaces:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=no_structural_interface,indent=0]
+----
+
+In other words, Groovy does not define structural typing. It is however possible to make an instance of an object
+implement an interface at runtime, using the `as` coercion operator:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=interface_coercion,indent=0]
+----
+<1> create an instance of `DefaultGreeter` that does not implement the interface
+<2> coerce the instance into a `Greeter` at runtime
+<3> the coerced instance implements the `Greeter` interface
+
+You can see that there are two distinct objects: one is the source object, a `DefaultGreeter` instance, which does not
+implement the interface. The other is an instance of `Greeter` that delegates to the coerced object.
+
+TIP: Groovy interfaces do not support default implementation like Java 8 interfaces. If you are looking for something
+similar (but not equal), <<_traits,traits>> are close to interfaces, but allow default implementation as well as other
+important features described in this manual.
+
+=== Constructors
+
+Constructors are special methods used to initialize an object with a specific state. As in normal methods, it is possible for a class to declare more than one constructor. In Groovy there are two ways to invoke constructors: with positional parameters or named parameters. The former one is like we invoke Java constructors, while the second way allows one to specify the parameter names when invoking the constructor.
+
+==== Positional argument constructor
+
+To create an object by using positional argument constructors, the respective class needs to declare each of the constructors it allows being called. A side effect of this is that, once at least one constructor is declared, the class can only be instantiated by getting one of its constructors called. It is worth noting that, in this case, there is no way to create the class with named parameters.
+
+There is three forms of using a declared constructor. The first one is the normal Java way, with the `new` keyword. The others rely on coercion of lists into the desired types. In this case, it is possible to coerce with the `as` keyword and by statically typing the variable.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=constructor_positional_parameters,indent=0]
+----
+<1> Constructor declaration
+<2> Constructor invocation, classic Java way
+<3> Constructor usage, using coercion with `as` keyword
+<4> Constructor usage, using coercion in assignment
+
+
+==== Named argument constructor
+
+If no constructor is declared, it is possible to create objects by passing parameters in the form of a map (property/value pairs). This can be in handy in cases where one wants to allow several combinations of parameters. Otherwise, by using traditional positional parameters it would be necessary to declare all possible constructors.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=constructor_named_parameters,indent=0]
+----
+<1> No constructor declared
+<2> No parameters given in the instantiation
+<3> `name` parameter given in the instantiation
+<4> `age` parameter given in the instantiation
+<5> `name` and `age` parameters given in the instantiation
+
+It is important to highlight, however, that this approach gives more power to the constructor caller, while imposes a major responsibility to it. Thus, if a restriction is needed, one can just declare one or more constructors, and the instantiation by named parameters will no longer be available.
+
+
+=== Methods
+
+Groovy methods are quite similar to other languages. Some peculiarities will be shown in the next subsections. 
+
+==== Method definition
+
+A method is defined with a return type or with the `def` keyword, to make the return type untyped. A method can also receive any number of arguments, which may not have their types explicitly declared. Java modifiers can be used normally, and if no visibility modifier is provided, the method is public.
+
+Methods in Groovy always return some value. If no `return` statement is provided, the value evaluated in the last line executed will be returned. For instance, note that none of the following methods uses the `return` keyword.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=method_definition ,indent=0]
+----
+<1> Method with no return type declared and no parameter
+<2> Method with explicit return type and no parameter
+<3> Method with a parameter with no type defined
+<4> Static method with a String parameter
+
+==== Named arguments
+
+Like constructors, normal methods can also be called with named arguments. They need to receive the parameters as a map. In the method body, the values can be accessed as in normal maps (`map.key`).
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=named_arguments ,indent=0]
+----
+
+==== Default arguments
+
+Default arguments make parameters optional. If the argument is not supplied, the method assumes a default value.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=default_arguments ,indent=0]
+----
+
+Note that no mandatory parameter can be defined after a default parameter is present, only other default parameters.
+
+==== Varargs
+
+Groovy supports methods with a variable number of arguments. They are defined like this: `def foo(p1, ..., pn, T... args)`.
+Here `foo` supports `n` arguments by default, but also an unspecified number of further arguments exceeding `n`.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=varargs_example,indent=0]
+----
+
+This example defines a method `foo`, that can take any number of arguments, including no arguments at all.
+`args.length` will return the number of arguments given. Groovy allows `T[]` as a alternative notation to `T...`.
+That means any method with an array as last parameter is seen by Groovy as a method that can take a variable number of arguments.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=varargs_array_notation,indent=0]
+----
+
+If a method with varargs is called with `null` as the vararg parameter, then the argument will be `null` and not an array of length one with `null` as the only element.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=varargs_null_parameter,indent=0]
+----
+
+If a varargs method is called with an array as an argument, then the argument will be that array instead of an array of length one containing the given array as the only element.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=varargs_array_parameter,indent=0]
+----
+
+Another important point are varargs in combination with method overloading. In case of method overloading Groovy will select the most specific method.
+For example if a method `foo` takes a varargs argument of type `T` and another method `foo` also takes one argument of type `T`, the second method is preferred.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/objectorientation/MethodsTest.groovy[tags=varargs_method_overloading,indent=0]
+----
+
+==== Method selection algorithm
+
+(TBD)
+
+==== Exception declaration
+
+(TBD)
+
+
+=== Fields and properties
+
+[[fields]]
+==== Fields
+
+A field is a member of a class or a trait which:
+
+* a mandatory _access modifier_ (`public`, `protected`, or `private`)
+* one or more optional _modifiers_ (`static`, `final`, `synchronized`)
+* an optional _type_
+* a mandatory _name_
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=field_declaration,indent=0]
+----
+<1> a `private` field named `id`, of type `int`
+<2> a `protected` field named `description`, of type `String`
+<3> a `public static final` field named _DEBUG_ of type `boolean`
+
+A field may be initialized directly at declaration:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=field_initialization,indent=0]
+----
+<1> the private field `id` is initialized with `IDGenerator.next()`
+
+It is possible to omit the type declaration of a field. This is however considered a bad practice and in general it
+is a good idea to use strong typing for fields:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=typing_fields,indent=0]
+----
+<1> the field `mapping` doesn't declare a type
+<2> the field `mapping` has a strong type
+
+The difference between the two is important if you want to use optional type checking later. It is also important
+for documentation. However in some cases like scripting or if you want to rely on duck typing it may be interesting
+to omit the type.
+
+[[properties]]
+==== Properties
+
+A property is a combination of a private field and getters/setters. You can define a property with:
+
+* an *absent* access modifier (no `public`, `protected` or `final`)
+* one or more optional _modifiers_ (`static`, `final`, `synchronized`)
+* an optional _type_
+* a mandatory _name_
+
+Groovy will then generate the getters/setters appropriately. For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=properties_definition,indent=0]
+----
+<1> creates a backing `private String name` field, a `getName` and a `setName` method
+<2> creates a backing `private int age` field, a `getAge` and a `setAge` method
+
+If a property is declared `final`, no setter is generated:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=readonly_property,indent=0]
+----
+<1> defines a read-only property of type `String`
+<2> defines a read-only property of type `int`
+<3> assigns the `name` parameter to the `name` field
+<4> assigns the `age` parameter to the `age` field
+
+Properties are accessed by name and will call the getter or setter transparently, unless the code is in the class
+which defines the property:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=property_access,indent=0]
+----
+<1> `this.name` will directly access the field because the property is accessed from within the class that defines it
+<2> similarily a read access is done directly on the `name` field
+<3> write access to the property is done outside of the `Person` class so it will implicitly call `setName`
+<4> read access to the property is done outside of the `Person` class so it will implicitly call `getName`
+<5> this will call the `name` method on `Person` which performs a direct access to the field
+<6> this will call the `wonder` method on `Person` which perfoms a direct read access to the field
+
+It is worth noting that this behavior of accessing the backing field directly is done in order to prevent a stack
+overflow when using the property access syntax within a class that defines the property.
+
+It is possible to list the properties of a class thanks to the meta `properties` field of an instance:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=properties_meta,indent=0]
+----
+
+By convention, Groovy will recognize properties even if there is no backing field, if there are getters or setters
+that follow the Java Beans specification. For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=pseudo_properties,indent=0]
+----
+<1> reading `p.name` is allowed because there is a pseudo-property `name`
+<2> reading `p.age` is allowed because there is a pseudo-readonly property `age`
+<3> writing `p.groovy` is allowed because there is a pseudo-writeonly property `groovy`
+
+This syntactic sugar is at the core of many DSLs written in Groovy.
+
+=== Annotation
+
+[[ann-definition]]
+==== Annotation definition
+
+An annotation is a kind of special interface dedicated at annotating elements of the code. An annotation is a type which
+superinterface is the jdk:java.lang.annotation.Annotation[Annotation] interface. Annotations are declared in a very
+similar way to interfaces, using the `@interface` keyword:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=define_annotation,indent=0]
+----
+
+An annotation may define members in the form of methods without bodies and an optional default value. The possible
+member types are limited to:
+
+* primitive types
+* jdk:java.lang.String[Strings]
+* jdk:java.lang.Class[Classes]
+* an jdk:java.lang.Enum[enumeration]
+* another jdk:java.lang.annotation.Annotation[annotation type]
+* or any array of the above
+
+For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_string,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_string_default,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_int,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_class,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_annotation,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_member_enum,indent=0]
+----
+<1> an annotation defining a `value` member of type `String`
+<2> an annotation defining a `value` member of type `String` with a default value of `something`
+<3> an annotation defining a `step` member of type the primitive type `int`
+<4> an annotation defining a `appliesTo` member of type `Class`
+<5> an annotation defining a `value` member which type is an array of another annotation type
+<6> an annotation defining a `dayOfWeek` member which type is the enumeration type `DayOfWeek`
+
+Unlike in the Java language, in Groovy, an annotation can be used to alter the semantics of the language. It is especially
+true of AST transformations which will generate code based on annotations.
+
+[[ann-placement]]
+==== Annotation placement
+
+An annotation can be applied on various elements of the code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=apply_annotation_1,indent=0]
+----
+<1> `@SomeAnnotation` applies to the `someMethod` method
+<2> `@SomeAnnotation` applies to the `SomeClass` class
+<3> `@SomeAnnotation` applies to the `var` variable
+
+In order to limit the scope where an annotation can be applied, it is necessary to declare it on the annotation
+definition, using the jdk:java.lang.annotation.Target[Target] annotation. For example, here is how you would
+declare that an annotation can be applied to a class or a method:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_target,indent=0]
+----
+<1> the `@Target` annotation is meant to annotate an annotation with a scope.
+<2> `@SomeAnnotation` will therefore only be allowed on `TYPE` or `METHOD`
+
+The list of possible targets is available in the jdk:java.lang.annotation.ElementType[ElementType enumeration].
+
+WARNING: Groovy does not support the jdk:java.lang.annotation.ElementType#TYPE_PARAMETER[TYPE_PARAMETER] and
+jdk:java.lang.annotation.ElementType#TYPE_PARAMETER[TYPE_USE] element types which were introduced in Java 8.
+
+==== Annotation member values
+
+When an annotation is used, it is required to set at least all members that do not have a default value. For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=annotation_value_set,indent=0]
+----
+
+However it is possible to omit `value=` in the declaration of the value of an annotation if the member `value` is the
+only one being set:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=annotation_value_set_option,indent=0]
+----
+<1> we can omit the `statusCode` because it has a default value, but `value` needs to be set
+<2> since `value` is the only mandatory member without a default, we can omit `value=`
+<3> if both `value` and `statusCode` need to be set, it is required to use `value=` for the default `value` member
+
+==== Retention policy
+
+The visibility of an annotation depends on its retention policy. The retention policy of an annotation is set using
+the jdk:java.lang.annotation.Retention[Retention] annotation:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=ann_retention,indent=0]
+----
+<1> the `@Retention` annotation annotates the `@SomeAnnotation` annotation
+<2> so `@SomeAnnotation` will have a `SOURCE` retention
+
+The list of possible retention targets and description is available in the
+jdk:java.lang.annotation.RetentionPolicy[RetentionPolicy] enumeration. The
+choice usually depends on whether you want an annotation to be visible at
+compile time or runtime.
+
+==== Closure annotation parameters
+
+An interesting feature of annotations in Groovy is that you can use a closure as an annotation value. Therefore
+annotations may be used with a wide variety of expressions and still have IDE support. For example, imagine a
+framework where you want to execute some methods based on environmental constraints like the JDK version or the OS.
+One could write the following code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=closure_ann_example,indent=0]
+----
+
+For the `@OnlyIf` annotation to accept a `Closure` as an argument, you only have to declare the `value` as a `Class`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=closure_ann_def,indent=0]
+----
+
+To complete the example, let's write a sample runner that would use that information:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=closure_ann_runner,indent=0]
+----
+<1> create a new instance of the class passed as an argument (the task class)
+<2> emulate an environment which is JDK 6 and not Windows
+<3> iterate on all declared methods of the task class
+<4> if the method is public and takes no-argument
+<5> try to find the `@OnlyIf` annotation
+<6> if it is found get the `value` and create a new `Closure` out of it
+<7> set the `delegate` of the closure to our environment variable
+<8> call the closure, which is the annotation closure. It will return a `boolean`
+<9> if it is `true`, call the method
+<10> if the method is not annotated with `@OnlyIf`, execute the method anyway
+<11> after that, return the task object
+
+Then the runner can be used this way:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=closure_ann_runner_exec,indent=0]
+----
+
+==== Meta-annotations
+
+===== Declaring meta-annotations
+
+Meta-annotations, also known as annotation aliases are annotations that
+are replaced at compile time by other annotations (one meta-annotation
+is an alias for one or more annotations). Meta-annotations can be used to
+reduce the size of code involving multiple annotations.
+
+Let’s start with a simple example. Imagine you have the `@Service`
+and `@Transactional` annotations and that you want to annotate a class
+with both:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=transactionalservice_class,indent=0]
+----
+
+Given the multiplication of annotations that you could add to the same class, a meta-annotation
+could help by reducing the two annotations with a single one having the very same semantics. For example,
+we might want to write this instead:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=transactionalservice_class2,indent=0]
+----
+<1> `@TransactionalService` is a meta-annotation
+
+A meta-annotation is declared as a regular annotation but annotated with `@AnnotationCollector` and the
+list of annotations it is collecting. In our case, the `@TransactionalService` annotation can be written:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=metaann_ts,indent=0]
+----
+<1> annotate the meta-annotation with `@Service`
+<2> annotate the meta-annotation with `@Transactional`
+<3> annotate the meta-annotation with `@AnnotationCollector`
+
+[[meta-ann-behavior]]
+===== Behavior of meta-annotations
+
+Groovy supports both _precompiled_ and _source form_
+meta-annotations. This means that your meta-annotation _may_ be
+precompiled, or you can have it in the same source tree as the one you
+are currently compiling.
+
+INFO: Meta-annotations are a Groovy feature only. There is
+no chance for you to annotate a Java class with a meta-annotation and
+hope it will do the same as in Groovy. Likewise, you cannot write a
+meta-annotation in Java: both the meta-annotation definition *and* usage
+have to be Groovy code.
+
+When the Groovy compiler encounters a class annotated with a
+meta-annotation, it *replaces* it with the collected annotations. That
+is, in our previous example, that it will
+replace `@TransactionalService` with `@Transactional` and `@Service`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=annotations_expanded,indent=0]
+----
+
+The conversion from a meta-annotation to the collected annotations is performed during the
+_semantic analysis_ compilation phase. 
+
+In addition to replacing the alias with the collected annotations, a meta-annotation is capable of
+processing them, including arguments.
+
+[[meta-ann-members]]
+===== Meta-annotation parameters
+
+Meta-annotations can collect annotations which have parameters. To illustrate this, we will imagine two annotations,
+each of them accepting one argument:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=collected_ann_explosive,indent=0]
+----
+
+And that you want create a meta-annotation named `@Explosive`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=collected_ann_explosive,indent=0]
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=collector_ann_explosive,indent=0]
+----
+
+By default, when the annotations are replaced, they will get the
+values *as they were defined in the alias*. More interesting, the meta-annotation
+supports overriding specific values:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=example_bomb,indent=0]
+----
+<1> the `after` value provided as a parameter to `@Explosive` overrides the one defined in the `@Timeout` annotation
+
+If two annotations define the same parameter name, the
+default processor will copy the annotation value to all annotations that
+accept this parameter:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=collector_ann_same_values,indent=0]
+----
+<1> the `@Foo` annotation defines the `value` member of type `String`
+<2> the `@Bar` annotation also defines the `value` member of type `String`
+<3> the `@FooBar` meta-annotation aggregates `@Foo` and `@Bar`
+<4> class `Bob` is annotated with `@Foo` and `@Bar`
+<5> the value of the `@Foo` annotation on `Bob` is `a`
+<6> while the value of the `@Bar` annotation on `Bob` is `b`
+<7> class `Joe` is annotated with `@FooBar`
+<8> then the value of the `@Foo` annotation on `Joe` is `a`
+<9> and the value of the `@Bar` annotation on `Joe` is also `a`
+
+In the second case, the meta-annotation value was copied in
+both `@Foo` and `@Bar` annotations.
+
+WARNING: It is a compile time error if the collected annotations define the same members
+with incompatible types. For example if on the previous example `@Foo` defined a value of
+type `String` but `@Bar` defined a value of type `int`.
+
+It is however possible to customize the behavior of meta-annotations and describe how collected
+annotations are expanded.
+
+[[meta-ann-processor]]
+===== Custom annotation processors
+
+A custom annotation processor will let you choose how to expand a
+meta-annotation into collected annotations. The behaviour of the meta-annotation is,
+in this case, totally up to you. To do this, you must:
+
+* create a meta-annotation processor, extending gapi:org.codehaus.groovy.transform.AnnotationCollectorTransform[AnnotationCollectorTransform]
+* declare the processor to be used in the meta-annotation declaration
+
+To illustrate this, we are going to explore how the meta-annotation `@CompileDynamic` is implemented.
+
+`@CompileDynamic` is a meta-annotation that expands itself
+to `@CompileStatic(TypeCheckingMode.SKIP)`. The problem is that the
+default meta annotation processor doesn’t support enums and the
+annotation value `TypeCheckingMode.SKIP` is one.
+
+The naive implementation here would not work:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=compiledynamic_naive,indent=0]
+----
+
+Instead, we will define it like this:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=compiledynamic_def_fixed,indent=0]
+----
+
+The first thing you may notice is that our interface is no longer
+annotated with `@CompileStatic`. The reason for this is that we rely on
+the `processor` parameter instead, that references a class which
+will *generate* the annotation.
+
+Here is how the custom processor is implemented:
+
+[source,groovy]
+.CompileDynamicProcessor.groovy
+----
+include::{projectdir}/src/spec/test/ClassTest.groovy[tags=compiledynamic_processor,indent=0]
+----
+<1> our custom processor is written in Groovy, and for better compilation performance, we use static compilation
+<2> the custom processor has to extend gapi:org.codehaus.groovy.transform.AnnotationCollectorTransform[AnnotationCollectorTransform]
+<3> create a class node representing the `@CompileStatic` annotation type
+<4> create a class node representing the `TypeCheckingMode` enum type
+<5> `collector` is the `@AnnotationCollector` node found in the meta-annotation. Usually unused.
+<6> `aliasAnnotationUsage` is the meta-annotation being expanded, here it is `@CompileDynamic`
+<7> `aliasAnnotated` is the node being annotated with the meta-annotation
+<8> `sourceUnit` is the `SourceUnit` being compiled
+<9> we create a new annotation node for `@CompileStatic`
+<10> we create an expression equivalent to `TypeCheckingMode.SKIP`
+<11> we add that expression to the annotation node, which is now `@CompileStatic(TypeCheckingMode.SKIP)`
+<12> return the generated annotation
+
+In the example, the `visit` method is the only method which has to be overriden. It is meant to return a list of
+annotation nodes that will be added to the node annotated with the meta-annotation. In this example, we return a
+single one corresponding to `@CompileStatic(TypeCheckingMode.SKIP)`.
+
+=== Inheritance
+
+(TBD)
 
-=== Inheritance (TBD)
 
 [[generics]]
-=== Generics (TBD)
+=== Generics
+
+(TBD)
+
+
+include::{projectdir}/src/spec/doc/core-traits.adoc[leveloffset=+1]
 
-:leveloffset: 3
-include::{projectdir}/src/spec/doc/core-traits.adoc[]
-:leveloffset: 0
diff --git a/src/spec/doc/core-operators.adoc b/src/spec/doc/core-operators.adoc
index 9b851f8..2324413 100644
--- a/src/spec/doc/core-operators.adoc
+++ b/src/spec/doc/core-operators.adoc
@@ -18,27 +18,27 @@ The following binary arithmetic operators are available in Groovy:
 | Purpose
 | Remarks
 
-| +++
+| `+`
 | addition
 |
 
-| +-+
-| substraction
+| `-`
+| subtraction
 |
 
-| +*+
+| `*`
 | multiplication
 |
 
-| +/+
+| `/`
 | division
-| Use +intdiv()+ for integer division, and see the section about <<core-syntax.adoc#integer_division,the integer division>> for more information on the return type of the division.
+| Use `intdiv()` for integer division, and see the section about <<core-syntax.adoc#integer_division,integer division>> for more information on the return type of the division.
 
-| +%+
+| `%`
 | modulo
 |
 
-| +**+
+| `**`
 | power
 | See the section about <<core-syntax.adoc#power_operator,the power operation>> for more information on the return type of the operation.
 |====
@@ -52,7 +52,7 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=binary_arith_ops,i
 
 === Unary operators
 
-The +++ and +-+ operators are also available as unary operators:
+The `+` and `-` operators are also available as unary operators:
 
 [source,groovy]
 ----
@@ -60,27 +60,27 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=unary_plus_minus,i
 ----
 <1> Note the usage of parentheses to surround an expression to apply the unary minus to that surrounded expression.
 
-In terms of unary arithmetics operators, the ++++ (increment) and +--+ (decrement) operators are available, 
+In terms of unary arithmetics operators, the `++` (increment) and `--` (decrement) operators are available,
 both in prefix and postfix notation:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=plusplus_minusminus,indent=0]
 ----
-<1> The postfix increment will increment +a+ after the expression has been evaluated and assigned into +b+
-<2> The postfix decrement will decrement +c+ after the expression has been evaluated and assigned into +d+
-<3> The prefix increment will increment +e+ before the expression is evaluated and assigned into +f+
-<4> The prefix decrement will decrement +g+ before the expression is evaluated and assigned into +h+
+<1> The postfix increment will increment `a` after the expression has been evaluated and assigned into `b`
+<2> The postfix decrement will decrement `c` after the expression has been evaluated and assigned into `d`
+<3> The prefix increment will increment `e` before the expression is evaluated and assigned into `f`
+<4> The prefix decrement will decrement `g` before the expression is evaluated and assigned into `h`
 
 === Assignment arithmetic operators
 
 From the binary arithmetic operators we have seen above, certain of them are also available in an assignment form:
 
-* ++=+
-* +-=+
-* +*=+
-* +/=+
-* +%=+
+* `+=`
+* `-=`
+* `*=`
+* `/=`
+* `%=`
 
 Let's see them in action:
 
@@ -92,7 +92,7 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=binary_assign_oper
 == Relational operators
 
 Relational operators allow comparisons between objects, to know if two objects are the same or different,
-or if one is greater or lower than or equal to the other.
+or if one is greater than, less than, or equal to the other.
 
 The following operators are available:
 
@@ -101,26 +101,26 @@ The following operators are available:
 | Operator
 | Purpose
 
-| +==+
+| `==`
 | equal
 
-| +!=+
+| `!=`
 | different
 
-| +<+
+| `<`
 | less than
 
 | `<=`
 | less than or equal
 
-| +>+
+| `>`
 | greater than
 
-| +>=+
+| `>=`
 | greater than or equal
 |====
 
-These operators into action in simple number comparisons:
+Here are some examples of simple number comparisons using these operators:
 
 [source,groovy]
 ----
@@ -153,7 +153,7 @@ The logical "not" has a higher priority than the logical "and".
 ----
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=logical_precendence_1,indent=0]
 ----
-<1> Here, the assertion is true, because "not" has a higher precedence than "and", otherwise, the assertion would have failed
+<1> Here, the assertion is true (as the expression in parentheses is false), because "not" has a higher precedence than "and", so it only applies to the first "false" term; otherwise, it would have applied to the result of the "and", turned it into true, and the assertion would have failed
 
 The logical "and" has a higher priority than the logical "or".
 
@@ -161,21 +161,25 @@ The logical "and" has a higher priority than the logical "or".
 ----
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=logical_precendence_2,indent=0]
 ----
-<1> Here, the assertion is true, because "and" has a higher precedence than "or", otherwise, the assertion would have failed
+<1> Here, the assertion is true, because "and" has a higher precedence than "or", therefore the "or" is executed last and returns true, having one true argument; otherwise, the "and" would have executed last and returned false, having one false argument, and the assertion would have failed
 
-=== Short-circuiting for `||`
+=== Short-circuiting
 
-The logical "or" operator is supporting short-circuiting: if the left operand is true, it won't evaluate the right operand.
+The logical `||` operator supports short-circuiting: if the left operand is true, it knows that the result will be true in any case, so it won't evaluate the right operand.
 The right operand will be evaluated only if the left operand is false.
 
+Likewise for the logical `&&` operator: if the left operand is false, it knows that the result will be false in any case, so it won't evaluate the right operand.
+The right operand will be evaluated only if the left operand is true.
+
 [source,groovy]
 ----
-include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=logical_or_shortcircuit,indent=0]
+include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=logical_shortcircuit,indent=0]
 ----
-<1> We create a function that returns its boolean argument, but it sets the `called` flag 
-<2> In the first case, we confirm that the function is not called, as `||` short-circuits the evaluation of the right operand.
-<3> In the second case, the right operand is called, as indicated by the fact our flag is now true
-
+<1> We create a function that sets the `called` flag to true whenever it's called
+<2> In the first case, after resetting the called flag, we confirm that if the left operand to `||` is true, the function is not called, as `||` short-circuits the evaluation of the right operand
+<3> In the second case, the left operand is false and so the function is called, as indicated by the fact our flag is now true
+<4> Likewise for `&&`, we confirm that the function is not called with a false left operand
+<5> But the function is called with a true left operand
 
 == Bitwise operators
 
@@ -296,9 +300,10 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=direct_field_op,in
 ----
 <1> use of `.@` forces usage of the field instead of the getter
 
-=== Method reference operator
+[[method-pointer-operator]]
+=== Method pointer operator
 
-The method reference operator (`.&`) call be used to store a reference to a method in a variable, in order to call it
+The method pointer operator (`.&`) call be used to store a reference to a method in a variable, in order to call it
 later:
 
 [source,groovy]
@@ -310,7 +315,7 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=method_reference,i
 <3> `fun` can be called like a regular method
 <4> we can check that the result is the same as if we had called it directly on `str`
 
-There are multiple advantages in using method references. First of all, the type of such a method reference is
+There are multiple advantages in using method pointers. First of all, the type of such a method pointer is
 a `groovy.lang.Closure`, so it can be used in any place a closure would be used. In particular, it is suitable to
 convert an existing method for the needs of the strategy pattern:
 
@@ -320,11 +325,11 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=method_reference_s
 ----
 <1> the `transform` method takes each element of the list and calls the `action` closure on them, returning a new list
 <2> we define a function that takes a `Person` a returns a `String`
-<3> we create a method reference on that function
+<3> we create a method pointer on that function
 <4> we create the list of elements we want to collect the descriptors
-<5> the method reference can be used where a `Closure` was expected
+<5> the method pointer can be used where a `Closure` was expected
 
-Method references are bound by the receiver and a method name. Arguments are resolved at runtime, meaning that if you have
+Method pointers are bound by the receiver and a method name. Arguments are resolved at runtime, meaning that if you have
 multiple methods with the same name, the syntax is not different, only resolution of the appropriate method to be called
 will be done at runtime:
 
@@ -334,9 +339,9 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=method_reference_d
 ----
 <1> define an overloaded `doSomething` method accepting a `String` as an argument
 <2> define an overloaded `doSomething` method accepting an `Integer` as an argument
-<3> create a single method reference on `doSomething`, without specifying argument types
-<4> using the method reference with a `String` calls the `String` version of `doSomething`
-<5> using the method reference with an `Integer` calls the `Integer` version of `doSomething`
+<3> create a single method pointer on `doSomething`, without specifying argument types
+<4> using the method pointer with a `String` calls the `String` version of `doSomething`
+<5> using the method pointer with an `Integer` calls the `Integer` version of `doSomething`
 
 == Regular expression operators
 
@@ -370,8 +375,8 @@ instance:
 ----
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=pattern_matcher_op,indent=0]
 ----
-<1> `~=` creates a matcher against the `text` variable, using the pattern on the right hand side
-<2> the return type of `~=` is a `Matcher`
+<1> `=~` creates a matcher against the `text` variable, using the pattern on the right hand side
+<2> the return type of `=~` is a `Matcher`
 <3> equivalent to calling `if (!m.find())`
 
 Since a `Matcher` coerces to a `boolean` by calling its `find` method, the `=~` operator is consistent with the simple
@@ -386,11 +391,11 @@ and requires a strict match of the input string:
 ----
 include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=pattern_matcher_strict_op,indent=0]
 ----
-<1> `~==` matches the subject with the regular expression, but match must be strict
-<2> the return type of `~==` is therefore a `boolean`
+<1> `==~` matches the subject with the regular expression, but match must be strict
+<2> the return type of `==~` is therefore a `boolean`
 <3> equivalent to calling `if (text ==~ /match/)`
 
-== Other operators (WIP)
+== Other operators
 
 === Spread operator
 
@@ -513,7 +518,7 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=charrange,indent=0
 
 === Spaceship operator
 
-The spaceship operator (`<=>`) delegates to the `compareTo` method:
+The spaceship operator (`pass:[<=>]`) delegates to the `compareTo` method:
 
 [source,groovy]
 ----
@@ -580,7 +585,7 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=identity_op,indent
 === Coercion operator
 
 The coercion operator (`as`) is a variant of casting. Coercion converts object from one type to another *without* them
-being compatible for assignement. Let's take an example:
+being compatible for assignment. Let's take an example:
 
 [source,groovy]
 ----
@@ -636,7 +641,32 @@ include::{projectdir}/src/spec/test/OperatorsTest.groovy[tags=call_op,indent=0]
 <2> we can call the method using the classic method call syntax
 <3> or we can omit `.call` thanks to the call operator
 
-== Operator precedence (TBD)
+== Operator precedence
+The table below lists all groovy operators in order of precedence.
+
+[options="header"]
+|======================
+|Level | Operator(s) | Name(s)
+| 1 | `$x` | scope escape
+|   | `new` `()` | new, explicit parentheses
+|   | `()` `{}` `[]` | method call, closure, list/map
+|   | `.` `?.` `*.` | dot, safe dereferencing, spread-dot
+|   | `~` `!$` `(type)` | bitwise negate, not, typecast
+| 2 | `**` | power
+| 3 | `++` `--` `+` `-` | pre/post increment/decrement, unary plus, unary minus
+| 4 | `*` `/` `%` | multiply, div, modulo
+| 5 | `+` `-` | binary plus, binary minus
+| 6 | `<<` `>>` `>>>` `..` `..<` | left/right (unsigned) shift, inclusive/exclusive range
+| 7 | `<` `\<=` `>` `>=` `instanceof` `as` | less/greater than/or equal, instanceof, type coercion
+| 8 | `==` `!=` `pass:[<=>]` | equal, not equal, compare to
+| 9 | `&` | binary and
+| 10 | `^` | binary xor
+| 11 | `\|` | binary or
+| 12 | `&&` | logical and
+| 13 | `\|\|` | logical or
+| 14 | `?:` | ternary conditional
+| 15 | `=` `\**=` `*=` `/=` `%=` `+=` `-=` `pass:[<<=]` `>>=` `>>>=` `&=` `^=` `\|=` | various assignments
+|======================
 
 [[Operator-Overloading]]
 == Operator overloading
@@ -684,49 +714,49 @@ Here is a complete list of the operators and their corresponding methods:
 | Operator
 | Method
 
-| +++
+| `+`
 | a.plus(b)
-| +a[b]+
+| `a[b]`
 | a.getAt(b)
 
-| +-+
+| `-`
 | a.minus(b)
-| +a[b] = c+
+| `a[b] = c`
 | a.putAt(b, c)
 
-| +*+
+| `*`
 | a.multiply(b)
-| +<<+
+| `<<`
 | a.leftShift(b)
 
-| +/+
+| `/`
 | a.div(b)
-| +>>+
+| `>>`
 | a.rightShift(b)
 
-| +%+
+| `%`
 | a.mod(b)
 | `++`
 | a.next()
 
-| +**+
+| `**`
 | a.power(b)
-| +--+
+| `--`
 | a.previous()
 
-| +\|+
+| `\|`
 | a.or(b)
 | `+a`
 | a.positive()
 
-| +&+
+| `&`
 | a.and(b)
-| +-a+
+| `-a`
 | a.negative()
 
-| +^+
+| `^`
 | a.xor(b)
-| +~a+
+| `~a`
 | a.bitwiseNegative()
 |====
 
diff --git a/src/spec/doc/core-program-structure.adoc b/src/spec/doc/core-program-structure.adoc
index 929ebb7..5b9e4de 100644
--- a/src/spec/doc/core-program-structure.adoc
+++ b/src/spec/doc/core-program-structure.adoc
@@ -1,35 +1,25 @@
-= Program structure (Anto Aravinth)
+= Program structure
 
 This chapter covers the program structure of the Groovy programming language.
 
-== Package name (TBD)
+== Package names
 
-== Imports (TBD)
+Package names play exactly the same role as in Java. They allows us to separate the code base without any conflicts. Groovy classes must specify their package before the class definition, else the default package is assumed. 
 
-=== Default imports (TBD)
-=== Simple import (TBD)
-=== Star import (TBD)
-=== Static import (TBD)
-=== Static star import (TBD)
-=== Import aliasing (TBD)
-
-== Scripts versus classes (TBD)
-=======
-Package name plays exactly the same role as they used to play in Java. They allows us to separate the code base without any conflicts. Groovy classes must specify their package before the class definition, else the default package is assumed. 
-
-Defining a package is very similar to java, as you can see 
+Defining a package is very similar to Java:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=package_statement,indent=0]
 ----
 
-To refer the class ++Foo++ in the ++com.yoursite.com++ package then you need to use ++com.yoursite.com.Foo++ in your code else you can use ++import++ statement as we can see now. 
+To refer to some class `Foo` in the `com.yoursite.com` package you will need to use the fully qualified name `com.yoursite.com.Foo`, or else you can use an `import` statement as we'll see below.
 
 == Imports
 
-In order to refer any class you need a reference for it. Groovy follows Java's notion of allowing ++import++ statement to resolve the class references. Groovy provides several builder classes, 
-one such class is ++MarkupBuilder++. ++MarkupBuilder++ is inside the package ++groovy.xml++, in order to use this class, you need to ++import++ it as shown:
+In order to refer to any class you need a qualified reference to its package. Groovy follows Java's notion of allowing `import` statement to resolve class references.
+
+For example, Groovy provides several builder classes, such as `MarkupBuilder`. `MarkupBuilder` is inside the package `groovy.xml` so in order to use this class, you need to `import` it as shown:
 
 [source,groovy]
 ----
@@ -45,24 +35,23 @@ Default imports are the imports that Groovy language provides by default. For ex
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=default_import,indent=0]
 ----
 
-The same code in Java needs an import statement to ++Date++ class like this: ++import java.util.Date++. Groovy by default imports these classes for you. There are six packages that groovy imports for you, they are:
+The same code in Java needs an import statement to `Date` class like this: ++import java.util.Date++. Groovy by default imports these classes for you. There are six packages that groovy imports for you, they are:
 
--------------------------------------------------------------------
-								   import java.lang.*
-	                               import java.util.*
-	                               import java.io.*
-	                               import java.net.*
-	                               import groovy.lang.*
-	                               import groovy.util.*
-	                               import java.math.BigInteger
-	                               import java.math.BigDecimal
--------------------------------------------------------------------
-	
-	
+[source,groovy]
+----
+import java.lang.*
+import java.util.*
+import java.io.*
+import java.net.*
+import groovy.lang.*
+import groovy.util.*
+import java.math.BigInteger
+import java.math.BigDecimal
+----
 
 === Simple import
 
-Simple import is an import, where you fully define the class name along with the package. For example the import statement ++import groovy.xml.MarkupBuilder++ in the code below is the simple import, which directly refer the class inside the package.
+A simple import is an import statement where you fully define the class name along with the package. For example the import statement ++import groovy.xml.MarkupBuilder++ in the code below is a simple import which directly refers to the a class inside a package.
 
 [source,groovy]
 ----
@@ -71,21 +60,21 @@ include::{projectdir}/src/spec/test/PackageTest.groovy[tags=import_statement,ind
 
 === Star import
 
-Groovy (like Java) provides a special way to import all classes from a package using ++*++, they are called as Star import. ++MarkupBuilder++ is class which is in package ++groovy.xml++, another class called ++StreamingMarkupBuilder++ is in the same package. Consider the case, where you need to use two classes, then you can do:
+Groovy, like Java, provides a special way to import all classes from a package using `*`, a so called Star import. `MarkupBuilder` is a class which is in package `groovy.xml`, alongside another class called `StreamingMarkupBuilder`. In case you need to use both classes, you can do:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=multiple_import,indent=0]
 ----
 
-Thats a perfectly valid code. But with ++*++ import, we can do the same like this:
+That's perfectly valid code. But with a `*` import, we can achieve the same effect with just one line, where `*` imports all the classes under package `groovy.xml`:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=star_import,indent=0]
 ----
 
-where, ++*++ does imports all the class under package ++groovy.xml++. Using ++*++ import can clutters your local namespace. But with groovy type aliasing, this can be solved easily. 
+One problem with `*` imports is that they can clutter your local namespace. But with the kinds of aliasing provided by Groovy, this can be solved easily. 
 
 === Static import
 
@@ -96,64 +85,168 @@ Groovy's static import capability allows you to reference imported classes as if
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=static_imports,indent=0]
 ----
 
-As you can see, now we can able to refer the static variable ++FALSE++ in our code base cleanly. 
+As you can see, now we can able to refer to the static variable `FALSE` in our code base cleanly.
+
+=== Static import aliasing
 
-Static imports along with ++as++ keyword can make elegant solution. Consider you want to get the ++Calendar++ instance, using ++getInstance()++ method. Its a static method, so we can do a static import. But instead of calling ++getInstance()++ everytime, we can do this which can increase code readability:
+Static imports with the `as` keyword provide an elegant solution to namespace problems. Suppose you want to get a `Calendar` instance, using its `getInstance()` method. It's a static method, so we can use a static import. But instead of calling `getInstance()` every time, which can be misleading when separated from its class name, we can import it with an alias, to increase code readability:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=static_importswithas,indent=0]
 ----
 
-Thats clean and sweet!
+Now, that's clean!
 
 === Static star import
 
-Its very similar to the star import that we have seen earlier. It will import all the static methods from the given class. For example, lets say we need to calculate sin and cos for our application. 
-The class ++java.lang.Math++ has static methods named ++sin++,++cos++ which fits our need. With help of static star import, we can do:
+A static star import is very similar to the regular star import. It will import all the static methods from the given class.
+
+For example, lets say we need to calculate sines and cosines for our application. 
+The class `java.lang.Math` has static methods named `sin` and `cos` which fit our need. With the help of a static star import, we can do:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=static_importswithstar,indent=0]
 ----
 
-As you can see, we were able to access the methods ++sin++,++cos++ directly, instead like ++Math.sin++.
+As you can see, we were able to access the methods `sin` and `cos` directly, without the `Math.` prefix.
 
 === Import aliasing
 
-With type aliasing, we can refer to a fully qualified class name with the name of your choice. This can be done with ++as++ keyword in Groovy. 
+With type aliasing, we can refer to a fully qualified class name using a name of our choice. This can be done with the `as` keyword, as before.
 
-Consider the class with the following library code:
+Consider the following class, provided by some third-party library code:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/thirdpartylib/MultiplyTwo.groovy[tags=third_party_lib,indent=0]
 ----
 
-and we have some existing code using this library:
+Suppose we have some existing code using the library:
 
 [source,groovy]
 ----
-include::{projectdir}/src/spec/test/PackageTest.groovy[tags=using_thrid_party_lib,indent=0]
+include::{projectdir}/src/spec/test/PackageTest.groovy[tags=using_third_party_lib,indent=0]
 ----
 
-Obviously, the ++result++ variable contains the wrong result. And assume you have used this library through out your code-base. Groovy has an elegant way to fix this issue.
+Now suppose that, after using this library throughout your codebase, we discover that it doesn't give correct results. How can we fix it in one place, outside of the original class, without changing all the code that's using it? Groovy has an elegant solution to this problem.
 
-With the type aliasing in place, we can fix the bug using the below code:
+With a simple import aliasing, we can fix the bug like this:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/PackageTest.groovy[tags=fixing_thrid_party_lib,indent=0]
 ----
 
-Thats it! Notice how Groovy allowed us to use ++as++ keyword to solve the typical problem. 
+Thats it! Notice how Groovy allowed us to use the `as` keyword to rename our imported class and solve this common problem.
 
-With Type aliasing we can able to solve the name collision problem ( which can occur with ++*++ imports) elegantly.
+Type aliasing is also useful to solve name collision problems which can occur with `*` imports.
 
 == Scripts versus classes
 
-== Initializers (TBD)
+=== public static void main vs script
+Groovy supports both scripts and classes. Take the following code for example:
+
+[source,groovy]
+.Main.groovy
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=groovy_class_with_main_method,indent=0]
+----
+<1> define a `Main` class, the name is arbitrary
+<2> the `public static void main(String[])` method is usable as the main method of the class
+<3> the main body of the method
+
+This is typical code that you would find coming from Java, where code *has* to be embedded into a class to be executable.
+Groovy makes it easier, the following code is equivalent:
+
+[source,groovy]
+.Main.groovy
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=groovy_script,indent=0]
+----
+
+A script can be considered as a class without needing to declare it, with some differences.
+
+=== Script class
+
+A gapi:groovy.lang.Script[script] is always compiled into a class. The Groovy compiler will compile the class for you,
+with the body of the script copied into a `run` method. The previous example is therefore compiled as if it was the
+following:
+
+[source,groovy]
+.Main.groovy
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=groovy_script_equiv,indent=0]
+----
+<1> The `Main` class extends the `groovy.lang.Script` class
+<2> `groovy.lang.Script` requires a `run` method returning a value
+<3> the script body goes into the `run` method
+<4> the `main` method it automatically generated
+<5> and delegates the execution of the script on the `run` method
+
+If the script is in a file, then the base name of the file is used to determine the name of the generated script class.
+In this example, if the name of the file is `Main.groovy`, then the script class is going to be `Main`.
+
+=== Methods
+
+It is possible to define methods into a script, as illustrated here:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=method_in_script,indent=0]
+----
+
+You can also mix methods and code. The generated script class will carry all methods into the script class, and
+assemble all script bodies into the `run` method:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=multiple_methods_assembly,indent=0]
+----
+<1> script begins
+<2> a method is defined within the script body
+<3> and script continues
+
+This code is internally converted into:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=multiple_methods_assembly_equiv,indent=0]
+----
+<1> the `power` method is copied as is into the generated script class
+<2> first statement is copied into the `run` method
+<3> second statement is copied into the `run` method
+
+TIP: Even if Groovy creates a class from your script, it is totally transparent for the user. In particular, scripts
+are compiled to bytecode, and line numbers are preserved. This implies that if an exception is thrown in a script,
+the stack trace will show line numbers corresponding to the original script, not the generated code that we have shown.
+
+=== Variables
+
+Variables in a script do not require a type definition. This means that this script:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=script_with_variables,indent=0]
+----
+
+will behave the same as:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/ScriptsAndClassesSpecTest.groovy[tags=script_with_untyped_variables,indent=0]
+----
+
+However there is a semantic difference between the two:
 
-=== Static initializers (TBD)
-=== Instance initializers (TBD)
+* if the variable is declared as in the first example, it is a _local variable_. It will be declared in the `run`
+method that the compiler will generate and will *not* be visible outside of the script main body. In particular, such
+a variable will *not* be visible in other methods of the script
+* if the variable is undeclared, it goes into the gapi:groovy.lang.Script#getBinding()[script binding]. The binding is
+visible from the methods, and is especially important if you use a script to interact with an application and need to
+share data between the script and the application. Readers might refer to the link:integrating.html[integration guide]
+for more information.
 
+TIP: If you want a variable to become a field of the class without going into the `Binding`, you can use the
+link:metaprogramming.html#xform-Field[@Field annotation].
diff --git a/src/spec/doc/core-semantics.adoc b/src/spec/doc/core-semantics.adoc
index b009447..db2a287 100644
--- a/src/spec/doc/core-semantics.adoc
+++ b/src/spec/doc/core-semantics.adoc
@@ -102,7 +102,7 @@ include::{projectdir}/src/spec/test/SemanticsTest.groovy[tags=destructuring,inde
 <2> then, we use a multiple assignment to get the individual longitude and latitude values
 <3> and we can finally assert their values.
 
-=== Control structures (WIP)
+=== Control structures
 ==== Conditional structures
 ===== if / else
 
@@ -139,13 +139,13 @@ include::{projectdir}/src/spec/test/SemanticsTest.groovy[tags=switch_case_exampl
 
 Switch supports the following kinds of comparisons:
 
-* Class case values matches if the switch value is an instance of the class
+* Class case values match if the switch value is an instance of the class
 * Regular expression case values match if the `toString()` representation of the switch value matches the regex
 * Collection case values match if the switch value is contained in the collection. This also includes ranges (since they are Lists)
 * Closure case values match if the calling the closure returns a result which is true according to the <<Groovy-Truth,Groovy truth>>
 * If none of the above are used then the case value matches if the case value equals the switch value
 
-NOTE: +default+ must go at the end of the switch/case. While in Java the default can be placed anywhere in the switch/case, the default in Groovy is used more as an else than assigning a default case.
+NOTE: `default` must go at the end of the switch/case. While in Java the default can be placed anywhere in the switch/case, the default in Groovy is used more as an else than assigning a default case.
 
 NOTE: when using a closure case value, the default `it` parameter is actually the switch value (in our example, variable `x`)
 
@@ -187,7 +187,7 @@ Exception handling is the same as Java.
 
 ==== try / catch / finally
 
-You can specify a complete +try-catch-finally+, a +try-catch+, or a +try-finally+ set of blocks.
+You can specify a complete `try-catch-finally`, a `try-catch`, or a `try-finally` set of blocks.
 
 NOTE: Braces are required around each block's body.
 
@@ -216,16 +216,212 @@ try {
 }
 ----
 
-=== Power assertion (TBD)
-=== Labeled statements (TBD)
+=== Power assertion
 
-== Expressions (TBD)
+Unlike Java with which Groovy shares the `assert` keyword, the latter in Groovy behaves very differently. First of all,
+an assertion in Groovy is always executed, independently of the `-ea` flag of the JVM. It makes this a first class choice
+for unit tests. The notion of "power asserts" is directly related to how the Groovy `assert` behaves.
 
-=== GPath expressions (TBD)
+A power assertion is decomposed into 3 parts:
 
-== Promotion and coercion (TBD)
+----
+assert [left expression] == [right expression] : (optional message)
+----
+
+The result of the assertion is very different from what you would get in Java. If the assertion is true, then nothing
+happens. If the assertion is false, then it provides a visual representation of the value of each sub-expressions of the
+expression being asserted. For example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_code_1,indent=0]
+----
+
+Will yield:
+
+----
+Caught: Assertion failed:
+
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_error_1,indent=0]
+----
+
+Power asserts become very interesting when the expressions are more complex, like in the next example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_code_2,indent=0]
+----
+
+Which will print the value for each sub-expression:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_error_2,indent=0]
+----
+
+In case you don't want a pretty printed error message like above, you can fallback to a custom error message by
+changing the optional message part of the assertion, like in this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_code_3,indent=0]
+----
+
+Which will print the following error message:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/PowerAssertTest.groovy[tags=assert_error_3,indent=0]
+----
+
+
+=== Labeled statements
+
+Any statement can be associated with a label. Labels do not impact the semantics of the code and can be used to make
+the code easier to read like in the following example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/LabelsTest.groovy[tags=test_labels,indent=0]
+----
+
+Despite not changing the semantics of the the labelled statement, it is possible to use labels in the `break` instruction
+as a target for jump, as in the next example. However, even if this is allowed, this coding style is in general considered
+a bad practice:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/LabelsTest.groovy[tags=label_bad_practice,indent=0]
+----
+
+It is important to understand that by default labels have no impact on the semantics of the code, however they belong to the abstract
+syntax tree (AST) so it is possible for an AST transformation to use that information to perform transformations over
+the code, hence leading to different semantics. This is in particular what the http://spockframework.github.io/spock/docs/current/index.html[Spock Framework]
+does to make testing easier.
+
+== Expressions
+
+(TBD)
+
+
+[[gpath_expressions]]
+=== GPath expressions
+////
+This is covered in {projectdir}/subprojects/groovy-xml/{specfolder}/xml-userguide.adoc, where the legacy codehaus GPath wiki page
+have been converted.
+Current section should explain what is an GPath expression (not just example, but more like a formal language specification, but kept simple).
+
+////
+
+`GPath` is a path expression language integrated into Groovy which allows parts of nested structured data to be identified. In this
+sense, it has similar aims and scope as XPath does for XML.  GPath is often used in the context of processing XML, but it really applies
+to any object graph.  Where XPath uses a filesystem-like path notation, a tree hierarchy with parts separated by a slash `/`, GPath *use a
+dot-object notation* to perform object navigation.
+
+As an example, you can specify a path to an object or element of interest:
+
+* `a.b.c` -> for XML, yields all the `c` elements inside `b` inside `a`
+* `a.b.c` -> for POJOs, yields the `c` properties for all the `b` properties of `a` (sort of like `a.getB().getC()` in JavaBeans)
+
+In both cases, the GPath expression can be viewed as a query on an object graph.  For POJOs, the object graph is most often built by the
+program being written through object instantiation and composition; for XML processing, the object graph is the result of `parsing`
+the XML text, most often with classes like XmlParser or XmlSlurper.  See <<Processing XML>> for more in-depth details on consuming XML in Groovy.
+
+[TIP]
+====
+When querying the object graph generated from XmlParser or XmlSlurper, a GPath expression can refer to attributes defined on elements with
+the `@` notation:
+
+* `a["@href"]` -> map-like notation : the href attribute of all the a elements
+* `a.'@href'`  -> property notation : an alternative way of expressing this
+* `a. at href`    -> direct notation : yet another alternative way of expressing this
+====
+
+==== Object navigation
+
+Let's see an example of a GPath expression on a simple _object graph_, the one obtained using java reflection.  Suppose you are in a non-static method of a
+class having another method named `aMethodFoo`
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_on_reflection_1,indent=0]
+----
+
+the following GPath expression will get the name of that method:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_on_reflection_2,indent=0]
+----
+
+_More precisely_, the above GPath expression produces a list of String, each being the name of an existing method on `this` where that name ends with `Foo`.
+
+Now, given the following methods also defined in that class:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_on_reflection_3,indent=0]
+----
+
+then the following GPath expression will get the names of *(1)* and *(3)*, but not *(2)* or *(0)*:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_on_reflection_4,indent=0]
+----
+
+==== Expression Deconstruction
+
+We can decompose the expression `this.class.methods.name.grep(~/.*Bar/)` to get an idea of how a GPath is evaluated:
+
+`this.class`:: property accessor, equivalent to `this.getClass()` in Java, yields a `Class` object.
+`this.class.methods`:: property accessor, equivalent to `this.getClass().getMethods()`, yields an array of `Method` objects.
+`this.class.methods.name`:: apply a property accessor on each element of an array and produce a list of the results.
+`this.class.methods.name.grep(...)`:: call method `grep` on each element of the list yielded by `this.class.methods.name` and produce a list of the results.
+
+WARNING: a sub-expression like `this.class.methods` yields an array because this is what calling `this.getClass().getMethods()` in Java
+would produce : `GPath` expressions have not invented a convention where a `s` means a list or anything like that.
+
+One powerful feature of GPath expression is that property access on a collection is converted to a _property access on each element of the collection_ with
+the results collected into a collection.  Therefore, the expression `this.class.methods.name` could be expressed as follows in Java:
+[source,java]
+----
+List<String> methodNames = new ArrayList<String>();
+for (Method method : this.getClass().getMethods()) {
+   methodNames.add(method.getName());
+}
+return methodNames;
+----
+
+Array access notation can also be used in a GPath expression where a collection is present :
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_array_access_1,indent=0]
+----
+
+NOTE: array access are zero-based in GPath expressions
+
+==== GPath for XML navigation
+
+Here is an example with a XML document and various form of GPath expressions:
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/GPathTest.groovy[tags=gpath_on_xml_1,indent=0]
+----
 
-=== Number promotion (TBD)
+<1> There is one `level` node under `root`
+<2> There are two `sublevel` nodes under `root/level`
+<3> There is one element `sublevel` having an attribute `id` with value `1`
+<4> Text value of `key` element of first `keyVal` element of second `sublevel` element under `root/level` is 'anotherKey'
+
+== Promotion and coercion
+
+=== Number promotion
+
+The rules of number promotion are specified in the section on <<_math_operations,math operations>>.
+
+
+[[closure-coercion]]
 === Closure to type coercion
 ==== Assigning a closure to a SAM type
 A SAM type is a type which defines a single abstract method. This includes:
@@ -354,7 +550,7 @@ The type of the exception depends on the call itself:
 
 === String to enum coercion
 
-Groovy allows transparent +String+ (or +GString+) to enum values coercion. Imagine you define the following enum:
+Groovy allows transparent `String` (or `GString`) to enum values coercion. Imagine you define the following enum:
 
 [source,groovy]
 ----
@@ -368,7 +564,7 @@ then you can assign a string to the enum without having to use an explicit `as`
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=enum_coerce_assignment,indent=0]
 ----
 
-It is also possible to use a +GString+ as the value:
+It is also possible to use a `GString` as the value:
 
 [source,groovy]
 ----
@@ -376,7 +572,7 @@ include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=enum_coerce_assignm
 ----
 
 
-However, this would throw a runtime error (+IllegalArgumentException+):
+However, this would throw a runtime error (`IllegalArgumentException`):
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=enum_coerce_assignment_wrong,indent=0]
@@ -389,7 +585,7 @@ Note that it is also possible to use implicit coercion in switch statements:
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=enum_switch_method,indent=0]
 ----
 
-in particular, see how the `case` use string constants. But if you call a method that uses an enum with a +String+
+in particular, see how the `case` use string constants. But if you call a method that uses an enum with a `String`
 argument, you still have to use an explicit `as` coercion:
 
 [source,groovy]
@@ -399,9 +595,9 @@ include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=enum_switch_test,in
 
 === Custom type coercion
 
-It is possible for a class to define custom coercion strategies by implementing the +asType+ method. Custom coercion
+It is possible for a class to define custom coercion strategies by implementing the `asType` method. Custom coercion
 is invoked using the `as` operator and is never implicit. As an example,
-imagine you defined two classes, +Polar+ and +Cartesian+, like in the following example:
+imagine you defined two classes, `Polar` and `Cartesian`, like in the following example:
 
 [source,groovy]
 ----
@@ -411,21 +607,21 @@ include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=cartesian_class,ind
 ----
 
 And that you want to convert from polar coordinates to cartesian coordinates. One way of doing this is to define
-the +asType+ method in the +Polar+ class:
+the `asType` method in the `Polar` class:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=polar_class_astype,indent=0]
 ----
 
-which allows you to use the +as+ coercion operator:
+which allows you to use the `as` coercion operator:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=polar_astype_assert,indent=0]
 ----
 
-Putting it all together, the +Polar+ class looks like this:
+Putting it all together, the `Polar` class looks like this:
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=polar_class_header,indent=0]
@@ -433,7 +629,7 @@ include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=polar_class_astype,
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=polar_class_footer,indent=0]
 ----
 
-but it is also possible to define +asType+ outside of the +Polar+ class, which can be practical if you want to define
+but it is also possible to define `asType` outside of the `Polar` class, which can be practical if you want to define
 custom coercion strategies for "closed" classes or classes for which you don't own the source code, for example using
 a metaclass:
 
@@ -472,19 +668,158 @@ It is failing because the `as` keyword only works with class literals. Instead,
 include::{projectdir}/src/spec/test/CoercionTest.groovy[tags=fixed_as_usage,indent=0]
 ----
 
-== Optionality (TBD)
+== Optionality
+
+=== Optional parentheses
+
+Method calls can omit the parentheses if there is at least one parameter and there is no ambiguity:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=optional_parentheses,indent=0]
+----
+
+Parentheses are required for method calls without parameters or ambiguous method calls: 
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=required_parentheses,indent=0]
+----
+
+=== Optional semicolons
+
+In Groovy semicolons at the end of the line can be omitted, if the line contains only a single statement.
+
+This means that:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=single_statement_with_semicolon,indent=0]
+----
+
+can be more idiomatically written as:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=single_statement_without_semicolon,indent=0]
+----
+
+Multiple statements in a line require semicolons to separate them:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=statements_separated_by_semicolon,indent=0]
+----
+
+=== Optional return keyword
+
+In Groovy, the last expression evaluated in the body of a method or a closure is returned. This means that the `return` keyword is optional.
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=return_keyword,indent=0]
+----
+
+Can be shortened to:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=omitted_return_keyword,indent=0]
+----
+
+=== Optional public keyword
+
+By default, Groovy classes and methods are `public`. Therefore this class: 
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=public_keyword,indent=0]
+----
+
+is identical to this class:
 
-=== Optional parentheses (TBD)
-=== Optional semicolons (TBD)
-=== Optional return keyword (TBD)
-=== Optional public keyword (TBD)
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/OptionalityTest.groovy[tags=omitted_public,indent=0]
+----
 
 [[Groovy-Truth]]
-== The Groovy Truth (TBD)
+== The Groovy Truth
 
-=== Customizing the truth with asBoolean() methods (TBD)
+Groovy decides whether a expression is true or false by applying the rules given below.
 
-== Typing (WIP)
+=== Boolean expressions
+True if the corresponding Boolean value is `true`.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=boolean_truth,indent=0]
+----
+
+=== Collections
+Non-empty Collections are true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=collection_truth,indent=0]
+----
+
+=== Matchers
+True if the Matcher has at least one match.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=matcher_truth,indent=0]
+----
+
+=== Iterators and Enumerations
+Iterators and Enumerations with further elements are coerced to true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=iterator_enumeration_truth,indent=0]
+----
+
+=== Maps
+Non-empty Maps are evaluated to true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=map_truth,indent=0]
+----
+
+=== Strings
+Non-empty Strings, GStrings and CharSequences are coerced to true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=string_truth,indent=0]
+----
+
+=== Numbers
+Non-zero numbers are true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=number_truth,indent=0]
+----
+
+=== Object References
+Non-null object references are coerced to true.
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=object_truth,indent=0]
+----
+
+=== Customizing the truth with asBoolean() methods
+
+In order to customize whether groovy evaluates your object to `true` or `false` implement the `asBoolean()` method:
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=asBoolean_object,indent=0]
+----
+
+Groovy will call this method to coerce your object to a boolean value, e.g.:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/semantics/TheGroovyTruthTest.groovy[tags=asBoolean_usage,indent=0]
+----
+
+== Typing
 
 === Optional typing
 
@@ -526,7 +861,7 @@ include::{projectdir}/src/spec/test/typing/OptionalTypingTest.groovy[tags=option
 ----
 <1> both the return type and the parameter types use `def`
 <2> it makes it possible to use the method with `String`
-<3> but also with `int`s since the `plus` method is defined
+<3> but also with `int` since the `plus` method is defined
 
 TIP: Using the `def` keyword here is recommanded to describe the intent of a method which is supposed to work on any
 type, but technically, we could use `Object` instead and the result would be the same: `def` is, in Groovy, strictly
@@ -542,7 +877,7 @@ include::{projectdir}/src/spec/test/typing/OptionalTypingTest.groovy[tags=option
 ----
 <1> if we want to omit the return type, an explicit modifier has to be set.
 <2> it is still possible to use the method with `String`
-<3> and also with `int`s
+<3> and also with `int`
 
 TIP: Omitting types is in general considered a bad practice in method parameters or method return types for public APIs.
 While using `def` in a local variable is not really a problem because the visibility of the variable is limited to the
@@ -578,7 +913,8 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=stc_intr
 
 This means that in general, in Groovy, you can't make any assumption about the type of an object beyond its declaration
 type, and even if you know it, you can't determine at compile time what method will be called, or which property will
-be retrieved, and this is *perfectly fine*. This is how dynamic languages work, and it has a lot of interest.
+be retrieved. It has a lot of interest, going from writing DSLs to testing, which is discussed in other sections of this
+manual.
 
 However, if your program doesn't rely on dynamic features and that you come from the static world (in particular, from
 a Java mindset), not catching such "errors" at compile time can be surprising. As we have seen in the previous example,
@@ -679,7 +1015,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=stc_assi
 ----
 ====
 
-* _or_ `T` is an array and `A` is an array and the component type of `A` is assignable to the component type of `B`
+* _or_ `T` is an array and `A` is an array and the component type of `A` is assignable to the component type of `T`
 
 +
 
@@ -692,7 +1028,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=stc_assi
 ----
 ====
 
-* _or_ `T` is an array and `A` is a list and the component type of `A` is assignable to the component type of `B`
+* _or_ `T` is an array and `A` is a list and the component type of `A` is assignable to the component type of `T`
 
 +
 
@@ -891,7 +1227,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=stc_argp
 ----
 ====
 
-* _or_ `T` is an array and `A` is an array and the component type of `A` is assignable to the component type of `B`
+* _or_ `T` is an array and `A` is an array and the component type of `A` is assignable to the component type of `T`
 
 +
 
@@ -1098,7 +1434,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=map_lite
 
 |[source,groovy]
 ----
-include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=map_literal_inference_simple,indent=0]
+include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=map_literal_inference_gstring,indent=0]
 ----
 |`java.util.LinkedHashMap<GString,String>` be careful, the key is a `GString`!
 
@@ -1174,7 +1510,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=least_up
 <5> but `B` defines an additional `exit` method
 <6> the type of `list` is inferred as "list of the LUB of `A` and `B`"
 <7> so it is possible to call `greet` which is defined on both `A` and `B` through the `Greeter` interface
-<8> and it is possible to call `salut` which is defined on both `A` and `B` through the `Salut` interface
+<8> and it is possible to call `salute` which is defined on both `A` and `B` through the `Salute` interface
 <9> yet calling `exit` is a compile time error because it doesn't belong to the LUB of `A` and `B` (only defined in `B`)
 
 The error message will look like:
@@ -1212,7 +1548,7 @@ cast is *not* necessary. The compiler embeds _instanceof_ inference that makes t
 ===== Flow typing
 
 Flow typing is an important concept of Groovy in type checked mode and an extension of type inference. The idea is that
-the compiler is capable of infering the type of variables in the flow of the code, not just at initialization:
+the compiler is capable of inferring the type of variables in the flow of the code, not just at initialization:
 
 [source,groovy]
 ----
@@ -1371,7 +1707,7 @@ on the other side.
 
 ===== Return type inference
 
-The first thing that the type checker is capable of doing is infering the _return type_ of a closure. This is simply
+The first thing that the type checker is capable of doing is inferring the _return type_ of a closure. This is simply
  illustrated in the following example:
 
 [source,groovy]
@@ -1493,7 +1829,7 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingTest.groovy[tags=cl_pt_wo
 <2> it's not necessary to use an explicit type for `it`, which is inferred
 
 The `@ClosureParams` annotation minimally accepts one argument, which is named a _type hint_. A type hint is a class which
-is reponsible for completing type information at compile time for the closure. In this example, the type hint being used
+is responsible for completing type information at compile time for the closure. In this example, the type hint being used
 is `groovy.transform.stc.FirstParam` which indicated to the type checker that the closure will accept one parameter
 whose type is the type of the first parameter of the method. In this case, the first parameter of the method is `Person`,
 so it indicates to the type checker that the first parameter of the closure is in fact a `Person`.
@@ -1576,7 +1912,7 @@ the arguments if the arity of each method is different. In the example above, `f
 
 |`FromString`
 |Yes
-|Infers the closure parameter typs from the `options` argument. The `options` argument consists of an array of comma-separated
+|Infers the closure parameter types from the `options` argument. The `options` argument consists of an array of comma-separated
 non-primitive types. Each element of the array corresponds to a single signature, and each comma in an element separate
 parameters of the signature. In short, this is the most generic type hint, and each string of the `options` map is *parsed*
 as if it was a signature literal. While being very powerful, this type hint must be avoided if you can because it increases
@@ -1605,14 +1941,14 @@ include::{projectdir}/src/spec/test/typing/TypeCheckingHintsTest.groovy[tags=typ
 
 |===
 
-TIP: Even though you use `FirstParam`, `SecondParam` or `ThirdParam` as a type hint, it doesn't stricly mean that the
+TIP: Even though you use `FirstParam`, `SecondParam` or `ThirdParam` as a type hint, it doesn't strictly mean that the
 argument which will be passed to the closure *will* be the first (resp. second, third) argument of the method call. It
 only means that the *type* of the parameter of the closure will be the *same* as the type of the first (resp.  second,
  third) argument of the method call.
 
 In short, the lack of the `@ClosureParams` annotation on a method accepting a `Closure` will *not* fail compilation. If
  present (and it can be present in Java sources as well as Groovy sources), then the type checker has *more* information
- and can perform additional type inference. This makes this feature particularily interesting for framework developers.
+ and can perform additional type inference. This makes this feature particularly interesting for framework developers.
 
 ===== `@DelegatesTo`
 
@@ -1620,7 +1956,7 @@ The `@DelegatesTo` annotation is used by the type checker to infer the type of t
 to instruct the compiler what is the type of the delegate and the delegation strategy. The `@DelegatesTo` annotation is
 discussed in a link:core-domain-specific-languages.html#section-delegatesto[specific section].
 
-=== Static compilation (WIP)
+=== Static compilation
 
 ==== Dynamic vs static
 
@@ -1690,7 +2026,7 @@ There are several benefits of using `@CompileStatic` on your code:
 * immunity to <<compilestatic-annotation,monkey patching>>
 * performance improvements
 
-The performance improvements depend on the kind of program you are executing. It it is I/O bound, the difference between
+The performance improvements depend on the kind of program you are executing. If it is I/O bound, the difference between
 statically compiled code and dynamic code is barely noticeable. On highly CPU intensive code, since the bytecode which
 is generated is very close, if not equal, to the one that Java would produce for an equivalent program, the performance
 is greatly improved.
@@ -1701,3 +2037,5 @@ There is only one way to determine which version you should choose: measuring. T
 *and* the JVM that you use, the performance can be significantly different. In particular, the _invokedynamic_ version of
 Groovy is very sensitive to the JVM version in use.
 
+include::type-checking-extensions.adoc[leveloffset=+1]
+
diff --git a/src/spec/doc/core-syntax.adoc b/src/spec/doc/core-syntax.adoc
index 4de3004..9f252a1 100644
--- a/src/spec/doc/core-syntax.adoc
+++ b/src/spec/doc/core-syntax.adoc
@@ -8,8 +8,8 @@ but enhances it with specific constructs for Groovy, and allows certain simplifi
 
 === Single line comment
 
-Single line comments start with +//+ and can be found at any position in the line.
-The characters following +//+, till the end of the line, are considered part of the comment.
+Single line comments start with `//` and can be found at any position in the line.
+The characters following `//`, till the end of the line, are considered part of the comment.
 
 [source,groovy]
 ----
@@ -18,9 +18,9 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=single_line_comment,i
 
 === Multiline comment
 
-A multiline comment starts with +/\*+ and can be found at any position in the line.
-The characters following +/*+ will be considered part of the comment, including new line characters,
-up to the first +*/+ closing the comment.
+A multiline comment starts with `/\*` and can be found at any position in the line.
+The characters following `/*` will be considered part of the comment, including new line characters,
+up to the first `*/` closing the comment.
 Multiline comments can thus be put at the end of a statement, or even inside a statement.
 
 [source,groovy]
@@ -30,8 +30,8 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=multiline_comment,ind
 
 === GroovyDoc comment
 
-Similarly to multiline comments, GroovyDoc comments are multiline, but start with +/\**+ and end with +*/+.
-Lines following the first GroovyDoc comment line can optionally start with a star +*+.
+Similarly to multiline comments, GroovyDoc comments are multiline, but start with `/\**` and end with `*/`.
+Lines following the first GroovyDoc comment line can optionally start with a star `*`.
 Those comments are associated with:
 
 * type definitions (classes, interfaces, enums, annotations),
@@ -53,14 +53,14 @@ So you'll be able to use the same tags as with JavaDoc.
 
 Beside the single line comment, there is a special line comment, often called the _shebang_ line understood by UNIX systems
 which allows scripts to be run directly from the command-line, provided you have installed the Groovy distribution
-and the +groovy+ command is available on the +PATH+.
+and the `groovy` command is available on the `PATH`.
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=shebang_comment_line,indent=0]
 ----
 
-NOTE: The +#+ character must be the first character of the file. Any indentation would yield a compilation error.
+NOTE: The `#` character must be the first character of the file. Any indentation would yield a compilation error.
 
 == Keywords
 
@@ -110,9 +110,11 @@ The following list represents all the keywords of the Groovy language:
 |throw
 
 |throws
+|trait
 |true
 |try
-|while
+
+|while | | |
 
 |===
 
@@ -158,7 +160,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=keywords_valid_id_aft
 === Quoted identifiers
 
 Quoted identifiers appear after the dot of a dotted expression.
-For instance, the +name+ part of the +person.name+ expression can be quoted with +person."name"+ or +person.\'name'+.
+For instance, the `name` part of the `person.name` expression can be quoted with `person."name"` or `person.\'name'`.
 This is particularly interesting when certain identifiers contain illegal characters that are forbidden by the Java Language Specification,
 but which are allowed by Groovy when quoted. For example, characters like a dash, a space, an exclamation mark, etc.
 
@@ -187,19 +189,19 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=quoted_id_with_gstrin
 == Strings
 
 Text literals are represented in the form of chain of characters called strings.
-Groovy lets you instantiate +java.lang.String+ objects, as well as GStrings (+groovy.lang.GString+)
+Groovy lets you instantiate `java.lang.String` objects, as well as GStrings (`groovy.lang.GString`)
 which are also called _interpolated strings_ in other programming languages.
 
 === Single quoted string
 
-Single quoted strings are a series of characters surounded by single quotes:
+Single quoted strings are a series of characters surrounded by single quotes:
 
 [source,groovy]
 ----
-include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=quoted_id_with_gstring,indent=0]
+include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=string_1,indent=0]
 ----
 
-NOTE: Single quoted strings are plain +java.lang.String+ and don't support interpolation.
+NOTE: Single quoted strings are plain `java.lang.String` and don't support interpolation.
 
 === String concatenation
 
@@ -212,14 +214,14 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=string_plus,indent=0]
 
 === Triple single quoted string
 
-Triple single quoted strings are a series of characters surrounded by single quotes:
+Triple single quoted strings are a series of characters surrounded by triplets of single quotes:
 
 [source,groovy]
 ----
-include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=string_1,indent=0]
+include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=triple_single_0,indent=0]
 ----
 
-NOTE: Triple single quoted strings are plain +java.lang.String+ and don't support interpolation.
+NOTE: Triple single quoted strings are plain `java.lang.String` and don't support interpolation.
 
 Triple single quoted strings are multiline.
 You can span the content of the string across line boundaries without the need to split the string in several pieces, without contatenation or newline escape characters:
@@ -230,8 +232,8 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=triple_single_1,inden
 ----
 
 If your code is indented, for example in the body of the method of a class, your string will contain the whitespace of the indentation.
-The Groovy Development Kit contains methods for stripping out the indentation with the +String#stripIndent()+ method,
-and with the +String#stripMargin()+ method that takes a delimiter character to identify the text to remove from the beginning of a string.
+The Groovy Development Kit contains methods for stripping out the indentation with the `String#stripIndent()` method,
+and with the `String#stripMargin()` method that takes a delimiter character to identify the text to remove from the beginning of a string.
 
 When creating a string as follows:
 
@@ -298,7 +300,7 @@ Some special characters also use the backslash as escape character:
 
 ==== Unicode escape sequence
 
-For characters that are not present on your keyboard, you can use unicode escape sequances: 
+For characters that are not present on your keyboard, you can use unicode escape sequences: 
 a backslash, followed by 'u', then 4 hexadecimal digits.
 
 For example, the Euro currency symbol can be represented with:
@@ -317,8 +319,8 @@ Double quoted strings are a series of characters surrounded by double quotes:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=string_5,indent=0]
 ----
 
-NOTE: Double quoted strings are plain +java.lang.String+ if there's no interpolated expression, 
-but are +groovy.lang.GString+ instances if interpolation is present.
+NOTE: Double quoted strings are plain `java.lang.String` if there's no interpolated expression,
+but are `groovy.lang.GString` instances if interpolation is present.
 
 NOTE: To escape a double quote, you can use the backslash character: +"A double quote: \""+.
 
@@ -326,8 +328,8 @@ NOTE: To escape a double quote, you can use the backslash character: +"A double
 
 Any Groovy expression can be interpolated in all string literals, apart from single and triple single quoted strings.
 Interpolation is the act of replacing a placeholder in the string with its value upon evaluation of the string.
-The placeholder expressions are surrounded by +${}+ or prefixed with +$+ for dotted expressions.
-The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling +toString()+ on that expression.
+The placeholder expressions are surrounded by `${}` or prefixed with `$` for dotted expressions.
+The expression value inside the placeholder is evaluated to its string representation when the GString is passed to a method taking a String as argument by calling `toString()` on that expression.
 
 Here, we have a string with a placeholder referencing a local variable:
 
@@ -344,18 +346,18 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_2,indent=0]
 ----
 
 [NOTE]
-Not only expressions are actually allowed in between the +${}+ placeholder. Statements are also allowed, but a statement's value is just +null+. 
+Not only expressions are actually allowed in between the `${}` placeholder. Statements are also allowed, but a statement's value is just `null`.
 So if several statements are inserted in that placeholder, the last one should somehow return a meaningful value to be inserted. 
 For instance, +"The sum of 1 and 2 is equal to ${def a = 1; def b = 2; a + b}"+ is supported and works as expected but a good practice is usually to stick to simple expressions inside GString placeholders.
 
-In addition to +${}+ placeholders, we can also use a lone +$+ sign prefixing a dotted expression:
+In addition to `${}` placeholders, we can also use a lone `$` sign prefixing a dotted expression:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_3,indent=0]
 ----
 
-But only dotted expressions of the form +a.b+, +a.b.c+, etc, are valid, but expressions that would contain parentheses like method calls, curly braces for closures, or arithmetic operators would be invalid.
+But only dotted expressions of the form `a.b`, `a.b.c`, etc, are valid, but expressions that would contain parentheses like method calls, curly braces for closures, or arithmetic operators would be invalid.
 Given the following variable definition of a number:
 
 [source,groovy]
@@ -363,17 +365,17 @@ Given the following variable definition of a number:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_4,indent=0]
 ----
 
-The following statement will throw a +groovy.lang.MissingPropertyException+ because Groovy believes you're trying to access the +toString+ property of that number, which doesn't exist:
+The following statement will throw a `groovy.lang.MissingPropertyException` because Groovy believes you're trying to access the `toString` property of that number, which doesn't exist:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_5,indent=0]
 ----
 
-NOTE: You can think of +"$number.toString()"+ as being interpreted by the parser as +"${number.toString}()"+.
+NOTE: You can think of `"$number.toString()"` as being interpreted by the parser as `"${number.toString}()"`.
 
-If you need to escape the +$+ or +${}+ placeholders in a GString so they appear as is without interpolation, 
-you just need to use a +\+ backslash character to escape the dollar sign:
+If you need to escape the `$` or `${}` placeholders in a GString so they appear as is without interpolation,
+you just need to use a `\` backslash character to escape the dollar sign:
 
 [source,groovy]
 ----
@@ -382,14 +384,14 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=gstring_6,indent=0]
 
 ==== Special case of interpolating closure expressions
 
-So far, we've seen we could interpolate arbitrary expressions inside the +${}+ placeholder, but there is a special case and notation for closure expressions. When the placeholder contains an arrow, +${->}+, the expression is actually a closure expression -- you can think of it as a closure with a dollar prepended in front of it:
+So far, we've seen we could interpolate arbitrary expressions inside the `${}` placeholder, but there is a special case and notation for closure expressions. When the placeholder contains an arrow, `${->}`, the expression is actually a closure expression -- you can think of it as a closure with a dollar prepended in front of it:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=closure_in_gstring_1,indent=0]
 ----
 <1> The closure is a parameterless closure which doesn't take arguments.
-<2> Here, the closure takes a single +java.io.StringWriter+ argument, to which you can append content  with the +<<+ leftShift operator.
+<2> Here, the closure takes a single `java.io.StringWriter` argument, to which you can append content  with the `<<` leftShift operator.
 In either case, both placeholders are embedded closures.
 
 In appearance, it looks like a more verbose way of defining expressions to be interpolated,
@@ -401,10 +403,10 @@ Let's consider the following sample:
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=closure_in_gstring_2,indent=0]
 ----
-<1> We define a +number+ variable containing +1+ that we then interpolate within two GStrings, 
-as an expression in +eagerGString+ and as a closure in +lazyGString+.
-<2> We expect the resulting string to contain the same string value of 1 for +eagerGString+.
-<3> Similarily for +lazyGString+
+<1> We define a `number` variable containing `1` that we then interpolate within two GStrings,
+as an expression in `eagerGString` and as a closure in `lazyGString`.
+<2> We expect the resulting string to contain the same string value of 1 for `eagerGString`.
+<3> Similarily for `lazyGString`
 <4> Then we change the value of the variable to a new number
 <5> With a plain interpolated expression, the value was actually bound at the time of creation of the GString.
 <6> But with a closure expression, the closure is called upon each coercion of the GString into String,
@@ -412,13 +414,13 @@ resulting in an updated string containing the new number value.
 
 [NOTE]
 An embedded closure expression taking more than one parameter will generate an exception at runtime.
-Only closures with zero or one paramaters are allowed.
+Only closures with zero or one parameters are allowed.
 
 ==== Inteoperability with Java
 
-When a method (whether implemented in Java or Groovy) expects a +java.lang.String+, 
-but we pass a +groovy.lang.GString+ instance, 
-the +toString()+ method of the GString is automatically and transparently called.
+When a method (whether implemented in Java or Groovy) expects a `java.lang.String`,
+but we pass a `groovy.lang.GString` instance,
+the `toString()` method of the GString is automatically and transparently called.
 
 [source,groovy]
 ----
@@ -427,7 +429,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=java_gstring_interop_
 <1> We create a GString variable
 <2> We double check it's an instance of the GString
 <3> We then pass that GString to a method taking a String as parameter
-<4> The signature of the +takeString()+ method explicitly says its sole parameter is a String
+<4> The signature of the `takeString()` method explicitly says its sole parameter is a String
 <5> We also verify that the parameter is indeed a String and not a GString.
 
 ==== GString and String hashCodes
@@ -466,7 +468,7 @@ NOTE: Neither double quotes nor single quotes need be escaped in triple double q
 
 === Slashy string
 
-Beyond the usual quoted strings, Groovy offers slashy strings, which use +/+ as delimiters.
+Beyond the usual quoted strings, Groovy offers slashy strings, which use `/` as delimiters.
 Slashy strings are particularly useful for defining regular expressions and patterns, 
 as there is no need to escape backslashes.
 
@@ -510,7 +512,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=slashy_5,indent=0]
 
 === Dollar slashy string
 
-Dollar slashy strings are multiline GStrings delimited with an opening +$/+ and and a closing +/$+.
+Dollar slashy strings are multiline GStrings delimited with an opening `$/` and and a closing `/$`.
 The escaping character is the dollar sign, and it can escape another dollar, or a forward slash.
 But both dollar and forward slashes don't need to be escaped, except to escape the dollar of a string subsequence that would start like a GString placeholder sequence, or if you need to escape a sequence that would start like a closing dollar slashy string delimiter.
 
@@ -532,40 +534,40 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=dollar_slashy_1,inden
 |Escape character
 
 |Single quoted
-|+\'...'+
+|`\'...'`
 |icon:check-empty[]
 |icon:check-empty[]
-|+\+
+|`\`
 
 |Triple single quoted
-|+\'''...\'''+
+|`\'''...\'''`
 |icon:check-empty[]
 |icon:check[]
-|+\+
+|`\`
 
 |Double quoted
-|+"..."+
+|`"..."`
 |icon:check[]
 |icon:check-empty[]
-|+\+
+|`\`
 
 |Triple double quoted
-|+"""..."""+
+|`"""..."""`
 |icon:check[]
 |icon:check[]
-|+\+
+|`\`
 
 |Slashy
-|+/.../+
+|`/.../`
 |icon:check[]
 |icon:check[]
-|+\+
+|`\`
 
 |Dollar slashy
-|+$/.../$+
+|`$/.../$`
 |icon:check[]
 |icon:check[]
-|+$+
+|`$`
 |====
 
 === Characters
@@ -577,8 +579,8 @@ However, you can be explicit about making a Groovy string an actual character, b
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=char,indent=0]
 ----
-<1> by being explicit when declaring a variable holding the character by specifying the +char+ type
-<2> by using type coercion with the +as+ operator
+<1> by being explicit when declaring a variable holding the character by specifying the `char` type
+<2> by using type coercion with the `as` operator
 <3> by using a cast to char operation
 
 NOTE: The first option [conum,data-value=1]_1_ is interesting when the character is held in a variable,
@@ -586,18 +588,18 @@ while the other two ([conum,data-value=2]_2_ and [conum,data-value=3]_3_) are mo
 
 == Numbers
 
-Groovy supports different kinds of integral literals and decimal literals, backed by the usual +Number+ types of Java.
+Groovy supports different kinds of integral literals and decimal literals, backed by the usual `Number` types of Java.
 
 === Integral literals
 
 The integral literal types are the same as in Java:
 
-* +byte+
-* +char+
-* +short+
-* +int+
-* +long+
-* +java.lang.BigInteger+
+* `byte`
+* `char`
+* `short`
+* `int`
+* `long`
+* `java.lang.BigInteger`
 
 You can create integral numbers of those types with the following declarations:
 
@@ -606,7 +608,7 @@ You can create integral numbers of those types with the following declarations:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=int_decl,indent=0]
 ----
 
-If you use optional typing by using the +def+ keyword, the type of the integral number will vary:
+If you use optional typing by using the `def` keyword, the type of the integral number will vary:
 it'll adapt to the capacity of the type that can hold that number.
 
 For positive numbers:
@@ -627,7 +629,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=wide_int_negative,ind
 
 ===== Binary literal
 
-In Java 6 and before, as well as in Groovy, numbers could be represented in decimal, octal and hexadecimal bases, and with Java 7 and Groovy 2, you can use a binary notation with the ++0b++ prefix:
+In Java 6 and before, as well as in Groovy, numbers could be represented in decimal, octal and hexadecimal bases, and with Java 7 and Groovy 2, you can use a binary notation with the `0b` prefix:
 
 [source,groovy]
 ----
@@ -636,7 +638,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=binary_literal_exampl
 
 ===== Octal literal
 
-Octal numbers are specified in the typical format of ++0++ followed by octal digits.
+Octal numbers are specified in the typical format of `0` followed by octal digits.
 
 [source,groovy]
 ----
@@ -645,7 +647,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=octal_literal_example
 
 ===== Hexadecimal literal
 
-Hexadecimal numbers are specified in the typical format of ++0x++ followed by hex digits.
+Hexadecimal numbers are specified in the typical format of `0x` followed by hex digits.
 
 [source,groovy]
 ----
@@ -656,9 +658,9 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=hexadecimal_literal_e
 
 The decimal literal types are the same as in Java:
 
-* +float+
-* +double+
-* +java.lang.BigDecimal+
+* `float`
+* `double`
+* `java.lang.BigDecimal`
 
 You can create decimal numbers of those types with the following declarations:
 
@@ -667,7 +669,7 @@ You can create decimal numbers of those types with the following declarations:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=float_decl,indent=0]
 ----
 
-Decimals can use exponents, with the +e+ or +E+ exponent letter, followed by an optional sign,
+Decimals can use exponents, with the `e` or `E` exponent letter, followed by an optional sign,
 and a integral number representing the exponent:
 
 [source,groovy]
@@ -675,9 +677,9 @@ and a integral number representing the exponent:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=float_exp,indent=0]
 ----
 
-Conveniently for exact decimal number calculations, Groovy choses +java.lang.BigDecimal+ as its decimal number type.
-In addition, both +float+ and +double+ are supported, but require an explicit type declaration, type coercion or suffix.
-Even if +BigDecimal+ is the default for decimal numbers, such literals are accepted in methods or closures taking +float+ or +double+ as parameter types.
+Conveniently for exact decimal number calculations, Groovy choses `java.lang.BigDecimal` as its decimal number type.
+In addition, both `float` and `double` are supported, but require an explicit type declaration, type coercion or suffix.
+Even if `BigDecimal` is the default for decimal numbers, such literals are accepted in methods or closures taking `float` or `double` as parameter types.
 
 NOTE: Decimal numbers can't be represented using a binary, octal or hexadecimal representation.
 
@@ -700,22 +702,22 @@ We can force a number (including binary, octals and hexadecimals) to have a spec
 |Suffix
 
 |BigInteger
-|+G+ or +g+
+|`G` or `g`
 
 |Long
-|+L+ or +l+
+|`L` or `l`
 
 |Integer
-|+I+ or +i+
+|`I` or `i`
 
 |BigDecimal
-|+G+ or +g+
+|`G` or `g`
 
 |Double
-|+D+ or +d+
+|`D` or `d`
 
 |Float
-|+F+ or +f+
+|`F` or `f`
 |====
 
 Examples:
@@ -732,11 +734,11 @@ and what their resulting types are.
 
 Division and power binary operations aside (covered below),
 
-* binary operations between +byte+, +char+, +short+ and +int+ result in +int+
-* binary operations involving +long+ with +byte+, +char+, +short+ and +int+ result in +long+
-* binary operations involving +BigInteger+ and any other integral type result in +BigInteger+
-* binary operations between +float+, +double+ and +BigDecimal+ result in +double+
-* binary operations between two +BigDecimal+ result in +BigDecimal+
+* binary operations between `byte`, `char`, `short` and `int` result in `int`
+* binary operations involving `long` with `byte`, `char`, `short` and `int` result in `long`
+* binary operations involving `BigInteger` and any other integral type result in `BigInteger`
+* binary operations between `float`, `double` and `BigDecimal` result in `double`
+* binary operations between two `BigDecimal` result in `BigDecimal`
 
 The following table summarizes those rules:
 
@@ -854,48 +856,48 @@ The following table summarizes those rules:
 |====
 
 [NOTE]
-Thanks Groovy's operator overloading, the usual arithmetic operators work as well with +BigInteger+ and +BigDecimal+,
-unlike in Java where you have to use explict methods for operating on those numbers.
+Thanks Groovy's operator overloading, the usual arithmetic operators work as well with `BigInteger` and `BigDecimal`,
+unlike in Java where you have to use explicit methods for operating on those numbers.
 
 [[integer_division]]
 ==== The case of the division operator
 
-The division operators +/+ (and +/=+ for division and assignment) produce a +double+ result 
-if either operand is a +float+ or +double+, and a +BigDecimal+ result otherwise 
-(when both operands are any combination of an integral type +short+, +char+, +byte+, +int+, +long+,
-+BigInteger+ or +BigDecimal+).
+The division operators `/` (and `/=` for division and assignment) produce a `double` result
+if either operand is a `float` or `double`, and a `BigDecimal` result otherwise
+(when both operands are any combination of an integral type `short`, `char`, `byte`, `int`, `long`,
+`BigInteger` or `BigDecimal`).
 
-+BigDecimal+ division is performed with the +divide()+ method if the division is exact
+`BigDecimal` division is performed with the `divide()` method if the division is exact
 (ie. yielding a result that can be represented within the bounds of the same precision and scale),
-or using a +MathContext+ with a http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#precision()[precision] 
+or using a `MathContext` with a http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#precision()[precision]
 of the maximum of the two operands' precision plus an extra precision of 10,
 and a http://docs.oracle.com/javase/7/docs/api/java/math/BigDecimal.html#scale()[scale] 
 of the maximum of 10 and the maximum of the operands' scale.
 
 [NOTE]
-For integer division like in Java, you should use the +intdiv()+ method,
+For integer division like in Java, you should use the `intdiv()` method,
 as Groovy doesn't provide a dedicated integer division operator symbol.
 
 [[power_operator]]
 ==== The case of the power operator
 
-The power operation is represented by the +**+ operator, with two parameters: the base and the exponent.
+The power operation is represented by the `**` operator, with two parameters: the base and the exponent.
 The result of the power operation depends on its operands, and the result of the operation
 (in particular if the result can be represented as an integral value).
 
 The following rules are used by Groovy's power operation to determine the resulting type:
 
 * If the exponent is a decimal value
-** if the result can be represented as an +Integer+, then return an +Integer+
-** else if the result can be represented as a +Long+, then return a +Long+
-** otherwise return a +Double+
+** if the result can be represented as an `Integer`, then return an `Integer`
+** else if the result can be represented as a `Long`, then return a `Long`
+** otherwise return a `Double`
 * If the exponent is an integral value
-** if the exponent is strictly negative, then return an +Integer+, +Long+ or +Double+ if the result value fits in that type
+** if the exponent is strictly negative, then return an `Integer`, `Long` or `Double` if the result value fits in that type
 ** if the exponent is positive or zero
-*** if the base is a +BigDecimal+, then return a +BigDecimal+ result value
-*** if the base is a +BigInteger+, then return a +BigInteger+ result value
-*** if the base is an +Integer+, then return an +Integer+ if the result value fits in it, otherwise a +BigInteger+
-*** if the base is a +Long+, then return a +Long+ if the result value fits in it, otherwise a +BigInteger+
+*** if the base is a `BigDecimal`, then return a `BigDecimal` result value
+*** if the base is a `BigInteger`, then return a `BigInteger` result value
+*** if the base is an `Integer`, then return an `Integer` if the result value fits in it, otherwise a `BigInteger`
+*** if the base is a `Long`, then return a `Long` if the result value fits in it, otherwise a `BigInteger`
 
 We can illustrate those rules with a few examples:
 
@@ -906,7 +908,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=number_power,indent=0
 
 == Booleans
 
-Boolean is a special data type that is used to represent truth values: ++true++ and ++false++.
+Boolean is a special data type that is used to represent truth values: `true` and `false`.
 Use this data type for simple flags that track true/false <<_conditional_operators,conditions>>.
 
 Boolean values can be stored in variables, assigned into fields, just like any other data type:
@@ -916,7 +918,7 @@ Boolean values can be stored in variables, assigned into fields, just like any o
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=variable_store_boolean_value,indent=0]
 ----
 
-++true++ and ++false++ are the only two primitive boolean values.
+`true` and `false` are the only two primitive boolean values.
 But more complex boolean expressions can be represented using <<_bitwise_and_logical_operators,logical operators>>.
 
 In addition, Groovy has <<_the_groovy_truth,special rules>> (often referred to as _Groovy Truth_)
@@ -925,8 +927,8 @@ for coercing non-boolean objects to a boolean value.
 == Lists
 
 Groovy uses a comma-separated list of values, surrounded by square brackets, to denote lists.
-Groovy lists are plain JDK +java.util.List+, as Groovy doesn't define its own collection classes.
-The concrete list implementation used when defining list literals are +java.util.ArrayList+ by default,
+Groovy lists are plain JDK `java.util.List`, as Groovy doesn't define its own collection classes.
+The concrete list implementation used when defining list literals are `java.util.ArrayList` by default,
 unless you decide to specify otherwise, as we shall see later on.
 
 [source,groovy]
@@ -934,8 +936,8 @@ unless you decide to specify otherwise, as we shall see later on.
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=list_1,indent=0]
 ----
 <1> We define a list numbers delimited by commas and surrounded by square brackets, and we assign that list into a variable
-<2> The list is an instance of Java's +java.util+List+ interface
-<3> The size of the list can be queried with the +size()+ method, and shows our list contains 3 elements
+<2> The list is an instance of Java's `java.util.List` interface
+<3> The size of the list can be queried with the `size()` method, and shows our list contains 3 elements
 
 In the above example, we used a homogeneous list, but you can also create lists containing values of heterogeneous types:
 
@@ -945,29 +947,29 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=list_2,indent=0]
 ----
 <1> Our list here contains a number, a string and a boolean value
 
-We mentioned that by default, list literals are actually instances of +java.util.ArrayList+, 
+We mentioned that by default, list literals are actually instances of `java.util.ArrayList`,
 but it is possible to use a different backing type for our lists, 
-thanks to using type coercion with the +as+ operator, or with explicit type declaration for your variables:
+thanks to using type coercion with the `as` operator, or with explicit type declaration for your variables:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=coercion_of_list,indent=0]
 ----
-<1> We use coercion with the +as+ operator to explicitly request a +java.util.LinkedList+ implementation
-<2> We can say that the variable holding the list literal is of type +java.util.LinkedList+
+<1> We use coercion with the `as` operator to explicitly request a `java.util.LinkedList` implementation
+<2> We can say that the variable holding the list literal is of type `java.util.LinkedList`
 
-You can access elements of the list with the +[]+ subscript operator (both for reading and setting values)
+You can access elements of the list with the `[]` subscript operator (both for reading and setting values)
 with positive indices or negative indices to access elements from the end of the list, as well as with ranges,
-and use the +<<+ leftShift operator to append elements to a list:
+and use the `<<` leftShift operator to append elements to a list:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=subscript_and_leftshift,indent=0]
 ----
-<1> Access the first element of the list (zeroth-based counting)
+<1> Access the first element of the list (zero-based counting)
 <2> Access the last element of the list with a negative index: -1 is the first element from the end of the list
 <3> Use an assignment to set a new value for the third element of the list
-<4> Use the +<<+ leftShift operator to append an element at the end of the list
+<4> Use the `<<` leftShift operator to append an element at the end of the list
 <5> Access two elements at once, returning a new list containing those two elements
 <6> Use a range to access a range of values from the list, from a start to an end element position
 
@@ -991,7 +993,7 @@ include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=array_1,indent=0]
 ----
 <1> Define an array of strings using explicit variable type declaration
 <2> Assert that we created an array of strings
-<3> Create an array of ints with the +as+ operator
+<3> Create an array of ints with the `as` operator
 <4> Assert that we created an array of primitive ints
 
 You can also create multi-dimensional arrays:
@@ -1027,16 +1029,16 @@ and the whole keys and values surrounded by square brackets.
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=map_def_access,indent=0]
 ----
 <1> We define a map of string color names, associated with their hexadecimal-coded html colors
-<2> We use the subscript notation to check the content associated with the +red+ key
+<2> We use the subscript notation to check the content associated with the `red` key
 <3> We can also use the property notation to assert the color green's hexadecimal representation
 <4> Similarily, we can use the subscript notation to add a new key/value pair
-<5> Or the property notation, to add the +yellow+ color
+<5> Or the property notation, to add the `yellow` color
 
 [NOTE]
 When using names for the keys, we actually define string keys in the map.
 
 [NOTE]
-Groovy creates maps that are actually instances of +java.util.LinkedHashMap+.
+Groovy creates maps that are actually instances of `java.util.LinkedHashMap`.
 
 If you try to access a key which is not present in the map:
 
@@ -1045,7 +1047,7 @@ If you try to access a key which is not present in the map:
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=unknown_key,indent=0]
 ----
 
-You will retrieve a +null+ result.
+You will retrieve a `null` result.
 
 In the examples above, we used string keys, but you can also use values of other types as keys:
 
@@ -1062,9 +1064,9 @@ But consider the case you want to pass a variable in lieu of the key, to have th
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=variable_key_1,indent=0]
 ----
-<1> The +key+ associated with the +\'Guillaume'+ name will actually be the +"key"+ string, not the value associated with the +key+ variable
-<2> The map doesn't contain the +\'name'+ key
-<3> Instead, the map contains a +\'key'+ key
+<1> The `key` associated with the `\'Guillaume'` name will actually be the `"key"` string, not the value associated with the `key` variable
+<2> The map doesn't contain the `\'name'` key
+<3> Instead, the map contains a `\'key'` key
 
 [NOTE]
 You can also pass quoted strings as well as keys: +["name": "Guillaume"]+.
@@ -1077,9 +1079,9 @@ When you need to pass variable values as keys in your map definitions, you must
 ----
 include::{projectdir}/src/spec/test/SyntaxTest.groovy[tags=variable_key_2,indent=0]
 ----
-<1> This time, we surround the +key+ variable with parentheses, to instruct the parser we are passing a variable rather than defining a string key
-<2> The map does contain the +name+ key
-<3> But the map doesn't contain the +key+ key as before
+<1> This time, we surround the `key` variable with parentheses, to instruct the parser we are passing a variable rather than defining a string key
+<2> The map does contain the `name` key
+<3> But the map doesn't contain the `key` key as before
 
 
 
diff --git a/src/spec/doc/core-testing-guide.adoc b/src/spec/doc/core-testing-guide.adoc
index 1265835..7ec1abf 100644
--- a/src/spec/doc/core-testing-guide.adoc
+++ b/src/spec/doc/core-testing-guide.adoc
@@ -84,8 +84,8 @@ assert [[1,2,3,3,3,3,4]].first().unique() == [1,2,3]
 <1> The error message shows the actual state of the collection, not the state before the `unique` method was applied
 
 [NOTE]
-If you choose to provide a custom assertion error message this can be done by using the Java syntax +assert
-expression1 : expression2+ where +expression1+ is the Boolean expression and +expression2+ is the custom error message.
+If you choose to provide a custom assertion error message this can be done by using the Java syntax `assert
+expression1 : expression2` where `expression1` is the Boolean expression and `expression2` is the custom error message.
  Be aware though that this will disable the power assert and will fully fallback to custom
  error messages on assertion errors.
 
@@ -189,7 +189,7 @@ include::{projectdir}/src/spec/test/testingguide/MockingExampleTests.groovy[tags
 <4> a call to `verify` (optional) checks whether the number of method calls is as expected
 
 `MockFor` and `StubFor` can not be used to test statically compiled classes e.g for Java classes or Groovy classes that
-make use of + at CompileStatic+. To stub and/or mock these classes you can use Spock or one of the Java mocking libraries.
+make use of `@CompileStatic`. To stub and/or mock these classes you can use Spock or one of the Java mocking libraries.
 
 [[testing_guide_emc]]
 ==== Expando Meta-Class (EMC)
@@ -237,7 +237,8 @@ include::{projectdir}/src/spec/test/testingguide/MockingExampleTests.groovy[tags
 ----
 
 Another alternative is to register a `MetaClassRegistryChangeEventListener`, track the changed classes and remove
-the changes in the cleanup method of your chosen testing runtime. A good example can be found https://github.com/grails/grails-core/blob/master/grails-bootstrap/src/main/groovy/org/codehaus/groovy/grails/cli/support/MetaClassRegistryCleaner.java[in the Grails web
+the changes in the cleanup method of your chosen testing runtime. A good example can be found
+https://github.com/grails/grails-core/blob/master/grails-bootstrap/src/main/groovy/grails/build/support/MetaClassRegistryCleaner.java[in the Grails web
 development framework].
 
 Besides using the `ExpandoMetaClass` on a class-level, there is also support for using the meta-class on a per-object
@@ -355,7 +356,7 @@ make certain types of tests easier to write.
 
 
 In this section, we will have a look at some of the methods provided by `GroovyTestCase`. A full list of these can be
-found in the JavaDoc documentation for http://groovy.codehaus.org/api/groovy/util/GroovyTestCase.html[groovy.util.GroovyTestCase],
+found in the JavaDoc documentation for gapi:groovy.util.GroovyTestCase[] ,
 don't forget it is inherited from `junit.framework.TestCase` which inherits all the `assert*` methods.
 
 ==== Assertion Methods
@@ -608,57 +609,4 @@ the `Browser` configuration is externalized. `GebTest` delegates methods like `g
 === More Geb
 
 In the previous section we only scratched the surface of the available Geb features. More information on Geb can be found
-at the http://gebish.org[project homepage].
-
-== Other Testing Libraries and Frameworks
-
-=== TestNG
-
-http://testng.org/[TestNG] is a testing framework inspired from JUnit and NUnit but with new functionality to make
-it more powerful and easier to use. Features include:
-
-* JDK 5 Annotations
-* Flexible test configuration
-* Support for data-driven testing (with `@DataProvider`)
-* Support for parameters
-* Allows distribution of tests on slave machines
-* Powerful execution model (no more TestSuite)
-* Supported by a variety of tools and plug-ins (Eclipse, IDEA, Maven, etc...)
-* Embeds `BeanShell` for further flexibility
-* Default JDK functions for runtime and logging (no dependencies)
-* Dependent methods for application server testing
-
-=== Mockito
-
-https://code.google.com/p/mockito/[Mockito] is a Java mocking library. It has very slim API, almost no time is needed
-to start mocking. Features include:
-
-* Mocks concrete classes as well as interfaces
-* Little annotation syntax sugar - `@Mock`
-* Verification errors are clean - click on stack trace to see failed verification in test; click on exception's cause
-to navigate to actual interaction in code. Stack trace is always clean.
-* Allows flexible verification in order (e.g: verify in order what you want, not every single interaction)
-* Supports exact-number-of-times and at-least-once verification
-* Flexible verification or stubbing using argument matchers (`anyObject()`, `anyString()` or `refEq()` for reflection-based
-equality matching)
-* Allows creating custom argument matchers or using existing Hamcrest matchers
-
-=== EasyMock
-
-http://easymock.org/[EasyMock] is a mocking library for Java. Features include:
-
-* Hand-writing classes for Mock Objects is not needed.
-* Supports refactoring-safe Mock Objects: test code will not break at runtime when renaming methods or reordering method parameters
-* Supports return values and exceptions.
-* Supports checking the order of method calls, for one or more Mock Objects.
-
-=== JBehave
-
-http://jbehave.org/[JBehave] is a framework for Behaviour-Driven Development (BDD). BDD is an evolution of test-driven
-development and acceptance-test driven design, and is intended to make these practices more accessible and intuitive
-to newcomers and experts alike. It shifts the vocabulary from being test-based to behaviour-based, and positions itself
-as a design philosophy.
-
-=== JMockit
-
-https://code.google.com/p/jmockit/[jmockit] is a mocking library for Java.
\ No newline at end of file
+at the http://gebish.org[project homepage].
\ No newline at end of file
diff --git a/src/spec/doc/core-traits.adoc b/src/spec/doc/core-traits.adoc
index 4dae27d..379fec5 100644
--- a/src/spec/doc/core-traits.adoc
+++ b/src/spec/doc/core-traits.adoc
@@ -27,7 +27,7 @@ include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=bird,ind
 <2> instantiate a new `Bird`
 <3> the `Bird` class automatically gets the behavior of the `FlyingAbility` trait
 
-Traits allow a wide range of capabilities, from simple composition to testing, which are described throughfully in this section.
+Traits allow a wide range of capabilities, from simple composition to testing, which are described thoroughly in this section.
 
 == Methods
 === Public methods
@@ -142,10 +142,14 @@ will let you do that:
 ----
 include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=trait_with_private_field,indent=0]
 ----
+<1> declare a private field `count` inside a trait
+<2> declare a public method `count` that increments the counter and returns it
+<3> declare a class that implements the `Counter` trait
+<4> the `count` method can use the private field to keep state
 
 TIP: This is a major difference with http://docs.oracle.com/javase/tutorial/java/IandI/defaultmethods.html[Java 8 virtual extension methods]. While virtual extension methods
-do not carry state, traits can. Also interesting traits in Groovy are supported starting with Java 6, but their implementation do not rely on virtual extension methods. This
-means that even if a trait can be seen from a Java class as a regular interface, this interface will *not* have default methods, only abstract ones.
+do not carry state, traits can. Moreover, traits in Groovy are supported starting with Java 6, because their implementation does not rely on virtual extension methods. This
+means that even if a trait can be seen from a Java class as a regular interface, that interface will *not* have default methods, only abstract ones.
 
 === Public fields
 
@@ -170,7 +174,7 @@ in the implementing class, the public field will appear as:
 String my_package_Foo__bar
 ----
 
-WARNING: While traits support public fields, it is not recommanded to use them and considered as a bad practice.
+WARNING: While traits support public fields, it is not recommended to use them and considered as a bad practice.
 
 == Composition of behaviors
 
@@ -400,7 +404,7 @@ This works but this approach has drawbacks:
 . the logging logic is bound to a "concrete" handler
 . we have an explicit reference to `DefaultHandler` in the `on` method, meaning that if we happen to change the trait that our class implements, code will be broken
 
-As an alternative, we can write another trait which responsability is limited to logging:
+As an alternative, we can write another trait which responsibility is limited to logging:
 
 [source,groovy]
 -----
@@ -419,6 +423,7 @@ include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=handlerw
 -----
 
 which will print:
+
 ----
 include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=handlerwithlogger_assert_output,indent=0]
 ----
@@ -435,7 +440,7 @@ that start with `say`:
 include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=sayhandler,indent=0]
 -----
 <1> a handler specific precondition
-<2> if the precondition is not meant, pass the message to the next handler in the chain
+<2> if the precondition is not met, pass the message to the next handler in the chain
 
 Then our final handler looks like this:
 
@@ -449,7 +454,7 @@ Which means:
 
 * messages will first go through the logging handler
 * the logging handler calls `super` which will delegate to the next handler, which is the `SayHandler`
-* if the message starts with `say`, then the hanlder consumes the message
+* if the message starts with `say`, then the handler consumes the message
 * if not, the `say` handler delegates to the next handler in the chain
 
 This approach is very powerful because it allows you to write handlers that do not know each other and yet let you
@@ -478,7 +483,7 @@ not called anymore.
 
 === Semantics of super inside a trait
 
-If a class implements multiple traits and that a call to an unqualified `super` is found, then:
+If a class implements multiple traits and a call to an unqualified `super` is found, then:
 
 . if the class implements another trait, the call delegates to the next trait in the chain
 . if there isn't any trait left in the chain, `super` refers to the super class of the implementing class (_this_)
@@ -505,8 +510,8 @@ is used for `toString`, so that the string representation of the proxy object wh
 == Advanced features
 === SAM type coercion
 
-If a trait defines a single abstract method, it is candidate for SAM type coercion. For example, imagine the following
-trait:
+If a trait defines a single abstract method, it is candidate for SAM (Single Abstract Method) type coercion. For example,
+imagine the following trait:
 
 [source,groovy]
 ----
@@ -587,7 +592,7 @@ the trait in its interface list, the behavior will be borrowed from the trait im
 
 This feature is in particular useful when you don't have access to the super class source code. It can be used to
 mock methods or force a particular implementation of a method in a subclass. It lets you refactor your code to keep
-the overriden logic in a single trait and inherit a new behavior just by implementing it. The alternative, of course,
+the overridden logic in a single trait and inherit a new behavior just by implementing it. The alternative, of course,
 is to override the method in *every* place you would have used the new code.
 
 
@@ -660,7 +665,7 @@ include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=staticfi
 <4> a static method _init_ is made available to the implementing class
 <5> the static field is _remapped_ to avoid the diamond issue
 
-As usual, it is not recommanded to use public fields. Anyway, should you want this, you must understand that the following code would fail:
+As usual, it is not recommended to use public fields. Anyway, should you want this, you must understand that the following code would fail:
 
 [source,groovy]
 -----
@@ -715,7 +720,7 @@ include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=intcoupl
 ----
 
 The reason is that the `sum` method accesses the _fields_ of the trait. So it is using the `x` and `y` values defined
-in the trait. If you want to use the values from the implementing class, then you need to derefencence fields by using
+in the trait. If you want to use the values from the implementing class, then you need to dereference fields by using
 getters and setters, like in this last example:
 
 [source,groovy]
@@ -723,6 +728,75 @@ getters and setters, like in this last example:
 include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=intcouple_impl_override_directgetter,indent=0]
 ----
 
+== Self types
+=== Type constraints on traits
+
+Sometimes you will want to write a trait that can only be applied to some type. For example, you may want to apply a
+trait on a class that extends another class which is beyond your control, and still be able to call those methods.
+To illustrate this, let's start with this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=selftype_intro,indent=0]
+----
+<1> A `Service` class, beyond your control (in a library, ...) defines a `sendMessage` method
+<2> A `Device` class, beyond your control (in a library, ...)
+<3> Defines a communicating trait for devices that can call the service
+<4> Defines `MyDevice` as a communicating device
+<5> The method from the trait is called, and `id` is resolved
+
+It is clear, here, that the `Communicating` trait can only apply to `Device`. However, there's no explicit
+contract to tell that, because traits cannot extend classes. However, the code compiles and runs perfectly
+fine, because `id` in the trait method will be resolved dynamically. The problem is that there is nothing that
+prevents the trait from being applied to any class which is *not* a `Device`. Any class which has an `id` would
+work, while any class that does not have an `id` property would cause a runtime error.
+
+The problem is even more complex if you want to enable type checking or apply `@CompileStatic` on the trait: because
+the trait knows nothing about itself being a `Device`, the type checker will complain saying that it does not find
+the `id` property.
+
+One possibility is to explicitly add a `getId` method in the trait, but it would not solve all issues. What if a method
+requires `this` as a parameter, and actually requires it to be a `Device`?
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=selftype_securityservice,indent=0]
+----
+
+If you want to be able to call this in the trait, then you will explicitly need to cast `this` into a `Device`. This can
+quickly become unreadable with explicit casts to this everywhere.
+
+=== The @SelfType annotation
+
+In order to make this contract explicit, and to make the type checker aware of the _type of itself_, Groovy provides
+a `@SelfType` annotation that will:
+
+* let you declare the types that a class that implements this trait must inherit or implement
+* throw a compile time error if those type constraints are not satisfied
+
+So in our previous example, we can fix the trait using the `@groovy.transform.SelfType` annotation:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=selftype_fixed,indent=0]
+----
+
+Now if you try to implement this trait on a class that is *not* a device, a compile-time error will occur:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=selftype_compiletimeerror,indent=0]
+----
+
+The error will be:
+
+----
+class 'MyDevice' implements trait 'Communicating' but does not extend self type class 'Device'
+----
+
+In conclusion, self types are a powerful way of declaring constraints on traits without having to declare the contract
+directly in the trait or having to use casts everywhere, maintaining separation of concerns as tight as it should be.
+
 == Limitations
 === Compatibility with AST transformations
 
@@ -743,3 +817,4 @@ include::{projectdir}/src/spec/test/TraitsSpecificationTest.groovy[tags=prefix_p
 <2> `x` is defined within the trait, prefix decrement is not allowed
 
 A workaround is to use the `+=` operator instead.
+
diff --git a/src/spec/doc/design-pattern-adapter.adoc b/src/spec/doc/design-pattern-adapter.adoc
index 050ef04..d338e55 100644
--- a/src/spec/doc/design-pattern-adapter.adoc
+++ b/src/spec/doc/design-pattern-adapter.adoc
@@ -11,7 +11,7 @@ Suppose we have the following classes:
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=adapter_delegation_classes,indent=0]
 ----
 
-We can ask the ++RoundHole++ class if a ++RoundPeg++ fits in it, but if we ask the same question for a ++SquarePeg++, then it will fail because the ++SquarePeg++ class doesn't have a ++radius++ property (i.e. doesn't satisfy the required interface).
+We can ask the `RoundHole` class if a `RoundPeg` fits in it, but if we ask the same question for a `SquarePeg`, then it will fail because the `SquarePeg` class doesn't have a `radius` property (i.e. doesn't satisfy the required interface).
 
 To get around this problem, we can create an adapter to make it appear to have the correct interface. It would look like this:
 
diff --git a/src/spec/doc/design-pattern-bouncer.adoc b/src/spec/doc/design-pattern-bouncer.adoc
index 5dadc57..316f6aa 100644
--- a/src/spec/doc/design-pattern-bouncer.adoc
+++ b/src/spec/doc/design-pattern-bouncer.adoc
@@ -4,7 +4,7 @@ The http://www.c2.com/cgi/wiki?BouncerPattern[Bouncer Pattern] describes usage o
 
 When writing utility methods, you should always guard against faulty input arguments. When writing internal methods, you may be able to ensure that certain pre-conditions always hold by having sufficient unit tests in place. Under such circumstances, you may reduce the desirability to have guards on your methods.
 
-Groovy differs from other languages in that you frequently use the ++assert++ method within your methods rather than having a large number of utility checker methods or classes.
+Groovy differs from other languages in that you frequently use the `assert` method within your methods rather than having a large number of utility checker methods or classes.
 
 == Null Checking Example
 
diff --git a/src/spec/doc/design-pattern-chain-of-responsibility.adoc b/src/spec/doc/design-pattern-chain-of-responsibility.adoc
index 0e9ecfb..68bfb71 100644
--- a/src/spec/doc/design-pattern-chain-of-responsibility.adoc
+++ b/src/spec/doc/design-pattern-chain-of-responsibility.adoc
@@ -4,7 +4,7 @@ In the Chain of Responsibility Pattern, objects using and implementing an interf
 
 == Example
 
-In this example, the script sends requests to the ++lister++ object. The ++lister++ points to a ++UnixLister++ object. If it can't handle the request, it sends the request to the ++WindowsLister++. If it can't handle the request, it sends the request to the ++DefaultLister++.
+In this example, the script sends requests to the `lister` object. The `lister` points to a `UnixLister` object. If it can't handle the request, it sends the request to the `WindowsLister`. If it can't handle the request, it sends the request to the `DefaultLister`.
 
 [source,groovy]
 ----
@@ -19,8 +19,8 @@ image::assets/img/ChainOfResponsibilityClasses.gif[]
 
 Variations to this pattern:
 
-* we could have an explicit interface, e.g. ++Lister++, to statically type the implementations but because of _duck-typing_ this is optional
-* we could use a chain tree instead of a list, e.g. ++if (animal.hasBackbone())++ delegate to ++VertebrateHandler++ else delegate to ++InvertebrateHandler++
+* we could have an explicit interface, e.g. `Lister`, to statically type the implementations but because of _duck-typing_ this is optional
+* we could use a chain tree instead of a list, e.g. `if (animal.hasBackbone())` delegate to `VertebrateHandler` else delegate to `InvertebrateHandler`
 * we could always pass down the chain even if we processed a request
 * we could decide at some point to not respond and not pass down the chain
 * we could use Groovy’s meta-programming capabilities to pass unknown methods down the chain
\ No newline at end of file
diff --git a/src/spec/doc/design-pattern-composite.adoc b/src/spec/doc/design-pattern-composite.adoc
index 898784b..4814755 100644
--- a/src/spec/doc/design-pattern-composite.adoc
+++ b/src/spec/doc/design-pattern-composite.adoc
@@ -4,11 +4,11 @@ The http://en.wikipedia.org/wiki/Composite_pattern[Composite Pattern] allows you
 
 == Example
 
-Consider this usage of the composite pattern where we want to call ++toString()++ on either ++Leaf++ or ++Composite++ objects.
+Consider this usage of the composite pattern where we want to call `toString()` on either `Leaf` or `Composite` objects.
 
 image::assets/img/CompositeClasses.gif[]
 
-In Java, the ++Component++ class is essential as it provides the type used for both leaf and composite nodes. In Groovy, because of duck-typing, we don't need it for that purpose, however, it can still server as a useful place to place common behaviour between the leaf and composite nodes.
+In Java, the `Component` class is essential as it provides the type used for both leaf and composite nodes. In Groovy, because of duck-typing, we don't need it for that purpose, however, it can still server as a useful place to place common behaviour between the leaf and composite nodes.
 
 For our purposes, we will assemble the following hierarchy of components.
 
diff --git a/src/spec/doc/design-pattern-decorator.adoc b/src/spec/doc/design-pattern-decorator.adoc
index 5b23ba2..7745e66 100644
--- a/src/spec/doc/design-pattern-decorator.adoc
+++ b/src/spec/doc/design-pattern-decorator.adoc
@@ -4,16 +4,16 @@ The http://en.wikipedia.org/wiki/Decorator_pattern[Decorator Pattern] provides a
 
 == Traditional Example
 
-Suppose we have the following ++Logger++ class.
+Suppose we have the following `Logger` class.
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=decorator_logger_class,indent=0]
 ----
 
-There might be times when it is useful to timestamp a log message, or times when we might want to change the case of the message. We could try to build all of this functionality into our ++Logger++ class. If we did that, the ++Logger++ class would start to be very complex. Also, everyone would obtain all of features even when they might not want a small subset of the features. Finally, feature interaction would become quite difficult to control.
+There might be times when it is useful to timestamp a log message, or times when we might want to change the case of the message. We could try to build all of this functionality into our `Logger` class. If we did that, the `Logger` class would start to be very complex. Also, everyone would obtain all of features even when they might not want a small subset of the features. Finally, feature interaction would become quite difficult to control.
 
-To overcome these drawbacks, we instead define two decorator classes. Uses of the ++Logger++ class are free to embellish their base logger with zero or more decorator classes in whatever order they desire. The classes look like this:
+To overcome these drawbacks, we instead define two decorator classes. Uses of the `Logger` class are free to embellish their base logger with zero or more decorator classes in whatever order they desire. The classes look like this:
 
 [source,groovy]
 ----
@@ -38,21 +38,21 @@ Now the timestamp itself has also been changed to be uppercase.
 
 == A touch of dynamic behaviour
 
-Our previous decorators were specific to ++Logger++ objects. We can use Groovy's Meta-Object Programming capabilities to create a decorator which is far more general purpose in nature. Consider this class:
+Our previous decorators were specific to `Logger` objects. We can use Groovy's Meta-Object Programming capabilities to create a decorator which is far more general purpose in nature. Consider this class:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=decorator_dynamic_behaviour_class,indent=0]
 ----
 
-It takes any class and decorates it so that any ++String++ method parameter will automatically be changed to lower case.
+It takes any class and decorates it so that any `String` method parameter will automatically be changed to lower case.
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=decorator_dynamic_behaviour_usage,indent=0]
 ----
 
-Just be careful with ordering here. The original decorators were restricted to decorating ++Logger++ objects. This decorator work with any object type, so we can't swap the ordering around, i.e. this won't work:
+Just be careful with ordering here. The original decorators were restricted to decorating `Logger` objects. This decorator work with any object type, so we can't swap the ordering around, i.e. this won't work:
 
 ----
 // Can't mix and match Interface-Oriented and Generic decorators
@@ -63,7 +63,7 @@ We could overcome this limitation be generating an appropriate Proxy type at run
 
 == Runtime behaviour embellishment
 
-You can also consider using the ++ExpandoMetaClass++ from Groovy 1.1 to dynamically embellish a class with behaviour. This isn't the normal style of usage of the decorator pattern (it certainly isn't nearly as flexible) but may help you to achieve similar results in some cases without creating a new class.
+You can also consider using the `ExpandoMetaClass` from Groovy 1.1 to dynamically embellish a class with behaviour. This isn't the normal style of usage of the decorator pattern (it certainly isn't nearly as flexible) but may help you to achieve similar results in some cases without creating a new class.
 
 Here's what the code looks like:
 
@@ -83,7 +83,7 @@ Suppose we have a calculator class (Actually any class would do).
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=decorator_calc_class,indent=0]
 ----
 
-We might be interested in observing usage of the class over time. If it is buried deep within our codebase, it might be hard to determine when it is being called and with what parameters. Also, it might be hard to know if it is performing well. We can easily make a generic tracing decorator that prints out tracing information whenever any method on the ++Calc++ class is called and also provide timing information about how long it took to execute. Here is the code for the tracing decorator:
+We might be interested in observing usage of the class over time. If it is buried deep within our codebase, it might be hard to determine when it is being called and with what parameters. Also, it might be hard to know if it is performing well. We can easily make a generic tracing decorator that prints out tracing information whenever any method on the `Calc` class is called and also provide timing information about how long it took to execute. Here is the code for the tracing decorator:
 
 [source,groovy]
 ----
@@ -106,9 +106,9 @@ Got 15 in 31 ms
 
 == Decorating with an Interceptor
 
-The above timing example hooks into the lifecycle of Groovy objects (via ++invokeMethod++). This is such an important style performing meta-programming that Groovy has special support for this style of decorating using __interceptors__.
+The above timing example hooks into the lifecycle of Groovy objects (via `invokeMethod`). This is such an important style performing meta-programming that Groovy has special support for this style of decorating using __interceptors__.
 
-Groovy even comes with a built-in ++TracingInterceptor++. We can extend the built-in class like this:
+Groovy even comes with a built-in `TracingInterceptor`. We can extend the built-in class like this:
 
 [source,groovy]
 ----
@@ -135,7 +135,7 @@ Duration: 2 ms
 
 == Decorating with java.lang.reflect.Proxy
 
-If you are trying to decorate an object (i.e. just a particular instance of the class, not the class generally), then you can use Java's ++java.lang.reflect.Proxy++. Groovy makes working with this easier than just Java. Below is a code sample taken out of a grails project that wraps a ++java.sql.Connection++ so that it's close method is a no-op:
+If you are trying to decorate an object (i.e. just a particular instance of the class, not the class generally), then you can use Java's `java.lang.reflect.Proxy`. Groovy makes working with this easier than just Java. Below is a code sample taken out of a grails project that wraps a `java.sql.Connection` so that it's close method is a no-op:
 
 [source,groovy]
 ----
@@ -164,7 +164,7 @@ Here's the class:
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=decorator_spring_calc_impl,indent=0]
 ----
 
-Now, we define our wiring in a file called ++beans.xml++ as follows:
+Now, we define our wiring in a file called `beans.xml` as follows:
 
 [source,xml]
 ----
@@ -202,11 +202,11 @@ And when we run it, we see the results:
 FINEST: StopWatch 'util.Calc.add': running time (millis) = 16
 ----
 
-You may have to adjust your ++logging.properties++ file for messages at log level ++FINEST++ to be displayed.
+You may have to adjust your `logging.properties` file for messages at log level `FINEST` to be displayed.
 
 == Asynchronous Decorators using GPars
 
-Using the example code in http://www.cs.iastate.edu/~design/projects/panini/docs/starting.shtml[Panini] for inspiration. Here is a Groovy version that avoids using an ++ at AddedBehavior++ annotation at the expense of not having as general an algorithm for selecting the methods to decorate. This isn't a limitation of the particular approach chosen but just a simplification for illustrative purposes (but don't assume below is an exact equivalent).
+Using the example code in http://www.cs.iastate.edu/~design/projects/panini/docs/starting.shtml[Panini] for inspiration. Here is a Groovy version that avoids using an `@AddedBehavior` annotation at the expense of not having as general an algorithm for selecting the methods to decorate. This isn't a limitation of the particular approach chosen but just a simplification for illustrative purposes (but don't assume below is an exact equivalent).
 
 [source,groovy]
 ----
diff --git a/src/spec/doc/design-pattern-flyweight.adoc b/src/spec/doc/design-pattern-flyweight.adoc
index 9610597..3b71dd7 100644
--- a/src/spec/doc/design-pattern-flyweight.adoc
+++ b/src/spec/doc/design-pattern-flyweight.adoc
@@ -1,6 +1,6 @@
 = Flyweight Pattern
 
-The http://en.wikipedia.org/wiki/Flyweight_pattern[Flyweight Pattern] is a pattern for greatly reducing memory requirements by not requiring that heavy-weight objects be created in large numbers when dealing with systems that contain many things that are mostly the same. If for instance, a document was modeled using a complex character class that knew about unicode, fonts, positioning, etc., then the memory requirements could be quite large for large documents if each physical character  [...]
+The http://en.wikipedia.org/wiki/Flyweight_pattern[Flyweight Pattern] is a pattern for greatly reducing memory requirements by not requiring that heavy-weight objects be created in large numbers when dealing with systems that contain many things that are mostly the same. If for instance, a document was modelled using a complex character class that knew about unicode, fonts, positioning, etc., then the memory requirements could be quite large for large documents if each physical character [...]
 
 In such circumstances, we call the state that is shared with many other things (e.g. the character type) __instrinsic__ state. It is captured within the heavy-weight class. The state which distinguishes the physical character (maybe just its ASCII code or Unicode) is called its __extrinsic__ state.
 
diff --git a/src/spec/doc/design-pattern-in-groovy.adoc b/src/spec/doc/design-pattern-in-groovy.adoc
index 615279f..153868b 100644
--- a/src/spec/doc/design-pattern-in-groovy.adoc
+++ b/src/spec/doc/design-pattern-in-groovy.adoc
@@ -9,45 +9,41 @@ Using http://en.wikipedia.org/wiki/Design_pattern_%28computer_science%29[design
 
 == Patterns
 
-:leveloffset: 4
+include::{projectdir}/{specfolder}/design-pattern-abstract-factory.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-abstract-factory.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-adapter.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-adapter.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-bouncer.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-bouncer.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-chain-of-responsibility.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-chain-of-responsibility.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-composite.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-composite.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-decorator.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-decorator.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-delegation.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-delegation.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-flyweight.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-flyweight.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-iterator.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-iterator.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-loan-my-resource.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-loan-my-resource.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-null-object.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-null-object.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-pimp-my-library.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-pimp-my-library.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-proxy.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-proxy.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-singleton.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-singleton.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-state.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-state.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-strategy.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-strategy.adoc[]
+include::{projectdir}/{specfolder}/design-pattern-template-method.adoc[leveloffset=+2]
 
-include::{projectdir}/{specfolder}/design-pattern-template-method.adoc[]
-
-include::{projectdir}/{specfolder}/design-pattern-visitor.adoc[]
-
-:leveloffset: 2
+include::{projectdir}/{specfolder}/design-pattern-visitor.adoc[leveloffset=+2]
 
 == References
 
diff --git a/src/spec/doc/design-pattern-iterator.adoc b/src/spec/doc/design-pattern-iterator.adoc
index d5f5a32..67a4cd9 100644
--- a/src/spec/doc/design-pattern-iterator.adoc
+++ b/src/spec/doc/design-pattern-iterator.adoc
@@ -3,7 +3,7 @@
 
 The http://en.wikipedia.org/wiki/Iterator_pattern[Iterator Pattern] allows sequential access to the elements of an aggregate object without exposing its underlying representation.
 
-Groovy has the iterator pattern built right in to many of its closure operators, e.g. ++each++ and ++eachWithIndex++ as well as the ++for .. in++ loop.
+Groovy has the iterator pattern built right in to many of its closure operators, e.g. `each` and `eachWithIndex` as well as the `for .. in` loop.
 
 For example:
 
@@ -40,4 +40,4 @@ Position 0 contains 'java.awt.Color[r=0,g=0,b=0]'
 Position 1 contains 'java.awt.Color[r=255,g=255,b=255]'
 ----
 
-The iterator pattern is also built in to other special operators such as the ++eachByte++, ++eachFile++, ++eachDir++, ++eachLine++, ++eachObject++, ++eachMatch++ operators for working with streams, URLs, files, directories and regular expressions matches.
\ No newline at end of file
+The iterator pattern is also built in to other special operators such as the `eachByte`, `eachFile`, `eachDir`, `eachLine`, `eachObject`, `eachMatch` operators for working with streams, URLs, files, directories and regular expressions matches.
\ No newline at end of file
diff --git a/src/spec/doc/design-pattern-loan-my-resource.adoc b/src/spec/doc/design-pattern-loan-my-resource.adoc
index 3dc3ddc..710c6d0 100644
--- a/src/spec/doc/design-pattern-loan-my-resource.adoc
+++ b/src/spec/doc/design-pattern-loan-my-resource.adoc
@@ -21,7 +21,7 @@ We could also read back the contents of the file a line at a time and print each
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=loan_my_resource_example2,indent=0]
 ----
 
-Note that normal Java ++Reader++ and ++PrintWriter++ objects were used under the covers by Groovy but the code writer did not have to worry about explicitly creating or closing those resources. The built-in Groovy methods loan the respective reader or writer to the closure code and then tidy up after themselves. So, you are using this pattern without having to do any work.
+Note that normal Java `Reader` and `PrintWriter` objects were used under the covers by Groovy but the code writer did not have to worry about explicitly creating or closing those resources. The built-in Groovy methods loan the respective reader or writer to the closure code and then tidy up after themselves. So, you are using this pattern without having to do any work.
 
 Sometimes however, you wish to do things slightly differently to what you can get for free using Groovy's built-in mechanisms. You should consider utilising this pattern within your own resource-handling operations.
 
@@ -32,7 +32,7 @@ Consider how you might process the list of words on each line within the file. W
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=loan_my_resource_example3,indent=0]
 ----
 
-Notice that we now have an explicit call to ++close()++ in our code. If we didn't code it just right (here we didn't surround the code in a ++try ... finally++ block, we run the risk of leaving the file handle open.
+Notice that we now have an explicit call to `close()` in our code. If we didn't code it just right (here we didn't surround the code in a ``try ... finally`` block, we run the risk of leaving the file handle open.
 
 Let's now apply the loan pattern. First, we'll write a helper method:
 
@@ -48,4 +48,4 @@ Now, we can re-write our code as follows:
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=loan_my_resource_example5,indent=0]
 ----
 
-This is much simpler and has removed the explicit ++close()++. This is now catered for in one spot so we can apply the appropriate level of testing or reviewing in just one spot to be sure we have no problems.
\ No newline at end of file
+This is much simpler and has removed the explicit `close()`. This is now catered for in one spot so we can apply the appropriate level of testing or reviewing in just one spot to be sure we have no problems.
\ No newline at end of file
diff --git a/src/spec/doc/design-pattern-null-object.adoc b/src/spec/doc/design-pattern-null-object.adoc
index 61aadd4..0d46d4c 100644
--- a/src/spec/doc/design-pattern-null-object.adoc
+++ b/src/spec/doc/design-pattern-null-object.adoc
@@ -1,7 +1,7 @@
 = Null Object Pattern
 
 
-The http://en.wikipedia.org/wiki/Null_Object_pattern[Null Object Pattern] involves using a special object place-marker object representing null. Typically, if you have a reference to null, you can't invoke ++reference.field++ or ++reference.method()++. You receive the dreaded ++NullPointerException++. The null object pattern uses a special object representing null, instead of using an actual ++null++. This allows you to invoke field and method references on the null object. The result of [...]
+The http://en.wikipedia.org/wiki/Null_Object_pattern[Null Object Pattern] involves using a special object place-marker object representing null. Typically, if you have a reference to null, you can't invoke `reference.field` or `reference.method()` You receive the dreaded `NullPointerException`. The null object pattern uses a special object representing null, instead of using an actual `null`. This allows you to invoke field and method references on the null object. The result of using th [...]
 
 == Simple Example
 
@@ -12,30 +12,30 @@ Suppose we have the following system:
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=null_object_simple_example,indent=0]
 ----
 
-When run, this prints out ++1200++. Suppose now that we now invoke:
+When run, this prints out `1200`. Suppose now that we now invoke:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=null_object_simple_example2,indent=0]
 ----
 
-If we now try to calculate ++biggestSalary++ again, we receive a null pointer exception.
+If we now try to calculate `biggestSalary` again, we receive a null pointer exception.
 
-To overcome this problem, we can introduce a ++NullJob++ class and change the above statement to become:
+To overcome this problem, we can introduce a `NullJob` class and change the above statement to become:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=null_object_simple_example3,indent=0]
 ----
 
-This works as we require but it's not always the best way to do this with Groovy. Groovy's safe-dereference operator (++?.++) operator and null aware closures often allow Groovy to avoid the need to create a special null object or null class. This is illustrated by examining a groovier way to write the above example:
+This works as we require but it's not always the best way to do this with Groovy. Groovy's safe-dereference operator (`?.`) operator and null aware closures often allow Groovy to avoid the need to create a special null object or null class. This is illustrated by examining a groovier way to write the above example:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=null_object_simple_example4,indent=0]
 ----
 
-Two things are going on here to allow this to work. First of all, ++max()++ is __'null aware'__ so that ++[300, null, 400].max() == 400++. Secondly, with the ++?.++ operator, an expression like ++p?.job?.salary++ will be equal to null if ++salary++ is equal to null, or if ++job++ is equal to null or if ++p++ is equal to null. You don't need to code a complex nested ++if ... then ... else++ to avoid a ++NullPointerException++.
+Two things are going on here to allow this to work. First of all, `max()` is __'null aware'__ so that ++[300, null, 400].max() == 400++. Secondly, with the `?.` operator, an expression like `p?.job?.salary` will be equal to null if `salary` is equal to null, or if `job` is equal ` null or if `p` is equal to null. You don't need to code a complex nested ++if ... then ... else++ to avoid a `NullPointerException`.
 
 == Tree Example
 
@@ -48,7 +48,7 @@ Our first attempt has special logic within the calculation methods to handle nul
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=null_object_tree_example,indent=0]
 ----
 
-If we introduce the null object pattern (here by defining the ++NullTree++ class), we can now simplify the logic in the ++size()++, ++sum()++ and ++product()++ methods. These methods now much more clearly represent the logic for the normal (and now universal) case. Each of the methods within ++NullTree++ returns a value which represents doing nothing.
+If we introduce the null object pattern (here by defining the `NullTree` class), we can now simplify the logic in the `size()`, `sum()` and`product()` methods. These methods now much more clearly represent the logic for the normal (and now universal) case. Each of the methods within `NullTree` returns a value which represents doing nothing.
 
 [source,groovy]
 ----
diff --git a/src/spec/doc/design-pattern-pimp-my-library.adoc b/src/spec/doc/design-pattern-pimp-my-library.adoc
index 9252f45..1c05784 100644
--- a/src/spec/doc/design-pattern-pimp-my-library.adoc
+++ b/src/spec/doc/design-pattern-pimp-my-library.adoc
@@ -14,9 +14,9 @@ First, we'll define a suitable category.
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=pimp_my_library_example,indent=0]
 ----
 
-We have added two methods which augment the Integer methods by providing the ++greaterThanAll++ method. Categories follow conventions where they are defined as static methods with a special first parameter representing the class we wish to extend. The ++greaterThanAll(Integer self, others)++ static method becomes the ++greaterThanAll(other)++ instance method.
+We have added two methods which augment the Integer methods by providing the `greaterThanAll` method. Categories follow conventions where they are defined as static methods with a special first parameter representing the class we wish to extend. The ++greaterThanAll(Integer self, others)++ static method becomes the `greaterThanAll(other)` instance method.
 
-We defined two versions of ++greaterThanAll++. One which works for collections, ranges etc. The other which works with a variable number of ++Integer++ arguments.
+We defined two versions of `greaterThanAll`. One which works for collections, ranges etc. The other which works with a variable number of `Integer` arguments.
 
 Here is how you would use the category.
 
diff --git a/src/spec/doc/design-pattern-singleton.adoc b/src/spec/doc/design-pattern-singleton.adoc
index 163cd20..e002fcf 100644
--- a/src/spec/doc/design-pattern-singleton.adoc
+++ b/src/spec/doc/design-pattern-singleton.adoc
@@ -5,12 +5,12 @@ The http://en.wikipedia.org/wiki/Singleton_pattern[Singleton Pattern] is used to
 
 Weaknesses of the Singleton pattern include:
 
-- It can reduce reuse. For instance, there are issues if you want to use inheritance with Singletons. If ++SingletonB++ extends ++SingletonA++, should there be exactly (at most) one instance of each or should the creation of an object from one of the classes prohibit creation from the other. Also, if you decide both classes can have an instance, how do you override the ++getInstance()++ method which is static?
+- It can reduce reuse. For instance, there are issues if you want to use inheritance with Singletons. If `SingletonB` extends `SingletonA`, should there be exactly (at most) one instance of each or should the creation of an object from one of the classes prohibit creation from the other. Also, if you decide both classes can have an instance, how do you override the `getInstance()` method which is static?
 - It is also hard to test singletons in general because of the static methods but Groovy can support that if required.
 
 == Example: The Classic Java Singleton
 
-Suppose we wish to create a class for collecting votes. Because getting the right number of votes may be very important, we decide to use the singleton pattern. There will only ever be one ++VoteCollector++ object, so it makes it easier for us to reason about that objects creation and use.
+Suppose we wish to create a class for collecting votes. Because getting the right number of votes may be very important, we decide to use the singleton pattern. There will only ever be one `VoteCollector` object, so it makes it easier for us to reason about that objects creation and use.
 
 [source,groovy]
 ----
@@ -19,8 +19,8 @@ include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=singleton_vot
 
 Some points of interest about this code:
 
-- it has a private constructor, so no ++VoteCollector++ objects can be created in our system (except for the ++INSTANCE++ we create)
-- the ++INSTANCE++ is also private, so it can't be changed once set
+- it has a private constructor, so no `VoteCollector` objects can be created in our system (except for the `INSTANCE` we create)
+- the `INSTANCE` is also private, so it can't be changed once set
 - we haven't made the updating of votes thread-safe at this point (it doesn't add to this example)
 - the vote collector instance is not lazyily created (if we never reference the class, the instance won't be created; however, as soon as we reference the class, the instance will be created even if not needed initially)
 
@@ -43,8 +43,8 @@ Collector:15959960, Votes:2
 
 Variations to this pattern:
 
-- To support lazy-loading and multi-threading, we could just use the ++synchronized++ keyword with the ++getInstance()++ method. This has a performance hit but will work.
-- We can consider variations involving double-checked locking and the ++volatile++ keyword (for Java 5 and above), but see the limitations of this approach http://www.ibm.com/developerworks/java/library/j-dcl/index.html[here].
+- To support lazy-loading and multi-threading, we could just use the `synchronized` keyword with the `getInstance()` method. This has a performance hit but will work.
+- We can consider variations involving double-checked locking and the `volatile` keyword (for Java 5 and above), but see the limitations of this approach http://www.ibm.com/developerworks/java/library/j-dcl/index.html[here].
 
 == Example: Singleton via MetaProgramming
 
@@ -52,21 +52,21 @@ Groovy's meta-programming capabilities allow concepts like the singleton pattern
 
 Suppose we want to keep track of the total number of calculations that a calculator performs. One way to do that is to use a singleton for the calculator class and keep a variable in the class with the count.
 
-First we define some base classes. A ++Calculator++ class which performs calculations and records how many such calculations it performs and a ++Client++ class which acts as a facade to the calculator.
+First we define some base classes. A `Calculator` class which performs calculations and records how many such calculations it performs and a `Client` class which acts as a facade to the calculator.
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=singleton_meta_programming_classes,indent=0]
 ----
 
-Now we can define and register a __MetaClass__ which intercepts all attempts to create a ++Calculator++ object and always provides a pre-created instance instead. We also register this MetaClass with the Groovy system:
+Now we can define and register a __MetaClass__ which intercepts all attempts to create a `Calculator` object and always provides a pre-created instance instead. We also register this MetaClass with the Groovy system:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=singleton_meta_programming_meta_class,indent=0]
 ----
 
-Now we use instances of our ++Client++ class from within a script. The client class will attempt to create new instances of the calculator but will always get the singleton.
+Now we use instances of our `Client` class from within a script. The client class will attempt to create new instances of the calculator but will always get the singleton.
 
 [source,groovy]
 ----
@@ -86,14 +86,14 @@ We can also implement the Singleton Pattern using http://code.google.com/p/googl
 
 Consider the Calculator example again.
 
-Guice is a Java-oriented framework that supports Interface-Oriented design. Hence we create a ++Calculator++ interface first. We can then create our ++CalculatorImpl++ implementation and a ++Client++ object which our script will interact with. The ++Client++ class isn't strictly needed for this example but allows us to show that non-singleton instances are the default. Here is the code:
+Guice is a Java-oriented framework that supports Interface-Oriented design. Hence we create a `Calculator` interface first. We can then create our `CalculatorImpl` implementation and a `Client` object which our script will interact with. The `Client` class isn't strictly needed for this example but allows us to show that non-singleton instances are the default. Here is the code:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=singleton_guice,indent=0]
 ----
 
-Note the ++ at Inject++ annotation in the ++Client++ class. We can always tell right in the source code which fields will be injected.
+Note the `@Inject` annotation in the `Client` class. We can always tell right in the source code which fields will be injected.
 
 In this example we chose to use an __explicit__ binding. All of our dependencies (ok, only one in this example at the moment) are configured in the binding. The Guide injector knows about the binding and injects the dependencies as required when we create objects. For the singleton pattern to hold, you must always use Guice to create your instances. Nothing shown so far would stop you creating another instance of the calculator manually using ++new CalculatorImpl()++ which would of cours [...]
 
@@ -104,7 +104,7 @@ In other scenarios (though probably not in large systems), we could choose to ex
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=singleton_guice2,indent=0]
 ----
 
-Note the ++ at Singleton++ annotation on the ++CalculatorImpl++ class and the ++ at ImplementedBy++ annotation in the ++Calculator++ interface.
+Note the `@Singleton` annotation on the `CalculatorImpl` class and the `@ImplementedBy` annotation in the `Calculator` interface.
 
 When run, the above example (using either approach) yields (your hashcode values will vary):
 
diff --git a/src/spec/doc/design-pattern-state.adoc b/src/spec/doc/design-pattern-state.adoc
index 6efcf0c..c0f23c1 100644
--- a/src/spec/doc/design-pattern-state.adoc
+++ b/src/spec/doc/design-pattern-state.adoc
@@ -35,7 +35,7 @@ One approach we could take is to leverage http://www.pragmaticprogrammer.com/tit
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=state_variation1_interface,indent=0]
 ----
 
-Then our ++Client++, ++Online++ and ++Offline++ classes could be modified to implement that interface, e.g.:
+Then our `Client`, `Online` and 'Offline` classes could be modified to implement that interface, e.g.:
 
 [source,groovy]
 ----
@@ -62,7 +62,7 @@ This is all quite generic and can be used wherever we want to introduce the stat
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=state_variation2_impl,indent=0]
 ----
 
-You can see here the ++startFrom++ and ++transitionTo++ methods begin to give our example code a DSL feel.
+You can see here the `startFrom` and `transitionTo` methods begin to give our example code a DSL feel.
 
 == Variation 3: Bring on the DSL
 
@@ -87,6 +87,6 @@ Now we can define and test our state machine like this:
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=state_variation33,indent=0]
 ----
 
-This example isn't an exact equivalent of the others. It doesn't use predefined ++Online++ and ++Offline++ classes. Instead it defines the entire state machine on the fly as needed. See the http://www.bytemycode.com/snippets/snippet/640/[previous reference] for more elaborate examples of this style.
+This example isn't an exact equivalent of the others. It doesn't use predefined `Online` and `Offline` classes. Instead it defines the entire state machine on the fly as needed. See the http://www.bytemycode.com/snippets/snippet/640/[previous reference] for more elaborate examples of this style.
 
 See also: <<_model_based_testing_using_modeljunit,Model-based testing using ModelJUnit>>
\ No newline at end of file
diff --git a/src/spec/doc/design-pattern-strategy.adoc b/src/spec/doc/design-pattern-strategy.adoc
index cc71416..6d58731 100644
--- a/src/spec/doc/design-pattern-strategy.adoc
+++ b/src/spec/doc/design-pattern-strategy.adoc
@@ -16,7 +16,7 @@ First let's look at the traditional way of encapsulating the Strategy Pattern.
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=strategy_traditional,indent=0]
 ----
 
-Here we have defined an interface ++Calc++ which our concrete strategy classes will implement (we could also have used an abstract class). We then defined two algorithms for doing simple multiplication: ++CalcByMult++ the normal way, and ++CalcByManyAdds++ using only addition (don't try this one using negative numbers - yes we could fix this but it would just make the example longer). We then use normal http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming[polymorphism [...]
+Here we have defined an interface `Calc` which our concrete strategy classes will implement (we could also have used an abstract class). We then defined two algorithms for doing simple multiplication: `CalcByMult` the normal way, and ++CalcByManyAdds++ using only addition (don't try this one using negative numbers - yes we could fix this but it would just make the example longer). We then use normal http://en.wikipedia.org/wiki/Polymorphism_in_object-oriented_programming[polymorphism] to [...]
 
 Here is the Groovier way to achieve the same thing using Closures:
 
diff --git a/src/spec/doc/design-pattern-template-method.adoc b/src/spec/doc/design-pattern-template-method.adoc
index b2e1810..a434148 100644
--- a/src/spec/doc/design-pattern-template-method.adoc
+++ b/src/spec/doc/design-pattern-template-method.adoc
@@ -7,7 +7,7 @@ image::assets/img/TemplateMethodClasses.gif[]
 
 == Example
 
-In this example, ++Accumulator++ captures the essence of the accumulation algorithm. The base classes ++Sum++ and ++Product++ provide particular customised ways to use the generic accumulation algorithm.
+In this example, `Accumulator` captures the essence of the accumulation algorithm. The base classes `Sum` and `Product` provide particular customised ways to use the generic accumulation algorithm.
 
 [source,groovy]
 ----
diff --git a/src/spec/doc/design-pattern-visitor.adoc b/src/spec/doc/design-pattern-visitor.adoc
index ac82325..f5a7947 100644
--- a/src/spec/doc/design-pattern-visitor.adoc
+++ b/src/spec/doc/design-pattern-visitor.adoc
@@ -30,14 +30,14 @@ include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_simpl
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_advanced_example,indent=0]
 ----
 
-If we now use ++NodeType1Counter++ on a tree like this:
+If we now use `NodeType1Counter` on a tree like this:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_advanced_example2,indent=0]
 ----
 
-Then we have one ++NodeType1++ object as root and one of the children is also a ++NodeType1++ instance. The other child is a ++NodeType2++ instance. That means using ++NodeType1Counter++ here should count 2 ++NodeType1++ objects.
+Then we have one `NodeType1` object as root and one of the children is also a `NodeType1` instance. The other child is a `NodeType2` instance. That means using `NodeType1Counter` here should count 2 `NodeType1` objects.
 
 === Why to use this
 
@@ -56,37 +56,37 @@ Then you have a problem. since the node describes how to iterate, you have no in
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_advanced_example3,indent=0]
 ----
 
-Some small changes but with big effect... the visitor is now recursive and tells me how to iterate. The implementation in the Nodes is minimized to ++visitor.visit(this)++, ++DefaultVisitor++ is now able to catch the new types, we can stop iteration by not delegating to super. Of course the big disadvantage now is that it is no longer iterative, but you can't get all the benefits.
+Some small changes but with big effect... the visitor is now recursive and tells me how to iterate. The implementation in the Nodes is minimized to `visitor.visit(this)`, `DefaultVisitor` is now able to catch the new types, we can stop iteration by not delegating to super. Of course the big disadvantage now is that it is no longer iterative, but you can't get all the benefits.
 
 === Make it Groovy
 
-The question now is how to make that a bit more Groovy. Didn't you find this ++visitor.visit(this)++ strange? Why is it there? The answer is to simulate double dispatch. In Java the compile time type is used, so when I ++visitor.visit(children[i])++ then the compiler won't be able to find the correct method, because ++Visitor++ does not contain a method ++visit(Visitable)++. And even if it would, we would like to visit the more special methods with ++NodeType1++ or ++NodeType2++.
+The question now is how to make that a bit more Groovy. Didn't you find this `visitor.visit(this)` strange? Why is it there? The answer is to simulate double dispatch. In Java the compile time type is used, so when I `visitor.visit(children[i])` then the compiler won't be able to find the correct method, because `Visitor` does not contain a method `visit(Visitable)`. And even if it would, we would like to visit the more special methods with `NodeType1` or `NodeType2`.
 
-Now Groovy is not using the static type, Groovy uses the runtime type. This means I could do ++visitor.visit(children[i])++ directly. Hmm.. since we minimized the accept method to just do the double dispatch part and since the runtime type system of Groovy will already cover that.. do we need the accept method? I think you can guess that I would answer no. But we can do more. We had the disadvantage of not knowing how to handle unknown tree elements. We had to extends the interface ++Vis [...]
+Now Groovy is not using the static type, Groovy uses the runtime type. This means I could do `visitor.visit(children[i])` directly. Hmm.. since we minimized the accept method to just do the double dispatch part and since the runtime type system of Groovy will already cover that.. do we need the accept method? I think you can guess that I would answer no. But we can do more. We had the disadvantage of not knowing how to handle unknown tree elements. We had to extends the interface `Visito [...]
 
-But don't let us stop here... do we need the Visitor interface? If we don't have the accept method, then we don't need the ++Visitor++ interface at all. So the new code would be:
+But don't let us stop here... do we need the `Visitor` interface? If we don't have the accept method, then we don't need the `Visitor` interface at all. So the new code would be:
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_advanced_example4,indent=0]
 ----
 
-Looks like we saved a few lines of code here. But we made more. The Visitable nodes now do not refer to any ++Visitor++ class or interface. For me this is the best level of separation you could get here. But do we really need to stop here? No. Let us change the ++Visitable++ interface a little and let it return the children we want to visit next. This allows us a general iteration method.
+Looks like we saved a few lines of code here. But we made more. The `Visitable` nodes now do not refer to any `Visitor` class or interface. For me this is the best level of separation you could get here. But do we really need to stop here? No. Let us change the `Visitable` interface a little and let it return the children we want to visit next. This allows us a general iteration method.
 
 [source,groovy]
 ----
 include::{projectdir}/src/spec/test/DesignPatternsTest.groovy[tags=visitor_advanced_example5,indent=0]
 ----
 
-++DefaultVisitor++ now looks a bit different. I added a ++doIteration++ method that will get the children it should iterate over and then call visit on each element. Per default this will call ++visit(Visitable)++ which then iterates over the children of this child. I changed ++Visitable++ to ensure that any node will be able to return children (even if empty). I didn't have to change the ++NodeType1++ and ++NodeType2++ class, because the way the children filed was defined already made t [...]
+`DefaultVisitor` now looks a bit different. I added a `doIteration` method that will get the children it should iterate over and then call visit on each element. Per default this will call `visit(Visitable)` which then iterates over the children of this child. I changed `Visitable` to ensure that any node will be able to return children (even if empty). I didn't have to change the `NodeType1` and `NodeType2` class, because the way the children filed was defined already made them a proper [...]
 
 === Summary
 
 In the end we got ~40% less code, a robust and stable architecture and we completely removed the Visitor from the Visitable. I heard about visitor implementations based on Reflection to get a more generic version. Well, with this you see there is really no need to do such thing. If we add new types we don't need to change anything. It is said that the visitor pattern doesn't fit extreme programming techniques very well because you need to make changes to so many classes all the time. I t [...]
 
-There are variants of the Visitor pattern, like the acyclic visitor pattern, that tries to solve the problem of adding new node types with special visitors. I don't like that very much, it works with casts, catches the ++ClassCastException++ and other nasty things. In the end it tries to solve something we don't even get with the Groovy version.
+There are variants of the Visitor pattern, like the acyclic visitor pattern, that tries to solve the problem of adding new node types with special visitors. I don't like that very much, it works with casts, catches the `ClassCastException` and other nasty things. In the end it tries to solve something we don't even get with the Groovy version.
 
-One more thing. ++NodeType1Counter++ could be implemented in Java as well. Groovy will recognize the visit methods and call them as needed because ++DefaultVisitor++ is still Groovy and does all the magic.
+One more thing. `NodeType1Counter` could be implemented in Java as well. Groovy will recognize the visit methods and call them as needed because `DefaultVisitor` is still Groovy and does all the magic.
 
 == Further Information
 
diff --git a/src/spec/doc/grape.adoc b/src/spec/doc/grape.adoc
index 8c66005..cb5ff4e 100644
--- a/src/spec/doc/grape.adoc
+++ b/src/spec/doc/grape.adoc
@@ -1,6 +1,8 @@
 [[section-grape]]
 = Dependency management with Grape
+
 == Quick start
+
 === Add a Dependency
 
 Grape is a JAR dependency manager embedded into Groovy. Grape lets you quickly add maven repository dependencies to your
@@ -20,7 +22,7 @@ import org.springframework.jdbc.core.JdbcTemplate
 import org.springframework.jdbc.core.JdbcTemplate
 --------------------------------------------------------------------
 
-Note that we are using an annotated import here, which is the recommanded way. You can also search for
+Note that we are using an annotated import here, which is the recommended way. You can also search for
 dependencies on http://mvnrepository.com[mvnrepository.com] and it will
 provide you the `@Grab` annotation form of the `pom.xml` entry.
 
@@ -472,7 +474,7 @@ script, and cache them. We’re creating a new Jetty Server on port 8080,
 then expose Groovy’s TemplateServlet at the root of the context — Groovy
 comes with its own powerful template engine mechanism. We start the
 server and let it run for a certain duration. Each time someone will hit
-http://localhost:8080/somepage.gsp, it will display the somepage.gsp
++http://localhost:8080/somepage.gsp+, it will display the somepage.gsp
 template to the user — those template pages should be situated in the
 same directory as this server script.
 
diff --git a/src/spec/doc/groovy-contributions.adoc b/src/spec/doc/groovy-contributions.adoc
new file mode 100644
index 0000000..4582a40
--- /dev/null
+++ b/src/spec/doc/groovy-contributions.adoc
@@ -0,0 +1,1237 @@
+= Groovy Contributions
+ 
+++++
+<link rel="stylesheet" href="http://ajax.googleapis.com/ajax/libs/jqueryui/1.11.0/themes/blitzer/jquery-ui.css">
+++++
+
+<<<
+
+== Help !
+
+A key area we've been working on for a while is our new [blue]#Groovy# documentation. Peter Ledbrook has detailed how you can help us author some sections of the documentation. http://blog.cacoethes.co.uk/groovyandgrails/contributing-to-the-groovy-documentation[Read his post here]. 
+
+Like Peter, you can dedicate a bit of your time on a topic of your choice, to further deepen your understanding of a particular area of [blue]#Groovy# and share your knowledge with your peers.
+
+We really look forward to your contributions!
+
+.Your Contributions
+****
+The [blue]#Groovy# core team is a very small team, compared to the huge team a company like Oracle puts behind Java and the JVM, or Microsoft behind its languages and the .Net platform. So all contributions, in any form, do count, and are important to the success and evolution of the [blue]#Groovy# language.
+****
+
+<<<
+
+== Contributions Walk-Thru 
+
+.Prerequisites
+ - [*] Working internet connection
+ - [ ] Familiarity with computer directory organization, folders, sub-directories and structures of hierarchies
+ - [ ] Have a GitHub Account and familiarity with concepts about code repositories - also called *repo-s*
+ - [ ] Knowledge of computer terminal command line
+ - [ ] Installed *GIT* tool
+ - [ ] Plain text editor like TEXTEDIT, NOTEPAD, gedit, Leafpad; - a tool that does *NOT* include markup like bold,italics, etc. and saves file in the *UTF-8* character set
+ - [ ] Be familiar with http://asciidoctor.org/docs/user-manual/[Asciidoctor markup] and the  http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[syntax reference guide] ( more notes are listed below ).
+ - [ ] Optionally - have the http://asciidoctor.org/docs/install-toolchain/[*asciidoctor* toolchain] installed on your local system
+ - [ ] Be familiar with unit testing of individual programs; it may be necessary to write some new test cases for groovy modules. ( _Optional_ )
+ - [ ] Enthusiam and nice writing style  
+
+'''
+
+IMPORTANT: It's *NOT* necessary to have [blue]#Groovy# installed on your local system to be able to write documentation.
+
+'''
+
+=== Join Us !
+
+Please join any of our mailing lists at http://groovy-lang.org/mailing-lists.html[http://groovy-lang.org/mailing-lists.html]. 
+
+Whether you are a user, developer, or enthusiast, we have a choice of mailing lists you may find appealing. Ask and get answers for questions about the [blue]#Groovy# eco-system.
+
+You can find live icon:twitter[] https://twitter.com/hashtag/groovylang[#groovylang] feeds for up-to-the-minute news.
+
+.Mailing Lists
+ * dev at groovy.codehaus.org - for details about [blue]#Groovy# development
+ * user at groovy.codehaus.org - lots of questions and answers about [blue]#Groovy#
+ * announce at groovy.codehaus.org  - for new releases and news
+ * eclipse-plugin-user at groovy.codehaus.org - all about the [blue]#Groovy# plugin for Eclipse
+ * scm at groovy.codehaus.org - see those commits !
+
+'''
+
+
+=== Where is Groovy ?
+
+Open source developers often need somewhere to keep all their assets. These assets are typically stored in a repository somewhere on the internet. icon:github[link="https://github.com/"] https://github.com/[*GitHub*] is one such storage facility. At *[blue]#Groovy#*, we keep https://github.com/groovy/groovy-core[our _source code_ here]. 
+
+Visit our *[blue]#Groovy#* information portal at image:assets/img/groovy.png[Groovy Website, 60, 30, link="http://groovy-lang.org/"] 
+
+We build *[blue]#Groovy#* continuously at image:assets/img/teamcity.png[TeamCity, 73, 20, link="http://ci.groovy-lang.org/"]. Log in as a guest.
+
+
+=== How Do I Contribute ?
+
+There are two paths to contribute : 
+
+For small things, you can change the relevant document on-line, within the *GitHub* system. For spelling or punctuation typos, broken language, etc, you can edit the document live from within Github. We mention this approach for small contributions that don't require us to run the tests / create or update new tests. link:#_quick_fixes[Follow this trail.]
+
+For larger contributions, it's more likely you'll need to copy [blue]#Groovy# into your own work environment, then link:#_take_the_long_way_home[Take The Long Way Home.]
+
+'''
+
+
+++++
+<div id="accordion3">
+<h3>Q & A - The Future of Groovy Documentation</h3>
+<div>
+  <h4>1. Am assuming that future contributions to groovy-core will be done using asciidoctor markup. Correct ?</h4>
+  <div>GLA: Yes, going forward, all documentation is Asciidoctor based.
+(on the future website there are also Groovy templates actually, but otherwise, the reference documentation is indeed all Asciidoctor)
+</div>
+
+  <h4>2. Do we need to declare any asciidoctor attributes within the doc heading  ?</h4>
+<div><h4>Would i need any of these ?</h4>
+<p>
+<pre>
+:toc:
+:toc-title: Contributions to Groovy Documentation  
+:icons: font
+:linkattrs:
+:sectlinks:
+:compat-mode:
+</pre>
+<br />
+or just plain, without attributes ?</p>
+<hr />
+<p>GLA: Look at the existing adoc files we have.<br />
+No particular attributes, as that's the build which gives some defaults there (for CSS, TOC, etc).
+</p>
+<p>See here for the ones automatically added:<a href="https://github.com/glaforge/groovy-core/blob/master/gradle/asciidoctor.gradle#L24-24" target="_blank">https://github.com/glaforge/groovy-core/blob/master/gradle/asciidoctor.gradle#L24-24</a>
+</p>
+</div>
+ 
+<h4>3. Should we try to influence the look-and-feel of the result using stylesheets or just let the doc generation process provide whatever look-and-feel is in play at that time ?
+</h4>
+<div><p>GLA: The look and feel is already customized, as shown on the new Groovy website:<a href="http://beta.groovy-lang.org/syntax.html" target="_blank">
+http://beta.groovy-lang.org/syntax.html</a></p>
+<p>It embeds in an iframe the following asciidoctor-generated html file:<a href="http://docs.groovy-lang.org/docs/next/html/documentation/core-syntax.html" target="_blank">
+http://docs.groovy-lang.org/docs/next/html/documentation/core-syntax.html</a></p></div>
+ 
+<h4>4. The syntax (and LAF) of asciidoctor 1.5.0 differs from 1.4.0 in several ways, do we need to rejig existing *.adoc files to use the revised syntax ?</h4>
+<div><p>GLA: We need to go through all that's written so far to check for incompatibilities, indeed.</p></div>
+ 
+<h4>5. What groovy-core folder should hold the image assets relating to a particular .adoc file ? ( Like screen pix, or tiny icons )</h4>
+<div><p>It looks like groovy-core/src/spec/assets/img/ is a good candidate.</p> 
+<hr />
+<p>GLA: Yeah under that and respectively for submodules which also have their src/spec folders too.</p></div>
+</div>
+</div>
+++++
+
+<<<
+
+== Quick Fixes To Groovy
+
+Sometimes, you may spot a tiny flaw in our otherwise perfect product. It's bugging you, so you want to fix it quickly without all the trouble of porting [blue]#Groovy# to your own system. Can it be done ?
+
+[red yellow-background big]*Sure icon:exclamation[]*
+
+Let's say you need to fix the [blue]#Groovy# README.adoc file in https://github.com/groovy/groovy-core[https://github.com/groovy/groovy-core] - our core location.
+
+'''
+
+IMPORTANT: Only use this way to fix small stuff like spelling bits. Otherwise your fix may avoid our indepth testing process [red yellow-background big]*:-(*
+
+'''
+
+Click the core location address to get here :
+
+.Groovy Core Page
+image::assets/img/example15.png[Details, align="center"] 
+
+Your view should look like this, except it will say +groovy / groovy-core+ ( this view was from another example and has the wrong location name ). Confirm you are viewing +groovy / groovy-core+ then click the name of the resource to edit, in this case *README.adoc*. The following view opens.
+
+'''
+
+.README.adoc View
+image::assets/img/example16.png[Details, align="center", link="https://github.com/groovy/groovy-core/blob/master/README.adoc"] 
+
+This view is the current content of the *README* file. You can see ( but not edit ) the raw text by clicking the +RAW+ button. But for this example, you want to change some text. The red arrow points to the editor *PENCIL*. Click that to open an editable version of this page. See below.
+
+
+'''
+
+.Groovy-core/README.adoc page
+image::assets/img/example17.png[Details, align="center", link="https://github.com/groovy/groovy-core/blob/master/README.adoc"] 
+
+Confirm you're on the correct page ( blue square ). Then on line 80, after the words _Continuous Integration_ add the word _Server_
+
+'''
+
+Then add more details like this :
+
+.Ready To Roll
+image::assets/img/example18.png[Details, align="center"] 
+
+In the box marked *Commit changes* add a short descriptive title and add more detail below. Then click [white green-background big]*Commit changes* button to seal the deal. Easy-peasy icon:exclamation[]  icon:smile[]
+
+<<<
+
+== Take The Long Way Home
+
+This way needs more work on your part though it it is more rewarding too.
+
+First we look at the home of [blue]#Groovy# . Then we review the structure and important items. After that we pick up the story at link:#_getting_started[Getting Started.]
+
+=== Notes About GitHub
+
+At *[blue]#Groovy#*, we keep https://github.com/groovy/groovy-core[our _source code_ here].
+
+==== GitHub Information
+
+++++
+<div id="accordion2">
+  <h3>Typical Workflow Steps</h3>
+  <div>
+<ul>
+<li>join GitHub
+<li>sign in to your GitHub account
+<li>locate the groovy code base
+<li>make a copy ( FORK ) of it into your own online GitHub account
+ <li>make a local copy ( CLONE ) from your own online GitHub account
+ <li>create a new feature branch
+ <li>switch to your new feature branch
+ <li>build/amend the documents
+ <li>provide screen images if needed
+ <li>provide test cases to match your documentation
+ <li>build and test everything
+ <li>commit your changes
+ <li>switch to your master branch
+ <li>merge your branch full of changes into the master branch
+ <li>send ( PUSH ) your changes back to your own online account
+ <li>ask the groovy admins to include ( PULL ) your changes in the groovy code base
+</ul>
+  </div>
+
+  <h3>Git Clients</h3>
+  <div>
+<ul>
+<li><a href="http://git-scm.com/downloads/guis" target="_blank">Git Client GUIs for All Platforms</a></li>
+<li><a href="http://docs.oseems.com/general/operatingsystem/ubuntu/install-git-client" target="_blank">Git Client for Ubuntu</a></li>
+<li><a href="http://msysgit.github.io/" target="_blank">Git Client for Windows</a></li>
+</ul>
+</div>
+
+  <h3>Git References</h3>
+  <div>
+<ul>
+<li><a href="https://help.github.com/articles/set-up-git" target="_blank">Setup Git</a></li>
+<li><a href="https://help.github.com/articles/signing-up-for-a-new-github-account" target="_blank">Sign-up for a new Github account</a></li>
+<li><a href="https://help.github.com/articles/fork-a-repo" target="_blank">Fork a repo</a></li>
+<li><a href="http://gitref.org/branching/" target="_blank">Git Branching and Merging</a></li>
+<li><a href="https://gun.io/blog/how-to-github-fork-branch-and-pull-request/" target="_blank">Git Rebase</a></li>
+<li><a href="http://www.markjberger.com/git-tips-for-beginners/" target="_blank">Tips for beginners</a></li>
+<li><a href="http://blog.guy.ht/2010/12/using-branches-to-manage-documentation-on-github/" target="_blank">Manage With Branches</a></li>
+</ul>
+</div>
+
+
+</div>
+++++
+
++++<br />+++
+
+'''
+
+
+=== Groovy Directory Structure
+
+From here on, we've assumed you have logged into your own *GitHub* account. 
+
+==== Visit Groovy Core Repository on GitHub
+
+Open a web browser, then use address https://github.com/groovy/groovy-core[https://github.com/groovy/groovy-core] to review the [blue]#Groovy# code base. It looks like this :
+
+.Groovy Core on *Github* icon:github[link="https://github.com/groovy/groovy-core", window="_blank"]
+image::assets/img/github4.png[Groovy Core Repository on GitHub, 495, 436, link="https://github.com/groovy/groovy-core",align="center"] 
+
+There are a number of folders within the [blue]#Groovy# code base. The most important folders are */src* and */subprojects* as these folders hold the base code and scripts for [blue]#Groovy#.
+
+==== The +/src+ Folder
+
+The core of [blue]#Groovy# lives within this folder. Here is where we find a variety of artifacts, scripts, tests, resources, images, etc. 
+
+.Groovy Core Source Folder on *Github* icon:github[link="https://github.com/groovy/groovy-core/tree/master/src", window="_blank"]
+image::assets/img/github1.png[Groovy Core Source, 497, 313, link="https://github.com/groovy/groovy-core/tree/master/src",align="center"] 
+
+
+==== The +/subprojects+ Folder
+
+[blue]#Groovy# has many additional features that are not part of the core system. Source code for these added features can be found in the *subprojects* folder. It looks something like this :
+
+.Groovy Core Sub-Projects Source Folder on *Github*  icon:github[link="https://github.com/groovy/groovy-core/tree/master/subprojects", window="_blank"]
+image::assets/img/github2.png[Groovy Core Source, 499, 397, link="https://github.com/groovy/groovy-core/tree/master/subprojects",align="center"] 
+
+==== The Documentation Folder
+
+Within each */src* and */subproject/src* is a */spec* documents folder that exists, or will soon be created. 
+
+.Groovy Document Specifications Folder on *Github*  icon:github[link="https://github.com/groovy/groovy-core/tree/master/src/spec", window="_blank"]
+image::assets/img/github3.png[Groovy Documents Source, 500, 185, link="https://github.com/groovy/groovy-core/tree/master/src/spec",align="center"] 
+
+The two most useful folders here are */doc* and */test*. These two folders hold our documents and test cases.
+
+===== Documents
+
+All of our documents are written as typical text files encoded as *UTF-8* characters. The text is styled in the markup syntax known as http://asciidoctor.org/docs/user-manual/[*asciidoc*] or http://asciidoctor.org/docs/user-manual/[*asciidoctor*] ( the more recent version ). These text files have a filename suffix designation of *.adoc*.
+
+.Groovy Documentation Folder on *Github*
+image::assets/img/github5.png[Groovy Documents Folder, 501, 170, link="https://github.com/groovy/groovy-core/tree/master/src/spec/doc",align="center"] 
+
+===== Test Cases
+
+To prove that [blue]#Groovy# modules work as expected, we often construct test cases that exercise code logic. These test cases are actually [blue]#Groovy# scripts that reside in the */test* folder.
+
+.Groovy Core Test Folder on *Github* icon:github[link="https://github.com/groovy/groovy-core/tree/master/src/spec/test", window="_blank"]
+image::assets/img/github6.png[Groovy Testcase Folder, 505, 303, link="https://github.com/groovy/groovy-core/tree/master/src/spec/test",align="center"] 
+
+If you would like to know more about writing effective test cases, please http://groovy.codehaus.org/Testing+Guide[review this link] or to test web applications http://groovy.codehaus.org/Testing+Web+Applications[review this link].
+ 
+ 
+==== Wrap Up
+
+Ok, that's a quick review of our [blue]#Groovy# code base, the directory/folder structure and important bits. It _should_ give you a starting point  to explore [blue]#Groovy# icon:thumbs-up-alt[]
+
+'''
+
+<<<
+
+== Getting Started
+ 
+Let's assume you've logged into your *GitHub* account.
+
+.*GitHub* Home Panel
+image::assets/img/githubhomepanel.png[Github Home Panel, align="center"] 
+ 
+This is the typical panel you use to work with *GitHub*. It has a variety of things you can do. You'll need to search for the [blue]#Groovy# repository, so look at the top of this panel. See that field named +Search or type a command+ ? Let's use  that to icon:search[].
+
+'''
+
+=== Make [blue]#Groovy# Your Own 
+
+.Search icon:search[] on *GitHub* for Groovy-Core
+image::assets/img/githubsearch.png[Github Search Feature,align="center"] 
+
+Ok, let's look for the *groovy-core* repository. In the field named +Search or type a command+ enter *groovy-core* then click +Search+. You should see a repository named *groovy/groovy-core* so click that to visit the home of [blue]#Groovy#.
+
+''' 
+
+.Fork Groovy Core on *GitHub*
+image::assets/img/githubfork.png[Fork The Code, 541, 156, link="https://github.com/groovy/groovy-core",align="center"] 
+
+So you can work on your own version of [blue]#Groovy#, you'll need to make a copy of it. This copy is placed in your own *GitHub* account under your credentials. This task of making a copy is known as *Fork* -ing.
+
+Check you're logged into your own *GitHub* account before you start to search.
+
+Fork the https://github.com/groovy/groovy-core[groovy/groovy-core] repository on *GitHub* to your own *GitHub* account. Click the +Fork+ button while on the *groovy/groovy-core* panel. When you look at your own *GitHub* home page, you'll see the list of your forked repos and any new repos you make.
+
+.Fork Groovy Core on *GitHub*
+image::assets/img/repolist.png[List of Repos, link="https://github.com/groovy/groovy-core",align="center"] 
+
+You now have your own version of [blue]#Groovy# in your *GitHub* account on the remote server. Next, you'll want to bring a copy of it onto your local system. It's easier to work with documents and test cases that way.
+
+'''
+
+TIP: See this https://gun.io/blog/how-to-github-fork-branch-and-pull-request/[gun.io] tutorial covering fork, branch, pull tactics.
+
+'''
+
+=== Terminally Yours
+
+[source,role="console",options="nowrap"]
+.Commands
+----
+Open a terminal/command prompt
+Make a folder to hold your copy of Groovy; for now, create a folder named groovy-core
+Change directories ( cd ) into your groovy-core version of the directory.
+----
+
+=== Copy [blue]#Groovy#
+
+Clone/copy your forked repository from your own *GitHub* account to your local system, then check which version of the *Java* runtime environment you have. 
+
+[source,role="console",options="nowrap"]
+.Command - ( replace xxxxx with your *GitHub* nickname )
+----
+git clone https://github.com/xxxxxx/groovy-core.git
+cd groovy-core
+java -version
+----
+
+.Terminal Console Afterward
+image::assets/img/console1.png[List of Commands, align="center"] 
+
+If your java version is earlier than 1.6 you might not be able to do much testing. If it's recent then change directories into the *groovy-core* folder. 
+
+'''
+
+=== Check Your Installation
+
+To make sure you can build and test your [blue]#Groovy# version, try to build just the [blue]#Groovy# document suite. 
+
+.Run one of these commands depending on your operating system:
+ * +bash ./gradlew asciidocAll+ on Linux/Ubuntu 
+ * +gradlew asciidocAll+ on Windows
+ * +./gradlew asciidocAll+ for Apple
+
+Your sample log might look like this :
+
+++++
+<div id="accordion">
+  <h3>Sample Log</h3>
+  <div>
+    <pre>
+martin at martin-EC548AA-ABU-a1128-uk:/media/martin/LINKS/groovy-core/groovy-core$ bash ./gradlew asciidocAll
+To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.12/userguide/gradle_daemon.html.
+:buildSrc:clean UP-TO-DATE
+:buildSrc:compileJava
+:buildSrc:compileGroovy
+:buildSrc:processResources UP-TO-DATE
+:buildSrc:classes
+:buildSrc:jar
+:buildSrc:assemble
+:buildSrc:compileTestJava UP-TO-DATE
+:buildSrc:compileTestGroovy UP-TO-DATE
+:buildSrc:processTestResources UP-TO-DATE
+:buildSrc:testClasses UP-TO-DATE
+:buildSrc:test UP-TO-DATE
+:buildSrc:check UP-TO-DATE
+:buildSrc:build
+Using Java from /usr/lib/jvm/java-7-openjdk-i386/jre (version 1.7.0_55)
+Detected development environment
+:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-closures.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-differences-java.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-domain-specific-languages.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-gdk.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-getting-started.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-introduction.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-metaprogramming.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-object-orientation.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/core-operators.adoc
+asciidoctor: WARNING: src/spec/doc/design-pattern-abstract-factory.adoc: line 1: section title out of sequence: expected level 2, got level 4
+asciidoctor: WARNING: design-pattern-in-groovy.adoc: line 52: section title out of sequence: expected level 2, got level 3
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-iterator.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-loan-my-resource.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-null-object.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-pimp-my-library.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-proxy.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-singleton.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-state.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-strategy.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-template-method.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/design-pattern-visitor.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/grape.adoc
+asciidoctor: WARNING: grape.adoc: line 28: section title out of sequence: expected levels 0 or 1, got level 2
+asciidoctor: WARNING: grape.adoc: line 105: section title out of sequence: expected levels 0 or 1, got level 2
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/guide-integrating.adoc
+asciidoctor: WARNING: guide-integrating.adoc: line 11: section title out of sequence: expected levels 0 or 1, got level 2
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/index.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/invokedynamic-support.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/license-contributors.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/template-engines.adoc
+asciidoctor: WARNING: subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc: line 1: section title out of sequence: expected level 2, got level 3
+asciidoctor: WARNING: template-engines.adoc: line 145: section title out of sequence: expected level 2, got level 3
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyc.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyconsole.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovydoc.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovyeclipse.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-groovysh.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/tools-ide.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/version-scheme.adoc
+Rendering /media/martin/LINKS/groovy-core/groovy-core/src/spec/doc/windows-nsis-installer.adoc
+:asciidoctorAssets
+:asciidocAll
+:groovy-ant:asciidoctor SKIPPED
+:groovy-ant:asciidoctorAssets
+:groovy-ant:asciidocAll UP-TO-DATE
+:groovy-bsf:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc
+:groovy-bsf:asciidoctorAssets
+:groovy-bsf:asciidocAll
+:groovy-console:asciidoctor SKIPPED
+:groovy-console:asciidoctorAssets
+:groovy-console:asciidocAll UP-TO-DATE
+:groovy-docgenerator:asciidoctor SKIPPED
+:groovy-docgenerator:asciidoctorAssets
+:groovy-docgenerator:asciidocAll UP-TO-DATE
+:groovy-groovydoc:asciidoctor SKIPPED
+:groovy-groovydoc:asciidoctorAssets
+:groovy-groovydoc:asciidocAll UP-TO-DATE
+:groovy-groovysh:asciidoctor SKIPPED
+:groovy-groovysh:asciidoctorAssets
+:groovy-groovysh:asciidocAll UP-TO-DATE
+:groovy-jmx:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-jmx/src/spec/doc/jmx.adoc
+:groovy-jmx:asciidoctorAssets
+:groovy-jmx:asciidocAll
+:groovy-json:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
+:groovy-json:asciidoctorAssets
+:groovy-json:asciidocAll
+:groovy-jsr223:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc
+:groovy-jsr223:asciidoctorAssets
+:groovy-jsr223:asciidocAll
+:groovy-nio:asciidoctor SKIPPED
+:groovy-nio:asciidoctorAssets
+:groovy-nio:asciidocAll UP-TO-DATE
+:groovy-servlet:asciidoctor SKIPPED
+:groovy-servlet:asciidoctorAssets
+:groovy-servlet:asciidocAll UP-TO-DATE
+:groovy-sql:asciidoctor SKIPPED
+:groovy-sql:asciidoctorAssets
+:groovy-sql:asciidocAll UP-TO-DATE
+:groovy-swing:asciidoctor SKIPPED
+:groovy-swing:asciidoctorAssets
+:groovy-swing:asciidocAll UP-TO-DATE
+:groovy-templates:asciidoctor
+Rendering /media/martin/LINKS/groovy-core/groovy-core/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc
+:groovy-templates:asciidoctorAssets
+:groovy-templates:asciidocAll
+:groovy-test:asciidoctor SKIPPED
+:groovy-test:asciidoctorAssets
+:groovy-test:asciidocAll UP-TO-DATE
+:groovy-testng:asciidoctor SKIPPED
+:groovy-testng:asciidoctorAssets
+:groovy-testng:asciidocAll UP-TO-DATE
+:groovy-xml:asciidoctor SKIPPED
+:groovy-xml:asciidoctorAssets
+:groovy-xml:asciidocAll UP-TO-DATE
+
+BUILD SUCCESSFUL
+
+Total time: 5 mins 22.43 secs
+</pre>
+  </div>
+</div>
+++++
+
+
+=== Success ?
+
+If your command log looks something like the above, then you have a valid [blue]#Groovy# installation, and you've also constructed a fresh local copy of the [blue]#Groovy# documentation. 
+
+You can check your local copy to see if it looks good. Using the example above, you should have an *index.html* page located in +file:///media/martin/LINKS/groovy-core/target/asciidoc/index.html+ though your actual address of the index.html file will differ a little. Enter your own address as a browser address, then you should see this :
+
+.Groovy Document Index
+image::assets/img/console3.png[Groovy Document Index, align="center"] 
+
+As you update documents, you may need to see how it looks. Following the previous steps, you can do it using the +./gradlew asciidocAll+ command, then open the *Groovy Index* page and navigate to the topic you've updated.
+
+<<<
+
+== Choose Where To Contribute
+
+=== Identify Potential Topics 
+
+Do you have a special interest, or know some areas where you have some knowledge or where your skills may be useful ? There are many areas where your expertise can be put to good use. Here's one idea.
+
+Open the https://github.com/groovy/groovy-core/tree/master/src/spec/doc[Groovy Documentation Tree]. There are a large number of  document files, one for each core component and each separate sub-project extension within [blue]#Groovy#. These are simple text file (no funny stuff)  in a markup syntax called *asciidoc*. Document files end with *.adoc*.
+
+'''
+
+NOTE: This link is for documents in the core system. There are matching trees for each sub-project like json, xml, swing, etc.
+
+'''
+
+For an example, let's look at one document named _core-domain-specific-languages.adoc_. Confirm you are signed into *GitHub* then click the above link to see our live documentation tree. 
+
+You'll be taken into the document set for *domain specific languages* in the live [blue]#Groovy# code base - not your own *GitHub* version. 
+
+''' 
+
+TIP: Remember that [blue]#Groovy# development is dynamic and changes daily.  The copy you took will become dated and will not have newer changes, additions, etc. so it's more accurate to review live [blue]#Groovy# when deciding what you'd like to do.
+
+'''
+
+
+=== Drill Down
+
+See that module named +core-domain-specific-languages.adoc+ ?  Click on that filename.
+
+If you review +core-domain-specific-languages.adoc+, you'll see a button marked +Raw+ at the top right. Click +Raw+ to see the actual plain text markup within the +core-domain-specific-languages.adoc+ file. It starts like this:
+
+[source,role="console",options="nowrap"]
+.core-domain-specific-languages.adoc
+----
+ = Domain-Specific Languages
+
+ == Command chains
+
+Groovy lets you omit parentheses around the arguments of a
+method call for top-level statements. ``command chain'' feature extends this by allowing us to chain such
+parentheses-free method calls, requiring neither parentheses around arguments, nor dots between the chained calls.
+The general idea is that a call like `a b c d` will actually be equivalent to `a(b).c(d)`. This
+also works with multiple arguments, closure arguments, and even named arguments. Furthermore, such command chains can
+also appear on the right-hand side of assignments. Let's have a look at some examples
+supported by this new syntax:
+
+[source,groovy]
+---------------------------------------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/CommandChainsTest.groovy[tags=commandchain_1,indent=0]
+. .
+...
+----
+
+Then if you look below, you can see different topics like :
+
+[source,role="console",options="nowrap"]
+.Asciidoctor Heading One Titles
+----
+ == Operator overloading
+
+(TBD)
+
+ == Script base classes
+
+(TBD)
+
+ == Adding properties to numbers
+
+(TBD)
+
+----
+
+Since these titles are marked as *(TBD)* or *To Be Done* they need some work.
+
+=== Ready To Start ?
+
+So now you know how and where to look, you can review our [blue]#Groovy# documents depending on your area of interest. Find a subject title marked something like +== Operator overloading
+
+(TBD)
++ in one of our *.adoc* files, or whatever takes your fancy.
+
+Then after you decide how/where to donate, register your interest in that area and claim it as yours. Read on to learn how you do that.
+
+<<<
+
+== Stand And Declare
+
+=== Declare Your Interest 
+
+To let us know you're working on a topic, it's useful to put your id, like nickname, date, etc., next to your topic. Edit the *.adoc* file directly in your own online copy of groovy-core to insert your id. After that, save the document, comment and commit the change. Finally, you issue a *PULL* request to the [blue]#Groovy# admins icon:user[] to merge your amendment back into the [blue]#Groovy# code base from your *GitHub* account. 
+
+This way you stake a claim to a particular topic and everyone knows it's what you're working on. If someone else wants to work on that topic, they'll see your id and should avoid it. 
+
+'''
+
+NOTE: After you are finished writing, editing, updating and placing your changes back into the [blue]#Groovy# code base, you will need to remove your id.  
+
+'''
+
+==== Annotate The Topic Document
+
+.Raw Asciidoctor Markup for a Groovy Topic
+image::assets/img/console2.png[Sample Markup, align="center"] 
+
+Here's a demo we did earlier. Notice the line +==== MarkupBuilder
+
+(TBD)
+ - assigned to JNorthr 1July14+ assigned to one of our documentation team ?
+
+You need to do the same, to an +.adoc+ document in your own GitHub copy. Look in a folder named something like +./groovy-core/groovy-core/src/spec/doc+ to see where your topic has been discussed. Then edit it, adding your id and, if necessary, save as plain text format using the *UTF-8* character set.
+
+'''
+
+WARNING: We do not have a procedure yet for new topics. Can you suggest one ?
+
+'''
+
+If you've cloned/copied groovy-core to your local system, you can do the same thing this way :
+
+[source,role="console",options="nowrap"]
+.Add your remarks
+----
+cd ./groovy-core/groovy-core/src/spec/doc
+edit core-domain-specific-languages.adoc
+// add your id on the topic you'll document
+save core-domain-specific-languages.adoc as UTF-8
+----
+
+==== Promote Your Change 
+
+[source,role="console",options="nowrap"]
+.Send your remarks back to Groovy
+----
+cd ./groovyCore/groovy-core/src/spec/
+git status
+git add src/spec/doc/core-domain-specific-languages.adoc
+git commit -m 'add Builder topic to my list to be documented'
+git push origin master
+// provide your credentials to GitHub
+----
+
+<<<
+
+=== Fix *GitHub*
+
+Now your id is back in your own *GitHub* repo, you can send your change(s) back to [blue]#Groovy#. You must ask [blue]#Groovy# admin icon:user[] to merge your changes into [blue]#Groovy# from your own *GitHub* account. Go to your own *GitHub* home page and find the repository you copied from [blue]#Groovy#.
+
+.*GitHub* Pull Request
+image::assets/img/console5.png[Request Pull from Groovy Admin, align="center"] 
+
+A merge is known as a *PULL* request because you are asking [blue]#Groovy# admin icon:user[] to *PULL* your changes back into the [blue]#Groovy# codebase. 
+
+Click the +PULL+ button to see the next panel.
+
+'''
+
+IMPORTANT: Only one *PULL* request can be issued for each branch modification.
+
+'''
+
++++<br />+++
+
+.Declare New Pull Request
+image::assets/img/console6.png[Request Pull from Groovy Admin, align="center"] 
+
+Click the +New Pull Request+ button.
+
+You will need to enter a comment and title. It helps [blue]#Groovy# admin icon:user[] to understand what's going on.
+
+'''
+
+<<<
+
+=== Review Your Submission
+
+.Confirm Pull Request
+image::assets/img/console7.png[Request Pull from Groovy Admin, align="center"] 
+
+You can review your submitted details here. See where your _commit_ statement appears ? Under that, you can see your actual changes, the line in [red]#PINK# was removed and replaced by the line shown in [green]#GREEN#. ( This sample is from a more recent declaration ).
+
+<<<
+
+== Asciidoctor Markup, A Review
+
+This [blue]#Groovy# document, and most others, are written with  asciidoctor. Each time [blue]#Groovy# is rebuilt, a fresh version of all *.adoc* files are too. Visit our link:groovy-contributions.html#_success[Success] topic above to learn how to review your own  [blue]#Groovy# documents.
+
+Here's an overview of the http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[Asciidoctor Syntax]. It's a simple markup style that comes with a Ruby Gem. The markup syantax is based on an earlier effort named asciidoc and you can read more about that original version of Asciidoc  http://www.methods.co.nz/asciidoc/userguide.html[here]. Review a http://asciidoctor.org/docs/asciidoc-writers-guide/[style guide here].
+
+=== Why Use Asciidoctor ?
+
+*IN* these days of fast paced application development, it's *GR8* to have a simple markup language and tool to write stuff. The asciidoctor tool is a quick performing ruby gem we can use to write up documentation and reference materials. We can write them quickly, then translate them into either +HTML+ or +Docbook+ output, and we can do this outside the [blue]#Groovy# development environment. Of course, it's an automatic feature of full [blue]#Groovy# build, but on a small scale, it's mu [...]
+
+=== Install Your Own Doctor
+
+If you still wish to donate some expertise, but want to avoid a full [blue]#Groovy# install, it's possible to install the +asciidoctor+ tool on your own system.
+
+In a terminal console, try  +gem install asciidoctor+ using the asciidoctor toolchain guide http://asciidoctor.org/docs/install-toolchain/[here]. 
+
+Then you can write a simple sample plain text file using an editor ( without funny stuff or markup). Follow the syntax guide above. Then when you're ready, you can do this from a command line like  we did here to create this document. This text file is named *groovy-contributions.adoc* and and it was saved with a *UTF-8* character encoding.
+
+After +asciidoctor+ ran, we had an output file named *groovy-contributions.html* in the same directory as the .adoc file. Since the + 
+*CSS* icon:css3[] stylesheet is embedded in the .html document, you can view this result right away, though  images and javascript stuff may not be in the expected place.
+
++martin at EC548A:~/Desktop$ asciidoctor groovy-contributions.adoc+
+
+If you find you've created something useful, check out our mailing lists to see how you can donate it.
+
+'''
+
+NOTE: http://saltnlight5.blogspot.fr/2013/08/how-to-convert-asciidoc-text-to-html.html[Converting asciidoctor markup to html] - will give Groovy people an overview of other possibilities. 
+
+'''
+
+.Asciidoctor References
+ * http://asciidoctor.org/docs/user-manual/[Asciidoctor User Manual]
+ * http://asciidoctor.org/docs/asciidoc-writers-guide/[Writer's Guide]
+ * http://asciidoctor.org/docs/asciidoc-syntax-quick-reference/[Syntax Reference Guide]
+ * http://mrhaki.blogspot.fr/2014/04/awesome-asciidoc-include-partial-parts.html[Mr Haki] explains how to insert *INCLUDE* code snippets in Asciidoc documentation.
+ * http://mrhaki.blogspot.fr/2014/06/awesome-asciidoc-change-source-code.html[Mr Haki] shows how to indent source code.
+ * http://mrhaki.blogspot.fr/2014/05/awesome-asciidoc-explain-code-with.html[Mr Haki] shows how to explain testcode with callouts.
+
+<<<
+
+== Tag Annotations
+
+Documents benefit from the inclusion of code samples. Live tests that are part of a typical [blue]#Groovy# build are ideal candidates. We know that if a build succeeds, then all it's tests were successful too. Therefore samples from live tests can improve our documents.
+
+Before we get into the topic of test cases, here's a *heads-up* on how we do it using some asciidoctor features.
+
+=== Asciidoctor Includes and Tags
+
+Asciidoctor can identify parts of files for inclusion. Use the *include* statement to insert source material from another file. The *include* syntax offers a nice way to choose a piece of the file to include. The *tag* declaration identifies the piece. 
+
+'''
+
+TIP: *tag* names follow a convention of {name of script}_{name of method}_{incrementing number of this test within all tests}[]
+
+'''
+
+Given an asciidoctor declaration like this :
+
+.Sample BuilderSupportTest Include
+....
+ === Sample Asciidoc BuilderSupportTest Tag
+
+ [source,groovy]
+ .BuilderSupportTest.groovy Listing
+ ----
+ include::BuilderSupportTest.groovy[tags=BuilderSupportTest_add_node_with_value_object4]
+ ----
+....
+
+would only insert source statements between the +BuilderSupportTest_add_node_with_value_object4+ tag start and end as follows : 
+
+image::assets/img/example19.png[BuilderSupportTest.groovy Listing] 
+
+from this :
+
+.BuilderSupportTest.groovy
+....
+// tag::BuilderSupportTest_add_node_with_value_object4[]
+        // simple node with one attribute
+        def sb3 = new BuilderSupportTest()
+        def node3 = sb3.foo(name:'value')
+        
+        // node type 3 creation with map as name/value pair
+        assert sb3.log == ['cn3','foo', 'name','value', 'nc',null,'x']
+// end::BuilderSupportTest_add_node_with_value_object4[]
+....
+
+NOTE: +//+ characters identify the remainder of a line as remarks.
+
+'''
+
+Asciidoctor tags are simply remarks / comments and so are invisible at build time. They're declared in pairs as a tag set. The *tag* keyword preceeds the tag name +BuilderSupportTest_add_node_with_value_object4+ followed by the asciidoc required tag ending of +[]+
+
++// tag::+ says start using text after this line.
+
++// end::+ says stop using text before this line.
+
+
+Does this make sense ? It's possible to grab some of a live test and insert it into our document. It's always a valid example 'cos the build succeeded [red]#icon:exclamation[]#
+
+icon:thumbs-up[] Ok, let's review test cases next. 
+
+<<<
+
+== Examine Test Cases
+
+=== Review Current Tests
+
+Review the https://github.com/groovy/groovy-core/tree/master/src/spec/test[Test Case] folder. There may already be tests that cover your area of interest. Some were written before tag standards  came into existence. It might be as simple as adding asciidoctor tags around a test method.
+
+==== Change Known Test Cases 
+
+Here's an existing test case from +groovy-core/src/spec/test/builder/CliBuilderTest.groovy+ :
+
+Typical class comments preceed the class declaration with author attribution :
+
+[source,role="console",options="nowrap"]
+.CliBuilder Test Class
+----
+/**
+* Tests for CliBuilder. The tests directly in this file are specific
+* to CliBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+----
+
+Earlier test cases did not use *GroovyTestCase* as a basis, though more recent test cases do : + 
+
+[source,role="console",options="nowrap"]
+.Class
+----
+class CliBuilderTest extends GroovyTestCase {
+----
+
+[source,role="console",options="nowrap"]
+.Sample Test method
+----
+ void testObjectNotDefined() {
+
+	// tag::clibuilder_nullobject1[]
+	CliBuilder clibuilder;
+
+	// clibuilder should be null when not initialized
+	assert clibuilder == null;
+
+	// end::clibuilder_nullobject1[]
+
+} // end of method
+----
+
+[source,role="console",options="nowrap"]
+.Sample Result
+----
+	CliBuilder clibuilder;
+
+	// clibuilder should be null when not initialized
+	assert clibuilder == null;
+----
+
+TIP: The *assert* statement should have a remark before it. It should explain say why the test should succeed - *not* why it would fail icon:exclamation[]
+
+'''
+
+=== Add New Test Cases 
+
+It's outside the scope of this document, though if you feel something is missing in our test coverage, please raise a question. Our mailing lists are an ideal place to ask questions and receive suggestions about how you can contribute new test cases. Everyone says more tests improve product quality. Can you think of any tests  we missed ?
+
+==== Copyright Notice
+
+It's always useful to identify the license terms for use with any asset you create or amend. A copyright statement does just that. Here's a sample copyright often used when doing test cases :
+
+[source,role="console",options="nowrap"]
+.Copyright Notice
+----
+/*
+* Copyright 2014 the original author or authors.
+*
+* Licensed under the Apache License, Version 2.0 (the "License");
+* you may not use this file except in compliance with the License.
+* You may obtain a copy of the License at
+*
+* http://www.apache.org/licenses/LICENSE-2.0
+*
+* Unless required by applicable law or agreed to in writing, software
+* distributed under the License is distributed on an "AS IS" BASIS,
+* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+* See the License for the specific language governing permissions and
+* limitations under the License.
+*/
+----
+
+
+=== Forget Test Cases ?
+
+Well, why not ? It's not critical to have samples of test stuff. Plenty of great documentation does not require any reference to tests or the content may not even be about code, logic, tests, scripts.
+
+<<<
+
+== How To Write Documentation
+
+Review current [blue]#Groovy# documents to gain an understanding of how it's written and what sort of content it has. http://groovy-lang.org/json.html[Look at this page about Json]. It uses our latest document standards. Now you know about *tags* you can appreciate how test samples are picked from external sources.
+
+=== Our Suggestions
+
+An introduction describes the purpose of the document. Major topical areas are started by level one headings. More detailed text pieces would be started with level two headings. 
+
+Follow guidelines for version 1.4.0 of Asciidoctor.
+
+=== Refer To Testcase Tags 
+
+As per our notes above about *tags*, write your document to include external text when appropriate.
+
+.Sample Include
+....
+ [source,groovy]
+ .Test.groovy Listing
+ ----
+ include::Test.groovy[tags=Test_add_new_json_node_with_value_7]
+ ----
+....
+
+ 
+=== Images Go Where ?
+
+Images of GUI panels improve understanding and act as a powerful aid to learn new and/or difficult concepts.
+
+Groovy-core images and GUI  related stuff can be put in the  +groovy-core/src/spec/assets/img+ folder.  Sub-projects have their own image folders, so +groovy-core/subprojects/groovy-servlet/src/spec/assets/img+ could keep images if a document concerns servlets. 
+
+'''
+
+WARNING: Some assets/img folders do not exist and must be created.
+
+'''
+
+Please try to keep the size of images small rather than use a very large image then ask asciidoctor to re-scale it smaller. This improves page load times for end users.
+
+<<<
+
+== Review Output
+
+After making changes, adding new features, images, external links, etc., it's useful to review how it all looks on your own local system. If things don't work out, it's easier to fix than after promotion.
+
+=== Regen Groovy Docs 
+
+First, change directories to the *groovy-core* directory created in link:groovy-contributions.html#_copy_span_class_blue_groovy_span[Copy Groovy] step.
+
+[source,bash]
+.Partial asciidocAll Listing
+----
+~/.gradle $ cd /media/martin/LINKS/groovyCore/groovy-core
+/media/martin/LINKS/groovyCore/groovy-core $ ./gradlew asciidocAll
+To honour the JVM settings for this build a new JVM will be forked. Please consider using the daemon: http://gradle.org/docs/1.12/userguide/gradle_daemon.html.
+:buildSrc:compileJava UP-TO-DATE
+:buildSrc:compileGroovy UP-TO-DATE
+:buildSrc:processResources UP-TO-DATE
+:buildSrc:classes UP-TO-DATE
+:buildSrc:jar UP-TO-DATE
+:asciidoctor
+Rendering /media/martin/LINKS/groovyCore/groovy-core/src/spec/doc/core-closures.adoc
+----
+
+To rebuild your version of [blue]#Groovy# documents, try this. Run one of these commands depending on your operating system:
+
+ * +bash ./gradlew asciidocAll+ on Linux/Ubuntu 
+ * +gradlew asciidocAll+ on Windows
+ * +./gradlew asciidocAll+ for Apple
+
+=== Review Generated Results 
+
+If your command worked ok, you'll  have a fresh local copy of the [blue]#Groovy# documentation. 
+
+You can check your local copy to see if it looks good. After a regen, there should be *index.html* page located in +./groovy-core/groovy-core/target/asciidoc/index.html+ ( your actual address may differ ). 
+
+Enter your own address in a browser to see this :
+
+.Groovy Document Index
+[.thumb]
+image::assets/img/example1.png[Groovy Document Index, 290, 425, align="center"] 
+
+As you modify documents, you can now see how they look. Just navigate to the topic you've updated and enjoy the fruits of your efforts  icon:apple[]
+
+<<<
+
+== Cleanup
+
+Ok, we have everything in place. All our changes are good-to-go so now they can go back to +groovy-core+  [red]#icon:exclamation[]#
+
+=== Commit Changes 
+
++git commit -am \'put a nice clear note here about what you did'+
+
+=== Go To Master Branch
+
++git checkout master+ 
+
+=== Merge Mods
+
++git merge <your branch name>+
+
+=== Promote Changes 
+
++git push origin master+
+
+=== Remove Your Interest Id 
+
+Follow the directions given in link:groovy-contributions.html#_stand_and_declare[Stand And Declare] to remove your id marker.
+
+
+'''
+
+=== Your Merge Request 
+
+==== Groovy *PULL* Requests
+
+In a browser, enter https://github.com/groovy/groovy-core[https://github.com/groovy/groovy-core] to see the *groovy-core* home page in *GitHub*. It's where we can get to the feature to ask our changes to be merged.
+
+image::assets/img/example2.png[GitHub Groovy-core, 794, 182, align="center", link="https://github.com/groovy/groovy-core"] 
+
+Take a look here. See *[blue]#Pull Request#* +24+  ? This is where you can see how many other *PULL* requests are open, waiting to be done. Clicking +Pull Requests+ gives you the next view.  The [white green-background]*New pull request* button is there
+
++++<br />+++
+
+'''
+
+==== *PULL* The Other One
+
+image::assets/img/example4.png[Groovy-core PULL list, 877, 463, align="center", link="https://github.com/groovy/groovy-core/pulls"] 
+
+These are the current *PULL* requests for [blue]#Groovy#. Notice how each request has a title ? It's important to provide some idea about what a request will do.
+
+As this example is about adding new documentation, click the [white green-background]*New pull request* button.
+
+'''
+
+.Pick a Branch
+image::assets/img/example12.png[Groovy-core PULL list,  505, 337, align="center",] 
+
+Pick a release to donate to. Typically, this would be the +master+ branch, though if your work is for a future release, you could pick a more relevant branch.
+ 
+Click the branch title where your request should go.
+
+'''
+
+.Picked Release 2.4.0-beta-1
+image::assets/img/example13.png[Groovy-core PULL list,  505, 337,align="center"] 
+
+For this example, we'll donate our work to release 2.4.0-beta-1. From this view, we can also see what's going into, or will be removed from this release.  See the [white green-background]*Create pull request* button ?  Click that.
+
+'''
+
+==== Do The Deed
+
+.Provide Some Info
+image::assets/img/example14.png[Groovy-core PULL list, 505, 337, align="center",] 
+
+The [blue]#Groovy# admins icon:user[] use info from this view. Include a title for your request. Put some comments in too to start the thread of conversation about this donation. Click [white green-background]*Create Pull request*. You should receive a pull request number and the  *[blue]#Pull Request#* +24+  count from the home page will become +25+ when your request is confirmed.
+ 
+
++++<br />+++
+
+'''
+
+
++++<br />+++
+
+.Chill
+****
+icon:asterisk[] You've done everything you can - so chill. Have a cuppa icon:coffee[] , brew icon:beer[] or whatever. 
+
+Robust software needs time to mature. Often there are challenges about why or how something was written, developed, documented or coded. It can result in conversations with a variety of your peers and other knowledge experts about how to proceed. Changes may be needed before a request can merge into [blue]#Groovy#. 
+
+icon:thumbs-up[] It's just part of the process to build better products. icon:ok-sign[]
+****
+
+<<<
+
+== A Waiting Game
+
+Now, you've submitted your request to [blue]#Groovy# admins icon:user[]  and received a *PULL* / +merge+ request number.
+
+=== Track Your Changes
+
+Again, do the same thing we did to create the request.
+
+To follow the progress of your request, in a browser, enter https://github.com/groovy/groovy-core[https://github.com/groovy/groovy-core] to see the *groovy-core* home page in *GitHub*. 
+
+image::assets/img/example2.png[GitHub Groovy-core, 794, 182, align="center", link="https://github.com/groovy/groovy-core"] 
+
+Look again. This is where you can saw how many other *PULL* requests were open, waiting to be done, including yours. Clicking +Pull Request+ took you to the next page for that view.  
+
++++<br />+++
+
+'''
+
+==== The *PULL* List
+
+.List Of Requests
+image::assets/img/example4.png[Groovy-core PULL list, 877, 463, align="center", link="https://github.com/groovy/groovy-core/pulls"] 
+
+Here are waiting *PULL* requests for [blue]#Groovy#. As this example is about adding *new Builder Documentation*, it was given a request number *488*. Look down the page to find it. 
+
+To learn more about any request, click a request title. *GitHub* opens a request details view as seen below. 
+
+Everything about a request is shown there. It's the data [blue]#Groovy# admins icon:user[] work with. 
+
+Queries might be raised about something in your submission. These comments may require further improvements and/or changes to your submission. It's a bit like a message thread where interested people can follow progress of a submission, make suggestions, etc.
+
+'''
+
+NOTE:  [green]#Green icon:check[] marks# confirm the success of a request. Click the [green]#icon:check[]# icon to see how the request was processed.
+
+'''
+
+At the right of each entry are comment icons icon:comment[2x] with the number of comments made about each request. Click the icon to get the following view.
+
+'''
+
+==== Comments Thread
+
+.Conversation Thread
+image::assets/img/example5.png[PULL Request 488 Details, 843, 555, align="center"] 
+
+We can see all related commentary in this place. It's for a single *PULL* request.
+
+'''
+
+<<<
+
+=== Verify Success
+
+'''
+
+TIP: This step is optional
+
+'''
+
+image:assets/img/teamcity.png[TeamCity, 73, 20, link="http://www.jetbrains.com/teamcity/"]  is a continuous integration service. It's the foundation of the service we use to build *[blue]#Groovy#*.  
+
+To see what's going on, log in as a guest when you visit image:assets/img/teamcity.png[TeamCity, 73, 20, link="http://ci.groovy-lang.org/"]
+
+.TeamCity Login
+image::assets/img/example7.png[TeamCity Login, 429, 273, align="center", link="http://ci.groovy-lang.org/"] 
+
+'''
+
+.Most Recently Executing Merge ( PULL ) Requests
+image::assets/img/example8.png[TeamCity Tasks List, align="center"] 
+
+*PULL* requests become +merge+ requests upon acceptance. Each +merge+ is given a task number, for this example our +merge+ /  *PULL* request *488* is assigned task number *2093*. It was merged into the +master+ core branch of [blue]#Groovy#. Click +488/merge+ to drill down into the details. 
+
+The next view has specific details  about every build attempt made for this request..
+
+'''
+
+.Task List For A Specific Request
+image::assets/img/example9.png[PULL Req 488 Details, align="center"] 
+
+Here we can see that our request *488* has been executed a number of times. Each time it received another task execution number. The most recent task was *2093* marked with [green]#Green icon:check[] mark.# That means *Success* ! 
+
+'''
+
+NOTE: Task *1968* failed as there is a  [red]#red# icon:exclamation[]
+
+'''
+
+For even more detail, we can drill down again into task messages by clicking the request number. Click task +Tests passed 17761+ for next view.
+
+'''
+
+.PULL Request 488 Task 2093 Details
+image::assets/img/example10.png[PULL Request 488 Task 2093 Details, align="center"] 
+
+Ok, so here is the good news ! Request was successful. It passed all 17,761 tests. 
+
+'''
+
+.PULL Request 488 Task 1968 Failure
+image::assets/img/example11.png[PULL Request 488 Task 1968 Details, align="center"] 
+
+Oops  icon:exclamation[]  There was an error ! icon:thumbs-down[] 
+
+As seen above in the task execution list, task +1968+ had bad news. Clicking +1968+ displays this view. 
+
+This needed some icon:ambulance[] work on the part of the submitter to remedy the failure. The image:assets/img/teamcity.png[TeamCity, 73, 20, link="http://ci.groovy-lang.org/"] continuous integration server then scheduled and re-executed the revised submission.
+
+'''
+
+<<<
+
+=== Declare Victory 
+
+When your request is merged into [blue]#Groovy# let everyone know icon:exclamation[]
+
+Please join any of our mailing lists at http://groovy-lang.org/mailing-lists.html[http://groovy-lang.org/mailing-lists.html]. 
+
+Whether you are a user, developer, or just plain interested, we have a choice of mailing lists you may find appealing. 
+
+You can find a live icon:twitter[] https://twitter.com/hashtag/groovylang[#groovylang] feed for up-to-the-minute news.
+
+.Mailing Lists
+ * dev at groovy.codehaus.org - for details about [blue]#Groovy# development
+ * user at groovy.codehaus.org - lots of questions and answers about [blue]#Groovy#
+ * announce at groovy.codehaus.org  - for new releases and news
+ * eclipse-plugin-user at groovy.codehaus.org - all about the [blue]#Groovy# plugin for Eclipse
+ * scm at groovy.codehaus.org - see those commits !
+
+'''
+
+++++
+<script src="http://code.jquery.com/jquery-1.10.2.js"></script>
+<script src="http://code.jquery.com/ui/1.11.0/jquery-ui.js"></script>
+<script>
+  $(function() {
+    $( "#accordion" ).accordion({ collapsible: true, active:false, heightStyle: "content" });
+    $( "#accordion2" ).accordion({ collapsible: true, active:false, heightStyle: "content" });
+    $( "#accordion3" ).accordion({ collapsible: true, active:false, heightStyle: "content" });
+  });
+</script>
+++++
+ 
diff --git a/src/spec/doc/guide-integrating.adoc b/src/spec/doc/guide-integrating.adoc
index 438fc75..667fcae 100644
--- a/src/spec/doc/guide-integrating.adoc
+++ b/src/spec/doc/guide-integrating.adoc
@@ -1,4 +1,5 @@
 = Integrating Groovy in a Java application
+
 == Groovy integration mechanisms
 
 The Groovy language proposes several ways to integrate itself into applications (Java or even Groovy) at runtime, from
@@ -296,14 +297,10 @@ Ultimately, it is possible to perform more operations during compilation by rely
 compilation and would let you introduce new steps or even stop compilation at various phases. This is for example how
 stub generation is done, for the joint compiler.
 
-However, overriding `CompilationUnit` is not recommanded and should only be done if no other standard solution works.
+However, overriding `CompilationUnit` is not recommended and should only be done if no other standard solution works.
 
-:leveloffset: 3
-include::{projectdir}/subprojects/groovy-bsf/{specfolder}/integrating-bsf.adoc[]
-:leveloffset: 2
+include::{projectdir}/subprojects/groovy-bsf/{specfolder}/integrating-bsf.adoc[leveloffset=+1]
 
-:leveloffset: 3
-include::{projectdir}/subprojects/groovy-jsr223/{specfolder}/integrating-jsr223.adoc[]
-:leveloffset: 2
+include::{projectdir}/subprojects/groovy-jsr223/{specfolder}/integrating-jsr223.adoc[leveloffset=+1]
 
 
diff --git a/src/spec/doc/index.adoc b/src/spec/doc/index.adoc
index 7fc7673..736618d 100644
--- a/src/spec/doc/index.adoc
+++ b/src/spec/doc/index.adoc
@@ -6,91 +6,81 @@ include::{projectdir}/src/spec/doc/core-introduction.adoc[]
 
 == Groovy Language Specification
 
-:leveloffset: 2
+include::{projectdir}/src/spec/doc/core-syntax.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-syntax.adoc[]
+include::{projectdir}/src/spec/doc/core-operators.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-operators.adoc[]
+include::{projectdir}/src/spec/doc/core-program-structure.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-program-structure.adoc[]
+include::{projectdir}/src/spec/doc/core-object-orientation.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-object-orientation.adoc[]
+include::{projectdir}/src/spec/doc/core-closures.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-closures.adoc[]
-
-include::{projectdir}/src/spec/doc/core-semantics.adoc[]
-
-:leveloffset: 0
+include::{projectdir}/src/spec/doc/core-semantics.adoc[leveloffset=+2]
 
 == Tools
 
-:leveloffset: 2
+include::{projectdir}/src/spec/doc/tools-groovyc.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/tools-groovyc.adoc[]
+include::{projectdir}/subprojects/groovy-groovysh/{specfolder}/groovysh.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/tools-groovysh.adoc[]
+include::{projectdir}/subprojects/groovy-console/{specfolder}/groovy-console.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/tools-groovyconsole.adoc[]
+include::{projectdir}/subprojects/groovy-groovydoc/{specfolder}/groovydoc.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/tools-groovydoc.adoc[]
+include::{projectdir}/src/spec/doc/tools-ide.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/tools-ide.adoc[]
+== User Guides
 
-:leveloffset: 0
+include::{projectdir}/src/spec/doc/core-getting-started.adoc[leveloffset=+2]
 
-== User Guides
+include::{projectdir}/src/spec/doc/core-differences-java.adoc[leveloffset=+2]
 
-:leveloffset: 2
+include::{projectdir}/src/spec/doc/core-gdk.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-getting-started.adoc[]
+include::{projectdir}/src/spec/doc/core-metaprogramming.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-differences-java.adoc[]
+include::{projectdir}/src/spec/doc/grape.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-gdk.adoc[]
+include::{projectdir}/src/spec/doc/core-testing-guide.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-metaprogramming.adoc[]
+include::{projectdir}/subprojects/groovy-json/{specfolder}/json-userguide.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/grape.adoc[]
+=== Interacting with a SQL database
 
-include::{projectdir}/src/spec/doc/core-testing-guide.adoc[]
+(TBD)
 
-include::{subprojroot}json/{specfolder}/json-userguide.adoc[]
 
-=== Interacting with a SQL database (TBD)
-=== Processing XML (TBD)
-=== Scripting Ant tasks (TBD)
+include::{projectdir}/subprojects/groovy-xml/{specfolder}/xml-userguide.adoc[leveloffset=+2]
 
-:leveloffset: 2
+=== Scripting Ant tasks
 
-include::{projectdir}/src/spec/doc/template-engines.adoc[]
+Groovy integrates very well with http://ant.apache.org[Apache Ant] thanks to <<_antbuilder,AntBuilder>>.
 
-:leveloffset: 0
+include::{projectdir}/subprojects/groovy-templates/{specfolder}/template-engines.adoc[leveloffset=+2]
 
-=== Servlet support (TBD)
+include::{projectdir}/subprojects/groovy-servlet/{specfolder}/servlet-userguide.adoc[leveloffset=+2]
 
-:leveloffset: 2
+include::{projectdir}/src/spec/doc/guide-integrating.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/guide-integrating.adoc[]
+include::{projectdir}/src/spec/doc/core-domain-specific-languages.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/core-domain-specific-languages.adoc[]
+include::{projectdir}/subprojects/groovy-jmx/src/spec/doc/jmx.adoc[leveloffset=+2]
 
-include::{projectdir}/subprojects/groovy-jmx/src/spec/doc/jmx.adoc[]
+=== Creating Swing UIs
 
-:leveloffset: 0
+Creating Swing UIs is made easy thanks to the use of <<swingbuilder,SwingBuilder>>.
 
-=== Creating Swing UIs (TBD)
-=== Security (TBD)
+=== Security
 
-:leveloffset: 2
+(TBD)
 
-include::{projectdir}/src/spec/doc/design-pattern-in-groovy.adoc[]
 
-:leveloffset: 0
+include::{projectdir}/src/spec/doc/design-pattern-in-groovy.adoc[leveloffset=+2]
 
 == Acknowledgements
 
-:leveloffset: 2
+include::{projectdir}/src/spec/doc/contributors.adoc[leveloffset=+2]
 
-include::{projectdir}/src/spec/doc/license-contributors.adoc[]
+include::{projectdir}/src/spec/doc/license.adoc[leveloffset=+2]
 
-:leveloffset: 0
diff --git a/src/spec/doc/invokedynamic-support.adoc b/src/spec/doc/invokedynamic-support.adoc
index 65a7663..5664ca5 100644
--- a/src/spec/doc/invokedynamic-support.adoc
+++ b/src/spec/doc/invokedynamic-support.adoc
@@ -3,7 +3,7 @@
 
 == Foreword
 
-Since Groovy 2.0, we added support for the JVM http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html#invokedynamic[invokedynamic] instruction. This instruction is supported since Java 7 and is a new bytecode instruction in the JVM that allows easier implementation of dynamic languages. This instruction will also be used internally, by the JVM, for the upcoming lamdba support in Java 8.
+Since Groovy 2.0, we added support for the JVM http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html#invokedynamic[invokedynamic] instruction. This instruction is supported since Java 7 and is a new bytecode instruction in the JVM that allows easier implementation of dynamic languages. This instruction will also be used internally, by the JVM, for the lambda support in Java 8.
 
 This means that unlike APIs, AST transformations or syntactic sugar, this feature is **not visible** to the developer or the end user. It is a compilation and runtime feature only. This means that given two programs written in Groovy, you have the choice to compile it with or without invokedynamic support. Whatever you choose, it comes with pros and cons:
 
@@ -26,7 +26,7 @@ The first jar is Groovy compiled without invokedynamic support, while the second
 Both jars contain a fully working groovy implementation. They are mutually exclusive (don't put both on classpath).
 
 === Command-line and indy
-If you download the distribution and that you use the command line, it's always the "normal" version of Groovy which is picked up in classpath. This means that whatever command you use (++groovy++, ++groovyc++, ++groovysh++ or ++groovyConsole++), invokedynamic support is not available out of the box. To use the invokedynamic version, you have to switch the jars manually. The distribution makes use of the jars in the ++lib++ directory, while the indy jars are available in the ++indy++ dir [...]
+If you download the distribution and that you use the command line, it's always the "normal" version of Groovy which is picked up in classpath. This means that whatever command you use (`groovy`, `groovyc`, `groovysh` or `groovyConsole`), invokedynamic support is not available out of the box. To use the invokedynamic version, you have to switch the jars manually. The distribution makes use of the jars in the ++lib++ directory, while the indy jars are available in the ++indy++ directory.  [...]
 
 - remove or rename the groovy-*.jar files in the lib directory
 - replace them with the indy version from the indy directory
diff --git a/src/spec/doc/license-contributors.adoc b/src/spec/doc/license-contributors.adoc
deleted file mode 100644
index 624c310..0000000
--- a/src/spec/doc/license-contributors.adoc
+++ /dev/null
@@ -1,21 +0,0 @@
-= Contributors
-
-
-The Groovy team would like to thank the contributors of this documentation (by alphabetical order):
-
-* https://github.com/bura[Andrey Bloschetsov]
-* https://github.com/jeffbrown[Jeff Scott Brown]
-* http://twitter.com/CedricChampeau[Cédric Champeau]
-* http://twitter.com/werdnagreb[Andrew Eisenberg]
-* http://twitter.com/paulk_asert[Paul King]
-* http://twitter.com/glaforge[Guillaume Laforge]
-* http://twitter.com/pledbrook[Peter Ledbrook]
-* https://github.com/PascalSchumacher[Pascal Schumacher]
-* https://twitter.com/asteingr[André Steingreß]
-* http://grantmcconnaughey.github.io/[Grant McConnaughey]
-
-= License
-
-This work is licensed under a http://creativecommons.org/licenses/by-sa/3.0/deed.en[Creative Commons Attribution-ShareAlike 3.0 Unported License].
-
-image::http://i.creativecommons.org/l/by-sa/3.0/88x31.png[Creative Commons BY-SA]
\ No newline at end of file
diff --git a/src/spec/doc/license.adoc b/src/spec/doc/license.adoc
new file mode 100644
index 0000000..cdd3819
--- /dev/null
+++ b/src/spec/doc/license.adoc
@@ -0,0 +1,6 @@
+= License
+
+This work is licensed under a http://creativecommons.org/licenses/by-sa/3.0/deed.en[Creative Commons Attribution-ShareAlike 3.0 Unported License].
+
+image::http://i.creativecommons.org/l/by-sa/3.0/88x31.png[Creative Commons BY-SA]
+
diff --git a/src/spec/doc/style-guide.adoc b/src/spec/doc/style-guide.adoc
new file mode 100644
index 0000000..d244687
--- /dev/null
+++ b/src/spec/doc/style-guide.adoc
@@ -0,0 +1,682 @@
+= Groovy style and language feature guidelines for Java developers
+
+A Java developer embarking on a Groovy adventure will always have Java in mind, and will progressively learn Groovy,
+one feature at a time, becoming more productive and writing more idiomatic Groovy code.
+This document's purpose is to guide such a developer along the way, teaching some common Groovy syntax style,
+new operators, and new features like closures, etc.
+This guide is not complete and only serves as a quick intro and a base for further guideline sections
+should you feel like contributing to the document and enhancing it.
+
+== No semicolons
+
+When coming from a C / C++ / C# / Java background, we're so used to semicolons, that we put them everywhere.
+Even worse, Groovy supports 99% of Java's syntax, and sometimes,
+it's so easy to paste some Java code into your Groovy programs, that you end up with tons of semicolons everywhere.
+But... semicolons are optional in Groovy, you can omit them, and it's more idiomatic to remove them.
+
+== Return keyword optional
+
+In Groovy, the last expression evaluated in the body of a method can be returned without necessitating the `return` keyword.
+Especially for short methods and for closures, it's nicer to omit it for brevity:
+
+[source,groovy]
+----
+String toString() { return "a server" }
+String toString() { "a server" }
+----
+
+But sometimes, this doesn't look to good when you're using a variable, and see it visually twice on two rows:
+
+[source,groovy]
+----
+def props() {
+    def m1 = [a: 1, b: 2]
+    m2 = m1.findAll { k, v -> v % 2 == 0 }
+    m2.c = 3
+    m2
+}
+----
+
+In such case, either putting a newline before the last expression, or explicitly using `return` may yield better readability.
+
+I, for myself, sometimes use the `return` keyword, sometimes not, it's often a matter of taste.
+But often, inside of closure, we omit it more often than not, for example. So even if the keyword is optional,
+this is by no means mandatory to not use it if you think it halters the readability of your code.
+
+A word of caution, however. When using methods which are defined with the `def` keyword instead of a specific concrete type,
+you may be surprise to see the last expression being returned sometimes. So usually prefer using a specific return type like void or a type.
+In our example above, imagine we forgot to put m2 as last statement to be returned,
+the last expression would be `m2.c = 3`, which would return... `3`, and not the map you expect.
+
+Statements like `if`/`else`, `try`/`catch` can thus return a value as well, as there's a "last expression" evaluated in those statements:
+
+[source,groovy]
+----
+def foo(n) {
+    if(n == 1) {
+        "Roshan"
+    } else {
+        "Dawrani"
+    }
+}
+
+assert foo(1) == "Roshan"
+assert foo(2) == "Dawrani"
+----
+
+== Def and type
+
+As we're talking about `def` and types, I often see developers using both `def` and a type. But `def` is redundant here.
+So make a choice, either use `def` or a type.
+
+So don't write:
+
+[source,groovy]
+----
+def String name = "Guillaume"
+----
+
+But:
+
+[source,groovy]
+----
+String name = "Guillaume"
+----
+
+When using `def` in Groovy, the actual type holder is `Object` (so you can assign any object to variables defined with `def`,
+and return any kind of object if a method is declared returning `def`).
+
+When defining a method with untyped parameters, you can use `def` but it's not needed, so we tend to omit them.
+So instead of:
+
+[source,groovy]
+----
+void doSomething(def param1, def param2) { }
+----
+
+Prefer:
+
+[source,groovy]
+----
+void doSomething(param1, param2) { }
+----
+
+But as we mention in the last section of the document, it's usually better to type your method parameters,
+so as to help with documenting your code, and also help IDEs for code-completion,
+or for leveraging the static type checking or static compilation capabilities of Groovy.
+
+Another place where `def` is redundant and should be avoided is when defining constructors:
+
+[source,groovy]
+----
+class MyClass {
+    def MyClass() {}
+}
+----
+
+Instead, just remove the `def`:
+
+[source,groovy]
+----
+class MyClass {
+    MyClass() {}
+}
+----
+
+== Public by default
+
+By default, Groovy considers classes and methods `public`.
+So you don't have to use the `public` modifier everywhere something is public.
+Only if it's not public, you should put a visibility modifier.
+
+So instead of:
+
+[source,groovy]
+----
+public class Server {
+    public String toString() { return "a server" }
+}
+----
+
+Prefer the more concise:
+
+[source,groovy]
+----
+class Server {
+    String toString() { "a server" }
+}
+----
+
+You may wonder about the 'package-scope' visibility,
+and the fact Groovy allows one to omit 'public' means that this scope is not supported by default,
+but there's actually a special Groovy annotation which allows you to use that visibility:
+
+[source,groovy]
+----
+class Server {
+    @PackageScope Cluster cluster
+}
+----
+
+== Omitting parentheses
+
+Groovy allows you to omit the parentheses for top-level expressions, like with the `println` command:
+
+[source,groovy]
+----
+println "Hello"
+method a, b
+----
+
+vs:
+
+[source,groovy]
+----
+println("Hello")
+method(a, b)
+----
+
+When a closure is the last parameter of a method call, like when using Groovy's `each{}` iteration mechanism,
+you can put the closure outside the closing parentheses, and even omit the parentheses:
+
+[source,groovy]
+----
+list.each( { println it } )
+list.each(){ println it }
+list.each  { println it }
+----
+
+Always prefer the third form, which is more natural, as an empty pair of parentheses is just useless syntactical noise!
+
+There are some cases where Groovy doesn't allow you to remove parentheses.
+As I said, top-level expressions can omit them, but for nested method calls or on the right-hand side of an assignment,
+you can't omit them there.
+
+[source,groovy]
+----
+def foo(n) { n }
+
+println foo 1 // won't work
+def m = foo 1
+----
+
+== Classes as first-class citizens
+
+The `.class` suffix is not needed in Groovy, a bit like in Java's `instanceof`.
+
+For example:
+
+[source,groovy]
+----
+connection.doPost(BASE_URI + "/modify.hqu", params, ResourcesResponse.class)
+----
+
+Using GStrings we're going to cover below, and using first class citizens:
+
+[source,groovy]
+----
+connection.doPost("${BASE_URI}/modify.hqu", params, ResourcesResponse)
+----
+
+== Getters and Setters
+
+In Groovy, a getters and setters form what we call a "property",
+and offers a shortcut notation for accessing and setting such properties.
+So instead of the Java-way of calling getters / setters, you can use a field-like access notation:
+
+[source,groovy]
+----
+resourceGroup.getResourcePrototype().getName() == SERVER_TYPE_NAME
+resourceGroup.resourcePrototype.name == SERVER_TYPE_NAME
+
+resourcePrototype.setName("something")
+resourcePrototype.name = "something"
+----
+
+When writing your beans in Groovy, often called POGOs (Plain Old Groovy Objects),
+you don't have to create the field and getter / setter yourself, but let the Groovy compiler do it for you.
+
+So instead of:
+
+[source,groovy]
+----
+class Person {
+    private String name
+    String getName() { return name }
+    void setName(String name) { this.name = name }
+}
+----
+
+You can simply write:
+
+[source,groovy]
+----
+class Person {
+    String name
+}
+----
+
+As you can see, a free standing 'field' without modifier visibility actually
+makes the Groovy compiler to generate a private field and a getter and setter for you.
+
+When using such POGOs from Java, the getter and setter are indeed there, and can be used as usual, of course.
+
+Although the compiler creates the usual getter/setter logic,
+if you wish to do anything additional or different in those getters/setters,
+you're free to still provide them, and the compiler will use your logic, instead of the default generated one.
+
+== Initializing beans with named parameters and the default constructor
+
+With a bean like:
+
+[source,groovy]
+----
+class Server {
+    String name
+    Cluster cluster
+}
+----
+
+Instead of setting each setter in subsequent statements as follows:
+
+[source,groovy]
+----
+def server = new Server()
+server.name = "Obelix"
+server.cluster = aCluster
+----
+
+You can use named parameters with the default constructor (first the constructor is called, then the setters are called in turn):
+
+[source,groovy]
+----
+def server = new Server(name: "Obelix", cluster: aCluster)
+----
+
+== Using with() for repeated operations on the same bean
+
+Named-parameters with the default constructor is interesting when creating new instances,
+but what if you are updating an instance that was given to you, do you have to repeat the 'server' prefix again and again?
+No, thanks to the with() method that Groovy adds on all objects of any kind:
+
+[source,groovy]
+----
+server.name = application.name
+server.status = status
+server.sessionCount = 3
+server.start()
+server.stop()
+----
+
+vs:
+
+[source,groovy]
+----
+server.with {
+    name = application.name
+    status = status
+    sessionCount = 3
+    start()
+    stop()
+}
+----
+
+== Equals and `==`
+
+Java's `==` is actually Groovy's `is()` method, and Groovy's `==` is a clever `equals()`!
+
+To compare the references of objects, instead of `==`, you should use `a.is(b)`.
+
+But to do the usual `equals()` comparison, you should prefer Groovy's `==`,
+as it also takes care of avoiding `NullPointerException`, independently of whether the left or right is `null` or not.
+
+Instead of:
+
+[source,groovy]
+----
+status != null && status.equals(ControlConstants.STATUS_COMPLETED)
+----
+
+Do:
+
+[source,groovy]
+----
+status == ControlConstants.STATUS_COMPLETED
+----
+
+== GStrings (interpolation, multiline)
+
+We often use string and variable concatenation in Java, with many opening `/` closing of double quotes, plus signs,
+and `\n` characters for newlines.
+ With interpolated strings (called GStrings), such strings look better and are less painful to type:
+
+[source,groovy]
+----
+throw new Exception("Unable to convert resource: " + resource)
+----
+
+vs:
+
+[source,groovy]
+----
+throw new Exception("Unable to convert resource: ${resource}")
+----
+
+Inside the curly braces, you can put any kind of expression, not just variables.
+For simple variables, or `variable.property`, you can even drop the curly braces:
+
+[source,groovy]
+----
+throw new Exception("Unable to convert resource: $resource")
+----
+
+You can even lazily evaluate those expressions using a closure notation with `${-> resource }`.
+When the GString will be coerced to a String, it'll evaluate the closure and get the `toString()` representation of the return value.
+
+Example:
+
+[source,groovy]
+----
+int i = 3
+
+def s1 = "i's value is: ${i}"
+def s2 = "i's value is: ${-> i}"
+
+i++
+
+assert s1 == "i's value is: 3" // eagerly evaluated, takes the value on creation
+assert s2 == "i's value is: 4" // lazily evaluated, takes the new value into account
+----
+
+When strings and their concatenated expression are long in Java:
+
+[source,groovy]
+----
+throw new PluginException("Failed to execute command list-applications:" +
+    " The group with name " +
+    parameterMap.groupname[0] +
+    " is not compatible group of type " +
+    SERVER_TYPE_NAME)
+----
+
+You can use the `\` continuation character (this is not a multiline string):
+
+[source,groovy]
+----
+throw new PluginException("Failed to execute command list-applications: \
+The group with name ${parameterMap.groupname[0]} \
+is not compatible group of type ${SERVER_TYPE_NAME}")
+----
+
+Or using multiline strings with triple quotes:
+
+[source,groovy]
+----
+throw new PluginException("""Failed to execute command list-applications:
+    The group with name ${parameterMap.groupname[0]}
+    is not compatible group of type ${SERVER_TYPE_NAME)}""")
+----
+
+You can also strip the indentation appearing on the left side of the multiline strings by calling `.stripIndent()` on that string.
+
+Also note the difference between single quotes and double quotes in Groovy: single quotes always create Java Strings,
+without interpolation of variables, whereas double quotes either create Java Strings or GStrings when interpolated variables are present.
+
+For multiline strings, you can triple the quotes: ie. triple double quotes for GStrings and triple single quotes for mere Strings.
+
+If you need to write regular expression patterns, you should use the "slashy" string notation:
+
+[source,groovy]
+----
+assert "foooo/baaaaar" ==~ /fo+\/ba+r/
+----
+
+The advantage of the "slashy" notation is that you don't need to double escape backslashes, making working with regex a bit simpler.
+
+Last but not least, prefer using single quoted strings when you need string constants,
+and use double quoted strings when you are explicitly relying on string interpolation.
+
+== Native syntax for data structures
+
+Groovy provides native syntax constructs for data structures like lists, maps, regex, or ranges of values.
+Make sure to leverage them in your Groovy programs.
+
+Here are some examples of those native constructs:
+
+[source,groovy]
+----
+def list = [1, 4, 6, 9]
+
+// by default, keys are Strings, no need to quote them
+// you can wrap keys with () like [(variableStateAcronym): stateName] to insert a variable or object as a key.
+def map = [CA: 'California', MI: 'Michigan']
+
+def range = 10..20
+def pattern = ~/fo*/
+
+// equivalent to add()
+list << 5
+
+// call contains()
+assert 4 in list
+assert 5 in list
+assert 15 in range
+
+// subscript notation
+assert list[1] == 4
+
+// add a new key value pair
+map << [WA: 'Washington']
+// subscript notation
+assert map['CA'] == 'California'
+// property notation
+assert map.WA == 'Washington'
+
+// matches() strings against patterns
+assert 'foo' =~ pattern
+----
+
+== The Groovy Development Kit
+
+Continuing on the data structures, when you need to iterate over collections,
+Groovy provides various additional methods, decorating Java's core data structures,
+like `each{}`, `find{}`, `findAll{}`, `every{}`, `collect{}`, `inject{}`.
+These methods add a functional flavor to the programming language and help working with complex algorithms more easily.
+Lots of new methods are applied to various types, through decoration, thanks to the dynamic nature of the language.
+You can find lots of very useful methods on String, Files, Streams, Collections, and much more:
+
+http://beta.groovy-lang.org/gdk.html
+
+== The power of switch
+
+Groovy's `switch` is much more powerful than in C-ish languages which usually only accept primitives and assimilated.
+Groovy's `switch` accepts pretty much any kind of type.
+
+[source,groovy]
+----
+def x = 1.23
+def result = ""
+switch (x) {
+    case "foo": result = "found foo"
+    // lets fall through
+    case "bar": result += "bar"
+    case [4, 5, 6, 'inList']:
+        result = "list"
+        break
+    case 12..30:
+        result = "range"
+        break
+    case Integer:
+        result = "integer"
+        break
+    case Number:
+        result = "number"
+        break
+    case { it > 3 }
+        result = "number > 3"
+        break
+    default: result = "default"
+}
+assert result == "number"
+----
+
+And more generally, types with an `isCase()` method can also decide whether a value corresponds with a case
+
+== Import aliasing
+
+In Java, when using two classes of the same name but from different packages, like `java.util.List` and `java.awt.List`,
+you can import one class, but have to use a fully-qualified name for the other.
+
+Also sometimes, in your code, when using often a long class name, and the code becomes a bit more verbose.
+
+To improve such situations, Groovy features import aliasing:
+
+[source,groovy]
+----
+import java.util.List as juList
+import java.awt.List as aList
+
+import java.awt.WindowConstants as WC
+----
+
+You can also import methods statically:
+
+[source,groovy]
+----
+import static pkg.SomeClass.foo
+foo()
+----
+
+== Groovy Truth
+
+All objects can be 'coerced' to a boolean value: everything that's `null`, `void`, equal to zero,
+or empty evaluates to `false`, and if not, evaluates to `true`.
+
+So instead of writing:
+
+[source,groovy]
+----
+if (name != null && name.length > 0) {}
+----
+
+You can just do:
+
+[source,groovy]
+----
+if (name) {}
+----
+
+Same thing for collections, etc.
+
+Thus, you can use some shortcuts in things like `while()`, `if()`, the ternary operator, the Elvis operator (see below), etc.
+
+It's even possible to customize the Groovy Truth, by adding an boolean `asBoolean()` method to your classes!
+
+== Safe graph navigation
+
+Groovy supports a variant of the `.` operator to safely navigate an object graph.
+
+In Java, when you're interested in a node deep in the graph and need to check for `null`,
+you often end up writing complex `if`, or nested `if` statements like this:
+
+[source,groovy]
+----
+if (order != null) {
+    if (order.getCustomer() != null) {
+        if (order.getCustomer().getAddress() != null) {
+            System.out.println(order.getCustomer().getAddress());
+        }
+    }
+}
+----
+
+With `?.` safe dereference operator, you can simplify such code with:
+
+[source,groovy]
+----
+println order?.customer?.address
+----
+
+Nulls are checked throughout the call chain and no `NullPointerException` will be thrown if any element is `null`,
+and the resulting value will be null if something's `null`.
+
+== Assert
+
+To check your parameters, your return values, and more, you can use the `assert` statement.
+
+Contrary to Java's `assert`, `assert`s don't need to be activated to be working, so `assert`s are always checked.
+
+[source,groovy]
+----
+def check(String name) {
+    // name non-null and non-empty according to Groovy Truth
+    assert name
+    // safe navigation + Groovy Truth to check
+    assert name?.size() > 3
+}
+----
+
+You'll also notice the nice output that Groovy's "Power Assert" statement provides,
+with a graph view of the various values of each sub-expressions being asserted.
+
+== Elvis operator for default values
+
+The Elvis operator is a special ternary operator shortcut which is handy to use for default values.
+
+We often have to write code like:
+
+[source,groovy]
+----
+def result = name != null ? name : "Unknown"
+----
+
+Thanks to Groovy Truth, the `null` check can be simplified to just 'name'.
+
+And to go even further, since you return 'name' anyway, instead of repeating name twice in this ternary expression,
+we can somehow remove what's in between the question mark and colon, by using the Elvis operator, so that the above becomes:
+
+[source,groovy]
+----
+def result = name ?: "Unknown"
+----
+
+== Catch any exception
+
+If you don't really care of the exception which are thrown inside your `try` block,
+you can simply catch any of them and simply omit the type of the caught exception.
+So instead of catching the exceptions like in:
+
+[source,groovy]
+----
+try {
+    // ...
+} catch (Exception t) {
+    // something bad happens
+}
+----
+
+Then catch anything ('any' or 'all', or whatever makes you think it's anything):
+
+[source,groovy]
+----
+try {
+    // ...
+} catch (any) {
+    // something bad happens
+}
+----
+
+[NOTE]
+Note that it's catching all Exceptions, not `Throwable`s. If you need to really catch "everything",
+you'll have to be explicit and say you want to catch `Throwable`s.
+
+== Optional typing advice
+
+I'll finish on some words on when and how to use optional typing.
+Groovy lets you decide whether you use explicit strong typing, or when you use `def`.
+
+I've got a rather simple rule of thumb: whenever the code you're writing is going to be used by others as a public API,
+you should always favor the use of strong typing, it helps making the contract stronger,
+avoids possible passed arguments type mistakes, gives better documentation, and also helps the IDE with code completion.
+Whenever the code is for your use only, like private methods,
+or when the IDE can easily infer the type, then you're more free to decide when to type or not.
diff --git a/src/spec/doc/template-engines.adoc b/src/spec/doc/template-engines.adoc
deleted file mode 100644
index d432ab6..0000000
--- a/src/spec/doc/template-engines.adoc
+++ /dev/null
@@ -1,147 +0,0 @@
-= Template engines
-
-== Introduction
-
-Groovy supports multiple ways to generate text dynamically including ++GStrings++, ++printf++ if you are using Java 5, and <<_markupbuilder, MarkupBuilder>> just to name a few. In addition to these, there is a dedicated template framework which is well-suited to applications where the text to be generated follows the form of a static template.
-
-== Template framework
-
-The template framework in Groovy consists of a ++TemplateEngine++ abstract base class that engines must implement and a ++Template++ interface that the resulting templates they generate must implement.
-
-Included with Groovy are several template engines:
-
-- ++SimpleTemplateEngine++ - for basic templates
-- ++GStringTemplateEngine++ - stores the template as writable closures (useful for streaming scenarios)
-- ++XmlTemplateEngine++ - works well when the template and output are valid XML
-- ++MarkupTemplateEngine++ - a very complete, optimized, template engine
-
-== SimpleTemplateEngine
-
-Shown here is the ++SimpleTemplateEngine++ that allows you to use JSP-like scriptlets (see example below), script, and EL expressions in your template in order to generate parameterized text. Here is an example of using the system:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine1,indent=0]
-----
-
-While it is generally not deemed good practice to mix processing logic in your template (or view), sometimes very simple logic can be useful. E.g. in the example above, we could change this:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine2,indent=0]
-----
-
-to this (assuming we have set up a static import for capitalize **inside** the template):
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine3,indent=0]
-----
-
-or this:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine4,indent=0]
-----
-
-to this:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine5,indent=0]
-----
-
-=== Advanced Usage Note
-
-If you happen to be embedding your template directly in your script (as we did above) you have to be careful about backslash escaping. Because the template string itself will be parsed by Groovy before it is passed to the the templating framework, you have to escape any backslashes inside GString expressions or scriptlet 'code' that are entered as part of a Groovy program. E.g. if we wanted quotes around __The Big Apple__ above, we would use:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine6,indent=0]
-----
-
-Similarly, if we wanted a newline, we would use:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine7,indent=0]
-----
-
-in any GString expression or scriptlet $$'code'$$ that appears inside a Groovy script. A normal "++\n++" is fine within the static template text itself or if the entire template itself is in an external template file. Similarly, to represent an actual backslash in your text you would need
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
-----
-
-in an external file or
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
-----
-
-in any GString expression or scriptlet $$'code'$$. (Note: the necessity to have this extra slash may go away in a future version of Groovy if we can find an easy way to support such a change.)
-
-== GStringTemplateEngine
-
-As an example of using the ++GStringTemplateEngine++, here is the example above done again (with a few changes to show some other options). First we will store the template in a file this time:
-
-[source,groovy]
-.test.template
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine1,indent=0]
-----
-
-Note that we used ++out++ instead of ++print++ to support the streaming nature of ++GStringTemplateEngine++. Because we have the template in a separate file, there is no need to escape the backslashes. Here is how we call it:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine2,indent=0]
-----
-
-and here is the output:
-
-----
-Dear "Sam Pullara",
-So nice to meet you in "The Big Apple".
-See you in December,
-Groovy-Dev
-----
-
-== XmlTemplateEngine
-
-++XmlTemplateEngine++ for use in templating scenarios where both the template source and the expected output are intended to be XML. Templates may use the normal ++${expression}++ and ++$variable++ notations to insert an arbitrary expression into the template. In addition, support is also provided for special tags: ++<gsp:scriptlet>++ (for inserting code fragments) and ++<gsp:expression>++ (for code fragments which produce output).
-
-Comments and processing instructions will be removed as part of processing and special XML characters such as ++<++, ++>++, ++"++ and ++'++ will be escaped using the respective XML notation. The output will also be indented using standard XML pretty printing.
-
-The xmlns namespace definition for gsp: tags will be removed but other namespace definitions will be preserved (but may change to an equivalent position within the XML tree).
-
-Normally, the template source will be in a file but here is a simple example providing the XML template as a string:
-
-[source,groovy]
-----
-include::{projectdir}/src/spec/test/TemplateEnginesTest.groovy[tags=xml_template_engine,indent=0]
-----
-
-This example will produce this output:
-
-[source,xml]
-----
-<document type='letter'>
-  Dearest
-  <foo:to xmlns:foo='baz'>
-    Jochen "blackdrag" Theodorou
-  </foo:to>
-  How are you today?
-</document>
-----
-
-:leveloffset: 3
-include::{rootDir}/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc[]
-:leveloffset: 2
-
-== Other solutions
-
-Also, there are other templating solutions that can be used along with Groovy, such as http://freemarker.org[FreeMarker], http://velocity.apache.org[Velocity], http://stringtemplate.org[StringTemplate] and others.
\ No newline at end of file
diff --git a/src/spec/doc/tools-groovyc.adoc b/src/spec/doc/tools-groovyc.adoc
index 972ad7d..888cae1 100644
--- a/src/spec/doc/tools-groovyc.adoc
+++ b/src/spec/doc/tools-groovyc.adoc
@@ -1,6 +1,6 @@
 = Compiling Groovy
 
-
+[[section-groovyc-compiler]]
 == groovyc, the Groovy compiler
 
 `groovyc` is the Groovy compiler command line tool. It allows you to compile Groovy sources into bytecode. It plays
@@ -200,12 +200,28 @@ the enclosing `groovyc` task.
 
 More details about joint compilation can be found in the <<section-jointcompilation,joint compilation>> section.
 
+[[Gant]]
+== Gant
+https://github.com/Gant/Gant[Gant] is a tool for scripting Ant tasks using Groovy
+instead of XML to specify the logic. As such, it has exactly the same features
+as the Groovyc Ant task.
+
+[[Gradle]]
+== Gradle
+http://www.gradle.org/[Gradle] is a build tool that allows you to leverage the
+flexibility of http://ant.apache.org/[Ant], while keeping the simplicity of
+convention over configuration that tools like http://maven.apache.org/[Maven]
+offer. Builds are specified using a Groovy DSL, which offers great flexibility
+and succinctness.
+
 == Maven integration
 There are several approaches to compiling Groovy code in your Maven
-projects. <<section-gmaven,GMaven>> is the
-most flexible and feature rich, but it has some difficulties with joint
-Java-Groovy projects and it is no longer under active development. The
-<<section-groovyeclipse,Groovy-Eclipse compiler plugin for Maven>> sidesteps the joint compilation issues. Read
+projects. <<section-gmavenplus,GMavenPlus>> is the
+most flexible and feature rich, but like most Groovy compiler tools, it can
+have difficulties with joint Java-Groovy projects (for the same reason
+<<section-gmaven,GMaven>> and <<Gradle>> can have issues).
+The <<section-groovyeclipse,Groovy-Eclipse compiler plugin for Maven>>
+sidesteps the joint compilation issues. Read
 <<Groovy-EclipsecompilerpluginforMaven-WhyanotherGroovycompilerforMavenWhataboutGMaven, this>>
 for a deeper discussion of the benefits and disadvantages of the two
 approaches.
@@ -309,78 +325,42 @@ execute the jar phase bundling up all of your compiled production
 classes into a jar after all of the unit tests pass. For more detail on
 Maven build phases consult the Maven2 documentation.
 
-== GMaven and GMavenPlus
+=== GMaven and GMavenPlus
 [[section-gmaven]]
-=== GMaven
-GMaven is a separate project and documentation for http://docs.codehaus.org/display/GMAVEN[GMaven] can
-be found http://docs.codehaus.org/display/GMAVEN[here].
-
-*Example:*
-
-[source,xml]
-----
-<dependencies>
-    <dependency>
-        <groupId>org.codehaus.gmaven.runtime</groupId>
-        <artifactId>gmaven-runtime-default</artifactId>
-    </dependency>
-</dependencies>
-
-<build>
-    <plugins>
-        <plugin>
-            <groupId>org.codehaus.gmaven</groupId>
-            <artifactId>gmaven-plugin</artifactId>
-            <executions>
-                <execution>
-                    <goals>
-                        <goal>generateStubs</goal>
-                        <goal>compile</goal>
-                        <goal>generateTestStubs</goal>
-                        <goal>testCompile</goal>
-                    </goals>
-                </execution>
-            </executions>
-        </plugin>
-    </plugins>
-</build>
-----
+==== GMaven
+https://github.com/groovy/gmaven[GMaven] is the original Maven plugin
+for Groovy, supporting both compiling and scripting Groovy.
 
 *Important:*
 
-You should be aware that GMaven is *not supported anymore* and has problems with <<section-jointcompilation,joint compilation>>.
-Should you need joint compilation, we advise that you use the <<section-groovyeclipse,Groovy Eclipse maven plugin>>.
+You should be aware that GMaven is *not supported anymore* and can have
+difficulties with <<section-jointcompilation,joint compilation>>.
+<<section-gmavenplus,GMavenPlus>> can be a good replacement, but if you
+are having problems with joint compilation, you might consider the
+<<section-groovyeclipse,Groovy Eclipse maven plugin>>.
 
 [[section-gmavenplus]]
-=== GMavenPlus
+==== GMavenPlus
 
-https://github.com/groovy/GMavenPlus[GMavenPlus] is a rewrite of <<section-gmaven,GMaven>> which is in active development. It does not support all the features
-of <<section-gmaven,GMaven>> but supports newer versions of Groovy, invokedynamic, as well as joint compilation, through stubs (which
-means it has the same potential issues as <<section-gmaven,GMaven>>). The main advantage over its predecessor is that
-it compiles with recent versions of the compiler and supports choosing what version of Groovy is used.
+https://github.com/groovy/GMavenPlus[GMavenPlus] is a rewrite of
+<<section-gmaven,GMaven>> and is in active development. It supports most of the
+features of GMaven (a couple notable exceptions being
+http://maven.apache.org/plugin-tools/maven-plugin-tools-java/index.html[mojo Javadoc tags]
+and support for older Groovy versions). Its joint compilation uses stubs (which
+means it has the same potential issues as GMaven and <<Gradle>>). The main
+advantages over its predecessor are that it supports recent Groovy versions,
+InvokeDynamic, Groovy on Android, and GroovyDoc.
 
 [[section-gmaven2]]
-=== GMaven2
-
-See http://groovy.github.io/gmaven/[GMaven 2]
-
-Unlike the name seems to indicate, http://groovy.github.io/gmaven/[GMaven 2] is not aimed at replacing
-<<section-gmaven,GMaven>>. In fact, it's a rewrite of the scripting features of the GMaven plugin. Interestingly,
-it supports the missing features of <<section-gmavenplus,GMavenPlus>>, that is to say:
+==== GMaven 2
 
-* Script execution
-* Command-line shell access
-* GUI console access
-
-So it may be used as a complement to <<section-groovyeclipse,the Groovy Eclipse plugin>> or <<section-gmavenplus,GMavenPlus>>.
+Unlike the name might seem to suggest, http://groovy.github.io/gmaven/[GMaven 2]
+is not aimed at replacing <<section-gmaven,GMaven>>. In fact, it removes the
+non-scripting features of the GMaven plugin. It has not yet had any release and
+appears to be inactive currently.
 
 [[section-groovyeclipse]]
-
-:leveloffset: 3
-
-include::{projectdir}/{specfolder}/tools-groovyeclipse.adoc[]
-
-:leveloffset: 1
+include::{projectdir}/{specfolder}/tools-groovyeclipse.adoc[leveloffset=+2]
 
 [[section-jointcompilation]]
 === Joint compilation
@@ -399,3 +379,58 @@ It is important to know that if you don't enable joint compilation and try to co
 Java source files with the Groovy compiler, the Java source files will be compiled as
 if they were Groovy sources. In some situations, this might work since most of the Java
 syntax is compatible with Groovy, but semantics would be different.
+
+[[section-android]]
+== Android support
+
+It is possible to write an Android application in Groovy. However this requires a special
+version of the compiler, meaning that you cannot use the regular
+<<section-groovyc-compiler,groovyc tool>> to target Android bytecode. In particular, Groovy
+provides specific JAR files for Android, which have a classifier of `grooid`. In order to make
+things easier, a https://github.com/groovy/groovy-android-gradle-plugin[Gradle plugin] adds
+support for the Groovy language in the Android Gradle toolchain.
+
+The plugin can be applied like this:
+
+```groovy
+
+buildscript {
+    repositories {
+        jcenter()
+    }
+    dependencies {
+        // ...
+        classpath 'org.codehaus.groovy:gradle-groovy-android-plugin:0.3.5'
+    }
+}
+
+apply plugin: 'groovyx.grooid.groovy-android'
+```
+
+Then you will need to add a dependency on the `grooid` version of the Groovy compiler:
+
+```groovy
+dependencies {
+    compile 'org.codehaus.groovy:groovy:2.4.0:grooid'
+}
+```
+
+Note that if a Groovy jar does not provide a `grooid` classifier alternative, then it means
+that the jar is directly compatible with Android. In that case, you can add the dependency directly
+like this:
+
+```groovy
+dependencies {
+    compile 'org.codehaus.groovy:groovy:2.4.0:grooid'       // requires the grooid classifier
+    compile ('org.codehaus.groovy:groovy-json:2.4.0') {     // no grooid version available
+        transitive = false                                  // so do not depend on non-grooid version
+    }
+}
+```
+
+Note that the `transitive=false` parameter for `groovy-json` will let Gradle download the JSON support jar
+without adding a dependency onto the normal jar of Groovy.
+
+Please make sure to go to the https://github.com/groovy/groovy-android-gradle-plugin[plugin homepage] in order to
+find the latest documentation and version.
+
diff --git a/src/spec/doc/tools-groovyconsole.adoc b/src/spec/doc/tools-groovyconsole.adoc
deleted file mode 100644
index f7510b0..0000000
--- a/src/spec/doc/tools-groovyconsole.adoc
+++ /dev/null
@@ -1,188 +0,0 @@
-= groovyConsole, the Groovy swing console
-
-[[title-heading]]
-== Groovy : Groovy Console
-
-The Groovy Swing Console allows a user to enter and run Groovy scripts.
-This page documents the features of this user interface.
-
-[[GroovyConsole-Basics]]
-== Basics
-
-image:assets/img/GroovyConsole.gif[image]
-
-. Groovy Console is launched via `groovyConsole` or
-`groovyConsole.bat`, both located in `$GROOVY_HOME/bin`
-. The Console has an input area and an output area.
-. You type a Groovy script in the input area.
-. When you select `Run` from the `Actions` menu, the console
-compiles the script and runs it.
-. Anything that would normally be printed on `System.out` is printed in
-the output area.
-. If the script returns a non-null result, that result is printed.
-
-[[GroovyConsole-Features]]
-== Features
-
-[[GroovyConsole-RunningScripts]]
-=== Running Scripts
-
-There are several shortcuts that you can use to run scripts or code snippets:
-
-* `Ctrl+Enter` and `Ctrl+R` are both shortcut keys for `Run Script`.
-* If you highight just part of the text in the input area, then Groovy
-runs just that text.
-* The result of a script is the the value of the last expression
-executed.
-* You can turn the System.out capture on and off by selecting `Capture
-System.out` from the `Actions` menu
-
-[[GroovyConsole-EditingFiles]]
-=== Editing Files
-
-You can open any text file, edit it, run it (as a Groovy Script) and
-then save it again when you are finished.
-
-* Select `File > Open` (shortcut key `ctrl+O`) to open a file
-* Select `File > Save` (shortcut key `ctrl+S`) to save a file
-* Select `File > New File` (shortcut key `ctrl+Q`) to start again with a
-blank input area
-
-[[GroovyConsole-Historyandresults]]
-=== History and results
-
-* You can pop-up a gui inspector on the last (non-null) result by
-selecting `Inspect Last` from the `Actions` menu. The inspector is a
-convenient way to view lists and maps.
-* The console remembers the last ten script runs. You can scroll back
-and forth through the history by selecting `Next` and `Previous`
-from the `Edit` menu. `Ctrl-N` and `ctrl-P` are convenient shortcut keys.
-* The last (non-null) result is bound to a variable named `_` (an
-underscore).
-* The last result (null and non-null) for every run in the history is
-bound into a list variable named `__` (two underscores). The result of
-the last run is `__[-1]`, the result of the second to last run is
-`__[-2]` and so forth.
-
-[[GroovyConsole-Interrupt]]
-=== Interrupting a script
-
-The Groovy console is a very handy tool to develop scripts. Often, you will
-find yourself running a script multiple times until it works the way you want
-it to. However, what if your code takes too long to finish or worse, creates
-an infinite loop? Interrupting script execution can be acheived by clicking
-the `interrupt` button on the small dialog box that pops up when a script
-is executing or through the `interrupt` icon in the tool bar.
-
-image:assets/img/gconsole-toolbar.png[Toolbar]
-
-However, this may not be sufficient to interrupt a script: clicking the button
-will interrupt the execution thread, but if your code doesn't handle the interrupt
-flag, the script is likely to keep running without you being able to effectively
-stop it. To avoid that, you have to make sure that the `Script > Allow interruption`
-menu item is flagged. This will automatically apply an AST transformation to your
-script which will take care of checking the interrupt flag (`@ThreadInterrupt`).
-This way, you guarantee that the script can be interrupted even if you don't explicitly
-handle interruption, at the cost of extra execution time.
-
-[[GroovyConsole-Andmore]]
-=== And more
-
-* You can change the font size by selecting `Smaller Font` or `Larger
-Font` from the `Actions menu`
-* The console can be run as an Applet thanks to `groovy.ui.ConsoleApplet`
-* Code is auto indented when you hit return
-* You can drag’n drop a Groovy script over the text area to open a file
-* You can modify the classpath with which the script in the console is
-being run by adding a new JAR or a directory to the classpath from the
-`Script` menu
-* Error hyperlinking from the output area when a compilation error is
-expected or when an exception is thrown
-
-[[GroovyConsole-EmbeddingtheConsole]]
-== Embedding the Console
-
-To embed a Swing console in your application, simply create the Console
-object, +
- load some variables, and then launch it. The console can be embedded in
-either Java or Groovy code. +
- The Java code for this is:
-
-[source,java]
---------------------------------------------------
-import groovy.ui.Console;
-
-    ...
-
-    Console console = new Console();
-    console.setVariable("var1", getValueOfVar1());
-    console.setVariable("var2", getValueOfVar2());
-    console.run();
-
-    ...
---------------------------------------------------
-
-Once the console is launched, you can use the variable values in Groovy
-code.
-
-An example of how to embed either the GroovyConsole or GroovyShell in a
-Spring Web application can be found at
-http://groovy.codehaus.org/Embedding+a+Groovy+Console+in+a+Java+Server+Application[Embedding
-a Groovy Console in a Java Server Application]
-
-[[GroovyConsole-Visualizingscriptoutputresults]]
-== Visualizing script output results
-
-You can customize the way script output results are visualized. Let’s
-see how we can customize this. For example, viewing a map result would
-show something like this:
-
-image:assets/img/gconsole-sc-without-visu.png[image]
-
-What you see here is the usual textual representation of a Map. But,
-what if we enabled custom visualization of certain results? The Swing
-console allows you to do just that. First of all, you have to ensure
-that the visualization option is ticked: `View -> Visualize Script
-Results` — for the record, all settings of the Groovy Console are stored
-and remembered thanks to the Preference API. There are a few result
-visualizations built-in: if the script returns a `java.awt.Image`, a
-`javax.swing.Icon`, or a `java.awt.Component` with no parent, the object is
-displayed instead of its `toString()` representation. Otherwise,
-everything else is still just represented as text. Now, create the
-following Groovy script in `~/.groovy/OutputTransforms.groovy`:
-
-[source,groovy]
----------------------------------------------------------
-import javax.swing.*
-
-transforms << { result ->
-    if (result instanceof Map) {
-        def table = new JTable(
-            result.collect{ k, v ->
-                [k, v?.inspect()] as Object[]
-            } as Object[][],
-            ['Key', 'Value'] as Object[])
-        table.preferredViewportSize = table.preferredSize
-        return new JScrollPane(table)
-    }
-}
----------------------------------------------------------
-
-The Groovy Swing console will execute that script on startup, injecting
-a transforms list in the binding of the script, so that you can add your
-own script results representations. In our case, we transform the Map
-into a nice-looking Swing JTable. And we’re now able to visualize maps
-in a friendly and attractive fashion, as the screenshot below shows:
-
-image:assets/img/gconsole-sc-with-visu.png[image]
-
-[[GroovyConsole-ASTbrowser]]
-== AST browser
-
-Groovy Console can visualize the AST (Abstract Syntax Tree) representing
-the currently edited script, as shown by the screenshot below. This is
-particularly handy when you want to develop AST transformations.
-
-image:assets/img/astbrowser.png[AST Browser]
-
-:leveloffset: 2
diff --git a/src/spec/doc/tools-groovydoc.adoc b/src/spec/doc/tools-groovydoc.adoc
deleted file mode 100644
index bd8e1d5..0000000
--- a/src/spec/doc/tools-groovydoc.adoc
+++ /dev/null
@@ -1,214 +0,0 @@
-= groovydoc, the Groovy & Java documentation generator
-
-GroovyDoc is a tool responsible for generating documentation from your code. It acts like the Javadoc tool in the
-Java world but is capable of handling both `groovy` and `java` files. The distribution comes with two ways of generating
-documentation: from <<Groovydoc-CommandLine,command line>> or from <<Groovydoc-Ant,Apache Ant>>. Other build tools
-like Maven or Gradle also offer wrappers for Groovydoc.
-
-[[Groovydoc-CommandLine]]
-== The groovydoc command line tool
-
-The `groovydoc` command line can be invoked to generate groovydocs:
-
-----
-groovydoc [options] [packagenames] [sourcefiles]
-----
-
-where options must be picked from the following table:
-
-[cols="2,2,5",options="header,footer"]
-|=======================================================================
-|Short version |Long version |Description
-|-author | |Include @author paragraphs (currently not used)
-|-charset <charset>| |Charset for cross-platform viewing of generated documentation
-|-classpath, -cp | --classpath |Specify where to find the class files - must be
-first argument
-|-d |--destdir <dir> |Destination directory for output files
-| |--debug|Enable debug output
-|-doctitle <html> | |Include title for the overview page
-|-exclude <pkglist>| | Specify a list of packages to exclude
-(separated by colons for all operating systems)
-|-fileEncoding <charset>| |Charset for generated documentation files
-|-footer <html> | |Include footer text for each page
-|-header <html> | |Include header text for each page
-|-help|--help|Display help message
-|-nomainforscripts| |Don't include the implicit 'public static void
-main' method for scripts
-|-noscripts| |Don't process Groovy Scripts
-|-overview <file>| |Read overview documentation from HTML file
-|-package| |Show package/protected/public classes and members
-|-private| |Show all classes and members
-|-protected| |Show protected/public classes and members (default)
-|-public| |Show only public classes and members
-|-quiet| |Suppress superfluous output
-|-sourcepath <pathlist>| |Specify where to find source files (dirs
-separated by platform path separator)
-|-stylesheetfile <path>| |File to change style of the generated documentation
-|-verbose| |Enable verbose output
-| |--version|Display the version
-|-windowtitle <text>| |Browser window title for the documentation
-|=======================================================================
-
-[[Groovydoc-Ant]]
-== The groovydoc Ant task
-
-The `groovydoc` Ant task allows generating groovydocs from an Ant build.
-
-[[ThegroovydocAnttask-Requiredtaskdef]]
-=== Required taskdef
-
-Assuming +groovy-all-{groovyversion}.jar+ is in _my.classpath_ you will need to
-declare this task at some point in the build.xml prior to the groovydoc
-task being invoked.
-
-[source,xml]
------------------------------------------------------------
-<taskdef name         = "groovydoc"
-         classname    = "org.codehaus.groovy.ant.Groovydoc"
-         classpathref = "my.classpath"/>
------------------------------------------------------------
-
-[[ThegroovydocAnttask-groovydocAttributes]]
-=== <groovydoc> Attributes
-
-[cols="1,2,1",options="header,footer"]
-|=======================================================================
-|Attribute |Description |Required
-|destdir |Location to store the class files. |Yes
-|sourcepath |The sourcepath to use. |No
-|packagenames |Comma separated list of package files (with terminating
-wildcard). |No
-|use |Create class and package usage pages. |No
-|windowtitle |Browser window title for the documentation (text). |No
-|doctitle |Include title for the package index(first) page (html-code).
-|No
-|header |Include header text for each page (html-code). |No
-|footer |Include footer text for each page (html-code). |No
-|overview |Read overview documentation from HTML file. |No
-|private |Show all classes and members (i.e. including private ones) if
-set to ``true''. |No
-|=======================================================================
-
-[[ThegroovydocAnttask-groovydocNestedElements]]
-=== <groovydoc> Nested Elements
-
-[[ThegroovydocAnttask-link]]
-==== link
-
-Create link to groovydoc/javadoc output at the given URL.
-
-[cols="<,<,<",options="header,footer"]
-|=======================================================
-|Attribute |Description |Required
-|packages |Comma separated list of package prefixes |Yes
-|href |Base URL of external site |Yes
-|=======================================================
-
-[[ThegroovydocAnttask-Example1-groovydocAnttask]]
-==== Example #1 - <groovydoc> Ant task
-
-[source,xml]
-----------------------------------------------------------------------------------------------------------------
-<taskdef name           = "groovydoc"
-         classname      = "org.codehaus.groovy.ant.Groovydoc"
-         classpathref   = "path_to_groovy_all"/>
-
-<groovydoc destdir      = "${docsDirectory}/gapi"
-           sourcepath   = "${mainSourceDirectory}"
-           packagenames = "**.*"
-           use          = "true"
-           windowtitle  = "${title}"
-           doctitle     = "${title}"
-           header       = "${title}"
-           footer       = "${docFooter}"
-           overview     = "src/main/overview.html"
-           private      = "false">
-        <link packages="java.,org.xml.,javax.,org.xml." href="http://download.oracle.com/javase/6/docs/api"/>
-        <link packages="org.apache.tools.ant."          href="http://evgeny-goldin.org/javadoc/ant/api"/>
-        <link packages="org.junit.,junit.framework."    href="http://kentbeck.github.com/junit/javadoc/latest"/>
-        <link packages="groovy.,org.codehaus.groovy."   href="http://groovy.codehaus.org/api/"/>
-        <link packages="org.codehaus.gmaven."           href="http://evgeny-goldin.org/javadoc/gmaven"/>
-</groovydoc>
-----------------------------------------------------------------------------------------------------------------
-
-[[ThegroovydocAnttask-Example2-ExecutinggroovydocfromGroovy]]
-==== Example #2 - Executing <groovydoc> from Groovy
-
-[source,groovy]
---------------------------------------------------------------------------------------------------------------
-def ant = new AntBuilder()
-ant.taskdef(name: "groovydoc", classname: "org.codehaus.groovy.ant.Groovydoc")
-ant.groovydoc(
-    destdir      : "${docsDirectory}/gapi",
-    sourcepath   : "${mainSourceDirectory}",
-    packagenames : "**.*",
-    use          : "true",
-    windowtitle  : "${title}",
-    doctitle     : "${title}",
-    header       : "${title}",
-    footer       : "${docFooter}",
-    overview     : "src/main/overview.html",
-    private      : "false") {
-        link(packages:"java.,org.xml.,javax.,org.xml.",href:"http://download.oracle.com/javase/6/docs/api")
-        link(packages:"groovy.,org.codehaus.groovy.",  href:"http://groovy.codehaus.org/api")
-        link(packages:"org.apache.tools.ant.",         href:"http://evgeny-goldin.org/javadoc/ant/api")
-        link(packages:"org.junit.,junit.framework.",   href:"http://kentbeck.github.com/junit/javadoc/latest")
-        link(packages:"org.codehaus.gmaven.",          href:"http://evgeny-goldin.org/javadoc/gmaven")
-}
---------------------------------------------------------------------------------------------------------------
-
-=== Custom templates
-
-The `groovydoc` Ant task supports custom templates, but it requires two steps:
-
-. A custom groovydoc class
-. A new groovydoc task definition
-
-==== Custom Groovydoc class
-
-The first step requires you to extend the `Groovydoc` class, like in the following example:
-
-[source,java]
-----
-package org.codehaus.groovy.tools.groovydoc;
-
-import org.codehaus.groovy.ant.Groovydoc;
-
-/**
- * Overrides GroovyDoc's default class template - for testing purpose only.
- *
- * @author Andre Steingress
- */
-public class CustomGroovyDoc extends Groovydoc {
-
-    @Override
-    protected String[] getClassTemplates() {
-        return new String[]{"org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html"};
-    }
-}
-----
-
-You can override the following methods:
-
-* `getClassTemplates` for class-level templates
-* `getPackageTemplates` for package-level templates
-* `getDocTemplates` for top-level templates
-
-You can find the list of default templates in the `org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo`
-class.
-
-==== Using the custom groovydoc task
-
-Once you've written the class, using it is just a matter of redefining the `groovydoc` task:
-
-[source,xml]
-----
-<taskdef name           = "groovydoc"
-         classname      = "org.codehaus.groovy.ant.CustomGroovyDoc"
-         classpathref   = "path_to_groovy_all"/>
-----
-
-Please note that template customization is provided as is. APIs are subject to change, so you must consider this as a
-fragile feature.
-
-:leveloffset: 2
\ No newline at end of file
diff --git a/src/spec/doc/tools-groovyeclipse.adoc b/src/spec/doc/tools-groovyeclipse.adoc
index 9dcf7ce..7d1e703 100644
--- a/src/spec/doc/tools-groovyeclipse.adoc
+++ b/src/spec/doc/tools-groovyeclipse.adoc
@@ -1,20 +1,17 @@
 = The Groovy Eclipse Maven plugin
 
-
 Groovy-Eclipse provides a compiler plugin for Maven. Using the compiler
 plugin, it is possible to compile your maven projects using the
 Groovy-Eclipse compiler.
 
 The most recent version of the Groovy-Eclipse-Compiler plugin for maven
-is 2.8.0-01.2.9.0-01-SNAPSHOT is now available from
-http://nexus.codehaus.org/snapshots/ .The most recent version of the
-groovy-eclipse-batch artifact is 2.1.5-03 (for Groovy 2.1) and 2.0.7-03
-(for Groovy 2.0). They are both available from maven central. 
+is 2.9.1-01. The most recent version of the groovy-eclipse-batch artifact is 2.3.7-01.
+They are both available from maven central.
 
 [[Groovy-EclipsecompilerpluginforMaven-Howtousethecompilerplugin---SettingupthePOM]]
 == How to use the compiler plugin—Setting up the POM
 
-In your plugin section, you must change the compiler used by the
+In the plugin section, change the compiler used by the
 http://maven.apache.org/plugins/maven-compiler-plugin/[maven-compiler-plugin].
 Like the http://ant.apache.org/manual/Tasks/javac.html[javac ant task],
 the maven-compiler-plugin does not actually compile, but rather
@@ -24,36 +21,31 @@ delegates the compilation to a different artifact (in our case, the
 [source,xml]
 --------------------------------------------------------------------------------------------------
 <build>
-...
-<plugins>
-  <plugin>
-    <artifactId>maven-compiler-plugin</artifactId>
-    <!-- 2.8.0-01 and later require maven-compiler-plugin 3.0 or higher -->
-    <version>3.0</version>
-    <configuration>
-      <compilerId>groovy-eclipse-compiler</compilerId>
-      <!-- set verbose to be true if you want lots of uninteresting messages -->
-      <!-- <verbose>true</verbose> -->
-    </configuration>
-    <dependencies>
-      <dependency>
-        <groupId>org.codehaus.groovy</groupId>
-        <artifactId>groovy-eclipse-compiler</artifactId>
-        <version>2.8.0-01</version>
-      </dependency>
-      <!-- for 2.8.0-01 and later you must have an explicit dependency on groovy-eclipse-batch -->
-      <dependency>
-        <groupId>org.codehaus.groovy</groupId>
-        <artifactId>groovy-eclipse-batch</artifactId>
-        <version>2.1.5-03</version>
-        <!-- or choose a different compiler version -->
-        <!-- <version>1.8.6-01</version> -->
-        <!-- <version>1.7.10-06</version> -->
-</dependency>
- </dependencies>
-  </plugin>
-  ...
-</plugins>
+    ...
+    <plugins>
+      <plugin>
+        <artifactId>maven-compiler-plugin</artifactId>
+        <!-- 2.8.0-01 and later require maven-compiler-plugin 3.1 or higher -->
+        <version>3.1</version>
+        <configuration>
+          <compilerId>groovy-eclipse-compiler</compilerId>
+        </configuration>
+        <dependencies>
+          <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-eclipse-compiler</artifactId>
+            <version>2.9.1-01</version>
+          </dependency>
+          <!-- for 2.8.0-01 and later you must have an explicit dependency on groovy-eclipse-batch -->
+          <dependency>
+            <groupId>org.codehaus.groovy</groupId>
+            <artifactId>groovy-eclipse-batch</artifactId>
+            <version>2.3.7-01</version>
+          </dependency>
+        </dependencies>
+      </plugin>
+    </plugins>
+    ...
 </build>
 --------------------------------------------------------------------------------------------------
 
@@ -62,8 +54,8 @@ recognizes all settings supported by the
 http://maven.apache.org/plugins/maven-compiler-plugin/[maven-compiler-plugin].
 
 Remember that you still need to specify a groovy artifact as a build
-dependency in addition to the `maven-compiler-plugin` dependency.  The
-groovy dependency version should match the compiler version.  Something
+dependency in addition to the `maven-compiler-plugin` dependency. The
+groovy dependency version should match the compiler version. Something
 like this:
 
 [source,xml]
@@ -73,7 +65,7 @@ like this:
   <dependency>
     <groupId>org.codehaus.groovy</groupId>
     <artifactId>groovy-all</artifactId>
-    <version>1.8.6</version>
+    <version>2.3.7</version>
   </dependency>
   ...
 </dependencies>
@@ -131,7 +123,7 @@ referencing the groovy-eclipse-compiler mojo. Just add this to the
   <plugin>
     <groupId>org.codehaus.groovy</groupId>
     <artifactId>groovy-eclipse-compiler</artifactId>
-    <version>2.8.0-01</version>
+    <version>2.9.1-01</version>
     <extensions>true</extensions>
   </plugin>
   ...
@@ -197,53 +189,10 @@ The benefit of using this approach is that you do not need to make any
 changes to the default lifecycle. The downside is, of course, that you
 need 31 lines of configuration to do this!
 
-[[Groovy-EclipsecompilerpluginforMaven-Sampleprojectandsourcecode]]
-== Sample project and source code
-
-There is an archetype available for this project. You can use it through
-a command like this:
-
-[source,xml]
-------------------------------------------------------------------------------------
-mvn archetype:generate \
-    -DarchetypeGroupId=org.codehaus.groovy \
-    -DarchetypeArtifactId=groovy-eclipse-quickstart \
-    -DarchetypeVersion=2.5.2-01 \
-    -DgroupId=foo \
-    -DartifactId=bar \
-    -Dversion=1 \
-    -DinteractiveMode=false \
-    -DarchetypeRepository=https://nexus.codehaus.org/content/repositories/snapshots/
-------------------------------------------------------------------------------------
-
-_(This archetype is not actively maintained.)_
-
-A
-https://svn.codehaus.org/groovy/eclipse/trunk/extras/groovy-eclipse-maven-tests[sample
-project] using the compiler plugin as well as the source code for the
-plugin itself are available from the
-https://github.com/groovy/groovy-eclipse/[github repository]:
-
-The full URL to the maven projects
-is:https://github.com/groovy/groovy-eclipse/tree/master/extrasThere are
-several projects in the repository:groovy-eclipse-compiler : the
-compiler plugin itself (an m2eclipse
-project).groovy-eclipse-batch-builder : a set of ant scripts and
-configuration files used to build the groovy-eclipse-batch artifact.
-This artifact is an amalgamation of all jars required for compiling
-Groovy and Java code in Eclipse, including ecj (the Eclipse compiler for
-Java), the non-UI components of Groovy-Eclipse, the Groovy jars, and
-various required Eclipse bundles.groovy-eclipse-maven-tests : a sample
-project that uses the compiler plugin (an m2eclipse
-project).org.codehaus.groovy.m2eclipse : an Eclipse plugin that provides
-integration between Groovy-Eclipse and m2eclipse (the Maven tooling for
-Eclipse).Feature org.codehaus.groovy.m2eclipse : an Eclipse feature that
-is required for building and releasing the org.codehaus.groovy.m2eclipse
-plugin.
-
-The sample project and archetype is not maintained as well as we would
-like. Some community help with this would be greatly appreciated. Please
-see http://jira.codehaus.org/browse/GRECLIPSE-1285[GRECLIPSE-1285].
+[[Groovy-EclipsecompilerpluginforMaven-Sourcecode]]
+== Source code
+The source code for the plugin itself is available from the
+https://github.com/groovy/groovy-eclipse/[github repository].
 
 [[Groovy-EclipsecompilerpluginforMaven-WhyanotherGroovycompilerforMavenWhataboutGMaven]]
 == Why another Groovy compiler for Maven? What about GMaven?
@@ -282,7 +231,7 @@ appropriate for your project will depend on your requirements.
 
 http://projectlombok.org/[Project Lombok] is compatible with the
 groovy-eclipse-compiler.  There is some extra configuration that you
-need to do.  The lombok jar needs to be added to _both the build and
+need to do. The lombok jar needs to be added to _both the build and
 compile dependencies sections_:
 
 [source,xml]
@@ -290,7 +239,7 @@ compile dependencies sections_:
 <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
-  <version>0.10.4</version>
+  <version>1.14.8</version>
 </dependency>
 --------------------------------------
 
@@ -324,38 +273,33 @@ done so already). Select the _Groovy-Eclipse M2E integration_.
 [[Groovy-EclipsecompilerpluginforMaven-ReleaseBuilds]]
 == Release Builds
 
-[cols="<,<",]
+[cols="25,75" options="header"]
 |=================================================================
 |Eclipse level |Release update site
-|4.2 (Juno) |http://dist.springsource.org/release/GRECLIPSE/e4.2
-|3.7 (Indigo) |http://dist.springsource.org/release/GRECLIPSE/e3.7
+|4.4 |http://dist.springsource.org/release/GRECLIPSE/e4.4
+|4.3 |http://dist.springsource.org/release/GRECLIPSE/e4.3
+|4.3-j8 |http://dist.springsource.org/release/GRECLIPSE/e4.3-j8 (Includes the Java 8 Patch for Eclipse 4.3)
+|4.2 |http://dist.springsource.org/release/GRECLIPSE/e4.2
+|3.7 |http://dist.springsource.org/release/GRECLIPSE/e3.7 (untested, provided 'as is')
 |=================================================================
 
 [[Groovy-EclipsecompilerpluginforMaven-DevelopmentBuilds]]
 == Development Builds
 
-
-[cols="<,<",]
+[cols="25,75" options="header"]
 |==================================================================
 |Eclipse level |Development update site
-|4.2 (Juno) |http://dist.springsource.org/snapshot/GRECLIPSE/e4.2
-|3.7 (Indigo) |http://dist.springsource.org/snapshot/GRECLIPSE/e3.7
+|4.4 |http://dist.springsource.org/snapshot/GRECLIPSE/e4.4
+|4.3 |http://dist.springsource.org/snapshot/GRECLIPSE/e4.3
 |==================================================================
 
 The Groovy-Eclipse configurator for m2eclipse is not compatible with
-AspectJ or Scala.  So you cannot use a joint AspectJ/Scala/Groovy
+AspectJ or Scala. So you cannot use a joint AspectJ/Scala/Groovy
 project in Eclipse. These languages must be separated into separate
 sub-projects.
 
 [[Groovy-EclipsecompilerpluginforMaven-Wheretofindmoreinformationandaskquestions]]
 == Where to find more information and ask questions
 
-Please ask all questions on the Groovy-Eclipse mailing list. Any bugs or
-feature enhancements should go on Groovy-Eclipse’s jira.
-
-The compiler plugin was originally described
-http://contraptionsforprogramming.blogspot.com/2010/09/where-are-all-my-stubs.html[here]
-and
-http://contraptionsforprogramming.blogspot.com/2010/10/more-on-groovy-eclipse-and-maven.html[here],
-but these posts are no longer updated and this page will always contain
-the more recent information.
+Please ask all questions on the http://groovy.codehaus.org/Mailing+Lists[Groovy-Eclipse mailing list]. Any bugs or
+feature enhancements should go to the https://jira.codehaus.org/browse/GRECLIPSE[Groovy-Eclipse’s jira].
diff --git a/src/spec/doc/tools-groovysh.adoc b/src/spec/doc/tools-groovysh.adoc
deleted file mode 100644
index c1ac627..0000000
--- a/src/spec/doc/tools-groovysh.adoc
+++ /dev/null
@@ -1,592 +0,0 @@
-= groovysh, the Groovy shell
-
-== Groovy : Groovy Shell
-
-The Groovy Shell, aka. `groovysh` is a command-line application which
-allows easy access to evaluate Groovy expressions, define classes and
-run simple experiments.
-
-[[GroovyShell-Features]]
-=== Features
-
-* No need for `go` command to execute buffer.
-* Rich cross-platform edit-line editing, history and completion thanks
-to http://jline.sf.net[JLine].
-* ANSI colors (prompt, exception traces, etc).
-* Simple, yet robust, command system with online help, user alias
-support and more.
-* User profile support
-
-[[GroovyShell-Command-lineOptionsandArguments]]
-=== Command-line Options and Arguments
-
-The shell supports several options to control verbosity, ANSI coloring
-and other features.
-
-[source,groovy]
------------------------------------------------------------------
-./bin/groovysh --help
-usage: groovysh [options] [...]
-  -C, --color[=FLAG]         Enable or disable use of ANSI colors
-  -D, --define=NAME=VALUE    Define a system property
-  -T, --terminal=TYPE        Specify the terminal TYPE to use
-  -V, --version              Display the version
-  -d, --debug                Enable debug output
-  -h, --help                 Display this help message
-  -q, --quiet                Suppress superfluous output
-  -v, --verbose              Enable verbose output
------------------------------------------------------------------
-
-In addition to options, commands or expressions can be given on the
-command-line which will invoke the shell in non-interactive mode. The
-commands or expressions will be evaluated and the shell will exit. If no
-additional arguments are given the shell will startup interactively.
-
-[[GroovyShell-ExecuteaCommand]]
-==== Execute a Command
-
----------------------------------
-./bin/groovysh 'show preferences'
-No preferences are set
----------------------------------
-
-[[GroovyShell-EvaluateanExpression]]
-==== Evaluate an Expression
-
---------------------------------------------------------------------------------------------
-./bin/groovysh 'System.properties.each { k, v -> println("$k = $v") }'
-java.runtime.name = Java(TM) 2 Runtime Environment, Standard Edition
-sun.boot.library.path = /System/Library/Frameworks/JavaVM.framework/Versions/1.5.0/Libraries
-java.vm.version = 1.5.0_07-87
-awt.nativeDoubleBuffering = true
-gopherProxySet = false
-...
---------------------------------------------------------------------------------------------
-
-[[GroovyShell-EvaluatingExpressions]]
-=== Evaluating Expressions
-
-[[GroovyShell-SimpleExpressions]]
-==== Simple Expressions
-
-[source,groovy]
----------------
-println "Hello"
----------------
-
-[[GroovyShell-EvaluationResult]]
-==== Evaluation Result
-
-When a complete expression is found, it is compiled and evaluated. The
-result of the evaluation is stored into the _ variable.
-
-[[GroovyShell-Multi-lineExpressions]]
-==== Multi-line Expressions
-
-Multi-line/complex expressions (like closure or class definitions) may
-be defined over several lines. When the shell detects that it has a
-complete expression it will compile and evaluate it.
-
-[[GroovyShell-DefineaClass]]
-===== Define a Class
-
-[source,groovy]
----------------------
-class Foo {
-    def bar() {
-        println "baz"
-    }
-}
----------------------
-
-[[GroovyShell-UsetheClass]]
-===== Use the Class
-
-[source,groovy]
----------------
-foo = new Foo()
-foo.bar()
----------------
-
-[[GroovyShell-Variables]]
-==== Variables
-
-Shell variables are *all* untyped (ie. no `def` or other type
-information).
-
-This *will* set a shell variable:
-
-[source,groovy]
------------
-foo = "bar"
------------
-
-But, this will evaluate a local variable and will *not* be saved to the
-shell’s environment:
-
-[source,groovy]
----------------
-def foo = "bar"
----------------
-
-[[GroovyShell-Functions]]
-==== Functions
-
-Functions can be defined in the shell, and will be saved for later use.
-
-Defining a function is easy:
-
-[source,groovy]
-----------------------------------
-groovy:000> def hello(name) {
-groovy:001> println("Hello $name")
-groovy:002> }
-----------------------------------
-
-And then using it is as one might expect:
-
-[source,groovy]
---------------
-hello("Jason")
---------------
-
-Internally the shell creates a closure to encapsulate the function and
-then binds the closure to a variable. So variables and functions share
-the same namespace.
-
-[[GroovyShell-Commands]]
-=== Commands
-
-The shell has a number of different commands, which provide rich access
-to the shell’s environment.
-
-Commands all have a _name_ and a _shortcut_ (which is something like
-`\h`). Commands may also have some predefined system _aliases_. Users
-may also create their own aliases.
-
-[[GroovyShell-RecognizedCommands]]
-==== Recognized Commands
-
-[[GroovyShell-help]]
-===== `help`
-
-Display the list of commands (and aliases) or the help text for specific
-command.
-
-[[GroovyShell-TheCommandList]]
-The Command List
-
-----------------------------------------------------------------------------------
-groovy:000> help
-
-For information about Groovy, visit:
-    http://groovy.codehaus.org
-
-Available commands:
-  help      (\h ) Display this help message
-  ?         (\? ) Alias to: help
-  exit      (\x ) Exit the shell
-  quit      (\q ) Alias to: exit
-  import    (\i ) Import a class into the namespace
-  display   (\d ) Display the current buffer
-  clear     (\c ) Clear the buffer and reset the prompt counter.
-  show      (\S ) Show variables, classes or imports
-  inspect   (\n ) Inspect a variable or the last result with the GUI object browser
-  purge     (\p ) Purge variables, classes, imports or preferences
-  edit      (\e ) Edit the current buffer
-  load      (\l ) Load a file or URL into the buffer
-  .         (\. ) Alias to: load
-  save      (\s ) Save the current buffer to a file
-  record    (\r ) Record the current session to a file
-  history   (\H ) Display, manage and recall edit-line history
-  alias     (\a ) Create an alias
-  set       (\= ) Set (or list) preferences
-  register  (\rc) Registers a new command with the shell
-  doc       (\D ) Opens a browser window displaying the doc for the argument
-
-For help on a specific command type:
-    help <command>
-----------------------------------------------------------------------------------
-
-[[GroovyShell-HelpforaCommand]]
-Help for a Command
-
-While in the interactive shell, you can ask for help for any command to
-get more details about its syntax or function. Here is an example of
-what happens when you ask for help for the `help` command:
-
-------------------------------------------------------------
-groovy:000> help help
-
-usage: help [<command>]
-
-Display the list of commands or the help text for <command>.
-------------------------------------------------------------
-
-[[GroovyShell-exit]]
-===== `exit`
-
-Exit the shell.
-
-This is the *only* way to exit the shell. Well, you can still `CTRL-C`,
-but the shell will complain about an abnormal shutdown of the JVM.
-
-[[GroovyShell-import]]
-===== `import`
-
-Add a custom import which will be included for all shell evaluations.
-
-This command can be given at any time to add new imports.
-
-[[GroovyShell-display]]
-===== `display`
-
-Display the contents of the current buffer.
-
-This only displays the buffer of an incomplete expression. Once the
-expression is complete, the buffer is rest. The prompt will update to
-show the size of the current buffer as well.
-
-[[GroovyShell-Example]]
-Example
-
------------------------
-groovy:000> class Foo {
-groovy:001> def bar
-groovy:002> def baz() {
-groovy:003> display
- 001> class Foo {
- 002> def bar
- 003> def baz() {
------------------------
-
-[[GroovyShell-clear]]
-===== `clear`
-
-Clears the current buffer, resetting the prompt counter to 000. Can be used to recover from compilation errors.
-
-[[GroovyShell-show]]
-===== `show`
-
-Show variables, classes or preferences or imports.
-
-[[GroovyShell-showvariables]]
-`show variables`
-
---------------------------
-groovy:000> show variables
-Variables:
-  _ = true
---------------------------
-
-[[GroovyShell-showclasses]]
-`show classes`
-
-[[GroovyShell-showimports]]
-`show imports`
-
-[[GroovyShell-showpreferences]]
-`show preferences`
-
-[[GroovyShell-showall]]
-`show all`
-
-[[GroovyShell-inspect]]
-===== `inspect`
-
-Opens the GUI object browser to inspect a variable or the result of the
-last evaluation.
-
-[[GroovyShell-purge]]
-===== `purge`
-
-Purges objects from the shell.
-
-[[GroovyShell-purgevariables]]
-`purge variables`
-
-[[GroovyShell-purgeclasses]]
-`purge classes`
-
-[[GroovyShell-purgeimports]]
-`purge imports`
-
-[[GroovyShell-purgepreferences]]
-`purge preferences`
-
-[[GroovyShell-purgeall]]
-`purge all`
-
-[[GroovyShell-edit]]
-===== `edit`
-
-Edit the current buffer in an external editor.
-
-Currently only works on UNIX systems which have the `EDITOR` environment
-variable set, or have configured the `editor` preference.
-
-[[GroovyShell-load]]
-===== `load`
-
-Load one or more files (or urls) into the buffer.
-
-[[GroovyShell-save]]
-===== `save`
-
-Saves the buffer’s contents to a file.
-
-[[GroovyShell-record]]
-===== `record`
-
-Record the current session to a file.
-
-[[GroovyShell-recordstart]]
-`record start`
-
-[[GroovyShell-recordstop]]
-`record stop`
-
-[[GroovyShell-recordstatus]]
-`record status`
-
-[[GroovyShell-history]]
-===== `history`
-
-Display, manage and recall edit-line history.
-
-[[GroovyShell-historyshow]]
-`history show`
-
-[[GroovyShell-historyrecall]]
-`history recall`
-
-[[GroovyShell-historyflush]]
-`history flush`
-
-[[GroovyShell-historyclear]]
-`history clear`
-
-[[GroovyShell-alias]]
-===== `alias`
-
-Create an alias.
-
-[[GroovyShell-doc]]
-===== `doc`
-
-Opens a browser with documentation for the provided class. For example:
-
-----
-doc java.net.URL
-----
-
-will open two windows (or tabs, depending on your browser):
-
-* one for the JDK documentation
-* one for the GDK documentation
-
-[[GroovyShell-set]]
-===== `set`
-
-Set or list preferences.
-
-[[GroovyShell-Preferences]]
-=== Preferences
-
-Some of aspects of `groovysh` behaviors can be customized by setting
-preferences. Preferences are set using the `set` command or the `\=`
-shortcut.
-
-[[GroovyShell-RecognizedPreferences]]
-==== Recognized Preferences
-
-[[GroovyShell-verbosity]]
-===== `verbosity`
-
-Set the shell’s verbosity level. Expected to be one of:
-
-* `DEBUG`
-* `VERBOSE`
-* `INFO`
-* `QUIET`
-
-Default is `INFO`.
-
-If this preference is set to an invalid value, then the previous setting
-will be used, or if there is none, then the preference is removed and
-the default is used.
-
-[[GroovyShell-show-last-result]]
-===== `show-last-result`
-
-Show the last result after an execution.
-
-Default is `true`.
-
-[[GroovyShell-sanitize-stack-trace]]
-===== `sanitize-stack-trace`
-
-Sanitize (trim-down/filter) stack traces.
-
-Default is `true`.
-
-[[GroovyShell-editor]]
-===== `editor`
-
-Configures the editor used by the `edit` command.
-
-Default is the value of the system environment variable `EDITOR`.
-
-Mac OS XTo use TextEdit, the default text editor on Mac OS X, configure:
-set editor /Applications/TextEdit.app/Contents/MacOS/TextEdit
-
-[[GroovyShell-SettingaPreference]]
-==== Setting a Preference
-
--------------------
-set verbosity DEBUG
--------------------
-
-[[GroovyShell-ListingPreferences]]
-==== Listing Preferences
-
-To list the current _set_ preferences (and their values):
-
-----------------
-show preferences
-----------------
-
-LimitationAt the moment, there is no way to list all of the
-known/available preferences to be set.
-
-[[GroovyShell-ClearingPreferencesieResettingtoDefaults]]
-==== Clearing Preferences (ie. Resetting to Defaults)
-
------------------
-purge preferences
------------------
-
-[[GroovyShell-UserProfileScriptsandState]]
-=== User Profile Scripts and State
-
-[[GroovyShell-ProfileScripts]]
-==== Profile Scripts
-
-[[GroovyShell-HOMEgroovygroovyshprofile]]
-===== `$HOME/.groovy/groovysh.profile`
-
-This script, if it exists, is loaded when the shell starts up.
-
-[[GroovyShell-HOMEgroovygroovyshrc]]
-===== `$HOME/.groovy/groovysh.rc`
-
-This script, if it exists, is loaded when the shell enters interactive
-mode.
-
-[[GroovyShell-State]]
-==== State
-
-[[GroovyShell-HOMEgroovygroovyshhistory]]
-===== `$HOME/.groovy/groovysh.history`
-
-Edit-line history is stored in this file.
-
-[[GroovyShell-register]]
-=== Custom commands
-
-The `register` command allows you to register custom commands in the shell. For example, writing the following
-will register the `Stats` command:
-
-----
-register Stats
-----
-
-where the `Stats` class is a class extending the `org.codehaus.groovy.tools.shell.CommandSupport` class. For example:
-
-[source,groovy]
-----
-import org.codehaus.groovy.tools.shell.CommandSupport
-import org.codehaus.groovy.tools.shell.Groovysh
-
-class Stats extends CommandSupport {
-    protected Stats(final Groovysh shell) {
-        super(shell, 'stats', 'T')
-    }
-
-    public Object execute(List args) {
-        println "Free memory: ${Runtime.runtime.freeMemory()}"
-    }
-
-}
-----
-
-Then the command can be called using:
-
-----
-groovy:000> stats
-stats
-Free memory: 139474880
-groovy:000>
-----
-
-Note that the command class must be found on classpath: you cannot define a new command from within the shell.
-
-[[GroovyShell-ScreenShots]]
-=== Screen Shots
-
-These shots have been taken over the development of the new shell, so
-some of the content might look slightly different. Also, note the yellow
-colors here are the shell’s _bold_ color, so the colors might look
-different depending on how the enclosing shell has its colors setup.
-
-image:assets/img/groovysh3.jpg[image,title="groovysh3.jpg"]
-
-image:assets/img/groovysh2.jpg[image,title="groovysh2.jpg"]
-
-image:assets/img/groovysh4.jpg[image,title="groovysh4.jpg"]
-
-[[GroovyShell-Troubleshooting]]
-=== Troubleshooting
-
-Please http://jira.codehaus.org/browse/GROOVY[report] any problems you
-run into. Please be sure to mark the JIRA issue with the `Groovysh`
-component.
-
-[[GroovyShell-PlatformProblems]]
-==== Platform Problems
-
-[[GroovyShell-ProblemsloadingtheJLineDLL]]
-===== Problems loading the JLine DLL
-
-On Windows, http://jline.sf.net[JLine] (which is used for the fancy
-shell input/history/completion fluff), uses a *tiny* DLL file to trick
-the *evil* Windows faux-shell (`CMD.EXE` or `COMMAND.COM`) into
-providing Java with unbuffered input. In some rare cases, this might
-fail to load or initialize.
-
-One solution is to disable the frills and use the unsupported terminal
-instance. You can do that on the command-line using the `--terminal`
-flag and set it to one of:
-
-* `none`
-* `false`
-* `off`
-* `jline.UnsupportedTerminal`
-
-------------------------
-groovysh --terminal=none
-------------------------
-
-[[GroovyShell-ProblemswithCygwinonWindows]]
-===== Problems with Cygwin on Windows
-as
-Some people have issues when running groovysh with cygwin. If you have
-troubles, the following may help:
-
-------------------------
-stty -icanon min 1 -echo
-groovysh --terminal=unix
-stty icanon echo
-------------------------
-
-:leveloffset: 2
\ No newline at end of file
diff --git a/src/spec/doc/tools-ide.adoc b/src/spec/doc/tools-ide.adoc
index 0eb2c0a..603af90 100644
--- a/src/spec/doc/tools-ide.adoc
+++ b/src/spec/doc/tools-ide.adoc
@@ -10,9 +10,9 @@ The Groovy language is supported by lots of IDEs and text editors.
 |http://www.jetbrains.com/idea/features/groovy.html[IntelliJ IDEA]|[icon-star]_{empty}_ [icon-star]_{empty}_ [icon-star]_{empty}_|Yes|Yes|Yes
 |https://netbeans.org/features/groovy/[Netbeans]|[icon-star]_{empty}_ [icon-star]_{empty}_ [icon-star]_{empty}_|Yes|Yes|Yes
 |http://grails.org/products/ggts[Groovy and Grails Toolsuite]|[icon-star]_{empty}_ [icon-star]_{empty}_ [icon-star]_{empty}_|Yes|Yes|Yes
-|http://groovy.codehaus.org/Emacs+Groovy+Mode[Emacs Groovy Mode]|[icon-star]_{empty}_ [icon-star]_{empty}_|Yes|Brackets|No
-|https://github.com/textmate/groovy.tmbundle[TextMate]|[icon-star]_{empty}_ [icon-star]_{empty}_|Yes|Snippets|No
+|http://groovy.codehaus.org/Emacs+Groovy+Mode[Emacs Groovy Mode]|[icon-star]_{empty}_ [icon-star]_{empty}_|Yes|No|No
+|https://github.com/textmate/groovy.tmbundle[TextMate]|[icon-star]_{empty}_ [icon-star]_{empty}_|Yes|No|No
 |http://www.vim.org/[vim]|[icon-star]_{empty}_|Yes|No|No
-|http://www.ultraedit.com/[UltraEdit]|[icon-star]_{empty}_|Yes|Text based|No
+|http://www.ultraedit.com/[UltraEdit]|[icon-star]_{empty}_|Yes|No|No
 |=======================================================================
 
diff --git a/src/spec/doc/type-checking-extensions.adoc b/src/spec/doc/type-checking-extensions.adoc
new file mode 100644
index 0000000..31c04ad
--- /dev/null
+++ b/src/spec/doc/type-checking-extensions.adoc
@@ -0,0 +1,1073 @@
+= Type checking extensions
+
+== Writing a type checking extension
+
+=== Towards a smarter type checker
+
+Despite being a dynamic language, Groovy can be used with a static type
+checker at compile time, enabled using the <<static-type-checking, at TypeChecked>>
+annotation. In this mode, the compiler becomes
+more verbose and throws errors for, example, typos, non-existent
+methods,… This comes with a few limitations though, most of them coming
+from the fact that Groovy remains inherently a dynamic language. For
+example, you wouldn’t be able to use type checking on code that uses the markup builder:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=intro_stc_extensions,indent=0]
+----
+
+In the previous example, none of the `html`, `head`, `body` or `p` methods
+exist. However if you execute the code, it works because Groovy uses dynamic dispatch
+and converts those method calls at runtime. In this builder, there’s no limitation about
+the number of tags that you can use, nor the attributes, which means there is no chance
+for a type checker to know about all the possible methods (tags) at compile time, unless
+you create a builder dedicated to HTML for example.
+
+Groovy is a platform of choice when it comes to implement internal DSLs. The flexible syntax,
+combined with runtime and compile-time metaprogramming capabilities make Groovy an interesting
+choice because it allows the programmer to focus on the DSL rather than
+on tooling or implementation. Since Groovy DSLs are Groovy code, it’s
+easy to have IDE support without having to write a dedicated plugin for
+example.
+
+In a lot of cases, DSL engines are written in Groovy (or Java) then user
+code is executed as scripts, meaning that you have some kind of wrapper
+on top of user logic. The wrapper may consist, for example, in a
+`GroovyShell` or `GroovyScriptEngine` that performs some tasks transparently
+before running the script (adding imports, applying AST transforms,
+extending a base script,…). Often, user written scripts come to
+production without testing because the DSL logic comes to a point
+where *any* user may write code using the DSL syntax. In the end, a user
+may just ignore that what he writes is actually *code*. This adds some
+challenges for the DSL implementer, such as securing execution of user
+code or, in this case, early reporting of errors.
+
+For example, imagine a DSL which goal is to drive a rover on Mars
+remotely. Sending a message to the rover takes around 15 minutes. If the
+rover executes the script and fails with an error (say a typo), you have
+two problems:
+
+* first, feedback comes only after 30 minutes (the time needed for the
+rover to get the script and the time needed to receive the error)
+* second, some portion of the script has been executed and you may have
+to change the fixed script significantly (implying that you need to know
+the current state of the rover…)
+
+Type checking extensions is a mechanism that will
+allow the developer of a DSL engine to make those scripts safer by
+applying the same kind of checks that static type checking allows on
+regular groovy classes.
+
+The principle, here, is to fail early, that is
+to say fail compilation of scripts as soon as possible, and if possible
+provide feedback to the user (including nice error messages).
+
+In short, the idea behind type checking extensions is to make the compiler
+aware of all the runtime metaprogramming tricks that the DSL uses, so that
+scripts can benefit the same level of compile-time checks as a verbose statically
+compiled code would have. We will see that you can go even further by performing
+checks that a normal type checker wouldn't do, delivering powerful compile-time
+checks for your users.
+
+[[Typecheckingextensions-Howdoesitwork]]
+=== The extensions attribute
+
+The `@TypeChecked` annotation supports an attribute
+named `extensions`. This parameter takes an array of strings
+corresponding to a list of _type checking extensions scripts. Those
+scripts are found at *compile time* on classpath. For example, you would
+write:
+
+[source,groovy]
+------------------------------------------------------
+ at TypeChecked(extensions='/path/to/myextension.groovy')
+void foo() { ...}
+------------------------------------------------------
+
+In that case, the _foo_ methods would be type checked with the rules of
+the normal type checker completed by those found in
+the _myextension.groovy_ script. Note that while internally the type
+checker supports multiple mechanisms to implement type checking
+extensions (including plain old java code), the recommended way is to
+use those type checking extension scripts.
+
+=== A DSL for type checking
+The idea behind type checking extensions is to use a DSL to extend the
+type checker capabilities. This DSL allows you to hook into the
+compilation process, more specifically the type checking phase, using an
+"event-driven" API. For example, when the type checker enters a method
+body, it throws a _beforeVisitMethod_ event that the extension can react to:
+
+[source,groovy]
+--------------------------------------
+beforeVisitMethod { methodNode ->
+ println "Entering ${methodNode.name}"
+}
+--------------------------------------
+
+Imagine that you have this rover DSL at hand. A user would write:
+
+[source,groovy]
+--------------
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_script,indent=0]
+--------------
+
+If you have a class defined as such:
+
+[source,groovy]
+----------------------------
+include::{projectdir}/src/spec/test/typing/Robot.groovy[tags=example_robot_classdef,indent=0]
+----------------------------
+
+The script can be type checked before being executed using the following
+script:
+
+[source,groovy]
+------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_setup,indent=0]
+------------------------------------------------------------------------------
+<1> a compiler configuration adds the `@TypeChecked` annotation to all classes
+<2> use the configuration in a `GroovyShell`
+<3> so that scripts compiled using the shell are compiled with `@TypeChecked` without the user having to add it explicitly
+
+Using the compiler configuration above, we can apply _ at TypeChecked_
+transparently to the script. In that case, it will fail at compile
+time:
+
+------------------------------------------------------------
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_expected_err,indent=0]
+------------------------------------------------------------
+
+Now, we will slightly update the configuration to include the
+``extensions'' parameter:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_fixed_conf,indent=0]
+----
+
+Then add the following to your classpath:
+
+[source,groovy]
+.robotextension.groovy
+-------------------------------------
+include::{projectdir}/src/spec/test-resources/robotextension.groovy[tags=example_robot_extension,indent=0]
+-------------------------------------
+
+Here, we’re telling the compiler that if an _unresolved variable_ is found
+and that the name of the variable is _robot_, then we can make sure that the type of this
+variable is `Robot`.
+
+[[Typecheckingextensions-TheAPI]]
+=== Type checking extensions API
+
+[[Typecheckingextensions-AST]]
+==== AST
+
+The type checking API is a low level API, dealing with the Abstract
+Syntax Tree. You will have to know your AST well to develop extensions,
+even if the DSL makes it much easier than just dealing with AST code
+from plain Java or Groovy.
+
+[[Typecheckingextensions-Events]]
+==== Events
+
+The type checker sends the following events, to which an extension
+script can react:
+
+[[event-setup]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| setup
+| *Called When*
+| Called after the type checker finished initialization
+
+| *Arguments*
+|
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/setup.groovy[tags=event,indent=0]
+----
+
+Can be used to perform setup of your extension
+|===
+
+[[event-finish]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| finish
+| *Called When*
+| Called after the type checker completed type checking
+
+| *Arguments*
+|
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/finish.groovy[tags=event,indent=0]
+----
+
+Can be used to perform additional checks after the type checker has finished its job.
+|===
+
+[[event-unresolvedVariable]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| unresolvedVariable
+| *Called When*
+| Called when the type checker finds an
+  unresolved variable
+| *Arguments*
+| VariableExpression var
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/unresolvedvariable.groovy[tags=event,indent=0]
+----
+
+Allows the developer to help the type checker with user-injected variables.
+|===
+
+[[event-unresolvedProperty]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| unresolvedProperty
+| *Called When*
+| Called when the type checker cannot find
+  a property on the receiver
+| *Arguments*
+| PropertyExpression pexp
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/unresolvedproperty.groovy[tags=event,indent=0]
+----
+
+Allows the developer to handle "dynamic" properties
+|===
+
+[[event-unresolvedAttribute]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| unresolvedAttribute
+| *Called When*
+| Called when the type checker cannot
+  find an attribute on the receiver
+| *Arguments*
+| AttributeExpression aex
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/unresolvedattribute.groovy[tags=event,indent=0]
+----
+
+Allows the developer to handle missing attributes
+|===
+
+[[event-beforeMethodCall]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| beforeMethodCall
+| *Called When*
+| Called before the type checker starts type
+  checking a method call
+| *Arguments*
+| MethodCall call
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/beforemethodcall.groovy[tags=event,indent=0]
+----
+
+Allows you to intercept method calls before the
+type checker performs its own checks. This is useful if you want to
+replace the default type checking with a custom one for a limited scope.
+In that case, you must set the handled flag to true, so that the type
+checker skips its own checks.
+|===
+
+[[event-afterMethodCall]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| afterMethodCall
+| *Called When*
+| Called once the type checker has finished
+  type checking a method call
+| *Arguments*
+| MethodCall call
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/aftermethodcall.groovy[tags=event,indent=0]
+----
+
+Allow you to perform additional checks after the type
+checker has done its own checks. This is in particular useful if you
+want to perform the standard type checking tests but also want to ensure
+additional type safety, for example checking the arguments against each
+other.Note that `afterMethodCall` is called even if you did
+`beforeMethodCall` and set the handled flag to true.
+|===
+
+[[event-onMethodSelection]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| onMethodSelection
+| *Called When*
+| Called by the type checker when it finds
+  a method appropriate for a method call
+| *Arguments*
+| Expression expr, MethodNode node
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/onmethodselection.groovy[tags=event,indent=0]
+----
+
+The type checker works by inferring
+argument types of a method call, then chooses a target method. If it
+finds one that corresponds, then it triggers this event. It is for
+example interesting if you want to react on a specific method call, such
+as entering the scope of a method that takes a closure as argument (as
+in builders).Please note that this event may be thrown for various types
+of expressions, not only method calls (binary expressions for example).
+|===
+
+[[event-methodNotFound]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| methodNotFound
+| *Called When*
+| Called by the type checker when it fails to
+  find an appropriate method for a method call
+| *Arguments*
+| ClassNode receiver, String name, ArgumentListExpression argList, ClassNode[] argTypes,MethodCall call
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/methodnotfound.groovy[tags=event,indent=0]
+----
+
+Unlike `onMethodSelection`, this event is
+sent when the type checker cannot find a target method for a method call
+(instance or static). It gives you the chance to intercept the error
+before it is sent to the user, but also set the target method.For this,
+you need to return a list of `MethodNode`. In most situations, you would
+either return: an empty list, meaning that you didn’t find a
+corresponding method, a list with exactly one element, saying that there’s
+no doubt about the target methodIf you return more than one MethodNode,
+then the compiler would throw an error to the user stating that the
+method call is ambiguous, listing the possible methods.For convenience,
+if you want to return only one method, you are allowed to return it
+directly instead of wrapping it into a list.
+
+|===
+
+[[event-beforeVisitMethod]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| beforeVisitMethod
+| *Called When*
+| Called by the type checker before type
+  checking a method body
+| *Arguments*
+| MethodNode node
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/beforevisitmethod.groovy[tags=event,indent=0]
+----
+
+The type checker will call this method before
+starting to type check a method body. If you want, for example, to
+perform type checking by yourself instead of letting the type checker do
+it, you have to set the handled flag to true.This event can also be used
+to help defining the scope of your extension (for example, applying it
+only if you are inside method foo).
+|===
+
+[[event-afterVisitMethod]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| afterVisitMethod
+| *Called When*
+| Called by the type checker after type
+  checking a method body
+| *Arguments*
+| MethodNode node
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/aftervisitmethod.groovy[tags=event,indent=0]
+----
+
+Gives you the opportunity to perform additional
+checks after a method body is visited by the type checker. This is
+useful if you collect information, for example, and want to perform
+additional checks once everything has been collected.
+|===
+
+[[event-beforeVisitClass]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| beforeVisitClass
+| *Called When*
+| Called by the type checker before type checking a class
+| *Arguments*
+| ClassNode node
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/beforevisitclass.groovy[tags=event,indent=0]
+----
+
+If a class is type checked, then
+before visiting the class, this event will be sent. It is also the case
+for inner classes defined inside a class annotated with `@TypeChecked`. It
+can help you define the scope of your extension, or you can even totally
+replace the visit of the type checker with a custom type checking
+implementation. For that, you would have to set the `handled` flag to
+`true`. 
+|===
+
+[[event-afterVisitClass]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| afterVisitClass
+| *Called When*
+| Called by the type checker after having finished the visit of a type checked class
+| *Arguments*
+| ClassNode node
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/aftervisitclass.groovy[tags=event,indent=0]
+----
+
+Called
+for every class being type checked after the type checker finished its
+work. This includes classes annotated with `@TypeChecked` and any
+inner/anonymous class defined in the same class with is not skipped.
+|===
+
+[[event-incompatibleAssignment]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| incompatibleAssignment
+| *Called When*
+| Called when the type checker thinks
+    that an assignment is incorrect, meaning that the right hand side of an
+    assignment is incompatible with the left hand side
+| *Arguments*
+| ClassNode lhsType, ClassNode rhsType,  Expression assignment
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/incompatibleassignment.groovy[tags=event,indent=0]
+----
+
+Gives the
+developer the ability to handle incorrect assignments. This is for
+example useful if a class overrides `setProperty`, because in that case it
+is possible that assigning a variable of one type to a property of
+another type is handled through that runtime mechanism. In that case, you
+can help the type checker just by telling it that the assignment is
+valid (using `handled` set to `true`).
+|===
+
+[[event-ambiguousMethods]]
+[cols="1,3a",width="100%"]
+|===
+| *Event name*
+| ambiguousMethods
+| *Called When*
+| Called when the type checker cannot choose between several candidate methods
+| *Arguments*
+| List<MethodNode> methods,  Expression origin
+| *Usage*
+|
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/ambiguousmethods.groovy[tags=event,indent=0]
+----
+
+Gives the
+developer the ability to handle incorrect assignments. This is for
+example useful if a class overrides `setProperty`, because in that case it
+is possible that assigning a variable of one type to a property of
+another type is handled through that runtime mechanism. In that case, you
+can help the type checker just by telling it that the assignment is
+valid (using `handled` set to `true`).
+|===
+
+Of course, an extension script may consist of several blocks, and you
+can have multiple blocks responding to the same event. This makes the
+DSL look nicer and easier to write. However, reacting to events is far
+from sufficient. If you know you can react to events, you also need to
+deal with the errors, which implies several _helper_ methods that will
+make things easier.
+
+[[Typecheckingextensions-Workingwithextensions]]
+=== Working with extensions
+
+[[Typecheckingextensions-Supportclasses]]
+==== Support classes
+
+The DSL relies on a support class
+called gapi:org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport[] .
+This class itself
+extends gapi:org.codehaus.groovy.transform.stc.TypeCheckingExtension[] . Those
+two classes define a number of _helper_ methods that will make working
+with the AST easier, especially regarding type checking. One interesting
+thing to know is that you *have access to the type checker*. This means
+that you can programmatically call methods of the type checker,
+including those that allow you to *throw compilation errors*.
+
+The extension script delegates to
+the gapi:org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport[] class, meaning that you have
+direct access to the following variables:
+
+* _context_: the type checker context, of type gapi:org.codehaus.groovy.transform.stc.TypeCheckingContext[]
+* _typeCheckingVisitor_: the type checker itself, a gapi:org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor[] instance
+* _generatedMethods_: a list of "generated methods", which is in fact the list of "dummy" methods that you can create
+inside a type checking extension using the `newMethod` calls
+
+The type checking context contains a lot of information that is useful
+in context for the type checker. For example, the current stack of
+enclosing method calls, binary expressions, closures, … This information
+is in particular important if you have to know _where_ you are when an
+error occurs and that you want to handle it.
+
+[[Typecheckingextensions-Classnodes]]
+==== Class nodes
+
+Handling class nodes is something that needs particular attention when
+you work with a type checking extension. Compilation works with an
+abstract syntax tree (AST) and the tree may not be complete when you are
+type checking a class. This also means that when you refer to types, you
+must not use class literals such as `String` or `HashSet`, but to class
+nodes representing those types. This requires a certain level of
+abstraction and understanding how Groovy deals with class nodes. To make
+things easier, Groovy supplies several helper methods to deal with class
+nodes. For example, if you want to say "the type for String", you can
+write:
+
+[source,groovy]
+--------------------
+include::{projectdir}/src/spec/test-resources/selfcheck.groovy[tags=classnodefor,indent=0]
+--------------------
+
+You would also note that there is a variant of _classNodeFor_ that takes
+a `String` as an argument, instead of a `Class`. In general, you
+should *not* use that one, because it would create a class node for
+which the name is `String`, but without any method, any property, …
+defined on it. The first version returns a class node that is _resolved_
+but the second one returns one that is _not_. So the latter should be
+reserved for very special cases.
+
+The second problem that you might encounter is referencing a type which
+is not yet compiled. This may happen more often than you think. For
+example, when you compile a set of files together. In that case, if you
+want to say "that variable is of type Foo" but `Foo` is not yet
+compiled, you can still refer to the `Foo` class node
+using `lookupClassNodeFor`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test-resources/selfcheck.groovy[tags=lookupclassnodefor,indent=0]
+----
+
+[[Typecheckingextensions-Helpingthetypechecker]]
+==== Helping the type checker
+
+Say that you know that variable `foo` is of type `Foo` and you want to
+tell the type checker about it. Then you can use the `storeType` method,
+which takes two arguments: the first one is the node for which you want
+to store the type and the second one is the type of the node. If you
+look at the implementation of `storeType`, you would see that it
+delegates to the type checker equivalent method, which itself does a lot
+of work to store node metadata. You would also see that storing the type
+is not limited to variables: you can set the type of any expression.
+
+Likewise, getting the type of an AST node is just a matter of
+calling `getType` on that node. This would in general be what you want,
+but there’s something that you must understand:
+
+* `getType` returns the *inferred type* of an expression. This means
+that it will not return, for a variable declared of type `Object` the
+class node for `Object`, but the inferred type of this variable *at this
+point of the code* (flow typing)
+* if you want to access the origin type of a variable (or
+field/parameter), then you must call the appropriate method on the AST
+node
+
+[[Typecheckingextensions-Throwinganerror]]
+==== Throwing an error
+
+To throw a type checking error, you only have to call the
+`addStaticTypeError` method which takes two arguments:
+
+* a _message_ which is a string that will be displayed to the end user
+* an _AST node_ responsible for the error. It’s better to provide the best
+suiting AST node because it will be used to retrieve the line and column
+numbers
+
+[[Typecheckingextensions-isXXXExpression]]
+==== isXXXExpression
+
+It is often required to know the type of an AST node. For readability,
+the DSL provides a special isXXXExpression method that will delegate to
+`x instance of XXXExpression`. For example, instead of writing:
+
+[source,groovy]
+---------------------------------------
+if (node instanceof BinaryExpression) {
+   ...
+}
+---------------------------------------
+
+which requires you to import the `BinaryExpression` class, you can just
+write:
+
+[source,groovy]
+-------------------------------
+if (isBinaryExpression(node)) {
+   ...
+}
+-------------------------------
+
+[[Typecheckingextensions-Virtualmethods]]
+==== Virtual methods
+
+When you perform type checking of dynamic code, you may often face the
+case when you know that a method call is valid but there is no ``real''
+method behind it. As an example, take the Grails dynamic finders. You
+can have a method call consisting of a method named _findByName(…)_. As
+there’s no _findByName_ method defined in the bean, the type checker
+would complain. Yet, you would know that this method wouldn’t fail at
+runtime, and you can even tell what is the return type of this method.
+For this case, the DSL supports two special constructs that consist of
+_phantom methods_. This means that you will return a method node that
+doesn’t really exist but is defined in the context of type checking.
+Three methods exist:
+
+* `newMethod(String name, Class returnType)`
+* `newMethod(String name, ClassNode returnType)`
+* `newMethod(String name, Callable<ClassNode> return Type)`
+
+All three variants do the same: they create a new method node which name
+is the supplied name and define the return type of this method.
+Moreover, the type checker would add those methods in
+the `generatedMethods` list (see `isGenerated` below). The reason why we
+only set a name and a return type is that it is only what you need in
+90% of the cases. For example, in the `findByName` example upper, the
+only thing you need to know is that `findByName` wouldn’t fail at
+runtime, and that it returns a domain class. The `Callable` version of
+return type is interesting because it defers the computation of the
+return type when the type checker actually needs it. This is interesting
+because in some circumstances, you may not know the actual return type
+when the type checker demands it, so you can use a closure that will be
+called each time `getReturnType` is called by the type checker on this
+method node. If you combine this with deferred checks, you can achieve
+pretty complex type checking including handling of forward references.
+
+[source,groovy]
+----------------------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test-resources/newmethod.groovy[tags=newmethod,indent=0]
+----------------------------------------------------------------------------------------------
+
+Should you need more than the name and return type, you can always
+create a new `MethodNode` by yourself.
+
+[[Typecheckingextensions-Scoping]]
+==== Scoping
+
+Scoping is very important in DSL type checking and is one of the reasons
+why we couldn’t use a _pointcut_ based approach to DSL type checking.
+Basically, you must be able to define very precisely when your extension
+applies and when it does not. Moreover, you must be able to handle
+situations that a regular type checker would not be able to handle, such
+as forward references:
+
+[source,groovy]
+---------------------------------------
+point a(1,1)
+line a,b // b is referenced afterwards!
+point b(5,2)
+---------------------------------------
+
+Say for example that you want to handle a builder:
+
+[source,groovy]
+-------------
+builder.foo {
+   bar
+   baz(bar)
+}
+-------------
+
+Your extension, then, should only be active once you’ve entered
+the `foo` method, and inactive outside of this scope. But you could have
+complex situations like multiple builders in the same file or embedded
+builders (builders in builders). While you should not try to fix all
+this from start (you must accept limitations to type checking), the type
+checker does offer a nice mechanism to handle this: a scoping stack,
+using the `newScope` and `scopeExit` methods.
+
+* `newScope` creates a new scope and puts it on top of the stack
+* `scopeExits` pops a scope from the stack
+
+A scope consists of:
+
+* a parent scope
+* a map of custom data
+
+If you want to look at the implementation, it’s simply a `LinkedHashMap`
+(gapi:org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport.TypeCheckingScope[]),
+but it’s quite powerful. For example, you can use such a scope to store
+a list of closures to be executed when you exit the scope. This is how
+you would handle forward references: 
+
+[source,groovy]
+------------------------------------------------------
+include::{projectdir}/src/spec/test-resources/scoping.groovy[tags=newscope,indent=0]
+include::{projectdir}/src/spec/test-resources/scoping.groovy[tags=scopeexit,indent=0]
+------------------------------------------------------
+
+That is to say, that if at some point you are not able to determine the
+type of an expression, or that you are not able to check at this point
+that an assignment is valid or not, you can still make the check later…
+This is a very powerful feature. Now, `newScope` and `scopeExit`
+provide some interesting syntactic sugar:
+
+[source,groovy]
+------------------------------------------------------
+include::{projectdir}/src/spec/test-resources/scoping_alt.groovy[tags=newscope,indent=0]
+------------------------------------------------------
+
+At anytime in the DSL, you can access the current scope
+using `getCurrentScope()` or more simply `currentScope`:
+
+[source,groovy]
+------------------------------------------------------
+include::{projectdir}/src/spec/test-resources/scoping_alt.groovy[tags=currentscope,indent=0]
+------------------------------------------------------
+
+The general schema would then be:
+
+* determine a _pointcut_ where you push a new scope on stack and
+initialize custom variables within this scope
+* using the various events, you can use the information stored in your
+custom scope to perform checks, defer checks,…
+* determine a _pointcut_ where you exit the scope, call `scopeExit`
+and eventually perform additional checks
+
+[[Typecheckingextensions-Otherusefulmethods]]
+==== Other useful methods
+
+For the complete list of helper methods, please refer to
+the gapi:org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport[] and 
+gapi:org.codehaus.groovy.transform.stc.TypeCheckingExtension[] classes. However,
+take special attention to those methods:
+
+* `isDynamic`: takes a VariableExpression as argument and returns true
+if the variable is a DynamicExpression, which means, in a script, that
+it wasn’t defined using a type or def.
+* `isGenerated`: takes a MethodNode as an argument and tells if the
+method is one that was generated by the type checker extension using
+the `newMethod` method
+* `isAnnotatedBy`: takes an AST node and a Class (or ClassNode), and
+tells if the node is annotated with this class. For example:
+`isAnnotatedBy(node, NotNull)`
+* `getTargetMethod`: takes a method call as argument and returns
+the `MethodNode` that the type checker has determined for it
+* `delegatesTo`: emulates the behaviour of the `@DelegatesTo`
+annotation. It allows you to tell that the argument will delegate to a
+specific type (you can also specify the delegation strategy)
+
+== Advanced type checking extensions
+=== Precompiled type checking extensions
+
+All the examples above use type checking scripts. They are found in source form in classpath, meaning that:
+
+* a Groovy source file, corresponding to the type checking extension, is available on compilation classpath
+* this file is compiled by the Groovy compiler for each source unit being compiled (often, a source unit corresponds
+to a single file)
+
+It is a very convenient way to develop type checking extensions, however it implies a slower compilation phase, because
+of the compilation of the extension itself for each file being compiled. For those reasons, it can be practical to rely
+on a precompiled extension. You have two options to do this:
+
+* write the extension in Groovy, compile it, then use a reference to the extension class instead of the source
+* write the extension in Java, compile it, then use a reference to the extension class
+
+Writing a type checking extension in Groovy is the easiest path. Basically, the idea is that the type checking extension
+script becomes the body of the main method of a type checking extension class, as illustrated here:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/PrecompiledExtension.groovy[tags=precompiled_groovy_extension,indent=0]
+----
+<1> extending the `TypeCheckingDSL` class is the easiest
+<2> then the extension code needs to go inside the `run` method
+<3> and you can use the very same events as an extension written in source form
+
+Setting up the extension is very similar to using a source form extension:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=setup_precompiled,indent=0]
+----
+
+The difference is that instead of using a path in classpath, you just specify the fully qualified class name of the
+precompiled extension.
+
+In case you really want to write an extension in Java, then you will not benefit from the type checking extension DSL.
+The extension above can be rewritten in Java this way:
+
+[source,java]
+----
+include::{projectdir}/src/spec/test/typing/PrecompiledJavaExtension.java[tags=precompiled_java_extension,indent=0]
+----
+<1> extend the `AbstractTypeCheckingExtension` class
+<2> then override the `handleXXX` methods as required
+
+=== Using @Grab in a type checking extension
+
+It is totally possible to use the `@Grab` annotation in a type checking extension.
+This means you can include libraries that would only be
+available at compile time. In that case, you must understand that you
+would increase the time of compilation significantly (at least, the
+first time it grabs the dependencies).
+
+=== Sharing or packaging type checking extensions
+
+A type checking extension is just a script that need to be on classpath. As such,
+you can share it as is, or bundle it in a jar file that would be added to classpath.
+
+=== Global type checking extensions
+
+While you can configure the compiler to transparently add type checking extensions to your
+script, there is currently no way to apply an extension transparently just by having it on
+classpath.
+
+=== Type checking extensions and @CompileStatic
+
+Type checking extensions are used with `@TypeChecked` but can also be used with `@CompileStatic`. However, you must
+be aware that:
+
+* a type checking extension used with `@CompileStatic` will in general not be sufficient to let the compiler know how
+to generate statically compilable code from "unsafe" code
+* it is possible to use a type checking extension with `@CompileStatic` just to enhance type checking, that is to say
+introduce *more* compilation errors, without actually dealing with dynamic code
+
+Let's explain the first point, which is that even if you use an extension, the compiler will not know how to compile
+your code statically: technically, even if you tell the type checker what is the type of a dynamic
+variable, for example, it would not know how to compile it. Is it `getBinding('foo')`, `getProperty('foo')`,
+`delegate.getFoo()`,…? There's absolutely no direct way to tell the static compiler how to compile such
+code even if you use a type checking extension (that would, again, only give hints about the type).
+
+One possible solution for this particular example is to instruct the compiler to use <<mixed-mode,mixed mode compilation>>.
+The more advanced one is to use <<ast-xform-as-extension,AST transformations during type checking>> but it is far more
+complex.
+
+Type checking extensions allow you to help the type checker where it
+fails, but it also allow you to fail where it doesn’t. In that context,
+it makes sense to support extensions for `@CompileStatic` too. Imagine
+an extension that is capable of type checking SQL queries. In that case,
+the extension would be valid in both dynamic and static context, because
+without the extension, the code would still pass.
+
+[[mixed-mode]]
+=== Mixed mode compilation
+
+In the previous section, we highlighted the fact that you can activate type checking extensions with
+`@CompileStatic`. In that context, the type checker would not complain anymore about some unresolved variables or
+unknown method calls, but it would still wouldn't know how to compile them statically.
+
+Mixed mode compilation offers a third way, which is to instruct the compiler that whenever an unresolved variable
+or method call is found, then it should fall back to a dynamic mode. This is possible thanks to type checking extensions
+and a special `makeDynamic` call.
+
+To illustrate this, let's come back to the `Robot` example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_script,indent=0]
+----
+
+And let's try to activate our type checking extension using `@CompileStatic` instead of `@TypeChecked`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_setup_compilestatic,indent=0]
+----
+<1> Apply `@CompileStatic` transparently
+<2> Activate the type checking extension
+
+The script will run fine because the static compiler is told about the type of the `robot` variable, so it is capable
+of making a direct call to `move`. But before that, how did the compiler know how to get the `robot` variable? In fact
+by default, in a type checking extension, setting `handled=true` on an unresolved variable will automatically trigger
+a dynamic resolution, so in this case you don't have anything special to make the compiler use a mixed mode. However,
+let's slightly update our example, starting from the robot script:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_script_direct,indent=0]
+----
+
+Here you can notice that there is no reference to `robot` anymore. Our extension will not help then because we will not
+be able to instruct the compiler that `move` is done on a `Robot` instance. This example of code can be executed in a
+totally dynamic way thanks to the help of a gapi:groovy.util.DelegatingScript[]:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_setup_dynamic,indent=0]
+----
+<1> we configure the compiler to use a `DelegatingScript` as the base class
+<2> the script source needs to be parsed and will return an instance of `DelegatingScript`
+<3> we can then call `setDelegate` to use a `Robot` as the delegate of the script
+<4> then execute the script. `move` will be directly executed on the delegate
+
+If we want this to pass with `@CompileStatic`, we have to use a type checking extension, so let's update our configuration:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=example_robot_setup_compilestatic2,indent=0]
+----
+<1> apply `@CompileStatic` transparently
+<2> use an alternate type checking extension meant to recognize the call to `move`
+
+Then in the previous section we have learnt how to deal with unrecognized method calls, so we are able to write this
+extension:
+
+[source,groovy]
+.robotextension2.groovy
+-------------------------------------
+include::{projectdir}/src/spec/test-resources/robotextension2.groovy[tags=example_robot_extension,indent=0]
+-------------------------------------
+<1> if the call is a method call (not a static method call)
+<2> that this call is made on "implicit this" (no explicit `this.`)
+<3> that the method being called is `move`
+<4> and that the call is done with a single argument
+<5> and that argument is of type `int`
+<6> then tell the type checker that the call is valid
+<7> and that the return type of the call is `Robot`
+
+If you try to execute this code, then you could be surprised that it actually fails at runtime:
+
+----
+include::{projectdir}/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy[tags=robot_runtime_error_cs,indent=0]
+----
+
+The reason is very simple: while the type checking extension is sufficient for `@TypeChecked`, which does not involve
+static compilation, it is not enough for `@CompileStatic` which requires additional information. In this case, you told
+the compiler that the method existed, but you didn't explain to it *what* method it is in reality, and what is the
+receiver of the message (the delegate).
+
+Fixing this is very easy and just implies replacing the `newMethod` call with something else:
+
+[source,groovy]
+.robotextension3.groovy
+-------------------------------------
+include::{projectdir}/src/spec/test-resources/robotextension3.groovy[tags=example_robot_extension,indent=0]
+-------------------------------------
+<1> tell the compiler that the call should be make dynamic
+
+The `makeDynamic` call does 3 things:
+
+* it returns a virtual method just like `newMethod`
+* automatically sets the `handled` flag to `true` for you
+* but also marks the `call` to be done dynamically
+
+So when the compiler will have to generate bytecode for the call to `move`, since it is now marked as a dynamic call,
+it will fallback to the dynamic compiler and let it handle the call. And since the extension tells us that the return
+type of the dynamic call is a `Robot`, subsequent calls will be done statically!
+
+Some would wonder why the static compiler doesn't do this by default without an extension. It is a design decision:
+
+* if the code is statically compiled, we normally want type safety and best performance
+* so if unrecognized variables/method calls are made dynamic, you loose type safety, but also all support for typos at
+compile time!
+
+In short, if you want to have mixed mode compilation, it *has* to be explicit, through a type checking extension, so
+that the compiler, and the designer of the DSL, are totally aware of what they are doing.
+
+`makeDynamic` can be used on 3 kind of AST nodes:
+
+* a method node (`MethodNode`)
+* a variable (`VariableExpression`)
+* a property expression (`PropertyExpression`)
+
+If that is not enough, then it means that static compilation cannot be done directly and that you have to rely on AST
+transformations.
+
+[[ast-xform-as-extension]]
+=== Transforming the AST in an extension
+
+Type checking extensions look very attractive from an AST transformation design point of view: extensions have access
+to context like inferred types, which is often nice to have. And an extension has a direct access to the abstract
+syntax tree. Since you have access to the AST, there is nothing in theory that prevents
+you from modifying the AST. However, we do not recommend you to do so, unless you are an advanced AST transformation
+designer and well aware of the compiler internals:
+
+* First of all, you would explicitly break the contract of type checking, which is to annotate,
+and only annotate the AST. Type checking should *not* modify the AST tree because you wouldn’t be able to
+guarantee anymore that code without the _ at TypeChecked_ annotation
+behaves the same without the annotation.
+* If your extension is meant to work with _ at CompileStatic_, then you *can* modify the AST because
+this is indeed what _ at CompileStatic_ will eventually do. Static compilation doesn’t guarantee the same semantics at
+dynamic Groovy so there is effectively a difference between code compiled with _ at CompileStatic_ and code compiled
+with _ at TypeChecked_. It’s up to you to choose whatever strategy you want to update the AST, but probably
+using an AST transformation that runs before type checking is easier.
+* if you cannot rely on a transformation that kicks in before the type checker, then you must be *very* careful
+
+WARNING: The type checking phase is the last phase running in the compiler before bytecode generation. All other AST
+transformations run before that and the compiler does a very good job at "fixing" incorrect AST generated before the
+type checking phase. As soon as you perform a transformation during type checking, for example directly in a type
+checking extension, then you have to do all this work of generating a 100% compiler compliant abstract syntax tree by
+yourself, which can easily become complex. That's why we do not recommend to go that way if you are beginning with
+type checking extensions and AST transformations.
+
+=== Examples
+
+Examples of real life type checking extensions are easy to find. You can download the source code for Groovy and
+take a look at the
+https://github.com/groovy/groovy-core/blob/master/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy[TypeCheckingExtensionsTest]
+class which is linked to
+https://github.com/groovy/groovy-core/tree/master/src/test-resources/groovy/transform/stc[various extension scripts].
+
+But an example of the most complex type checking extension can be found in the link:markup-template-engine.html[Markup Template Engine]
+source code: this template engine relies on a type checking extension and AST transformations to transform templates into
+fully statically compiled code. Sources for this can be found
+https://github.com/groovy/groovy-core/tree/master/subprojects/groovy-templates/src/main/groovy/groovy/text/markup[here].
\ No newline at end of file
diff --git a/src/spec/doc/windows-nsis-installer.adoc b/src/spec/doc/windows-nsis-installer.adoc
index 6ca1a63..9c81a0a 100644
--- a/src/spec/doc/windows-nsis-installer.adoc
+++ b/src/spec/doc/windows-nsis-installer.adoc
@@ -11,11 +11,11 @@ The installer first copies the groovy files to where the user wants,
 
 image::assets/img/outdir.png[]
 
-then asks for permission to create a variable ++GROOVY_HOME++ and to add the respective bin directory (++%GROOVY_HOME%/bin++) to the path, if no reference to groovy already exists in it.
+then asks for permission to create a variable `GROOVY_HOME` and to add the respective bin directory (`%GROOVY_HOME%/bin` to the path, if no reference to groovy already exists in it.
 
 image::assets/img/variables.jpg[]
 
-The user can decide whether to put these into the user or system environment (on Win 95 and Win 98 this information is appended to the autoexec.bat instead) i.e., whether the installation will be for the current user or for all users. Then the installer checks for the existence of ++JAVA_HOME++. If it doesn't exist, a message box points out the potential problem.
+The user can decide whether to put these into the user or system environment (on Win 95 and Win 98 this information is appended to the autoexec.bat instead) i.e., whether the installation will be for the current user or for all users. Then the installer checks for the existence of `JAVA_HOME`. If it doesn't exist, a message box points out the potential problem.
 
 Next the user can decide whether or not to install the native launcher,
 
@@ -34,7 +34,7 @@ As you can see in the screen shots (they are clickable thumbnails), currently en
 
 Oh, and whatever you do, do not use the command line option -russel.
 
-The french translation has been contributed by Xavier Mehaut and Tugduall Grall, the spanisch translation by Andres Almiray, and the tranlation to brazilian portuguese has been provided by Marcos Silva Pereira.
+The french translation has been contributed by Xavier Mehaut and Tugduall Grall, the spanish translation by Andres Almiray, and the translation to brazilian portuguese has been provided by Marcos Silva Pereira.
 
 Thank you very much for your help.
 
diff --git a/src/spec/doc/working-with-collections.adoc b/src/spec/doc/working-with-collections.adoc
new file mode 100644
index 0000000..28d12db
--- /dev/null
+++ b/src/spec/doc/working-with-collections.adoc
@@ -0,0 +1,443 @@
+= Working with collections
+:gdk: http://www.groovy-lang.org/gdk.html[Groovy development kit]
+:java-util-list: http://docs.oracle.com/javase/8/docs/api/java/util/List.html[java.util.List]
+:java-lang-comparable: java.lang.Comparable
+
+Groovy provides native support for various collection types, including <<Collections-Lists,lists>>,
+<<Collections-Maps,maps>> or <<Collections-Ranges,ranges>>. Most of those are based on the Java
+collection types and decorated with additional methods found in the {gdk}.
+
+[[Collections-Lists]]
+== Lists
+
+=== List literals
+
+You can create lists as follows. Notice that `[]` is the empty list
+expression.
+
+[source,groovy]
+-------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_literals,indent=0]
+-------------------------------------
+
+Each list expression creates an implementation of {java-util-list}.
+
+Of course lists can be used as a source to construct another list:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_construct,indent=0]
+----------------------------------------------------------------------------
+
+
+A list is an ordered collection of objects:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_usecases,indent=0]
+----------------------------------------------------------------------------
+
+=== List as a boolean expression
+
+Lists can be evaluated as a `boolean` value:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_to_bool,indent=0]
+----------------------------------------------------------------------------
+
+=== Iterating on a list
+
+Iterating on elements of a list is usually done calling the `each` and `eachWithIndex` methods, which execute code on each
+item of a list:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_each,indent=0]
+----------------------------------------------------------------------------
+
+In addition to iterating, it is often useful to create a new list by transforming each of its elements into
+something else. This operation, often called mapping, is done in Groovy thanks to the `collect` method:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_collect,indent=0]
+----------------------------------------------------------------------------
+
+=== Manipulating lists
+
+[[List-Filtering]]
+==== Filtering and searching
+
+The {gdk} contains a lot of methods on collections that enhance
+the standard collections with pragmatic methods, some of which are illustrated here:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk1,indent=0]
+----------------------------------------------------------------------------
+
+And here is idiomatic Groovy code for finding the maximum and minimum in a collection:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk2,indent=0]
+----------------------------------------------------------------------------
+
+In addition to closures, you can use a `Comparator` to define the comparison criteria:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_comparator,indent=0]
+----------------------------------------------------------------------------
+
+==== Adding or removing elements
+
+We can use `[]` to assign a new empty list and `<<` to append items to it:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_leftshift,indent=0]
+----------------------------------------------------------------------------
+
+We can add to a list in many ways:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_add,indent=0]
+----------------------------------------------------------------------------
+
+It is however important that the `+` operator on a list is *not mutating*. Compared to `<<`, it will create a new
+list, which is often not what you want and can lead to performance issues.
+
+The {gdk} also contains methods allowing you to easily remove elements from a list by value:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk3,indent=0]
+----------------------------------------------------------------------------
+
+It is also possible to remove an element by referring to its index, in which case the list is mutated:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk4,indent=0]
+----------------------------------------------------------------------------
+
+In case you only want to remove the first element having the same value in a list, instead of removing all
+elements, you call call the `remove` method:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk5,indent=0]
+----------------------------------------------------------------------------
+
+And removing all the elements in a list can be done by calling the `clear` method:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk6,indent=0]
+----------------------------------------------------------------------------
+
+==== Set operations
+
+The {gdk} also includes methods making it easy to reason on sets:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_gdk7,indent=0]
+----------------------------------------------------------------------------
+
+==== Sorting
+
+Working with collections often implies sorting. Groovy offers a variety of options to sort lists,
+from using closures to comparators, as in the following examples:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_sort,indent=0]
+----------------------------------------------------------------------------
+
+==== Duplicating elements
+
+The {gdk} also takes advantage of operator overloading to provide methods allowing duplication of elements
+of a list:
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=list_multiply,indent=0]
+----------------------------------------------------------------------------
+
+[[Collections-Maps]]
+== Maps
+
+=== Map literals
+
+In Groovy, maps (also known as associative arrays) can be created using the map literal syntax: `[:]`:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_literal,indent=0]
+--------------------------------------------------
+
+Map keys are strings by default: `[a:1]` is equivalent to `['a':1]`. This can be confusing if you define a variable
+named `a` and that you want the *value* of `a` to be the key in your map. If this is the case, then you *must* escape
+the key by adding parenthesis, like in the following example:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_literal_gotcha,indent=0]
+--------------------------------------------------
+
+In addition to map literals, it is possible, to get a new copy of a map, to clone it:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_construct,indent=0]
+--------------------------------------------------
+
+The resulting map is a *shallow* copy of the original one, as illustrated in the previous example.
+
+=== Map property notation
+
+Maps also act like beans so you can use the property notation to get/set
+items inside the `Map` as long as the keys are strings which are valid
+Groovy identifiers:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_property,indent=0]
+--------------------------------------------------
+
+Note: by design `map.foo` will always look for the key `foo` in the map. This
+means `foo.class` will return `null` on a map that doesn't contain the `class` key. Should you really want to know
+the class, then you must use `getClass()`:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_property_gotcha,indent=0]
+--------------------------------------------------
+
+=== Iterating on maps
+
+As usual in the {gdk}, idiomatic iteration on maps makes use of the `each` and `eachWithIndex` methods.
+It's worth noting that maps created using the map literal notation are *ordered*, that is to say that if you iterate
+on map entries, it is guaranteed that the entries will be returned in the same order they were added in the map.
+
+[source,groovy]
+--------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_iteration,indent=0]
+--------------------------------------------------------------------------------
+
+=== Manipulating maps
+
+==== Adding or removing elements
+
+Adding an element to a map can be done either using the `put` method, the subscript operator or using `putAll`:
+
+[source,groovy]
+---------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_add,indent=0]
+---------------------
+
+Removing all the elements of a map can be done by calling the `clear` method:
+
+[source,groovy]
+---------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_gdk1,indent=0]
+---------------------
+
+Maps generated using the map literal syntax are using the object `equals` and `hashcode` methods. This means that
+you should *never* use an object which hash code is subject to change over time, or you wouldn't be able to get
+the associated value back.
+
+It is also worth noting that you should *never* use a `GString` as the key of a map, because the hash code of a `GString`
+is not the same as the hash code of an equivalent `String`:
+
+[source,groovy]
+---------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=gstring_gotcha,indent=0]
+---------------------
+
+[[JN1035-Maps-Collectionviewsofamap]]
+==== Keys, values and entries
+
+We can inspect the keys, values, and entries in a view:
+
+[source,groovy]
+-------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_views,indent=0]
+-------------------------------------------------------------------------
+
+Mutating values returned by the view (be it a map entry, a key or a value) is highly discouraged because success
+of the operation directly depends on the type of the map being manipulated. In particular, Groovy relies on collections
+from the JDK that in general make no guarantee that a collection can safely be manipulated through `keySet`, `entrySet`, or
+`values`.
+
+==== Filtering and searching
+
+The {gdk} contains filtering, searching and collecting methods similar to those found
+for <<List-Filtering,lists>>:
+
+[source,groovy]
+-----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_gdk2,indent=0]
+-----------------------------------------------------------------------------
+
+[[Maps-Grouping]]
+==== Grouping
+
+We can group a list into a map using some criteria:
+
+[source,groovy]
+----------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=map_gdk3,indent=0]
+----------------------------------------------------------------
+
+[[Collections-Ranges]]
+== Ranges
+
+Ranges allow you to create a list of sequential values. These can be
+used as `List` since
+http://docs.groovy-lang.org/latest/html/api/groovy/lang/Range.html[Range] extends
+{java-util-list}.
+
+Ranges defined with the `..` notation are inclusive (that is the list
+contains the from and to value).
+
+Ranges defined with the `..<` notation are half-open, they include the
+first value but not the last value.
+
+[source,groovy]
+----------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=intrange,indent=0]
+----------------------------------------------------------------------------
+
+Note that int ranges are implemented efficiently, creating a lightweight
+Java object containing a from and to value.
+
+Ranges can be used for any Java object which implements {java-lang-comparable}
+for comparison and also have methods `next()` and `previous()` to return the
+next / previous item in the range. For example, you can create a range of `String` elements:
+
+[source,groovy]
+--------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=stringrange,indent=0]
+--------------------------------------
+
+You can iterate on a range using a classic `for` loop:
+
+[source,groovy]
+----------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=range_for,indent=0]
+----------------------
+
+but alternatively you can achieve the same effect in a more Groovy idiomatic style, by iterating a range
+with `each` method:
+
+[source,groovy]
+----------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=range_each,indent=0]
+----------------------
+
+Ranges can be also used in the `switch` statement:
+
+[source,groovy]
+----------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=range_switch,indent=0]
+----------------------
+
+== Syntax enhancements for collections
+
+=== GPath support
+
+Thanks to the support of property notation for both lists and maps, Groovy provides syntactic sugar making it
+really easy to deal with nested collections, as illustrated in the following examples:
+
+[source,groovy]
+------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=gpath_support_1,indent=0]
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=gpath_support_2,indent=0]
+------------------------------------------------------------------------------
+
+=== Spread operator
+
+The spread operator can be used to "inline" a collection into another. It is syntactic sugar which often avoids calls
+to `putAll` and facilitates the realization of one-liners:
+
+[source,groovy]
+------------------------------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=gpath_support_3,indent=0]
+------------------------------------------------------------------------------
+
+[[Collections-Gettingefficientwiththestar-dotoperator]]
+=== The star-dot `*.' operator
+
+The "star-dot" operator is a shortcut operator allowing you to call a method or a property on all elements of a
+collection:
+
+[source,groovy]
+-------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=stardot_1,indent=0]
+
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=stardot_2,indent=0]
+-------------------------------------------------
+
+[[Collections-Slicingwiththesubscriptoperator]]
+=== Slicing with the subscript operator
+
+You can index into lists, arrays, maps using the subscript expression. It is interesting that strings
+are considered as special kinds of collections in that context:
+
+[source,groovy]
+--------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=subscript,indent=0]
+--------------------------------------------------
+
+Notice that you can use ranges to extract part of a collection:
+
+[source,groovy]
+-----------------------------------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=subscript_2,indent=0]
+-----------------------------------------------------------
+
+The subscript operator can be used to update an existing collection (for collection type which are not immutable):
+
+[source,groovy]
+---------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=subscript_3,indent=0]
+---------------------------------
+
+It is worth noting that negative indices are allowed, to extract more easily from the end of a collection:
+
+You can use negative indices to count from the end of the List, array,
+String etc.
+
+[source,groovy]
+--------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=subscript_4,indent=0]
+--------------------------------
+
+Eventually, if you use a backwards range (the starting index is greater than
+the end index), then the answer is reversed.
+
+[source,groovy]
+--------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithCollectionsTest.groovy[tags=subscript_5,indent=0]
+--------------------------------
+
+[[Collections-EnhancedCollectionMethods]]
+== Enhanced Collection Methods
+
+In addition to <<Collections-Lists,lists>>, <<Collections-Maps,maps>> or <<Collections-Ranges,ranges>>, Groovy offers
+a lot of additional methods for filtering, collecting, grouping, counting, ... which are directly available on either
+collections or more easily iterables.
+
+In particular, we invite you to read the {gdk} API docs and specifically:
+
+* methods added to `Iterable` can be found http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Iterable.html[here]
+* methods added to `Iterator` can be found http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Iterator.html[here]
+* methods added to `Collection` can be found http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Collection.html[here]
+* methods added to `List` can be found http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/List.html[here]
+* methods added to `Map` can be found http://docs.groovy-lang.org/latest/html/groovy-jdk/java/util/Map.html[here]
+
diff --git a/src/spec/doc/working-with-io.adoc b/src/spec/doc/working-with-io.adoc
new file mode 100644
index 0000000..2db3d77
--- /dev/null
+++ b/src/spec/doc/working-with-io.adoc
@@ -0,0 +1,279 @@
+= Working with IO
+
+Groovy provides a number of
+link:gdk.html[helper methods] for working
+with I/O. While you could use standard Java code in Groovy to deal with those,
+Groovy provides much more convenient ways to handle files, streams, readers, ...
+
+In particular, you should take a look at methods added to:
+
+* the `java.io.File` class : http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/File.html
+* the `java.io.InputStream` class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html
+* the `java.io.OutputStream` class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/OutputStream.html
+* the `java.io.Reader` class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Reader.html
+* the `java.io.Writer` class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/Writer.html
+* the `java.nio.file.Path` class: http://docs.groovy-lang.org/latest/html/groovy-jdk/java/nio/file/Path.html
+
+The following section focuses on sample idiomatic constructs using helper methods available above but is not meant
+to be a complete description of all available methods. For that, please read the link:gdk.html[GDK API].
+
+== Reading files
+
+As a first example, let's see how you would print all lines of a text file in Groovy:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=print_file_lines,indent=0]
+----
+
+The `eachLine` method is a method added to the `File` class automatically by Groovy and has many variants, for example
+if you need to know the line number, you can use this variant:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=print_file_lines2,indent=0]
+----
+
+If for whatever reason the an exception is thrown in the `eachLine` body, the method makes sure that the resource
+is properly closed. This is true for all I/O resource methods that Groovy adds.
+
+For example in some cases you will prefer to use a `Reader`, but still benefit from the automatic resource management
+from Groovy. In the next example, the reader *will* be closed even if the exception occurs:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=withreader_exception,indent=0]
+----
+
+Should you need to collect the lines of a text file into a list, you can do:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=collect_lines,indent=0]
+----
+
+Or you can even leverage the `as` operator to get the contents of the file into an array of lines:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=lines_as_strings,indent=0]
+----
+
+How many times did you have to get the contents of a file into a `byte[]` and how much code does it require? Groovy
+makes it very easy actually:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=file_bytes,indent=0]
+----
+
+Working with I/O is not limited to dealing with files. In fact, a lot of operations rely on input/output streams,
+hence why Groovy adds a lot of support methods to those, as you can see in the
+http://docs.groovy-lang.org/latest/html/groovy-jdk/java/io/InputStream.html[documentation].
+
+As an example, you can obtain an `InputStream` from a `File` very easily:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=newinputstream,indent=0]
+----
+
+However you can see that it requires you to deal with closing the inputstream. In Groovy it is in general a better
+idea to use the `withInputStream` idiom that will take care of that for you:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=withinputstream,indent=0]
+----
+
+== Writing files
+
+Of course in some cases you won't want to read but write a file. One of the options is to use a `Writer`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=withwriter_example,indent=0]
+----
+
+But for such a simple example, using the `<<` operator would have been enough:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=file_leftshift,indent=0]
+----
+
+Of course we do not always deal with text contents, so you could use the `Writer` or directly write bytes as in
+this example:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=file_setbytes,indent=0]
+----
+
+Of course you can also directly deal with output streams. For example, here is how you would create an output
+stream to write into a file:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=newoutputstream,indent=0]
+----
+
+However you can see that it requires you to deal with closing the output stream. Again it is in general a better
+idea to use the `withOutputStream` idiom that will handle the exceptions and close the stream in any case:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=withoutputstream,indent=0]
+----
+
+== Traversing file trees
+
+In scripting contexts it is a common task to traverse a file tree in order to find some specific files and do
+something with them. Groovy provides multiple methods to do this. For example you can perform something on all files
+of a directory:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=eachfile,indent=0]
+----
+<1> executes the closure code on each file found in the directory
+<2> executes the closure code on files in the directory matching the specified pattern
+
+Often you will have to deal with a deeper hierarchy of files, in which case you can use `eachFileRecurse`:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=eachfilerecurse,indent=0]
+----
+<1> executes the closure code on each file or directory found in the directory, recursively
+<2> executes the closure code only on files, but recursively
+
+For more complex traversal techniques you can use the `traverse` method, which requires you to set a special flag
+indicating what to do with the traversal:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=traverse,indent=0]
+----
+<1> if the current file is a directory and its name is `dir`, stop the traversal
+<2> otherwise print the file name and continue
+
+== Data and objects
+
+It is not uncommon to serialize data, in Java, using the `java.io.DataOutputStream` and
+`java.io.DataOutputStream` classes. Groovy will make it even easier to deal with them. For example, you could
+serialize data into a file and deserialize it using this code:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=data_in_out,indent=0]
+----
+
+And similarily, if the data you want to serialize implements the `Serializable` interface, you can proceed with
+an object output stream, as illustrated here:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=object_in_out,indent=0]
+----
+
+[[process-management]]
+== Executing External Processes
+
+The previous section described how easy it was to deal with files, readers or streams in Groovy. However in domains
+like system administration or devops it is often required to communicate with external processes.
+
+Groovy provides a simple way to execute command line processes. Simply
+write the command line as a string and call the `execute()` method.
+E.g., on a *nix machine (or a windows machine with appropriate *nix
+commands installed), you can execute this:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=process_list_files,indent=0]
+----
+<1> executes the `ls` command in an external process
+<2> consume the output of the command and retrieve the text
+
+The `execute()` method returns a `java.lang.Process` instance which will
+subsequently allow the in/out/err streams to be processed and the exit
+value from the process to be inspected etc.
+
+e.g. here is the same command as above but we will now process the
+resulting stream a line at a time:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=process_list_files_line_by_line,indent=0]
+----
+<1> executes the `ls` command in an external process
+<2> for each line of the input stream of the process
+<3> print the line
+
+It is worth noting that `in` corresponds to an input stream to the standard output of the command. `out` will refer
+to a stream where you can send data to the process (its standard input).
+
+Remember that many commands are shell built-ins and need special
+handling. So if you want a listing of files in a directory on a Windows
+machine and write:
+
+[source,groovy]
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=dir_windows,indent=0]
+----
+
+you will receive an `IOException` saying  _Cannot run program "dir":
+CreateProcess error=2, The system cannot find the file specified._
+
+This is because `dir` is built-in to the Windows shell (`cmd.exe`) and
+can’t be run as a simple executable. Instead, you will need to write:
+
+[source,groovy]
+----------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=dir_windows_fixed,indent=0]
+----------------------------------
+
+Also, because this functionality currently makes use of
+`java.lang.Process` undercover, the deficiencies of that class
+must be taken into consideration. In particular, the javadoc
+for this class says:
+
+________________________________________________________________________
+Because some native platforms only provide limited buffer size for
+standard input and output streams, failure to promptly write the input
+stream or read the output stream of the subprocess may cause the
+subprocess to block, and even deadlock
+________________________________________________________________________
+
+Because of this, Groovy provides some additional helper methods which
+make stream handling for processes easier.
+
+Here is how to gobble all of the output (including the error stream
+output) from your process:
+
+[source,groovy]
+----------------------------------
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=consumeoutput,indent=0]
+----------------------------------
+
+There are also variations of `consumeProcessOutput` that make use of `StringBuffer`, `InputStream`,
+`OutputStream` etc... For a complete list, please read the
+http://docs.groovy-lang.org/latest/html/groovy-jdk/java/lang/Process.html[GDK API for java.lang.Process]
+
+In addition, these is a `pipeTo` command (mapped to `|`
+to allow overloading) which lets the output stream of one process be fed
+into the input stream of another process.
+
+Here are some examples of use:
+
+[source,groovy]
+.Pipes in action
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=pipe_example_1,indent=0]
+----
+
+[source,groovy]
+.Consuming errors
+----
+include::{projectdir}/src/spec/test/gdk/WorkingWithIOSpecTest.groovy[tags=pipe_example_2,indent=0]
+----
diff --git a/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
index 32e83c0..cf31895 100644
--- a/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
+++ b/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
@@ -14,10 +14,9 @@
 # limitations under the License.
 #
 
-# tag::extension_descriptor[]
-moduleName=Test module for specifications
+# DO NOT REMOVE BELOW!
+# IT IS A WORKAROUND FOR 2 DESCRIPTORS ON CLASSPATH!
+moduleName=Test module
 moduleVersion=1.0-test
-extensionClasses=support.MaxRetriesExtension
-staticExtensionClasses=support.StaticStringExtension
-# end::extension_descriptor[]
-
+extensionClasses=support.MaxRetriesExtension,org.codehaus.groovy.runtime.m12n.TestStringExtension,org.codehaus.groovy.runtime.m12n.Groovy6496Extension
+staticExtensionClasses=support.StaticStringExtension,org.codehaus.groovy.runtime.m12n.TestStaticStringExtension
diff --git a/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModuleSpec b/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModuleSpec
new file mode 100644
index 0000000..90f76fe
--- /dev/null
+++ b/src/spec/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModuleSpec
@@ -0,0 +1,38 @@
+#
+# Copyright 2003-2014 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+#
+# Copyright 2003-2014 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+# tag::extension_descriptor[]
+moduleName=Test module for specifications
+moduleVersion=1.0-test
+extensionClasses=support.MaxRetriesExtension
+staticExtensionClasses=support.StaticStringExtension
+# end::extension_descriptor[]
diff --git a/src/spec/test-resources/aftermethodcall.groovy b/src/spec/test-resources/aftermethodcall.groovy
new file mode 100644
index 0000000..8b397f1
--- /dev/null
+++ b/src/spec/test-resources/aftermethodcall.groovy
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+// tag::event[]
+afterMethodCall { call ->
+    if (getTargetMethod(call).name=='toUpperCase') {
+        addStaticTypeError('Not allowed',call)
+        handled = true
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/aftervisitclass.groovy b/src/spec/test-resources/aftervisitclass.groovy
new file mode 100644
index 0000000..3b612da
--- /dev/null
+++ b/src/spec/test-resources/aftervisitclass.groovy
@@ -0,0 +1,26 @@
+import org.codehaus.groovy.ast.ClassNode
+
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+afterVisitClass { ClassNode classNode ->
+    def name = classNode.nameWithoutPackage
+    if (!(name[0] in 'A'..'Z')) {
+        addStaticTypeError("Class '${name}' doesn't start with an uppercase letter",classNode)
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/aftervisitmethod.groovy b/src/spec/test-resources/aftervisitmethod.groovy
new file mode 100644
index 0000000..1e9f325
--- /dev/null
+++ b/src/spec/test-resources/aftervisitmethod.groovy
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+beforeVisitMethod { methodNode ->
+    newScope {
+        methods = 0
+    }
+}
+
+onMethodSelection { expr, node ->
+    if (currentScope) {
+        currentScope.methods++
+    }
+}
+
+// tag::event[]
+afterVisitMethod { methodNode ->
+    scopeExit {
+        if (methods>2) {
+            addStaticTypeError("Method ${methodNode.name} contains more than 2 method calls", methodNode)
+        }
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/ambiguousmethods.groovy b/src/spec/test-resources/ambiguousmethods.groovy
new file mode 100644
index 0000000..ae6b0fb
--- /dev/null
+++ b/src/spec/test-resources/ambiguousmethods.groovy
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+ambiguousMethods { methods, origin ->
+    // choose the method which has an Integer as parameter type
+    methods.find { it.parameters.any { it.type == classNodeFor(Integer) } }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/beforemethodcall.groovy b/src/spec/test-resources/beforemethodcall.groovy
new file mode 100644
index 0000000..51a52db
--- /dev/null
+++ b/src/spec/test-resources/beforemethodcall.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+beforeMethodCall { call ->
+    if (isMethodCallExpression(call)
+            && call.methodAsString=='toUpperCase') {
+        addStaticTypeError('Not allowed',call)
+        handled = true
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/beforevisitclass.groovy b/src/spec/test-resources/beforevisitclass.groovy
new file mode 100644
index 0000000..bd8c611
--- /dev/null
+++ b/src/spec/test-resources/beforevisitclass.groovy
@@ -0,0 +1,26 @@
+import org.codehaus.groovy.ast.ClassNode
+
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+beforeVisitClass { ClassNode classNode ->
+    def name = classNode.nameWithoutPackage
+    if (!(name[0] in 'A'..'Z')) {
+        addStaticTypeError("Class '${name}' doesn't start with an uppercase letter",classNode)
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/beforevisitmethod.groovy b/src/spec/test-resources/beforevisitmethod.groovy
new file mode 100644
index 0000000..8ab58de
--- /dev/null
+++ b/src/spec/test-resources/beforevisitmethod.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+// tag::event[]
+beforeVisitMethod { methodNode ->
+    // tell the type checker we will handle the body by ourselves
+    handled = methodNode.name.startsWith('skip')
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/finish.groovy b/src/spec/test-resources/finish.groovy
new file mode 100644
index 0000000..23b1772
--- /dev/null
+++ b/src/spec/test-resources/finish.groovy
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+finish {
+    // this is after completion
+    // of all type checking
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/incompatibleassignment.groovy b/src/spec/test-resources/incompatibleassignment.groovy
new file mode 100644
index 0000000..7946dd1
--- /dev/null
+++ b/src/spec/test-resources/incompatibleassignment.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+incompatibleAssignment { lhsType, rhsType, expr ->
+    if (isBinaryExpression(expr) && isAssignment(expr.operation.type)) {
+        if (lhsType==classNodeFor(int) && rhsType==classNodeFor(Closure)) {
+            handled = true
+        }
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/methodnotfound.groovy b/src/spec/test-resources/methodnotfound.groovy
new file mode 100644
index 0000000..41ef10f
--- /dev/null
+++ b/src/spec/test-resources/methodnotfound.groovy
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+methodNotFound { receiver, name, argList, argTypes, call ->
+    // receiver is the inferred type of the receiver
+    // name is the name of the called method
+    // argList is the list of arguments the method was called with
+    // argTypes is the array of inferred types for each argument
+    // call is the method call for which we couldn’t find a target method
+    if (receiver==classNodeFor(String)
+            && name=='longueur'
+            && argList.size()==0) {
+        handled = true
+        return newMethod('longueur', classNodeFor(String))
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/newmethod.groovy b/src/spec/test-resources/newmethod.groovy
new file mode 100644
index 0000000..363f6f3
--- /dev/null
+++ b/src/spec/test-resources/newmethod.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+methodNotFound { receiver, name, argList, argTypes, call ->
+    // tag::newmethod[]
+    newMethod(name) {
+        // each time getReturnType on this method node will be called, this closure will be called!
+        println 'Type checker called me!'
+        lookupClassNodeFor(Foo) // return type
+    }
+    // end::newmethod[]
+}
\ No newline at end of file
diff --git a/src/spec/test-resources/onmethodselection.groovy b/src/spec/test-resources/onmethodselection.groovy
new file mode 100644
index 0000000..b0467d6
--- /dev/null
+++ b/src/spec/test-resources/onmethodselection.groovy
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+def count = 0
+// tag::event[]
+onMethodSelection { expr, node ->
+    if (node.declaringClass.name == 'java.lang.String') {
+        // calling a method on 'String'
+        // let’s perform additional checks!
+        if (++count>2) {
+            addStaticTypeError("You can use only 2 calls on String in your source code",expr)
+        }
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/robotextension.groovy b/src/spec/test-resources/robotextension.groovy
new file mode 100644
index 0000000..e6fe453
--- /dev/null
+++ b/src/spec/test-resources/robotextension.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import typing.Robot
+
+// tag::example_robot_extension[]
+unresolvedVariable { var ->
+    if ('robot'==var.name) {
+        storeType(var, classNodeFor(Robot))
+        handled = true
+    }
+}
+// end::example_robot_extension[]
\ No newline at end of file
diff --git a/src/spec/test-resources/robotextension2.groovy b/src/spec/test-resources/robotextension2.groovy
new file mode 100644
index 0000000..b9bbfe2
--- /dev/null
+++ b/src/spec/test-resources/robotextension2.groovy
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+import typing.Robot
+
+// tag::example_robot_extension[]
+methodNotFound { receiver, name, argList, argTypes, call ->
+    if (isMethodCallExpression(call)                        // <1>
+        && call.implicitThis                                // <2>
+        && 'move'==name                                     // <3>
+        && argTypes.length==1                               // <4>
+        && argTypes[0] == classNodeFor(int)                 // <5>
+    ) {
+        handled = true                                      // <6>
+        newMethod('move', classNodeFor(Robot))              // <7>
+    }
+}
+// end::example_robot_extension[]
\ No newline at end of file
diff --git a/src/spec/test-resources/robotextension3.groovy b/src/spec/test-resources/robotextension3.groovy
new file mode 100644
index 0000000..b9d3993
--- /dev/null
+++ b/src/spec/test-resources/robotextension3.groovy
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import typing.Robot
+
+// tag::example_robot_extension[]
+methodNotFound { receiver, name, argList, argTypes, call ->
+    if (isMethodCallExpression(call)
+        && call.implicitThis
+        && 'move'==name
+        && argTypes.length==1
+        && argTypes[0] == classNodeFor(int)
+    ) {
+        makeDynamic(call, classNodeFor(Robot))              // <1>
+    }
+}
+// end::example_robot_extension[]
\ No newline at end of file
diff --git a/src/spec/test-resources/scoping.groovy b/src/spec/test-resources/scoping.groovy
new file mode 100644
index 0000000..8ab2eb8
--- /dev/null
+++ b/src/spec/test-resources/scoping.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+setup {
+    // tag::newscope[]
+    def scope = newScope()
+    scope.secondPassChecks = []
+    //...
+    scope.secondPassChecks << { println 'executed later' }
+    // ...
+    // end::newscope[]
+}
+
+finish {
+    // tag::scopeexit[]
+    scopeExit {
+        secondPassChecks*.run() // execute deferred checks
+    }
+    // end::scopeexit[]
+}
+
diff --git a/src/spec/test-resources/scoping_alt.groovy b/src/spec/test-resources/scoping_alt.groovy
new file mode 100644
index 0000000..01bcd10
--- /dev/null
+++ b/src/spec/test-resources/scoping_alt.groovy
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+setup {
+    // tag::newscope[]
+    newScope {
+        secondPassChecks = []
+    }
+    // end::newscope[]
+    // tag::currentscope[]
+    //...
+    currentScope.secondPassChecks << { println 'executed later' }
+    // ...
+    // end::currentscope[]
+}
+
+finish {
+    // tag::scopeexit[]
+    scopeExit {
+        secondPassChecks*.run() // execute deferred checks
+    }
+    // end::scopeexit[]
+}
+
diff --git a/src/spec/test-resources/selfcheck.groovy b/src/spec/test-resources/selfcheck.groovy
new file mode 100644
index 0000000..fd765db
--- /dev/null
+++ b/src/spec/test-resources/selfcheck.groovy
@@ -0,0 +1,32 @@
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor
+import org.codehaus.groovy.transform.stc.TypeCheckingContext
+
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+assert context instanceof TypeCheckingContext
+assert typeCheckingVisitor instanceof StaticTypeCheckingVisitor
+assert generatedMethods instanceof Set
+
+// tag::classnodefor[]
+assert classNodeFor(String) instanceof ClassNode
+// end::classnodefor[]
+
+// tag::lookupclassnodefor[]
+assert lookupClassNodeFor('Foo') instanceof ClassNode
+// end::lookupclassnodefor[]
diff --git a/src/spec/test-resources/setup.groovy b/src/spec/test-resources/setup.groovy
new file mode 100644
index 0000000..674e888
--- /dev/null
+++ b/src/spec/test-resources/setup.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+setup {
+    // this is called before anything else
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/unresolvedattribute.groovy b/src/spec/test-resources/unresolvedattribute.groovy
new file mode 100644
index 0000000..00dd334
--- /dev/null
+++ b/src/spec/test-resources/unresolvedattribute.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+unresolvedAttribute { aex ->
+    if (getType(aex.objectExpression)==classNodeFor(String)) {
+        storeType(aex,classNodeFor(String))
+        handled = true
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/unresolvedproperty.groovy b/src/spec/test-resources/unresolvedproperty.groovy
new file mode 100644
index 0000000..5e26000
--- /dev/null
+++ b/src/spec/test-resources/unresolvedproperty.groovy
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+// tag::event[]
+unresolvedProperty { pexp ->
+    if ('longueur'==pexp.propertyAsString &&
+        getType(pexp.objectExpression)==classNodeFor(String)) {
+        storeType(pexp,classNodeFor(int))
+        handled = true
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test-resources/unresolvedvariable.groovy b/src/spec/test-resources/unresolvedvariable.groovy
new file mode 100644
index 0000000..edbe132
--- /dev/null
+++ b/src/spec/test-resources/unresolvedvariable.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// tag::event[]
+unresolvedVariable { var ->
+    if ('people' == var.name) {
+        storeType(var, classNodeFor(List))
+        handled = true
+    }
+}
+// end::event[]
\ No newline at end of file
diff --git a/src/spec/test/BaseScriptSpecTest.groovy b/src/spec/test/BaseScriptSpecTest.groovy
new file mode 100644
index 0000000..5a4d1b4
--- /dev/null
+++ b/src/spec/test/BaseScriptSpecTest.groovy
@@ -0,0 +1,139 @@
+import groovy.transform.CompileStatic
+
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+ at CompileStatic
+class BaseScriptSpecTest extends GroovyTestCase {
+    void testSimpleScript() {
+        def script = '''
+// tag::simple_script[]
+println 'Hello from Groovy'
+// end::simple_script[]
+assert (this instanceof Script)
+'''
+        def shell = new GroovyShell()
+        def o = shell.parse(script)
+        assert o instanceof Script
+    }
+
+    void testScriptWithBinding() {
+        // tag::integ_binding[]
+        def binding = new Binding()             // <1>
+        def shell = new GroovyShell(binding)    // <2>
+        binding.setVariable('x',1)              // <3>
+        binding.setVariable('y',3)
+        shell.evaluate 'z=2*x+y'                // <4>
+        assert binding.getVariable('z') == 5    // <5>
+        // end::integ_binding[]
+    }
+
+    void testBaseClassThroughConfig() {
+        assertScript '''import org.codehaus.groovy.control.CompilerConfiguration
+            // tag::baseclass_def[]
+            abstract class MyBaseClass extends Script {
+                String name
+                public void greet() { println "Hello, $name!" }
+            }
+            // end::baseclass_def[]
+
+            // tag::use_custom_conf[]
+            def config = new CompilerConfiguration()                                // <1>
+            config.scriptBaseClass = 'MyBaseClass'                                  // <2>
+            def shell = new GroovyShell(this.class.classLoader, config)             // <3>
+            shell.evaluate """
+                setName 'Judith'                                                    // <4>
+                greet()
+            """
+            // end::use_custom_conf[]
+        '''
+    }
+
+    void testBaseClassThroughBaseScript() {
+        assertScript '''
+            abstract class MyBaseClass extends Script {
+                String name
+                public void greet() { println "Hello, $name!" }
+            }
+
+            def shell = new GroovyShell(this.class.classLoader)
+            shell.evaluate """
+                // tag::use_basescript[]
+                import groovy.transform.BaseScript
+
+                @BaseScript MyBaseClass baseScript
+                setName 'Judith'
+                greet()
+                // end::use_basescript[]
+            """
+        '''
+
+        assertScript '''
+            abstract class MyBaseClass extends Script {
+                String name
+                public void greet() { println "Hello, $name!" }
+            }
+
+            def shell = new GroovyShell(this.class.classLoader)
+            shell.evaluate """
+                // tag::use_basescript_alt[]
+                @BaseScript(MyBaseClass)
+                import groovy.transform.BaseScript
+
+                setName 'Judith'
+                greet()
+                // end::use_basescript_alt[]
+            """
+        '''
+    }
+
+
+    void testBaseClassCustomRunMethod() {
+        assertScript '''import org.codehaus.groovy.control.CompilerConfiguration
+
+            // tag::custom_run_method[]
+            abstract class MyBaseClass extends Script {
+                int count
+                abstract void scriptBody()                              // <1>
+                def run() {
+                    count++                                             // <2>
+                    scriptBody()                                        // <3>
+                    count                                               // <4>
+                }
+            }
+            // end::custom_run_method[]
+
+
+            def conf = new CompilerConfiguration()
+            conf.scriptBaseClass = 'MyBaseClass'
+            def shell = new GroovyShell(this.class.classLoader, conf)
+
+            // tag::custom_run_eval[]
+            def result = shell.evaluate """
+                println 'Ok'
+            """
+            assert result == 1
+            // end::custom_run_eval[]
+
+            // tag::custom_run_parse[]
+            def script = shell.parse("println 'Ok'")
+            assert script.run() == 1
+            assert script.run() == 2
+            // end::custom_run_parse[]
+        '''
+    }
+
+}
diff --git a/src/spec/test/ClassTest.groovy b/src/spec/test/ClassTest.groovy
new file mode 100644
index 0000000..3daca44
--- /dev/null
+++ b/src/spec/test/ClassTest.groovy
@@ -0,0 +1,774 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+class ClassTest extends GroovyTestCase {
+
+    void testClassDefinition() {
+        assertScript '''
+            // tag::class_definition[]
+            class Person {                       //<1>
+
+                String name                      //<2>
+                Integer age
+
+                def increaseAge(Integer years) { //<3>
+                    this.age += years
+                }
+            }
+            // end::class_definition[]
+
+            // tag::class_instantiation[]
+            def p = new Person()
+            // end::class_instantiation[]
+
+        '''
+    }
+
+    void testInnerClass() {
+        assertScript '''
+            // tag::inner_class[]
+            class Outer {
+                private String privateStr
+
+                def callInnerMethod() {
+                    new Inner().methodA()       //<1>
+                }
+
+                class Inner {                   //<2>
+                    def methodA() {
+                        println "${privateStr}." //<3>
+                    }
+                }
+            }
+            // end::inner_class[]
+            def o = new Outer()
+        '''
+    }
+
+    void testInnerClass2() {
+        assertScript '''
+            // tag::inner_class2[]
+            class Outer2 {
+                private String privateStr = 'some string'
+
+                def startThread() {
+                   new Thread(new Inner2()).start()
+                }
+
+                class Inner2 implements Runnable {
+                    void run() {
+                        println "${privateStr}."
+                    }
+                }
+            }
+            // end::inner_class2[]
+            def o2 = new Outer2()
+        '''
+    }
+
+    void testAnonymousInnerClass() {
+        assertScript '''
+            // tag::anonymous_inner_class[]
+            class Outer3 {
+                private String privateStr = 'some string'
+
+                def startThread() {
+                    new Thread(new Runnable() {      //<1>
+                        void run() {
+                            println "${privateStr}."
+                        }
+                    }).start()                       //<2>
+                }
+            }
+            // end::anonymous_inner_class[]
+            def o3 = new Outer3()
+        '''
+    }
+
+    void testAbstractClass() {
+        assertScript '''
+            // tag::abstract_class[]
+            abstract class Abstract {         //<1>
+                String name
+
+                abstract def abstractMethod() //<2>
+
+                def concreteMethod() {
+                    println 'concrete'
+                }
+            }
+            // end::abstract_class[]
+            def ac = new Abstract() { def abstractMethod() {} }
+        '''
+    }
+
+    void testConstructorPositionalParameters() {
+        assertScript '''
+            // tag::constructor_positional_parameters[]
+            class PersonConstructor {
+                String name
+                Integer age
+
+                PersonConstructor(name, age) {          //<1>
+                    this.name = name
+                    this.age = age
+                }
+            }
+
+            def person1 = new PersonConstructor('Marie', 1)  //<2>
+            def person2 = ['Marie', 2] as PersonConstructor  //<3>
+            PersonConstructor person3 = ['Marie', 3]         //<4>
+            // end::constructor_positional_parameters[]
+
+            assert person1.name == 'Marie'
+            assert person2.name == 'Marie'
+            assert person3.name == 'Marie'
+        '''
+    }
+
+    void testConstructorNamedParameters() {
+        assertScript '''
+            // tag::constructor_named_parameters[]
+            class PersonWOConstructor {                                  //<1>
+                String name
+                Integer age
+            }
+
+            def person4 = new PersonWOConstructor()                      //<2>
+            def person5 = new PersonWOConstructor(name: 'Marie')         //<3>
+            def person6 = new PersonWOConstructor(age: 1)                //<4>
+            def person7 = new PersonWOConstructor(name: 'Marie', age: 2) //<5>
+            // end::constructor_named_parameters[]
+
+            assert person4.name == null
+        '''
+    }
+
+    void testInterfaceDefinition() {
+        assertScript '''
+            // tag::interface_def_1[]
+            interface Greeter {                                         // <1>
+                void greet(String name)                                 // <2>
+            }
+            // end::interface_def_1[]
+
+            // tag::class_implements[]
+            class SystemGreeter implements Greeter {                    // <1>
+                void greet(String name) {                               // <2>
+                    println "Hello $name"
+                }
+            }
+
+            def greeter = new SystemGreeter()
+            assert greeter instanceof Greeter                           // <3>
+            // end::class_implements[]
+            greeter.greet('Laura')
+
+            // tag::extended_interface[]
+            interface ExtendedGreeter extends Greeter {                 // <4>
+                void sayBye(String name)
+            }
+            // end::extended_interface[]
+
+            // tag::no_structural_interface[]
+            class DefaultGreeter {
+                void greet(String name) { println "Hello" }
+            }
+
+            greeter = new DefaultGreeter()
+            assert !(greeter instanceof Greeter)
+            // end::no_structural_interface[]
+
+            def coerced
+            // tag::interface_coercion[]
+            greeter = new DefaultGreeter()                              // <1>
+            coerced = greeter as Greeter                                // <2>
+            assert coerced instanceof Greeter                           // <3>
+            // end::interface_coercion[]
+        '''
+
+        def err = shouldFail {
+            assertScript '''
+                // tag::protected_forbidden[]
+                interface Greeter {
+                    protected void greet(String name)           // <1>
+                }
+                // end::protected_forbidden[]
+                1
+            '''
+        }
+        assert err.contains("Method 'greet' is protected but should be public in interface 'Greeter'")
+
+        err = shouldFail {
+            assertScript '''
+                // tag::private_forbidden[]
+                interface Greeter {
+                    private void greet(String name)
+                }
+                // end::private_forbidden[]
+                1
+            '''
+        }
+        assert err.contains("Method 'greet' is private but should be public in interface 'Greeter'")
+    }
+
+
+    void testFields() {
+        assertScript '''
+            // tag::field_declaration[]
+            class Data {
+                private int id                                  // <1>
+                protected String description                    // <2>
+                public static final boolean DEBUG = false       // <3>
+            }
+            // end::field_declaration[]
+            def d = new Data()
+        '''
+        assertScript '''
+            class IDGenerator { static int next() {0} }
+            // tag::field_initialization[]
+            class Data {
+                private String id = IDGenerator.next() // <1>
+                // ...
+            }
+            // end::field_initialization[]
+            new Data()
+        '''
+
+        assertScript '''
+            // tag::typing_fields[]
+            class BadPractice {
+                private mapping                         // <1>
+            }
+            class GoodPractice {
+                private Map<String,String> mapping      // <2>
+            }
+            // end::typing_fields[]
+            BadPractice
+        '''
+    }
+
+    void testProperties() {
+        assertScript '''
+            // tag::properties_definition[]
+            class Person {
+                String name                             // <1>
+                int age                                 // <2>
+            }
+            // end::properties_definition[]
+
+            assert Person.declaredFields.name.containsAll (['name','age'])
+            assert Person.getDeclaredMethod('getName')
+            assert Person.getDeclaredMethod('getAge')
+            assert Person.getDeclaredMethod('setName',String)
+            assert Person.getDeclaredMethod('setAge',int)
+        '''
+
+        assertScript '''
+            // tag::readonly_property[]
+            class Person {
+                final String name                   // <1>
+                final int age                       // <2>
+                Person(String name, int age) {
+                    this.name = name                // <3>
+                    this.age = age                  // <4>
+                }
+            }
+            // end::readonly_property[]
+
+            def p = new Person('Bob', 42)
+            assert Person.declaredFields.name.containsAll (['name','age'])
+            assert Person.getDeclaredMethod('getName')
+            assert Person.getDeclaredMethod('getAge')
+            try {
+                assert Person.getDeclaredMethod('setName',String) == null
+            } catch (NoSuchMethodException e) {
+
+            }
+            try {
+                assert Person.getDeclaredMethod('setAge',int) == null
+            } catch (NoSuchMethodException e) {
+
+            }
+
+        '''
+
+        assertScript '''
+            // tag::property_access[]
+            class Person {
+                String name
+                void name(String name) {
+                    this.name = "Wonder$name"       // <1>
+                }
+                String wonder() {
+                    this.name                       // <2>
+                }
+            }
+            def p = new Person()
+            p.name = 'Marge'                        // <3>
+            assert p.name == 'Marge'                // <4>
+            p.name('Marge')                         // <5>
+            assert p.wonder() == 'WonderMarge'      // <6>
+            // end::property_access[]
+        '''
+
+        assertScript '''
+            // tag::properties_meta[]
+            class Person {
+                String name
+                int age
+            }
+            def p = new Person()
+            assert p.properties.keySet().containsAll(['name','age'])
+            // end::properties_meta[]
+
+        '''
+
+        assertScript '''
+            // tag::pseudo_properties[]
+            class PseudoProperties {
+                // a pseudo property "name"
+                void setName(String name) {}
+                String getName() {}
+
+                // a pseudo read-only property "age"
+                int getAge() { 42 }
+
+                // a pseudo write-only property "groovy"
+                void setGroovy(boolean groovy) {  }
+            }
+            def p = new PseudoProperties()
+            p.name = 'Foo'                      // <1>
+            assert p.age == 42                  // <2>
+            p.groovy = true                     // <3>
+            // end::pseudo_properties[]
+        '''
+    }
+
+
+    void testDefineAnnotation() {
+        assertScript '''
+            // tag::define_annotation[]
+            @interface SomeAnnotation {}
+            // end::define_annotation[]
+            SomeAnnotation
+        '''
+    }
+
+    void testAnnotationMembers() {
+        assertScript '''
+            // tag::ann_member_string[]
+            @interface SomeAnnotation {
+                String value()                          // <1>
+            }
+            // end::ann_member_string[]
+            SomeAnnotation
+        '''
+        assertScript '''
+            // tag::ann_member_string_default[]
+            @interface SomeAnnotation {
+                String value() default 'something'      // <2>
+            }
+            // end::ann_member_string_default[]
+            SomeAnnotation
+        '''
+        assertScript '''
+            // tag::ann_member_int[]
+            @interface SomeAnnotation {
+                int step()                              // <3>
+            }
+            // end::ann_member_int[]
+            SomeAnnotation
+        '''
+       assertScript '''
+            // tag::ann_member_class[]
+            @interface SomeAnnotation {
+                Class appliesTo()                       // <4>
+            }
+            // end::ann_member_class[]
+            SomeAnnotation
+        '''
+       assertScript '''
+            // tag::ann_member_annotation[]
+            @interface SomeAnnotation {}
+            @interface SomeAnnotations {
+                SomeAnnotation[] value()                // <5>
+            }
+            // end::ann_member_annotation[]
+            SomeAnnotation
+        '''
+        assertScript '''
+            // tag::ann_member_enum[]
+            enum DayOfWeek { mon, tue, wed, thu, fri, sat, sun }
+            @interface Scheduled {
+                DayOfWeek dayOfWeek()                   // <6>
+            }
+            // end::ann_member_enum[]
+            Scheduled
+        '''
+    }
+
+    void testApplyAnnotation() {
+        assertScript '''
+            @interface SomeAnnotation {
+                int value() default 0
+            }
+
+            // tag::apply_annotation_1[]
+            @SomeAnnotation                 // <1>
+            void someMethod() {
+                // ...
+            }
+
+            @SomeAnnotation                 // <2>
+            class SomeClass {}
+
+            @SomeAnnotation String var      // <3>
+
+            // end::apply_annotation_1[]
+            someMethod()
+        '''
+
+        assertScript '''
+            // tag::annotation_value_set[]
+            @interface Page {
+                int statusCode()
+            }
+
+            @Page(statusCode=404)
+            void notFound() {
+                // ...
+            }
+            // end::annotation_value_set[]
+        '''
+
+        assertScript '''
+            // tag::annotation_value_set_option[]
+            @interface Page {
+                String value()
+                int statusCode() default 200
+            }
+
+            @Page(value='/home')                    // <1>
+            void home() {
+                // ...
+            }
+
+            @Page('/users')                         // <2>
+            void userList() {
+                // ...
+            }
+
+            @Page(value='error',statusCode=404)     // <3>
+            void notFound() {
+                // ...
+            }
+            // end::annotation_value_set_option[]
+        '''
+
+
+    }
+
+    void testAnnotationTarget() {
+        assertScript '''
+            // tag::ann_target[]
+            import java.lang.annotation.ElementType
+            import java.lang.annotation.Target
+
+            @Target([ElementType.METHOD, ElementType.TYPE])     // <1>
+            @interface SomeAnnotation {}                        // <2>
+            // end::ann_target[]
+            SomeAnnotation
+        '''
+    }
+
+    void testAnnotationRetention() {
+        assertScript '''
+            // tag::ann_retention[]
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+
+            @Retention(RetentionPolicy.SOURCE)                   // <1>
+            @interface SomeAnnotation {}                         // <2>
+            // end::ann_retention[]
+            SomeAnnotation
+        '''
+    }
+
+    void testClosureAsAnnotationValue() {
+        assertScript '''
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+            import java.lang.reflect.Modifier
+            // tag::closure_ann_def[]
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface OnlyIf {
+                Class value()                    // <1>
+            }
+            // end::closure_ann_def[]
+
+            // tag::closure_ann_example[]
+            class Tasks {
+                Set result = []
+                void alwaysExecuted() {
+                    result << 1
+                }
+                @OnlyIf({ jdk>=6 })
+                void supportedOnlyInJDK6() {
+                    result << 'JDK 6'
+                }
+                @OnlyIf({ jdk>=7 && windows })
+                void requiresJDK7AndWindows() {
+                    result << 'JDK 7 Windows'
+                }
+            }
+            // end::closure_ann_example[]
+
+            // tag::closure_ann_runner[]
+            class Runner {
+                static <T> T run(Class<T> taskClass) {
+                    def tasks = taskClass.newInstance()                                         // <1>
+                    def params = [jdk:6, windows: false]                                        // <2>
+                    tasks.class.declaredMethods.each { m ->                                     // <3>
+                        if (Modifier.isPublic(m.modifiers) && m.parameterTypes.length == 0) {   // <4>
+                            def onlyIf = m.getAnnotation(OnlyIf)                                // <5>
+                            if (onlyIf) {
+                                Closure cl = onlyIf.value().newInstance(tasks,tasks)            // <6>
+                                cl.delegate = params                                            // <7>
+                                if (cl()) {                                                     // <8>
+                                    m.invoke(tasks)                                             // <9>
+                                }
+                            } else {
+                                m.invoke(tasks)                                                 // <10>
+                            }
+                        }
+                    }
+                    tasks                                                                       // <11>
+                }
+            }
+            // end::closure_ann_runner[]
+
+            // tag::closure_ann_runner_exec[]
+            def tasks = Runner.run(Tasks)
+            assert tasks.result == [1, 'JDK 6'] as Set
+            // end::closure_ann_runner_exec[]
+        '''
+    }
+
+    void testAnnotationCollector() {
+        assertScript '''import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Service {}
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Transactional {}
+
+            // tag::transactionalservice_class[]
+            @Service
+            @Transactional
+            class MyTransactionalService {}
+            // end::transactionalservice_class[]
+
+            MyTransactionalService
+        '''
+
+        assertScript '''import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Service {}
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Transactional {}
+
+            // tag::metaann_ts[]
+            import groovy.transform.AnnotationCollector
+
+            @Service                                        // <1>
+            @Transactional                                  // <2>
+            @AnnotationCollector                            // <3>
+            @interface TransactionalService {
+            }
+            // end::metaann_ts[]
+
+            // tag::transactionalservice_class2[]
+            @TransactionalService                           // <1>
+            class MyTransactionalService {}
+            // end::transactionalservice_class2[]
+
+            // tag::annotations_expanded[]
+            def annotations = MyTransactionalService.annotations*.annotationType()
+            assert (Service in annotations)
+            assert (Transactional in annotations)
+            // end::annotations_expanded[]
+        '''
+    }
+
+    void testAnnotationCollectorWithParams() {
+        assertScript '''
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+            import groovy.transform.AnnotationCollector
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Timeout { int after() }
+            @Retention(RetentionPolicy.RUNTIME)
+            @interface Dangerous { String type() }
+
+            // tag::collected_ann_explosive[]
+            @Timeout(after=3600)
+            @Dangerous(type='explosive')
+            // end::collected_ann_explosive[]
+            // tag::collector_ann_explosive[]
+            @AnnotationCollector
+            public @interface Explosive {}
+            // end::collector_ann_explosive[]
+
+            // tag::example_bomb[]
+            @Explosive(after=0)                 // <1>
+            class Bomb {}
+            // end::example_bomb[]
+            @Explosive
+            class ReferenceBomb {}
+
+            assert Bomb.getAnnotation(Timeout).after() == 0
+            assert ReferenceBomb.getAnnotation(Timeout).after() == 3600
+        '''
+    }
+
+    void testAnnotationCollectorWithSameParamNames() {
+        assertScript '''
+
+import groovy.transform.AnnotationCollector
+
+import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+
+            // tag::collector_ann_same_values[]
+            @Retention(RetentionPolicy.RUNTIME)
+            public @interface Foo {
+               String value()                                   // <1>
+            }
+            @Retention(RetentionPolicy.RUNTIME)
+            public @interface Bar {
+                String value()                                  // <2>
+            }
+
+            @Foo
+            @Bar
+            @AnnotationCollector
+            public @interface FooBar {}                         // <3>
+
+            @Foo('a')
+            @Bar('b')
+            class Bob {}                                        // <4>
+
+            assert Bob.getAnnotation(Foo).value() == 'a'        // <5>
+            println Bob.getAnnotation(Bar).value() == 'b'       // <6>
+
+            @FooBar('a')
+            class Joe {}                                        // <7>
+            assert Joe.getAnnotation(Foo).value() == 'a'        // <8>
+            println Joe.getAnnotation(Bar).value() == 'a'       // <9>
+            // end::collector_ann_same_values[]
+        '''
+
+        def err = shouldFail '''
+
+            import groovy.transform.AnnotationCollector
+
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+
+            @Retention(RetentionPolicy.RUNTIME)
+            public @interface Foo {
+               String value()
+            }
+            @Retention(RetentionPolicy.RUNTIME)
+            public @interface Bar {
+                int value()
+            }
+
+            @Foo
+            @Bar
+            @AnnotationCollector
+            public @interface FooBar {}
+
+            @FooBar(666)
+            class Evil {}
+            Evil
+        '''
+        assert err =~ /Attribute 'value' should have type 'java.lang.String'; but found type 'int' in @Foo/
+    }
+
+    void testCustomProcessor() {
+        assertScript '''import groovy.transform.AnnotationCollector
+            import groovy.transform.CompileStatic
+            import groovy.transform.TypeCheckingMode
+
+            // tag::compiledynamic_naive[]
+            @CompileStatic(TypeCheckingMode.SKIP)
+            @AnnotationCollector
+            public @interface CompileDynamic {}
+            // end::compiledynamic_naive[]
+
+            @CompileDynamic
+            class Foo {}
+            Foo
+        '''
+
+        assertScript '''import groovy.transform.AnnotationCollector
+            import groovy.transform.CompileStatic
+            import groovy.transform.TypeCheckingMode
+            import org.codehaus.groovy.ast.AnnotatedNode
+            import org.codehaus.groovy.ast.AnnotationNode
+            import org.codehaus.groovy.ast.ClassHelper
+            import org.codehaus.groovy.ast.ClassNode
+            import org.codehaus.groovy.ast.expr.ClassExpression
+            import org.codehaus.groovy.ast.expr.PropertyExpression
+            import org.codehaus.groovy.control.SourceUnit
+            import org.codehaus.groovy.transform.AnnotationCollectorTransform
+
+            // tag::compiledynamic_def_fixed[]
+            @AnnotationCollector(processor = "org.codehaus.groovy.transform.CompileDynamicProcessor")
+            public @interface CompileDynamic {
+            }
+            // end::compiledynamic_def_fixed[]
+
+            // tag::compiledynamic_processor[]
+            @CompileStatic                                                                  // <1>
+            class CompileDynamicProcessor extends AnnotationCollectorTransform {            // <2>
+                private static final ClassNode CS_NODE = ClassHelper.make(CompileStatic)    // <3>
+                private static final ClassNode TC_NODE = ClassHelper.make(TypeCheckingMode) // <4>
+
+                List<AnnotationNode> visit(AnnotationNode collector,                        // <5>
+                                           AnnotationNode aliasAnnotationUsage,             // <6>
+                                           AnnotatedNode aliasAnnotated,                    // <7>
+                                           SourceUnit source) {                             // <8>
+                    def node = new AnnotationNode(CS_NODE)                                  // <9>
+                    def enumRef = new PropertyExpression(
+                        new ClassExpression(TC_NODE), "SKIP")                               // <10>
+                    node.addMember("value", enumRef)                                        // <11>
+                    Collections.singletonList(node)                                         // <12>
+                }
+            }
+            // end::compiledynamic_processor[]
+
+            @CompileDynamic
+            class Foo {}
+            Foo
+        '''
+    }
+}
diff --git a/src/spec/test/ClosuresSpecTest.groovy b/src/spec/test/ClosuresSpecTest.groovy
new file mode 100644
index 0000000..890ddff
--- /dev/null
+++ b/src/spec/test/ClosuresSpecTest.groovy
@@ -0,0 +1,520 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ClosuresSpecTest extends GroovyTestCase {
+    static void sink(Closure cl) {}
+
+    void testClosureSyntax() {
+        sink
+                // tag::closure_syntax_1[]
+                { item++ }                                          // <1>
+                // end::closure_syntax_1[]
+        sink
+                // tag::closure_syntax_1bis[]
+                { -> item++ }                                       // <2>
+                // end::closure_syntax_1bis[]
+        sink
+                // tag::closure_syntax_2[]
+                { println it }                                      // <3>
+                // end::closure_syntax_2[]
+
+        sink
+                // tag::closure_syntax_3[]
+                { it -> println it }                                // <4>
+                // end::closure_syntax_3[]
+
+        sink
+                // tag::closure_syntax_4[]
+                { name -> println name }                            // <5>
+                // end::closure_syntax_4[]
+
+        sink
+                // tag::closure_syntax_5[]
+                { String x, int y ->                                // <6>
+                    println "hey ${x} the value is ${y}"
+                }
+                // end::closure_syntax_5[]
+
+        sink
+                // tag::closure_syntax_6[]
+                { reader ->                                         // <7>
+                    def line = reader.readLine()
+                    line.trim()
+                }
+                // end::closure_syntax_6[]
+    }
+
+    void testAssignClosureToAVariable() {
+        // tag::closure_is_an_instance_of_Closure[]
+        def listener = { e -> println "Clicked on $e.source" }      // <1>
+        assert listener instanceof Closure
+        Closure callback = { println 'Done!' }                      // <2>
+        Closure<Boolean> isTextFile = {
+            File it -> it.name.endsWith('.txt')                     // <3>
+        }
+        // end::closure_is_an_instance_of_Closure[]
+    }
+
+    void testCallClosure() {
+        // tag::closure_call_1[]
+        def code = { 123 }
+        // end::closure_call_1[]
+        // tag::closure_call_1_direct[]
+        assert code() == 123
+        // end::closure_call_1_direct[]
+        // tag::closure_call_1_explicit[]
+        assert code.call() == 123
+        // end::closure_call_1_explicit[]
+
+        // tag::closure_call_2[]
+        def isOdd = { int i-> i%2 == 1 }                            // <1>
+        assert isOdd(3) == true                                     // <2>
+        assert isOdd.call(2) == false                               // <3>
+
+        def isEven = { it%2 == 0 }                                  // <4>
+        assert isEven(3) == false                                   // <5>
+        assert isEven.call(2) == true                               // <6>
+        // end::closure_call_2[]
+    }
+
+    void testClosureParameters() {
+        // tag::closure_param_declaration[]
+        def closureWithOneArg = { str -> str.toUpperCase() }
+        assert closureWithOneArg('groovy') == 'GROOVY'
+
+        def closureWithOneArgAndExplicitType = { String str -> str.toUpperCase() }
+        assert closureWithOneArgAndExplicitType('groovy') == 'GROOVY'
+
+        def closureWithTwoArgs = { a,b -> a+b }
+        assert closureWithTwoArgs(1,2) == 3
+
+        def closureWithTwoArgsAndExplicitTypes = { int a, int b -> a+b }
+        assert closureWithTwoArgsAndExplicitTypes(1,2) == 3
+
+        def closureWithTwoArgsAndOptionalTypes = { a, int b -> a+b }
+        assert closureWithTwoArgsAndOptionalTypes(1,2) == 3
+
+        def closureWithTwoArgAndDefaultValue = { int a, int b=2 -> a+b }
+        assert closureWithTwoArgAndDefaultValue(1) == 3
+        // end::closure_param_declaration[]
+    }
+
+    void testImplicitIt() {
+        assertScript '''
+        // tag::implicit_it[]
+        def greeting = { "Hello, $it!" }
+        assert greeting('Patrick') == 'Hello, Patrick!'
+        // end::implicit_it[]
+        '''
+
+        assertScript '''
+        // tag::implicit_it_equiv[]
+        def greeting = { it -> "Hello, $it!" }
+        assert greeting('Patrick') == 'Hello, Patrick!'
+        // end::implicit_it_equiv[]
+        '''
+
+        assertScript '''
+        // tag::closure_no_arg_def[]
+        def magicNumber = { -> 42 }
+        // end::closure_no_arg_def[]
+        try {
+            // tag::closure_no_arg_fail[]
+            // this call will fail because the closure doesn't accept any argument
+            magicNumber(11)
+            // end::closure_no_arg_fail[]
+            assert false
+        } catch (MissingMethodException) {
+        }
+        '''
+    }
+
+    void testClosureVargs() {
+        // tag::closure_vargs[]
+        def concat1 = { String... args -> args.join('') }           // <1>
+        assert concat1('abc','def') == 'abcdef'                     // <2>
+        def concat2 = { String[] args -> args.join('') }            // <3>
+        assert concat2('abc', 'def') == 'abcdef'
+
+        def multiConcat = { int n, String... args ->                // <4>
+            args.join('')*n
+        }
+        assert multiConcat(2, 'abc','def') == 'abcdefabcdef'
+        // end::closure_vargs[]
+
+    }
+
+    void testThisObject() {
+        assertScript '''
+        // tag::closure_this[]
+        class Enclosing {
+            void run() {
+                def whatIsThisObject = { getThisObject() }          // <1>
+                assert whatIsThisObject() == this                   // <2>
+                def whatIsThis = { this }                           // <3>
+                assert whatIsThis() == this                         // <4>
+            }
+        }
+        class EnclosedInInnerClass {
+            class Inner {
+                Closure cl = { this }                               // <5>
+            }
+            void run() {
+                def inner = new Inner()
+                assert inner.cl() == inner                          // <6>
+            }
+        }
+        class NestedClosures {
+            void run() {
+                def nestedClosures = {
+                    def cl = { this }                               // <7>
+                    cl()
+                }
+                assert nestedClosures() == this                     // <8>
+            }
+        }
+        // end::closure_this[]
+        new Enclosing().run()
+        new EnclosedInInnerClass().run()
+        new NestedClosures().run()
+'''
+        assertScript '''
+            // tag::closure_this_call[]
+            class Person {
+                String name
+                int age
+                String toString() { "$name is $age years old" }
+
+                String dump() {
+                    def cl = {
+                        String msg = this.toString()               // <1>
+                        println msg
+                        msg
+                    }
+                    cl()
+                }
+            }
+            def p = new Person(name:'Janice', age:74)
+            assert p.dump() == 'Janice is 74 years old'
+            // end::closure_this_call[]
+        '''
+    }
+
+    void testOwner() {
+        assertScript '''
+        // tag::closure_owner[]
+        class Enclosing {
+            void run() {
+                def whatIsOwnerMethod = { getOwner() }               // <1>
+                assert whatIsOwnerMethod() == this                   // <2>
+                def whatIsOwner = { owner }                          // <3>
+                assert whatIsOwner() == this                         // <4>
+            }
+        }
+        class EnclosedInInnerClass {
+            class Inner {
+                Closure cl = { owner }                               // <5>
+            }
+            void run() {
+                def inner = new Inner()
+                assert inner.cl() == inner                           // <6>
+            }
+        }
+        class NestedClosures {
+            void run() {
+                def nestedClosures = {
+                    def cl = { owner }                               // <7>
+                    cl()
+                }
+                assert nestedClosures() == nestedClosures            // <8>
+            }
+        }
+        // end::closure_owner[]
+        new Enclosing().run()
+        new EnclosedInInnerClass().run()
+        new NestedClosures().run()
+'''
+    }
+
+    void testClosureDelegate() {
+        assertScript '''
+        // tag::delegate_is_owner[]
+        class Enclosing {
+            void run() {
+                def cl = { getDelegate() }                          // <1>
+                def cl2 = { delegate }                              // <2>
+                assert cl() == cl2()                                // <3>
+                assert cl() == this                                 // <4>
+                def enclosed = {
+                    { -> delegate }.call()                          // <5>
+                }
+                assert enclosed() == enclosed                       // <6>
+            }
+        }
+        // end::delegate_is_owner[]
+        new Enclosing().run()
+        '''
+
+        assertScript '''
+            // tag::change_delegate_classes[]
+            class Person {
+                String name
+            }
+            class Thing {
+                String name
+            }
+
+            def p = new Person(name: 'Norman')
+            def t = new Thing(name: 'Teapot')
+
+            // end::change_delegate_classes[]
+
+            // tag::change_delegate_closure[]
+            def upperCasedName = { delegate.name.toUpperCase() }
+            // end::change_delegate_closure[]
+
+            // tag::change_delegate_asserts[]
+            upperCasedName.delegate = p
+            assert upperCasedName() == 'NORMAN'
+            upperCasedName.delegate = t
+            assert upperCasedName() == 'TEAPOT'
+            // end::change_delegate_asserts[]
+
+            // tag::delegate_alernative[]
+            def target = p
+            def upperCasedNameUsingVar = { target.name.toUpperCase() }
+            assert upperCasedNameUsingVar() == 'NORMAN'
+            // end::delegate_alernative[]
+
+        '''
+    }
+
+    void testDelegationStrategy() {
+        assertScript '''
+                // tag::delegation_strategy_intro[]
+                class Person {
+                    String name
+                }
+                def p = new Person(name:'Igor')
+                def cl = { name.toUpperCase() }                 // <1>
+                cl.delegate = p                                 // <2>
+                assert cl() == 'IGOR'                           // <3>
+                // end::delegation_strategy_intro[]
+            '''
+    }
+
+    void testOwnerFirst() {
+        assertScript '''
+            // tag::closure_owner_first[]
+            class Person {
+                String name
+                def pretty = { "My name is $name" }             // <1>
+                String toString() {
+                    pretty()
+                }
+            }
+            class Thing {
+                String name                                     // <2>
+            }
+
+            def p = new Person(name: 'Sarah')
+            def t = new Thing(name: 'Teapot')
+
+            assert p.toString() == 'My name is Sarah'           // <3>
+            p.pretty.delegate = t                               // <4>
+            assert p.toString() == 'My name is Sarah'           // <5>
+            // end::closure_owner_first[]
+
+            // tag::closure_delegate_first[]
+            p.pretty.resolveStrategy = Closure.DELEGATE_FIRST
+            assert p.toString() == 'My name is Teapot'
+            // end::closure_delegate_first[]
+        '''
+    }
+
+    void testDelegateOnly() {
+        assertScript '''
+            // tag::delegate_only[]
+            class Person {
+                String name
+                int age
+                def fetchAge = { age }
+            }
+            class Thing {
+                String name
+            }
+
+            def p = new Person(name:'Jessica', age:42)
+            def t = new Thing(name:'Printer')
+            def cl = p.fetchAge
+            cl.delegate = p
+            assert cl() == 42
+            cl.delegate = t
+            assert cl() == 42
+            cl.resolveStrategy = Closure.DELEGATE_ONLY
+            cl.delegate = p
+            assert cl() == 42
+            cl.delegate = t
+            try {
+            cl()
+                assert false
+            } catch (MissingPropertyException ex) {
+                // "age" is not defined on the delegate
+            }
+            // end::delegate_only[]
+        '''
+    }
+
+    void testGStringEager() {
+        // tag::gstring_eager_intro[]
+        def x = 1
+        def gs = "x = ${x}"
+        assert gs == 'x = 1'
+        // end::gstring_eager_intro[]
+        /* do not uncomment, this is used in documentation!
+        // tag::gstring_eager_outro[]
+        x = 2
+        assert gs == 'x = 2'
+        // end::gstring_eager_outro[]
+        */
+        x = 2
+        assert gs == 'x = 1'
+    }
+
+    void testGStringLazy() {
+        // tag::gstring_lazy[]
+        def x = 1
+        def gs = "x = ${-> x}"
+        assert gs == 'x = 1'
+
+        x = 2
+        assert gs == 'x = 2'
+        // end::gstring_lazy[]
+    }
+
+    void testGStringWithMutation() {
+        assertScript '''
+            // tag::gstring_mutation[]
+            class Person {
+                String name
+                String toString() { name }          // <1>
+            }
+            def sam = new Person(name:'Sam')        // <2>
+            def lucy = new Person(name:'Lucy')      // <3>
+            def p = sam                             // <4>
+            def gs = "Name: ${p}"                   // <5>
+            assert gs == 'Name: Sam'                // <6>
+            p = lucy                                // <7>
+            assert gs == 'Name: Sam'                // <8>
+            sam.name = 'Lucy'                       // <9>
+            assert gs == 'Name: Lucy'               // <10>
+            // end::gstring_mutation[]
+        '''
+    }
+
+    void testGStringWithoutMutation() {
+        assertScript '''
+            // tag::gstring_no_mutation[]
+            class Person {
+                String name
+                String toString() { name }
+            }
+            def sam = new Person(name:'Sam')
+            def lucy = new Person(name:'Lucy')
+            def p = sam
+            // Create a GString with lazy evaluation of "p"
+            def gs = "Name: ${-> p}"
+            assert gs == 'Name: Sam'
+            p = lucy
+            assert gs == 'Name: Lucy'
+            // end::gstring_no_mutation[]
+        '''
+    }
+
+    void testLeftCurry() {
+        // tag::left_curry[]
+        def nCopies = { int n, String str -> str*n }    // <1>
+        def twice = nCopies.curry(2)                    // <2>
+        assert twice('bla') == 'blabla'                 // <3>
+        assert twice('bla') == nCopies(2, 'bla')        // <4>
+        // end::left_curry[]
+    }
+
+    void testRightCurry() {
+        // tag::right_curry[]
+        def nCopies = { int n, String str -> str*n }    // <1>
+        def blah = nCopies.rcurry('bla')                // <2>
+        assert blah(2) == 'blabla'                      // <3>
+        assert blah(2) == nCopies(2, 'bla')             // <4>
+        // end::right_curry[]
+    }
+
+    void testNCurry() {
+        // tag::ncurry[]
+        def volume = { double l, double w, double h -> l*w*h }      // <1>
+        def fixedWidthVolume = volume.ncurry(1, 2d)                 // <2>
+        assert volume(3d, 2d, 4d) == fixedWidthVolume(3d, 4d)       // <3>
+        def fixedWidthAndHeight = volume.ncurry(1, 2d, 4d)          // <4>
+        assert volume(3d, 2d, 4d) == fixedWidthAndHeight(3d)        // <5>
+        // end::ncurry[]
+    }
+
+    void testMemoize() {
+        // tag::naive_fib[]
+        def fib
+        fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }
+        assert fib(15) == 610 // slow!
+        // end::naive_fib[]
+        // tag::memoized_fib[]
+        fib = { long n -> n<2?n:fib(n-1)+fib(n-2) }.memoize()
+        assert fib(25) == 75025 // fast!
+        // end::memoized_fib[]
+    }
+
+    void testComposition() {
+        // tag::closure_composition[]
+        def plus2  = { it + 2 }
+        def times3 = { it * 3 }
+
+        def times3plus2 = plus2 << times3
+        assert times3plus2(3) == 11
+        assert times3plus2(4) == plus2(times3(4))
+
+        def plus2times3 = times3 << plus2
+        assert plus2times3(3) == 15
+        assert plus2times3(5) == times3(plus2(5))
+
+        // reverse composition
+        assert times3plus2(3) == (times3 >> plus2)(3)
+        // end::closure_composition[]
+
+    }
+
+    void testTrampoline() {
+        // tag::trampoline[]
+        def factorial
+        factorial = { int n, def accu = 1G ->
+            if (n < 2) return accu
+            factorial.trampoline(n - 1, n * accu)
+        }
+        factorial = factorial.trampoline()
+
+        assert factorial(1)    == 1
+        assert factorial(3)    == 1 * 2 * 3
+        assert factorial(1000) // == 402387260.. plus another 2560 digits
+        // end::trampoline[]
+    }
+}
diff --git a/src/spec/test/CodeGenerationASTTransformsTest.groovy b/src/spec/test/CodeGenerationASTTransformsTest.groovy
index cf4c53e..2b92780 100644
--- a/src/spec/test/CodeGenerationASTTransformsTest.groovy
+++ b/src/spec/test/CodeGenerationASTTransformsTest.groovy
@@ -128,6 +128,27 @@ assert p.toString() == 'Person(Jack, Nicholson, Id(1))'
         assertScript '''
 import groovy.transform.ToString
 
+// tag::tostring_example_includeSuperProperties[]
+
+class Person {
+    String name
+}
+
+ at ToString(includeSuperProperties = true, includeNames = true)
+class BandMember extends Person {
+    String bandName
+}
+
+def bono = new BandMember(name:'Bono', bandName: 'U2').toString()
+
+assert bono.toString() == 'BandMember(bandName:U2, name:Bono)'
+// end::tostring_example_includeSuperProperties[]
+
+'''
+
+        assertScript '''
+import groovy.transform.ToString
+
 // tag::tostring_example_ignoreNulls[]
 @ToString(ignoreNulls=true)
 class Person {
@@ -445,7 +466,7 @@ assert p2.toString() == 'Jack Nicholson: Actor'
 '''
 
         assertScript '''
-// tag::tupleconstructor_example_includeSuperProperties[]
+// tag::tupleconstructor_example_callSuper[]
 import groovy.transform.TupleConstructor
 
 class Base {
@@ -473,7 +494,7 @@ assert p1.firstName == p2.firstName
 assert p1.lastName == p2.lastName
 assert p1.toString() == 'Jack Nicholson: null'
 assert p2.toString() == 'Jack Nicholson: actor'
-// end::tupleconstructor_example_includeSuperProperties[]
+// end::tupleconstructor_example_callSuper[]
 '''
     }
 
@@ -557,6 +578,42 @@ new CustomException(new RuntimeException())
 // new CustomException("A custom message", new RuntimeException(), false, true)
 // end::inheritconstructors_simple[]
 '''
+        assertScript '''
+import groovy.transform.InheritConstructors
+import java.lang.annotation.*
+// tag::inheritconstructors_constructor_annotations[]
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target([ElementType.CONSTRUCTOR])
+public @interface ConsAnno {}
+
+class Base {
+  @ConsAnno Base() {}
+}
+
+ at InheritConstructors(constructorAnnotations=true)
+class Child extends Base {}
+
+assert Child.constructors[0].annotations[0].annotationType().name == 'ConsAnno'
+// end::inheritconstructors_constructor_annotations[]
+'''
+        assertScript '''
+import groovy.transform.InheritConstructors
+import java.lang.annotation.*
+// tag::inheritconstructors_parameter_annotations[]
+ at Retention(RetentionPolicy.RUNTIME)
+ at Target([ElementType.PARAMETER])
+public @interface ParamAnno {}
+
+class Base {
+  Base(@ParamAnno String name) {}
+}
+
+ at InheritConstructors(parameterAnnotations=true)
+class Child extends Base {}
+
+assert Child.constructors[0].parameterAnnotations[0][0].annotationType().name == 'ParamAnno'
+// end::inheritconstructors_parameter_annotations[]
+'''
     }
 
     void testIndexedProperty() {
diff --git a/src/spec/test/CoercionTest.groovy b/src/spec/test/CoercionTest.groovy
index 98d42c7..ba85dfb 100644
--- a/src/spec/test/CoercionTest.groovy
+++ b/src/spec/test/CoercionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class CoercionTest extends GroovyTestCase {
 
     void testStringToEnumValue() {
diff --git a/src/spec/test/CompilerDirectivesASTTransformsTest.groovy b/src/spec/test/CompilerDirectivesASTTransformsTest.groovy
index c7c9e26..d8b8f21 100644
--- a/src/spec/test/CompilerDirectivesASTTransformsTest.groovy
+++ b/src/spec/test/CompilerDirectivesASTTransformsTest.groovy
@@ -113,5 +113,21 @@ class Person {
 // end::packagescope_property_javalike[]
 assert Modifier.toString(Person.getDeclaredField('name').modifiers)==''
 '''
+
+        assertScript '''import groovy.transform.PackageScope
+import java.lang.reflect.Modifier
+// tag::packagescope_property_usingtarget[]
+import static groovy.transform.PackageScopeTarget.FIELDS
+ at PackageScope(FIELDS)
+class Person {
+  String name     // not a property, package protected
+  Date dob        // not a property, package protected
+  private int age // explicit modifier, so won't be touched
+}
+// end::packagescope_property_usingtarget[]
+assert Modifier.toString(Person.getDeclaredField('name').modifiers)==''
+assert Modifier.toString(Person.getDeclaredField('dob').modifiers)==''
+assert Modifier.toString(Person.getDeclaredField('age').modifiers)=='private'
+'''
     }
 }
diff --git a/src/spec/test/CustomizersTest.groovy b/src/spec/test/CustomizersTest.groovy
index 689c932..73d3538 100644
--- a/src/spec/test/CustomizersTest.groovy
+++ b/src/spec/test/CustomizersTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.transform.ConditionalInterrupt
 import groovy.util.logging.Log
 import org.codehaus.groovy.ast.ClassNode
@@ -55,7 +70,7 @@ class CustomizersTest extends GroovyTestCase {
         // "aliases" import
         icz.addImport('CHM', 'java.util.concurrent.ConcurrentHashMap')
         // "static" import
-        icz.addStaticImport('java.lang.Math', 'PI') // import static java.lang.Math.Pi
+        icz.addStaticImport('java.lang.Math', 'PI') // import static java.lang.Math.PI
         // "aliased static" import
         icz.addStaticImport('pi', 'java.lang.Math', 'PI') // import static java.lang.Math.PI as pi
         // "star" import
@@ -197,7 +212,8 @@ class A {
 
 def a = new A(val: 123)
 a. at val // <1>
-// end::secure_cz_custom_assert[]'''
+// end::secure_cz_custom_assert[]
+'''
         }
     }
 
diff --git a/src/spec/test/DeclarativeConcurrencyASTTransformsTest.groovy b/src/spec/test/DeclarativeConcurrencyASTTransformsTest.groovy
index 410cc46..15ec40e 100644
--- a/src/spec/test/DeclarativeConcurrencyASTTransformsTest.groovy
+++ b/src/spec/test/DeclarativeConcurrencyASTTransformsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class DeclarativeConcurrencyASTTransformsTest extends GroovyTestCase {
     void testSynchronizedASTTransform() {
         assertScript '''
diff --git a/src/spec/test/DelegatesToSpecTest.groovy b/src/spec/test/DelegatesToSpecTest.groovy
index 94331cf..5ebadd7 100644
--- a/src/spec/test/DelegatesToSpecTest.groovy
+++ b/src/spec/test/DelegatesToSpecTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 
 /*
@@ -494,4 +509,48 @@ class DelegatesToSpecTest extends GroovyTestCase {
         '''
 
     }
+
+    void testDelegatesToType() {
+        def msg = shouldFail '''
+
+// tag::delegatestotype_mapper[]
+class Mapper<T,U> {                             // <1>
+    final T value                               // <2>
+    Mapper(T value) { this.value = value }
+    U map(Closure<U> producer) {                // <3>
+        producer.delegate = value
+        producer()
+    }
+}
+// end::delegatestotype_mapper[]
+ at groovy.transform.CompileStatic
+void test() {
+    // tag::delegatestotype_mapper_test[]
+    def mapper = new Mapper<String,Integer>('Hello')
+    assert mapper.map { length() } == 5
+    // end::delegatestotype_mapper_test[]
+}
+'''
+        assert msg.contains('Static type checking] - Cannot find matching method')
+
+        assertScript '''
+
+// tag::delegatestotype_mapper_fixed[]
+class Mapper<T,U> {
+    final T value
+    Mapper(T value) { this.value = value }
+    U map(@DelegatesTo(type="T") Closure<U> producer) {  // <1>
+        producer.delegate = value
+        producer()
+    }
+}
+// end::delegatestotype_mapper_fixed[]
+ at groovy.transform.CompileStatic
+void test() {
+    def mapper = new Mapper<String,Integer>('Hello')
+    assert mapper.map { length() } == 5
+}
+test()
+'''
+    }
 }
diff --git a/src/spec/test/DesignPatternsTest.groovy b/src/spec/test/DesignPatternsTest.groovy
index de8b2ed..86ccfce 100644
--- a/src/spec/test/DesignPatternsTest.groovy
+++ b/src/spec/test/DesignPatternsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import gls.CompilableTestSupport
 
 class DesignPatternsTest extends CompilableTestSupport {
diff --git a/src/spec/test/DifferencesFromJavaTest.groovy b/src/spec/test/DifferencesFromJavaTest.groovy
index f3cea63..867a941 100644
--- a/src/spec/test/DifferencesFromJavaTest.groovy
+++ b/src/spec/test/DifferencesFromJavaTest.groovy
@@ -102,17 +102,19 @@ new A.B()
 '''
         assertScript '''
 // tag::innerclass_2[]
-boolean called = false
+import java.util.concurrent.CountDownLatch
+import java.util.concurrent.TimeUnit
+
+CountDownLatch called = new CountDownLatch(1)
 
 Timer timer = new Timer()
 timer.schedule(new TimerTask() {
     void run() {
-        called = true
+        called.countDown()
     }
 }, 0)
-sleep 100
 
-assert called
+assert called.await(10, TimeUnit.SECONDS)
 // end::innerclass_2[]
 '''
         assertScript '''
@@ -145,4 +147,42 @@ def x = Y.createX(y)
 assert (x.'this$0').is(y)
 '''
     }
+
+    void testStringsAndCharsGotchas() {
+        assertScript '''
+import org.codehaus.groovy.runtime.typehandling.GroovyCastException;
+
+// tag::type_depends_on_quoting_AND_whether_we_actually_interpolate[]
+assert 'c'.getClass()==String
+assert "c".getClass()==String
+assert "c${1}".getClass() in GString
+// end::type_depends_on_quoting_AND_whether_we_actually_interpolate[]
+// tag::single_char_strings_are_autocasted[]
+char a='a'
+assert Character.digit(a, 16)==10 : 'But Groovy does boxing'
+assert Character.digit((char) 'a', 16)==10
+
+try {
+  assert Character.digit('a', 16)==10
+  assert false: 'Need explicit cast'
+} catch(MissingMethodException e) {
+}
+// end::single_char_strings_are_autocasted[]
+// tag::chars_c_vs_groovy_cast[]
+// for single char strings, both are the same
+assert ((char) "c").class==Character
+assert ("c" as char).class==Character
+
+// for multi char strings they are not
+try {
+  ((char) 'cx') == 'c'
+  assert false: 'will fail - not castable'
+} catch(GroovyCastException e) {
+}
+assert ('cx' as char) == 'c'
+assert 'cx'.asType(char) == 'c'
+// end::chars_c_vs_groovy_cast[]
+        '''
+
+    }
 }
diff --git a/src/spec/test/IntegrationTest.groovy b/src/spec/test/IntegrationTest.groovy
index c7a3957..fbf7b19 100644
--- a/src/spec/test/IntegrationTest.groovy
+++ b/src/spec/test/IntegrationTest.groovy
@@ -141,7 +141,8 @@ def script = shell.parse('greet()')                                         // <
 assert script instanceof MyScript
 script.setName('Michel')
 assert script.run() == 'Hello, Michel!'
-// end::custom_script_usage[]'''
+// end::custom_script_usage[]
+'''
     }
 
     void testGroovyClassLoader() {
diff --git a/src/spec/test/OperatorsTest.groovy b/src/spec/test/OperatorsTest.groovy
index 0d31f08..4982c9b 100644
--- a/src/spec/test/OperatorsTest.groovy
+++ b/src/spec/test/OperatorsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import gls.CompilableTestSupport
 
 import java.util.regex.Matcher
@@ -116,30 +131,37 @@ class OperatorsTest extends CompilableTestSupport {
 
     void testLogicalOperatorPrecedence() {
         // tag::logical_precendence_1[]
-        assert !false && true    // <1>
+        assert (!false && false) == false   // <1>
         // end::logical_precendence_1[]
 
         // tag::logical_precendence_2[]
-        assert false || true && true    // <1>
+        assert true || true && false        // <1>
         // end::logical_precendence_2[]
     }
 
-    void testLogicalOrShortCircuit() {
+    void testLogicalShortCircuit() {
         assertScript '''
-            // tag::logical_or_shortcircuit[]
-            called = false
-
-            boolean somethingTrueOrFalse(boolean b) {  // <1>
-                called = true
-                return b
-            }
-
-            assert true || somethingTrueOrFalse(false)
-            assert !called                              // <2>
-
-            assert false || somethingTrueOrFalse(true)
-            assert called                               // <3>
-            // end::logical_or_shortcircuit[]
+	        // tag::logical_shortcircuit[]
+	        boolean checkIfCalled() {   // <1>
+	            called = true
+	        }
+
+	        called = false
+	        true || checkIfCalled()
+	        assert !called              // <2>
+
+	        called = false
+	        false || checkIfCalled()
+	        assert called               // <3>
+
+	        called = false
+	        false && checkIfCalled()
+	        assert !called              // <4>
+
+	        called = false
+	        true && checkIfCalled()
+	        assert called               // <5>
+	        // end::logical_shortcircuit[]
         '''
     }
 
@@ -161,12 +183,12 @@ class OperatorsTest extends CompilableTestSupport {
         assert result == 'Found'
         result = null
         // tag::conditional_op_ternary_ternary[]
-        result = (string!=null && string.length()>0)?'Found':'Not found'
+        result = (string!=null && string.length()>0) ? 'Found' : 'Not found'
         // end::conditional_op_ternary_ternary[]
         assert result == 'Found'
 
         // tag::conditional_op_ternary_groovytruth[]
-        result = string?'Found':'Not found'
+        result = string ? 'Found' : 'Not found'
         // end::conditional_op_ternary_groovytruth[]
         assert result == 'Found'
 
@@ -181,9 +203,9 @@ class OperatorsTest extends CompilableTestSupport {
 
     void testNullSafeOperator() {
         // tag::nullsafe[]
-        def person = Person.find { it.id == 123 }           // <1>
-        def name = person?.name                             // <2>
-        assert name == null                                 // <3>
+        def person = Person.find { it.id == 123 }    // <1>
+        def name = person?.name                      // <2>
+        assert name == null                          // <3>
         // end::nullsafe[]
     }
 
@@ -194,15 +216,15 @@ class OperatorsTest extends CompilableTestSupport {
         assertScript '''
 // tag::direct_field_class[]
 class User {
-    public final String name                               // <1>
+    public final String name                 // <1>
     User(String name) { this.name = name}
-    String getName() { "Name: $name" }                     // <2>
+    String getName() { "Name: $name" }       // <2>
 }
 def user = new User('Bob')
-assert user.name == 'Name: Bob'                            // <3>
+assert user.name == 'Name: Bob'              // <3>
 // end::direct_field_class[]
 // tag::direct_field_op[]
-assert user. at name == 'Bob'                                 // <1>
+assert user. at name == 'Bob'                   // <1>
 // end::direct_field_op[]
 '''
     }
@@ -222,30 +244,32 @@ assert user. at name == 'Bob'                                 // <1>
                 int age
             }
             // tag::method_reference_strategy[]
-            def transform(List elements, Closure action) {                                      // <1>
+            def transform(List elements, Closure action) {                    // <1>
                 def result = []
                 elements.each {
                     result << action(it)
                 }
                 result
             }
-            String describe(Person p) {                                                         // <2>
+            String describe(Person p) {                                       // <2>
                 "$p.name is $p.age"
             }
-            def action = this.&describe                                                         // <3>
-            def list = [new Person(name:'Bob', age:42), new Person(name:'Julia',age:35)]        // <4>
-            assert transform(list, action) == ['Bob is 42', 'Julia is 35']                      // <5>
+            def action = this.&describe                                       // <3>
+            def list = [
+                new Person(name: 'Bob',   age: 42),
+                new Person(name: 'Julia', age: 35)]                           // <4>
+            assert transform(list, action) == ['Bob is 42', 'Julia is 35']    // <5>
 
             // end::method_reference_strategy[]
         '''
 
         assertScript '''
             // tag::method_reference_dispatch[]
-            def doSomething(String str) { str.toUpperCase() }                                   // <1>
-            def doSomething(Integer x) { 2*x }                                                  // <2>
-            def reference = this.&doSomething                                                   // <3>
-            assert reference('foo') == 'FOO'                                                    // <4>
-            assert reference(123)   == 246                                                      // <5>
+            def doSomething(String str) { str.toUpperCase() }    // <1>
+            def doSomething(Integer x) { 2*x }                   // <2>
+            def reference = this.&doSomething                    // <3>
+            assert reference('foo') == 'FOO'                     // <4>
+            assert reference(123)   == 246                       // <5>
             // end::method_reference_dispatch[]
         '''
     }
@@ -257,25 +281,25 @@ assert user. at name == 'Bob'                                 // <1>
         assert p instanceof Pattern
         // end::pattern_op[]
         // tag::pattern_op_variants[]
-        p = ~'foo'                                                                              // <1>
-        p = ~'foo'                                                                              // <2>
-        p = ~$/dollar/slashy $ string/$                                                         // <3>
-        p = ~"${pattern}"                                                                       // <4>
+        p = ~'foo'                                                        // <1>
+        p = ~"foo"                                                        // <2>
+        p = ~$/dollar/slashy $ string/$                                   // <3>
+        p = ~"${pattern}"                                                 // <4>
         // end::pattern_op_variants[]
 
         // tag::pattern_matcher_op[]
         def text = "some text to match"
-        def m = text =~ /match/                                                                 // <1>
-        assert m instanceof Matcher                                                             // <2>
-        if (!m) {                                                                               // <3>
+        def m = text =~ /match/                                           // <1>
+        assert m instanceof Matcher                                       // <2>
+        if (!m) {                                                         // <3>
             throw new RuntimeException("Oops, text not found!")
         }
         // end::pattern_matcher_op[]
 
         // tag::pattern_matcher_strict_op[]
-        m = text ==~ /match/                                                                    // <1>
-        assert m instanceof Boolean                                                             // <2>
-        if (m) {                                                                                // <3>
+        m = text ==~ /match/                                              // <1>
+        assert m instanceof Boolean                                       // <2>
+        if (m) {                                                          // <3>
             throw new RuntimeException("Should not reach that point!")
         }
         // end::pattern_matcher_strict_op[]
@@ -289,18 +313,18 @@ class Car {
     String model
 }
 def cars = [
-       new Car(make:'Peugeot', model:'508'),
-       new Car(make:'Renault', model:'Clio')]                                    // <1>
-def makes = cars*.make                                                           // <2>
-assert makes == ['Peugeot', 'Renault']                                           // <3>
+       new Car(make: 'Peugeot', model: '508'),
+       new Car(make: 'Renault', model: 'Clio')]       // <1>
+def makes = cars*.make                                // <2>
+assert makes == ['Peugeot', 'Renault']                // <3>
 // end::spreaddot[]
 // tag::spreaddot_nullsafe[]
 cars = [
-   new Car(make:'Peugeot', model:'508'),
-   null,                                                                         // <1>
-   new Car(make:'Renault', model:'Clio')]
-assert cars*.make == ['Peugeot', null, 'Renault']                                // <2>
-assert null*.make == null                                                        // <3>
+   new Car(make: 'Peugeot', model: '508'),
+   null,                                              // <1>
+   new Car(make: 'Renault', model: 'Clio')]
+assert cars*.make == ['Peugeot', null, 'Renault']     // <2>
+assert null*.make == null                             // <3>
 // end::spreaddot_nullsafe[]
 '''
         assertScript '''
@@ -311,8 +335,8 @@ class Component {
 }
 class CompositeObject implements Iterable<Component> {
     def components = [
-        new Component(id:1, name: 'Foo'),
-        new Component(id:2, name:'Bar')]
+        new Component(id: 1, name: 'Foo'),
+        new Component(id: 2, name: 'Bar')]
 
     @Override
     Iterator<Component> iterator() {
@@ -357,7 +381,7 @@ assert function(*args,5,6) == 26
     void testSpreadMap() {
         assertScript '''
         // tag::spread_map[]
-        def m1 = [c: 3, d: 4]                 // <1>
+        def m1 = [c:3, d:4]                   // <1>
         def map = [a:1, b:2, *:m1]            // <2>
         assert map == [a:1, b:2, c:3, d:4]    // <3>
         // end::spread_map[]
@@ -365,7 +389,7 @@ assert function(*args,5,6) == 26
 
         assertScript '''
         // tag::spread_map_position[]
-        def m1 = [c: 3, d: 4]                 // <1>
+        def m1 = [c:3, d:4]                   // <1>
         def map = [a:1, b:2, *:m1, d: 8]      // <2>
         assert map == [a:1, b:2, c:3, d:8]    // <3>
         // end::spread_map_position[]
@@ -418,14 +442,14 @@ assert function(*args,5,6) == 26
         class User {
             Long id
             String name
-            def getAt(int i) {                                                  // <1>
+            def getAt(int i) {                                             // <1>
                 switch (i) {
                     case 0: return id
                     case 1: return name
                 }
                 throw new IllegalArgumentException("No such element $i")
             }
-            void putAt(int i, def value) {                                      // <2>
+            void putAt(int i, def value) {                                 // <2>
                 switch (i) {
                     case 0: id = value; return
                     case 1: name = value; return
@@ -433,11 +457,11 @@ assert function(*args,5,6) == 26
                 throw new IllegalArgumentException("No such element $i")
             }
         }
-        def user = new User(id: 1, name: 'Alex')                                // <3>
-        assert user[0] == 1                                                     // <4>
-        assert user[1] == 'Alex'                                                // <5>
-        user[1] = 'Bob'                                                         // <6>
-        assert user.name == 'Bob'                                               // <7>
+        def user = new User(id: 1, name: 'Alex')                           // <3>
+        assert user[0] == 1                                                // <4>
+        assert user[1] == 'Alex'                                           // <5>
+        user[1] = 'Bob'                                                    // <6>
+        assert user.name == 'Bob'                                          // <7>
         // end::subscript_destructuring[]
         '''
     }
@@ -561,4 +585,18 @@ assert (b1 + 11).size == 15
         String name
         static Person find(Closure c) { null }
     }
+
+    void testGStringEquals() {
+        assertScript '''
+            w = 'world'
+            str1 = "Hello $w"
+            str1 += "!"
+            str2 = "Hello $w!"
+            str3 = 'Hello world!'
+
+            assert str1 == str3
+            assert str2 == str3
+            assert str1 == str2
+            '''
+    }
 }
diff --git a/src/spec/test/PackageTest.groovy b/src/spec/test/PackageTest.groovy
index 2b74e09..e25dc71 100644
--- a/src/spec/test/PackageTest.groovy
+++ b/src/spec/test/PackageTest.groovy
@@ -1,179 +1,184 @@
-class PackageTest extends GroovyTestCase
-{
-	void testPackages() {
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+class PackageTest extends GroovyTestCase {
+    void testPackages() {
         assertScript '''
 			// tag::package_statement[]
-			//Defines a package named com.yoursite.com
-			package com.yoursite.com
+			// defining a package named com.yoursite
+			package com.yoursite
 			// end::package_statement[]
 
-			class Foo
-			{
+			class Foo {
 				
 			}
 			
 			def foo = new Foo()		
 			
-			assert foo != null	
+			assert foo != null
+		    assert Foo.class.name == 'com.yoursite.Foo'
 			'''
-			
-		assertScript '''
+
+        assertScript '''
 			//tag::import_statement[]
-			//imports the class MarkupBuilder
+			// importing the class MarkupBuilder
 			import groovy.xml.MarkupBuilder
 			
-			//uses the imported class to create an object
-			def xml = new MarkupBuilder( )
+			// using the imported class to create an object
+			def xml = new MarkupBuilder()
 			
 			assert xml != null
 			// end::import_statement[]
 			
 		'''
-	}
-	
-	void testDefaultImports()
-	{
-		assertScript '''
-			//tag:default_import[]
+    }
+
+    void testDefaultImports() {
+        assertScript '''
+			// tag::default_import[]
 			new Date()
-			//end:default_import[]
+			// end::default_import[]
 		'''
-	}
-	
-	void testMultipleImportsFromSamePackage()
-	{
-		assertScript '''
+    }
+
+    void testMultipleImportsFromSamePackage() {
+        assertScript '''
 			
-			//tag:multiple_import[]
+			// tag::multiple_import[]
 			import groovy.xml.MarkupBuilder
 			import groovy.xml.StreamingMarkupBuilder
 			
-			def markupBuilder = new MarkupBuilder( )
+			def markupBuilder = new MarkupBuilder()
 			
 			assert markupBuilder != null
 			
 			assert new StreamingMarkupBuilder() != null 
-			//end:multiple_import[]
+			// end::multiple_import[]
 			
 		'''
-	}
-	
-	void testStarImports()
-	{
-		assertScript '''
-			//tag:star_import[]
+    }
+
+    void testStarImports() {
+        assertScript '''
+			// tag::star_import[]
 			import groovy.xml.*
 			
-			def markupBuilder = new MarkupBuilder( )
+			def markupBuilder = new MarkupBuilder()
 			
 			assert markupBuilder != null
 			
 			assert new StreamingMarkupBuilder() != null
 			
-			//end:star_import[]
+			// end::star_import[]
 		'''
-	}
-	
-	/*
-	void testMakeItTwice()
-	{
-		assertScript '''
-			//tag:type_aliasing[]
-			
-			package com.lib
-			
-			public class MultiplyTwo
-			{
-				def multiplay(def value)
-				{
-					return value * 3 //intentionally wrong.
-				}
-			}
-			
-			assert 4 != new MultiplyTwo().multiplay(2)
-			
-			//end:type_aliasing[]
-		'''
-	}*/
-	
-	void testStaticImports()
-	{
-		assertScript '''
+    }
+
+    /*
+    void testMakeItTwice()
+    {
+        assertScript '''
+            //tag::type_aliasing[]
+
+            package com.lib
+
+            public class MultiplyTwo
+            {
+                def multiply(def value)
+                {
+                    return value * 3 //intentionally wrong.
+                }
+            }
+
+            assert 4 != new MultiplyTwo().multiply(2)
+
+            //end::type_aliasing[]
+        '''
+    }*/
+
+    void testStaticImports() {
+        assertScript '''
 			
-			//tag:static_imports[]
+			// tag::static_imports[]
 			
 			import static Boolean.FALSE
 			
 			assert !FALSE //use directly, without Boolean prefix!
 			
-			//end:static_imports[]
+			// end::static_imports[]
 			
 		'''
-	}
-	
-	void testStaticImportWithAs()
-	{
-		assertScript '''
+    }
+
+    void testStaticImportWithAs() {
+        assertScript '''
 			
-			//tag:static_importswithas[]
+			// tag::static_importswithas[]
 			
 			import static Calendar.getInstance as now
 			
 			assert now().class == Calendar.getInstance().class
 			
-			//end:static_importswithas[]
+			// end::static_importswithas[]
 			
 		'''
-	}
-	
-	void testStaticStarImport()
-	{
-		assertScript '''
-			//tag:static_importswithstar[]
+    }
+
+    void testStaticStarImport() {
+        assertScript '''
+			// tag::static_importswithstar[]
 			
 			import static java.lang.Math.*
 			
 			assert sin(0) == 0.0
 			assert cos(0) == 1.0
 			
-			//end:static_importswithstar[]
+			// end::static_importswithstar[]
 		'''
-	}
-	
-	void testThirdLib()
-	{
-		assertScript '''
+    }
+
+    void testThirdLib() {
+        assertScript '''
 			import thirdpartylib.MultiplyTwo
 			
-			//tag:using_thrid_party_lib[]
-			def result = new MultiplyTwo().multiplay(2)
-			//end:using_thrid_party_lib[]
+			// tag::using_third_party_lib[]
+			def result = new MultiplyTwo().multiply(2)
+			// end::using_third_party_lib[]
 		
-			assert 4 != new MultiplyTwo().multiplay(2)
+			assert 4 != new MultiplyTwo().multiply(2)
 		'''
-	}
-	
-	void testFixThirdLib()
-	{
-		assertScript '''
-			
-			//tag:fixing_thrid_party_lib[]
-			
+    }
+
+    void testFixThirdLib() {
+        assertScript '''
+			// tag::fixing_thrid_party_lib[]
 			import thirdpartylib.MultiplyTwo as OrigMultiplyTwo
+
 			class MultiplyTwo extends OrigMultiplyTwo {
-				def multiplay(def value)
-				{
-					return value * 2 //corrected here
+				def multiply(def value) {
+					return value * 2 // fixed here
 				}
 			}
-			// nothing changes below here
+
+			// nothing to change below here
 			def multiplylib = new MultiplyTwo()
 
-			//assert passes as well
-			assert 4 == new MultiplyTwo().multiplay(2)
-			//end:fixing_thrid_party_lib[]
+			// assert passes as well
+			assert 4 == new MultiplyTwo().multiply(2)
+			// end::fixing_thrid_party_lib[]
 		'''
-	}
-	
+    }
+
 }
 
diff --git a/src/spec/test/SaferScriptingASTTransformsTest.groovy b/src/spec/test/SaferScriptingASTTransformsTest.groovy
index 7611f61..a222934 100644
--- a/src/spec/test/SaferScriptingASTTransformsTest.groovy
+++ b/src/spec/test/SaferScriptingASTTransformsTest.groovy
@@ -97,7 +97,7 @@ assert binding.i > 0
 if (t.alive) {
     t.interrupt()
 }
-Thread.sleep(100)
+Thread.sleep(500)
 assert binding.i == -1'''
 // end::threadinterrupt_thrown[]
    }
@@ -138,7 +138,7 @@ def fib(int n) {
 def t = Thread.start {
     shell.evaluate(userCode)
 }
-t.join(2000)
+t.join(5000)
 assert !t.alive
 // end::timedinterrupt_control[]
 assert binding.result == 0'''
@@ -158,7 +158,7 @@ def result
 def t = Thread.start {
     result = new Slow().fib(500)
 }
-t.join(1000)
+t.join(5000)
 assert result == null
 assert !t.alive
 // end::timedinterrupt_duration[]
@@ -186,7 +186,7 @@ def t = Thread.start {
         result = -1
     }
 }
-t.join(2000)
+t.join(5000)
 assert result == -1
 // end::timedinterrupt_thrown[]
 '''
@@ -221,7 +221,7 @@ assert Quotas.quotas['user'] == 10
 def t = Thread.start {
     new UserCode().doSomething()
 }
-t.join(1000)
+t.join(5000)
 assert !t.alive
 assert Quotas.quotas['user'] < 0
 // end::conditionalinterrupt_assert[]
@@ -273,7 +273,7 @@ assert Quotas.quotas['user'] == 10
 def t = Thread.start {
     shell.evaluate(userCode)
 }
-t.join(1000)
+t.join(5000)
 assert !t.alive
 assert Quotas.quotas['user'] < 0
 // end::conditionalinterrupt_injected[]
@@ -330,7 +330,7 @@ def t = Thread.start {
         Quotas.quotas['user'] = 'Quota exceeded'
     }
 }
-t.join(1000)
+t.join(5000)
 assert !t.alive
 assert Quotas.quotas['user'] == 'Quota exceeded'
 // end::conditionalinterrupt_thrown[]
diff --git a/src/spec/test/ScriptsAndClassesSpecTest.groovy b/src/spec/test/ScriptsAndClassesSpecTest.groovy
new file mode 100644
index 0000000..cbd76f8
--- /dev/null
+++ b/src/spec/test/ScriptsAndClassesSpecTest.groovy
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+class ScriptsAndClassesSpecTest extends GroovyTestCase {
+    void testMainMethod() {
+        assertScript '''
+            // tag::groovy_class_with_main_method[]
+            class Main {                                    // <1>
+                static void main(String... args) {          // <2>
+                    println 'Groovy world!'                 // <3>
+                }
+            }
+            // end::groovy_class_with_main_method[]
+        '''
+        assertScript '''
+            // tag::groovy_script[]
+            println 'Groovy world!'
+            // end::groovy_script[]
+        '''
+
+        assertScript '''
+            // tag::groovy_script_equiv[]
+            import org.codehaus.groovy.runtime.InvokerHelper
+            class Main extends Script {                     // <1>
+                def run() {                                 // <2>
+                    println 'Groovy world!'                 // <3>
+                }
+                static void main(String[] args) {           // <4>
+                    InvokerHelper.runScript(Main, args)     // <5>
+                }
+            }
+            // end::groovy_script_equiv[]
+        '''
+    }
+
+    void testMethodDefinition() {
+        assertScript '''
+            // tag::method_in_script[]
+            int fib(int n) {
+                n<2?1:fib(n-1)+fib(n-2)
+            }
+            assert fib(10)==89
+            // end::method_in_script[]
+        '''
+
+        assertScript '''
+            // tag::multiple_methods_assembly[]
+            println 'Hello'                                 // <1>
+
+            int power(int n) { 2**n }                       // <2>
+
+            println "2^6==${power(6)}"                      // <3>
+            // end::multiple_methods_assembly[]
+        '''
+
+        assertScript '''
+            // tag::multiple_methods_assembly_equiv[]
+            import org.codehaus.groovy.runtime.InvokerHelper
+            class Main extends Script {
+                int power(int n) { 2** n}                   // <1>
+                def run() {
+                    println 'Hello'                         // <2>
+                    println "2^6==${power(6)}"              // <3>
+                }
+                static void main(String[] args) {
+                    InvokerHelper.runScript(Main, args)
+                }
+            }
+            // end::multiple_methods_assembly_equiv[]
+        '''
+    }
+
+    void testScriptVariables() {
+        assertScript '''
+            // tag::script_with_variables[]
+            int x = 1
+            int y = 2
+            assert x+y == 3
+            // end::script_with_variables[]
+        '''
+        assertScript '''
+            // tag::script_with_untyped_variables[]
+            x = 1
+            y = 2
+            assert x+y == 3
+            // end::script_with_untyped_variables[]
+        '''
+    }
+}
diff --git a/src/spec/test/SemanticsTest.groovy b/src/spec/test/SemanticsTest.groovy
index 533320d..bb45bb8 100644
--- a/src/spec/test/SemanticsTest.groovy
+++ b/src/spec/test/SemanticsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import gls.CompilableTestSupport
 import groovy.transform.Immutable
 
diff --git a/src/spec/test/SyntaxTest.groovy b/src/spec/test/SyntaxTest.groovy
index 4506975..b4b12da 100644
--- a/src/spec/test/SyntaxTest.groovy
+++ b/src/spec/test/SyntaxTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import gls.CompilableTestSupport
 
 class SyntaxTest extends CompilableTestSupport {
@@ -391,6 +406,10 @@ class SyntaxTest extends CompilableTestSupport {
     }
 
     void testTripleSingleQuotedString() {
+        // tag::triple_single_0[]
+        '''a triple single quoted string'''
+        // end::triple_single_0[]
+
         // tag::triple_single_1[]
         def aMultilineString = '''line one
         line two
@@ -686,11 +705,11 @@ class SyntaxTest extends CompilableTestSupport {
         String[] arrStr = ['Ananas', 'Banana', 'Kiwi']  // <1>
 
         assert arrStr instanceof String[]    // <2>
-        assert !(arrStr instanceof List)     // <3>
+        assert !(arrStr instanceof List)
 
-        def numArr = [1, 2, 3] as int[]      // <4>
+        def numArr = [1, 2, 3] as int[]      // <3>
 
-        assert numArr instanceof int[]       // <5>
+        assert numArr instanceof int[]       // <4>
         assert numArr.size() == 3
         // end::array_1[]
 
diff --git a/src/spec/test/TemplateEnginesTest.groovy b/src/spec/test/TemplateEnginesTest.groovy
deleted file mode 100644
index 9dc50ed..0000000
--- a/src/spec/test/TemplateEnginesTest.groovy
+++ /dev/null
@@ -1,146 +0,0 @@
-import gls.CompilableTestSupport
-
-class TemplateEnginesTest extends CompilableTestSupport {
-
-    void testSimpleTemplateEngine1() {
-        // tag::simple_template_engine1[]
-        def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
-
-        def binding = ["firstname":"Sam", "lastname":"Pullara", "city":"San Francisco", "month":"December", "signed":"Groovy-Dev"]
-
-        def engine = new groovy.text.SimpleTemplateEngine()
-        def template = engine.createTemplate(text).make(binding)
-
-        def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'
-
-        assert result == template.toString()
-        // end::simple_template_engine1[]
-    }
-
-    void testSimpleTemplateEngineOther() {
-        def binding = [firstname: 'andrey']
-        def engine = new groovy.text.SimpleTemplateEngine()
-        def text = '''\
-            // tag::simple_template_engine2[]
-            $firstname
-            // end::simple_template_engine2[]
-        '''
-        def template = engine.createTemplate(text).make(binding)
-        def result = template.toString()
-        assert result.readLines()[1].trim() == 'andrey'
-
-        text = '''\
-            // tag::simple_template_engine3[]
-            ${firstname.capitalize()}
-            // end::simple_template_engine3[]
-        '''
-        template = engine.createTemplate(text).make(binding)
-        result = template.toString()
-        assert result.readLines()[1].trim() == 'Andrey'
-
-        binding = [city: 'Moscow']
-        text = '''\
-            // tag::simple_template_engine4[]
-            <% print city %>
-            // end::simple_template_engine4[]
-        '''
-        template = engine.createTemplate(text).make(binding)
-        result = template.toString()
-        assert result.readLines()[1].trim() == 'Moscow'
-
-        binding = [city: 'New York']
-        text = '''\
-            // tag::simple_template_engine5[]
-            <% print city == "New York" ? "The Big Apple" : city %>
-            // end::simple_template_engine5[]
-        '''
-        template = engine.createTemplate(text).make(binding)
-        result = template.toString()
-        assert result.readLines()[1].trim() == 'The Big Apple'
-
-        text = '''\
-            // tag::simple_template_engine6[]
-            <% print city == "New York" ? "\\"The Big Apple\\"" : city %>
-            // end::simple_template_engine6[]
-        '''
-        template = engine.createTemplate(text).make(binding)
-        result = template.toString()
-        assert result.readLines()[1].trim() == '"The Big Apple"'
-
-        text = '''\
-            // tag::simple_template_engine7[]
-            \\n
-            // end::simple_template_engine7[]
-        '''
-        template = engine.createTemplate(text).make()
-        result = template.toString()
-        assert result.readLines().size() == 5
-
-        text = '''\
-            // tag::simple_template_engine8[]
-            \\\\
-            // end::simple_template_engine8[]
-        '''
-        template = engine.createTemplate(text).make()
-        result = template.toString()
-        assert result.readLines()[1].trim() == '\\'
-    }
-
-    void testGStringTemplateEngine() {
-        def binding = [firstname: 'Sam', lastname: 'Pullara', city: 'New York', month: 'December', signed: 'Groovy-Dev']
-        def engine = new groovy.text.GStringTemplateEngine()
-        def text = '''\
-            // tag::gstring_template_engine1[]
-            Dear "$firstname $lastname",
-            So nice to meet you in <% out << (city == "New York" ? "\\"The Big Apple\\"" : city) %>.
-            See you in ${month},
-            ${signed}
-            // end::gstring_template_engine1[]
-        '''
-        def template = engine.createTemplate(text).make(binding)
-        List result = template.toString().readLines()
-        result.remove(0); result.remove(result.size() - 2)
-        assert result.join('\n') == '''\
-            Dear "Sam Pullara",
-            So nice to meet you in "The Big Apple".
-            See you in December,
-            Groovy-Dev
-        '''
-
-        shouldCompile '''
-            // tag::gstring_template_engine2[]
-            def f = new File('test.template')
-            def engine = new groovy.text.GStringTemplateEngine()
-            def template = engine.createTemplate(f).make(binding)
-            println template.toString()
-            // end::gstring_template_engine2[]
-        '''
-    }
-
-    void testXmlTemplateEngine() {
-        // tag::xml_template_engine[]
-        def binding = [firstname: 'Jochen', lastname: 'Theodorou', nickname: 'blackdrag', salutation: 'Dear']
-        def engine = new groovy.text.XmlTemplateEngine()
-        def text = '''\
-            <document xmlns:gsp='http://groovy.codehaus.org/2005/gsp' xmlns:foo='baz' type='letter'>
-                <gsp:scriptlet>def greeting = "${salutation}est"</gsp:scriptlet>
-                <gsp:expression>greeting</gsp:expression>
-                <foo:to>$firstname "$nickname" $lastname</foo:to>
-                How are you today?
-            </document>
-        '''
-        def template = engine.createTemplate(text).make(binding)
-        println template.toString()
-        // end::xml_template_engine[]
-        
-        assert template.toString() == '''\
-<document type='letter'>
-  Dearest
-  <foo:to xmlns:foo='baz'>
-    Jochen "blackdrag" Theodorou
-  </foo:to>
-  How are you today?
-</document>
-'''
-    }
-}
\ No newline at end of file
diff --git a/src/spec/test/TestingASTTransformsTest.groovy b/src/spec/test/TestingASTTransformsTest.groovy
index 0d658e8..e71264e 100644
--- a/src/spec/test/TestingASTTransformsTest.groovy
+++ b/src/spec/test/TestingASTTransformsTest.groovy
@@ -121,4 +121,63 @@ class Something {
 def p = new Something()
 '''
     }
+
+    void testDumpASTTransforms() {
+        assertScript '''
+// tag::dump_ast_xforms[]
+import groovy.transform.ASTTest
+import groovy.transform.CompileStatic
+import groovy.transform.Immutable
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.control.CompilePhase
+
+ at ASTTest(value={
+    System.err.println "Compile phase: $compilePhase"
+    ClassNode cn = node
+    System.err.println "Global AST xforms: ${compilationUnit?.ASTTransformationsContext?.globalTransformNames}"
+    CompilePhase.values().each {
+        def transforms = cn.getTransforms(it)
+        if (transforms) {
+            System.err.println "Ast xforms for phase $it:"
+            transforms.each { map ->
+                System.err.println(map)
+            }
+        }
+    }
+})
+ at CompileStatic
+ at Immutable
+class Foo {
+}
+// end::dump_ast_xforms[]
+Foo
+'''
+    }
+
+    void testVariableMemorize() {
+        assertScript '''
+// tag::memorize_in_binding[]
+import groovy.transform.ASTTest
+import groovy.transform.ToString
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.control.CompilePhase
+
+ at ASTTest(value={
+    if (compilePhase==CompilePhase.INSTRUCTION_SELECTION) {             // <1>
+        println "toString() was added at phase: ${added}"
+        assert added == CompilePhase.CANONICALIZATION                   // <2>
+    } else {
+        if (node.getDeclaredMethods('toString') && added==null) {       // <3>
+            added = compilePhase                                        // <4>
+        }
+    }
+})
+ at ToString
+class Foo {
+    String name
+}
+// end::memorize_in_binding[]
+Foo
+'''
+    }
 }
diff --git a/src/spec/test/TraitsSpecificationTest.groovy b/src/spec/test/TraitsSpecificationTest.groovy
index 10b2e5a..339ffb0 100644
--- a/src/spec/test/TraitsSpecificationTest.groovy
+++ b/src/spec/test/TraitsSpecificationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.ast.ClassHelper
 import org.codehaus.groovy.ast.ClassNode
 
@@ -72,7 +87,8 @@ def p = new Person()
 assert p.greeting() == 'Hello, Bob!'                    // <5>
 assert p instanceof Named                               // <6>
 assert p instanceof Greetable                           // <7>
-// end::trait_implementing_interface[]'''
+// end::trait_implementing_interface[]
+'''
     }
 
     void testTraitWithProperty() {
@@ -84,7 +100,8 @@ class Person implements Named {}            // <2>
 def p = new Person(name: 'Bob')             // <3>
 assert p.name == 'Bob'                      // <4>
 assert p.getName() == 'Bob'                 // <5>
-// end::trait_with_property[]'''
+// end::trait_with_property[]
+'''
     }
 
     void testCompositionOfTraits() {
@@ -127,7 +144,8 @@ def d = new Duck()
 assert d.fly() == "I'm flying!"                         // <3>
 assert d.quack() == "Quack!"                            // <4>
 assert d.speak() == "Quack!"                            // <5>
-// end::quackingduck[]'''
+// end::quackingduck[]
+'''
     }
 
     void testPrivateMethodInTrait() {
@@ -163,6 +181,7 @@ trait Counter {
 class Foo implements Counter {}             // <3>
 def f = new Foo()
 assert f.count() == 1                       // <4>
+assert f.count() == 2
 // end::trait_with_private_field[]
 '''
     }
@@ -175,7 +194,8 @@ trait Named {
 class Person implements Named {}            // <2>
 def p = new Person()                        // <3>
 p.Named__name = 'Bob'                       // <4>
-// end::trait_with_public_field[]'''
+// end::trait_with_public_field[]
+'''
     }
 
     void testRemappedName() {
@@ -195,7 +215,8 @@ class Duck implements SpeakingDuck {
 }
 def d = new Duck()
 assert d.speak() == 'Quack!'                        // <3>
-// end::ducktyping[]'''
+// end::ducktyping[]
+'''
     }
 
     void testTraitInheritance() {
@@ -236,10 +257,10 @@ trait DynamicObject {                               // <1>
         name.toUpperCase()
     }
     def propertyMissing(String prop) {
-        props['prop']
+        props[prop]
     }
     void setProperty(String prop, Object value) {
-        props['prop'] = value
+        props[prop] = value
     }
 }
 
@@ -254,7 +275,8 @@ d.foo = 'bar'                                       // <6>
 assert d.foo == 'bar'                               // <7>
 assert d.existingMethod() == 'ok'                   // <8>
 assert d.someMethod() == 'SOMEMETHOD'               // <9>
-// end::dynamicobject[]'''
+// end::dynamicobject[]
+'''
     }
 
     void testDefaultMultipleInheritanceResolution() {
@@ -271,7 +293,8 @@ class C implements A,B {}               // <3>
 // tag::multiple_inherit_default_assert[]
 def c = new C()
 assert c.exec() == 'B'
-// end::multiple_inherit_default_assert[]'''
+// end::multiple_inherit_default_assert[]
+'''
     }
 
     void testUserMultipleInheritanceResolution() {
@@ -287,7 +310,8 @@ class C implements A,B {
 }
 def c = new C()
 assert c.exec() == 'A'                  // <2>
-// end::multiple_inherit_user[]'''
+// end::multiple_inherit_user[]
+'''
     }
 
     void testRuntimeCoercion() {
@@ -312,7 +336,8 @@ s.extra()
 def s = new Something() as Extra                        // <1>
 s.extra()                                               // <2>
 s.doSomething()                                         // <3>
-// end::runtime_success[]'''
+// end::runtime_success[]
+'''
     }
 
     void testWithTraits() {
@@ -355,7 +380,8 @@ Greeter greeter = { 'Alice' }               // <1>
 // tag::sam_trait_method[]
 void greet(Greeter g) { println g.greet() } // <1>
 greet { 'Alice' }                           // <2>
-// end::sam_trait_method[]'''
+// end::sam_trait_method[]
+'''
     }
 
     void testTraitOverrideBehavior() {
@@ -440,7 +466,8 @@ def p = new Person(name: 'Alice')
 assert p.name == 'Alice'                                // <3>
 def p2 = p as Bob                                       // <4>
 assert p2.name == 'Bob'                                 // <5>
-// end::runtime_forceoverride[]'''
+// end::runtime_forceoverride[]
+'''
     }
 
     void testDifferenceWithMixin() {
@@ -453,7 +480,8 @@ assert o.methodFromA() == 'A'                   // <4>
 assert o.methodFromB() == 'B'                   // <5>
 assert o instanceof A                           // <6>
 assert !(o instanceof B)                        // <7>
-// end::diff_mixin[]'''
+// end::diff_mixin[]
+'''
     }
 
     void testMeaningOfThis() {
@@ -469,7 +497,8 @@ foo.whoAmI()
 // end::meaningofthis_snippet[]
 // tag::meaningofthis_assert[]
 assert foo.whoAmI().is(foo)
-// end::meaningofthis_assert[]'''
+// end::meaningofthis_assert[]
+'''
     }
 
     void testPublicStaticFieldInTrait() {
@@ -571,7 +600,8 @@ use(PC) {
     def expect = """// tag::handlerwithlogger_assert_output[]
 Seeing test logging with payload [:]
 Received test logging with payload [:]
-// end::handlerwithlogger_assert_output[]"""
+// end::handlerwithlogger_assert_output[]
+"""
     assert PC.BUFFER.toString() == filterTags(expect)
     PC.reset()
 }
@@ -614,7 +644,8 @@ Seeing foo with payload [:]
 Received foo with payload [:]
 Seeing sayHello with payload [:]
 I say Hello!
-// end::implementinghandler_output[]"""
+// end::implementinghandler_output[]
+"""
     assert PC.BUFFER.toString() == filterTags(expect)
     PC.reset()
 }
@@ -632,7 +663,8 @@ def expect = """// tag::alternatehandler_output[]
 Seeing foo with payload [:]
 Received foo with payload [:]
 I say Hello!
-// end::alternatehandler_output[]"""
+// end::alternatehandler_output[]
+"""
     assert PC.BUFFER.toString() == filterTags(expect)
     PC.reset()
 PC.reset()
@@ -709,6 +741,104 @@ assert elem.f() == 7
 '''
     }
 
+    void testSelfType() {
+        assertScript '''
+// tag::selftype_intro[]
+class CommunicationService {
+    static void sendMessage(String from, String to, String message) {       // <1>
+        println "$from sent [$message] to $to"
+    }
+}
+
+class Device { String id }                                                  // <2>
+
+trait Communicating {
+    void sendMessage(Device to, String message) {
+        CommunicationService.sendMessage(id, to.id, message)                // <3>
+    }
+}
+
+class MyDevice extends Device implements Communicating {}                   // <4>
+
+def bob = new MyDevice(id:'Bob')
+def alice = new MyDevice(id:'Alice')
+bob.sendMessage(alice,'secret')                                             // <5>
+// end::selftype_intro[]
+
+// tag::selftype_securityservice[]
+class SecurityService {
+    static void check(Device d) { if (d.id==null) throw new SecurityException() }
+}
+// end::selftype_securityservice[]
+'''
+
+
+        assertScript '''import groovy.transform.SelfType
+import groovy.transform.CompileStatic
+
+class CommunicationService {
+    static void sendMessage(String from, String to, String message) {
+        println "$from sent [$message] to $to"
+    }
+}
+
+class Device { String id }
+
+// tag::selftype_fixed[]
+ at SelfType(Device)
+ at CompileStatic
+trait Communicating {
+    void sendMessage(Device to, String message) {
+        SecurityService.check(this)
+        CommunicationService.sendMessage(id, to.id, message)
+    }
+}
+// end::selftype_fixed[]
+
+class MyDevice extends Device implements Communicating {}
+
+def bob = new MyDevice(id:'Bob')
+def alice = new MyDevice(id:'Alice')
+bob.sendMessage(alice,'secret')
+
+class SecurityService {
+    static void check(Device d) { if (d.id==null) throw new SecurityException() }
+}
+
+'''
+
+        def message = shouldFail '''import groovy.transform.SelfType
+import groovy.transform.CompileStatic
+
+class CommunicationService {
+    static void sendMessage(String from, String to, String message) {
+        println "$from sent [$message] to $to"
+    }
+}
+
+class Device { String id }
+
+ at SelfType(Device)
+ at CompileStatic
+trait Communicating {
+    void sendMessage(Device to, String message) {
+        SecurityService.check(this)
+        CommunicationService.sendMessage(id, to.id, message)
+    }
+}
+
+// tag::selftype_compiletimeerror[]
+class MyDevice implements Communicating {} // forgot to extend Device
+// end::selftype_compiletimeerror[]
+
+class SecurityService {
+    static void check(Device d) { if (d.id==null) throw new SecurityException() }
+}
+
+'''
+        assert message.contains("class 'MyDevice' implements trait 'Communicating' but does not extend self type class 'Device'")
+    }
+
     static class PrintCategory {
         static StringBuilder BUFFER = new StringBuilder()
         static void println(Object self, String message) {
diff --git a/src/spec/test/asciidoctor/Utils.groovy b/src/spec/test/asciidoctor/Utils.groovy
new file mode 100644
index 0000000..ce01506
--- /dev/null
+++ b/src/spec/test/asciidoctor/Utils.groovy
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package asciidoctor
+
+import groovy.transform.CompileStatic
+
+ at CompileStatic
+class Utils {
+    public static String stripAsciidocMarkup(String string, String newline='\n') {
+        boolean inside = false
+        StringBuilder sb = new StringBuilder()
+        new StringReader(string).eachLine { line ->
+            if (line =~ 'tag::') {
+                inside = true
+            } else if (line =~ 'end::') {
+                inside = false
+            } else if (inside) {
+                if (sb.length() > 0) {
+                    sb.append(newline)
+                }
+                sb.append(line)
+            }
+        }
+        sb
+    }
+}
diff --git a/src/spec/test/builder/BuilderSupportTest.groovy b/src/spec/test/builder/BuilderSupportTest.groovy
new file mode 100644
index 0000000..145c60f
--- /dev/null
+++ b/src/spec/test/builder/BuilderSupportTest.groovy
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package builder
+
+import groovy.util.GroovyTestCase
+import org.junit.Test
+import static org.junit.Assert.*
+
+class BuilderSupportTest extends BuilderSupport{
+    def log = []
+    protected void setParent(Object parent, Object child){
+        log << "sp"
+        log << parent
+        log << child
+    }
+    protected Object createNode(Object name){
+        log << 'cn1'
+        log <<  name
+        return 'x'
+    }
+    protected Object createNode(Object name, Object value){
+        log << 'cn2'
+        log << name
+        log << value
+        return 'x'
+    }
+    protected Object createNode(Object name, Map attributes){
+        log << 'cn3'
+        log << name
+        attributes.each{entry -> log << entry.key; log << entry.value}
+        return 'x'
+    }
+    protected Object createNode(Object name, Map attributes, Object value){
+        log << 'cn4'
+        log << name
+        attributes.each{entry -> log << entry.key; log << entry.value}
+        log << value
+        return 'x'
+    }
+    protected void nodeCompleted(Object parent, Object node) {
+        log << 'nc'
+        log << parent
+        log << node
+    }
+    
+    public static void main(String[] args)
+    {
+    
+// tag::BuilderSupportTest_default_constructor_object1[]
+        def sb1 = new BuilderSupportTest()
+        // log should be empty after initialized
+        assertEquals sb1.log , []  
+// end::BuilderSupportTest_default_constructor_object1[]
+
+
+// tag::BuilderSupportTest_add_node_object2[]
+        def node1 = sb1.foo()
+        assert sb1.log == ['cn1','foo','nc',null, node1]
+// end::BuilderSupportTest_add_node_object2[]
+
+// tag::BuilderSupportTest_add_node_with_value_object3[]
+        // simple node with value
+        def sb2 = new BuilderSupportTest()
+        def node2 = sb2.foo('value')
+        
+        // node type 2 creation with name/value pair
+        assert sb2.log == ['cn2','foo','value', 'nc',null,node2]
+// end::BuilderSupportTest_add_node_with_value_object3[]
+
+
+// tag::BuilderSupportTest_add_node_with_value_object4[]
+        // simple node with one attribute
+        def sb3 = new BuilderSupportTest()
+        def node3 = sb3.foo(name:'value')
+        
+        // node type 3 creation with map as name/value pair
+        assert sb3.log == ['cn3','foo', 'name','value', 'nc',null,'x']
+// end::BuilderSupportTest_add_node_with_value_object4[]
+        
+        
+// tag::BuilderSupportTest_add_nested_nodes_object5[]
+        // how is closure applied?
+        def sb4 = new BuilderSupportTest()
+        sb4.foo(){
+            sb4.bar()
+        }
+
+        // nested node creation without name/value pairs
+        assert sb4.log == [
+            'cn1','foo',    // child node 1 is name of method
+            'cn1','bar',    // inner child node 2 is name of method
+            'sp', 'x', 'x', // set links so inner child points to outer child
+            'nc','x','x',   // inner node bar complete points back to outer
+            'nc',null,'x']  // outer node complete and no further outer child to link/point back to
+// end::BuilderSupportTest_add_nested_nodes_object5[]
+
+    } // end of main
+       
+} // end of class
\ No newline at end of file
diff --git a/src/spec/test/builder/ObjectGraphBuilderTest.groovy b/src/spec/test/builder/ObjectGraphBuilderTest.groovy
new file mode 100644
index 0000000..551e582
--- /dev/null
+++ b/src/spec/test/builder/ObjectGraphBuilderTest.groovy
@@ -0,0 +1,183 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package builder
+
+import asciidoctor.Utils
+
+/**
+* Tests for ObjectGraphBuilder. The tests directly in this file are specific
+* to ObjectGraphBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class ObjectGraphBuilderTest  extends GroovyTestCase {
+
+    void testBuilder() {
+        assertScript '''// tag::domain_classes[]
+package com.acme
+
+class Company {
+    String name
+    Address address
+    List employees = []
+}
+
+class Address {
+    String line1
+    String line2
+    int zip
+    String state
+}
+
+class Employee {
+    String name
+    int employeeId
+    Address address
+    Company company
+}
+// end::domain_classes[]
+
+// tag::builder_example[]
+def builder = new ObjectGraphBuilder()                          // <1>
+builder.classLoader = this.class.classLoader                    // <2>
+builder.classNameResolver = "com.acme"                          // <3>
+
+def acme = builder.company(name: 'ACME') {                      // <4>
+    3.times {
+        employee(id: it.toString(), name: "Drone $it") {        // <5>
+            address(line1:"Post street")                        // <6>
+        }
+    }
+}
+
+assert acme != null
+assert acme instanceof Company
+assert acme.name == 'ACME'
+assert acme.employees.size() == 3
+def employee = acme.employees[0]
+assert employee instanceof Employee
+assert employee.name == 'Drone 0'
+assert employee.address instanceof Address
+// end::builder_example[]
+'''
+    }
+
+
+    void testBuildImmutableFailure() {
+        def err = shouldFail '''
+package com.acme
+import groovy.transform.Immutable
+
+// tag::immutable_class[]
+ at Immutable
+class Person {
+    String name
+    int age
+}
+// end::immutable_class[]
+
+def builder = new ObjectGraphBuilder()
+builder.classLoader = this.class.classLoader
+builder.classNameResolver = "com.acme"
+
+// tag::immutable_fail_runtime[]
+def person = builder.person(name:'Jon', age:17)
+// end::immutable_fail_runtime[]
+        '''
+        assert err == Utils.stripAsciidocMarkup('''
+// tag::expected_error_immutable[]
+Cannot set readonly property: name for class: com.acme.Person
+// end::expected_error_immutable[]
+''')
+    }
+
+    void testBuildImmutableFixed() {
+        assertScript '''
+package com.acme
+import groovy.transform.Immutable
+
+ at Immutable
+class Person {
+    String name
+    Integer age
+}
+
+def builder = new ObjectGraphBuilder()
+builder.classLoader = this.class.classLoader
+builder.classNameResolver = "com.acme"
+
+// tag::newinstanceresolver[]
+builder.newInstanceResolver = { Class klazz, Map attributes ->
+    if (klazz.isAnnotationPresent(Immutable)) {
+        def o = klazz.newInstance(attributes)
+        attributes.clear()
+        return o
+    }
+    klazz.newInstance()
+}
+// end::newinstanceresolver[]
+def person = builder.person(name:'Jon', age:17)
+
+        '''
+    }
+
+    void testId() {
+        assertScript '''package com.acme
+
+class Company {
+    String name
+    Address address
+    List employees = []
+}
+
+class Address {
+    String line1
+    String line2
+    int zip
+    String state
+}
+
+class Employee {
+    String name
+    int employeeId
+    Address address
+    Company company
+}
+
+def builder = new ObjectGraphBuilder()
+builder.classLoader = this.class.classLoader
+builder.classNameResolver = "com.acme"
+
+// tag::test_id[]
+def company = builder.company(name: 'ACME') {
+    address(id: 'a1', line1: '123 Groovy Rd', zip: 12345, state: 'JV')          // <1>
+    employee(name: 'Duke', employeeId: 1, address: a1)                          // <2>
+    employee(name: 'John', employeeId: 2 ){
+      address( refId: 'a1' )                                                    // <3>
+    }
+}
+// end::test_id[]
+def e1 = company.employees[0]
+def e2 = company.employees[1]
+assert e1.name == 'Duke'
+assert e2.name == 'John'
+assert e1.address.line1 == '123 Groovy Rd'
+assert e2.address.line1 == '123 Groovy Rd'
+'''
+    }
+}
\ No newline at end of file
diff --git a/src/spec/test/gdk/ConfigSlurperTest.groovy b/src/spec/test/gdk/ConfigSlurperTest.groovy
index 6c958cb..81205fb 100644
--- a/src/spec/test/gdk/ConfigSlurperTest.groovy
+++ b/src/spec/test/gdk/ConfigSlurperTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gdk
 
 /*
diff --git a/src/spec/test/gdk/ExpandoTest.groovy b/src/spec/test/gdk/ExpandoTest.groovy
index 7bd2d14..1d3acd0 100644
--- a/src/spec/test/gdk/ExpandoTest.groovy
+++ b/src/spec/test/gdk/ExpandoTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gdk
 
 /*
diff --git a/src/spec/test/gdk/ObservableTest.groovy b/src/spec/test/gdk/ObservableTest.groovy
index 0751e59..e326078 100644
--- a/src/spec/test/gdk/ObservableTest.groovy
+++ b/src/spec/test/gdk/ObservableTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gdk
 
 import java.beans.PropertyChangeListener
diff --git a/src/spec/test/gdk/WorkingWithCollectionsTest.groovy b/src/spec/test/gdk/WorkingWithCollectionsTest.groovy
new file mode 100644
index 0000000..fc0ebb5
--- /dev/null
+++ b/src/spec/test/gdk/WorkingWithCollectionsTest.groovy
@@ -0,0 +1,733 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package gdk
+
+class WorkingWithCollectionsTest extends GroovyTestCase {
+    void testListLiterals() {
+        // tag::list_literals[]
+        def list = [5, 6, 7, 8]
+        assert list.get(2) == 7
+        assert list[2] == 7
+        assert list instanceof java.util.List
+
+        def emptyList = []
+        assert emptyList.size() == 0
+        emptyList.add(5)
+        assert emptyList.size() == 1
+        // end::list_literals[]
+    }
+
+    void testList() {
+        // tag::list_usecases[]
+        def list = [5, 6, 7, 8]
+        assert list.size() == 4
+        assert list.getClass() == ArrayList     // the specific kind of list being used
+
+        assert list[2] == 7                     // indexing starts at 0
+        assert list.getAt(2) == 7               // equivalent method to subscript operator []
+        assert list.get(2) == 7                 // alternative method
+
+        list[2] = 9
+        assert list == [5, 6, 9, 8,]           // trailing comma OK
+
+        list.putAt(2, 10)                       // equivalent method to [] when value being changed
+        assert list == [5, 6, 10, 8]
+        assert list.set(2, 11) == 10            // alternative method that returns old value
+        assert list == [5, 6, 11, 8]
+
+        assert ['a', 1, 'a', 'a', 2.5, 2.5f, 2.5d, 'hello', 7g, null, 9 as byte]
+        //objects can be of different types; duplicates allowed
+
+        assert [1, 2, 3, 4, 5][-1] == 5             // use negative indices to count from the end
+        assert [1, 2, 3, 4, 5][-2] == 4
+        assert [1, 2, 3, 4, 5].getAt(-2) == 4       // getAt() available with negative index...
+        try {
+            [1, 2, 3, 4, 5].get(-2)                 // but negative index not allowed with get()
+            assert false
+        } catch (e) {
+            assert e instanceof ArrayIndexOutOfBoundsException
+        }
+        // end::list_usecases[]
+    }
+
+    void testListsAsBoolean() {
+        // tag::list_to_bool[]
+        assert ![]             // an empty list evaluates as false
+
+        //all other lists, irrespective of contents, evaluate as true
+        assert [1] && ['a'] && [0] && [0.0] && [false] && [null]
+        // end::list_to_bool[]
+    }
+
+    void testLeftShiftOnList() {
+        // tag::list_leftshift[]
+        def list = []
+        assert list.empty
+
+        list << 5
+        assert list.size() == 1
+
+        list << 7 << 'i' << 11
+        assert list == [5, 7, 'i', 11]
+
+        list << ['m', 'o']
+        assert list == [5, 7, 'i', 11, ['m', 'o']]
+
+        //first item in chain of << is target list
+        assert ([1, 2] << 3 << [4, 5] << 6) == [1, 2, 3, [4, 5], 6]
+
+        //using leftShift is equivalent to using <<
+        assert ([1, 2, 3] << 4) == ([1, 2, 3].leftShift(4))
+
+        // end::list_leftshift[]
+    }
+
+    void testListAdd() {
+        // tag::list_add[]
+        assert [1, 2] + 3 + [4, 5] + 6 == [1, 2, 3, 4, 5, 6]
+        // equivalent to calling the `plus` method
+        assert [1, 2].plus(3).plus([4, 5]).plus(6) == [1, 2, 3, 4, 5, 6]
+
+        def a = [1, 2, 3]
+        a += 4      // creates a new list and assigns it to `a`
+        a += [5, 6]
+        assert a == [1, 2, 3, 4, 5, 6]
+
+        assert [1, *[222, 333], 456] == [1, 222, 333, 456]
+        assert [*[1, 2, 3]] == [1, 2, 3]
+        assert [1, [2, 3, [4, 5], 6], 7, [8, 9]].flatten() == [1, 2, 3, 4, 5, 6, 7, 8, 9]
+
+        def list = [1, 2]
+        list.add(3)
+        list.addAll([5, 4])
+        assert list == [1, 2, 3, 5, 4]
+
+        list = [1, 2]
+        list.add(1, 3) // add 3 just before index 1
+        assert list == [1, 3, 2]
+
+        list.addAll(2, [5, 4]) //add [5,4] just before index 2
+        assert list == [1, 3, 5, 4, 2]
+
+        list = ['a', 'b', 'z', 'e', 'u', 'v', 'g']
+        list[8] = 'x' // the [] operator is growing the list as needed
+        // nulls inserted if required
+        assert list == ['a', 'b', 'z', 'e', 'u', 'v', 'g', null, 'x']
+        // end::list_add[]
+    }
+
+    void testListIteration() {
+        // tag::list_each[]
+        [1, 2, 3].each {
+            println "Item: $it" // `it` is an implicit parameter corresponding to the current element
+        }
+        ['a', 'b', 'c'].eachWithIndex { it, i -> // `it` is the current element, while `i` is the index
+            println "$i: $it"
+        }
+        // end::list_each[]
+    }
+
+    void testListConstruct() {
+        // tag::list_construct[]
+        def list1 = ['a', 'b', 'c']
+        //construct a new list, seeded with the same items as in list1
+        def list2 = new ArrayList<String>(list1)
+
+        assert list2 == list1 // == checks that each corresponding element is the same
+
+        // clone() can also be called
+        def list3 = list1.clone()
+        assert list3 == list1
+        // end::list_construct[]
+    }
+
+    void testListCollect() {
+        // tag::list_collect[]
+        assert [1, 2, 3].collect { it * 2 } == [2, 4, 6]
+
+        // shortcut syntax instead of collect
+        assert [1, 2, 3]*.multiply(2) == [1, 2, 3].collect { it.multiply(2) }
+
+        def list = [0]
+        // it is possible to give `collect` the list which collects the elements
+        assert [1, 2, 3].collect(list) { it * 2 } == [0, 2, 4, 6]
+        assert list == [0, 2, 4, 6]
+        // end::list_collect[]
+    }
+
+    void testListGDK() {
+        // tag::list_gdk1[]
+        assert [1, 2, 3].find { it > 1 } == 2           // find 1st element matching criteria
+        assert [1, 2, 3].findAll { it > 1 } == [2, 3]   // find all elements matching critieria
+        assert ['a', 'b', 'c', 'd', 'e'].findIndexOf {      // find index of 1st element matching criteria
+            it in ['c', 'e', 'g']
+        } == 2
+
+        assert ['a', 'b', 'c', 'd', 'c'].indexOf('c') == 2  // index returned
+        assert ['a', 'b', 'c', 'd', 'c'].indexOf('z') == -1 // index -1 means value not in list
+        assert ['a', 'b', 'c', 'd', 'c'].lastIndexOf('c') == 4
+
+        assert [1, 2, 3].every { it < 5 }               // returns true if all elements match the predicate
+        assert ![1, 2, 3].every { it < 3 }
+        assert [1, 2, 3].any { it > 2 }                 // returns true if any element matches the predicate
+        assert ![1, 2, 3].any { it > 3 }
+
+        assert [1, 2, 3, 4, 5, 6].sum() == 21                // sum anything with a plus() method
+        assert ['a', 'b', 'c', 'd', 'e'].sum {
+            it == 'a' ? 1 : it == 'b' ? 2 : it == 'c' ? 3 : it == 'd' ? 4 : it == 'e' ? 5 : 0
+            // custom value to use in sum
+        } == 15
+        assert ['a', 'b', 'c', 'd', 'e'].sum { ((char) it) - ((char) 'a') } == 10
+        assert ['a', 'b', 'c', 'd', 'e'].sum() == 'abcde'
+        assert [['a', 'b'], ['c', 'd']].sum() == ['a', 'b', 'c', 'd']
+
+        // an initial value can be provided
+        assert [].sum(1000) == 1000
+        assert [1, 2, 3].sum(1000) == 1006
+
+        assert [1, 2, 3].join('-') == '1-2-3'           // String joining
+        assert [1, 2, 3].inject('counting: ') {
+            str, item -> str + item                     // reduce operation
+        } == 'counting: 123'
+        assert [1, 2, 3].inject(0) { count, item ->
+            count + item
+        } == 6
+        // end::list_gdk1[]
+
+        // tag::list_gdk2[]
+        def list = [9, 4, 2, 10, 5]
+        assert list.max() == 10
+        assert list.min() == 2
+
+        // we can also compare single characters, as anything comparable
+        assert ['x', 'y', 'a', 'z'].min() == 'a'
+
+        // we can use a closure to specify the sorting behaviour
+        def list2 = ['abc', 'z', 'xyzuvw', 'Hello', '321']
+        assert list2.max { it.size() } == 'xyzuvw'
+        assert list2.min { it.size() } == 'z'
+        // end::list_gdk2[]
+
+        assertScript '''
+            // tag::list_gdk3[]
+            assert ['a','b','c','b','b'] - 'c' == ['a','b','b','b']
+            assert ['a','b','c','b','b'] - 'b' == ['a','c']
+            assert ['a','b','c','b','b'] - ['b','c'] == ['a']
+
+            def list = [1,2,3,4,3,2,1]
+            list -= 3           // creates a new list by removing `3` from the original one
+            assert list == [1,2,4,2,1]
+            assert ( list -= [2,4] ) == [1,1]
+            // end::list_gdk3[]
+        '''
+
+        assertScript '''
+            // tag::list_gdk4[]
+            def list = [1,2,3,4,5,6,2,2,1]
+            assert list.remove(2) == 3          // remove the third element, and return it
+            assert list == [1,2,4,5,6,2,2,1]
+            // end::list_gdk4[]
+        '''
+
+        assertScript '''
+            // tag::list_gdk5[]
+            def list= ['a','b','c','b','b']
+            assert list.remove('c')             // remove 'c', and return true because element removed
+            assert list.remove('b')             // remove first 'b', and return true because element removed
+
+            assert ! list.remove('z')           // return false because no elements removed
+            assert list == ['a','b','b']
+            // end::list_gdk5[]
+        '''
+
+        assertScript '''
+            // tag::list_gdk6[]
+            def list= ['a',2,'c',4]
+            list.clear()
+            assert list == []
+            // end::list_gdk6[]
+        '''
+
+        assertScript '''
+            // tag::list_gdk7[]
+            assert 'a' in ['a','b','c']             // returns true if an element belongs to the list
+            assert ['a','b','c'].contains('a')      // equivalent to the `contains` method in Java
+            assert [1,3,4].containsAll([1,4])       // `containsAll` will check that all elements are found
+
+            assert [1,2,3,3,3,3,4,5].count(3) == 4  // count the number of elements which have some value
+            assert [1,2,3,3,3,3,4,5].count {
+                it%2==0                             // count the number of elements which match the predicate
+            } == 2
+
+            assert [1,2,4,6,8,10,12].intersect([1,3,6,9,12]) == [1,6,12]
+
+            assert [1,2,3].disjoint( [4,6,9] )
+            assert ![1,2,3].disjoint( [2,4,6] )
+            // end::list_gdk7[]
+        '''
+
+    }
+
+    void testListComparator() {
+        // tag::list_comparator[]
+        Comparator mc = { a, b -> a == b ? 0 : (a < b ? -1 : 1) }
+
+        def list = [7, 4, 9, -6, -1, 11, 2, 3, -9, 5, -13]
+        assert list.max(mc) == 11
+        assert list.min(mc) == -13
+
+        Comparator mc2 = { a, b -> a == b ? 0 : (Math.abs(a) < Math.abs(b)) ? -1 : 1 }
+
+
+        assert list.max(mc2) == -13
+        assert list.min(mc2) == -1
+
+        assert list.max { a, b -> a.equals(b) ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } == -13
+        assert list.min { a, b -> a.equals(b) ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } == -1
+        // end::list_comparator[]
+    }
+
+    void testListSort() {
+        // tag::list_sort[]
+        assert [6, 3, 9, 2, 7, 1, 5].sort() == [1, 2, 3, 5, 6, 7, 9]
+
+        def list = ['abc', 'z', 'xyzuvw', 'Hello', '321']
+        assert list.sort {
+            it.size()
+        } == ['z', 'abc', '321', 'Hello', 'xyzuvw']
+
+        def list2 = [7, 4, -6, -1, 11, 2, 3, -9, 5, -13]
+        assert list2.sort { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 } ==
+                [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13]
+
+        Comparator mc = { a, b -> a == b ? 0 : Math.abs(a) < Math.abs(b) ? -1 : 1 }
+
+        // JDK 8+ only
+        // list2.sort(mc)
+        // assert list2 == [-1, 2, 3, 4, 5, -6, 7, -9, 11, -13]
+
+        def list3 = [6, -3, 9, 2, -7, 1, 5]
+
+        Collections.sort(list3)
+        assert list3 == [-7, -3, 1, 2, 5, 6, 9]
+
+        Collections.sort(list3, mc)
+        assert list3 == [1, 2, -3, 5, 6, -7, 9]
+        // end::list_sort[]
+    }
+
+    void testListMultiply() {
+        // tag::list_multiply[]
+        assert [1, 2, 3] * 3 == [1, 2, 3, 1, 2, 3, 1, 2, 3]
+        assert [1, 2, 3].multiply(2) == [1, 2, 3, 1, 2, 3]
+        assert Collections.nCopies(3, 'b') == ['b', 'b', 'b']
+
+        // nCopies from the JDK has different semantics than multiply for lists
+        assert Collections.nCopies(2, [1, 2]) == [[1, 2], [1, 2]] //not [1,2,1,2]
+        // end::list_multiply[]
+    }
+
+    void testIntRange() {
+        // tag::intrange[]
+        // an inclusive range
+        def range = 5..8
+        assert range.size() == 4
+        assert range.get(2) == 7
+        assert range[2] == 7
+        assert range instanceof java.util.List
+        assert range.contains(5)
+        assert range.contains(8)
+
+        // lets use a half-open range
+        range = 5..<8
+        assert range.size() == 3
+        assert range.get(2) == 7
+        assert range[2] == 7
+        assert range instanceof java.util.List
+        assert range.contains(5)
+        assert !range.contains(8)
+
+        //get the end points of the range without using indexes
+        range = 1..10
+        assert range.from == 1
+        assert range.to == 10
+        // end::intrange[]
+    }
+
+    void testStringRange() {
+        // tag::stringrange[]
+        // an inclusive range
+        def range = 'a'..'d'
+        assert range.size() == 4
+        assert range.get(2) == 'c'
+        assert range[2] == 'c'
+        assert range instanceof java.util.List
+        assert range.contains('a')
+        assert range.contains('d')
+        assert !range.contains('e')
+        // end::stringrange[]
+    }
+
+    void testRangeIteration() {
+        // tag::range_for[]
+        for (i in 1..10) {
+            println "Hello ${i}"
+        }
+        // end::range_for[]
+        // tag::range_each[]
+        (1..10).each { i ->
+            println "Hello ${i}"
+        }
+        // end::range_each[]
+    }
+
+    void testRangeInSwitch() {
+        int years = 1
+        double interestRate
+        // tag::range_switch[]
+        switch (years) {
+            case 1..10: interestRate = 0.076; break;
+            case 11..25: interestRate = 0.052; break;
+            default: interestRate = 0.037;
+        }
+        // end::range_switch[]
+        assert interestRate == 0.076d
+
+    }
+
+    void testMapLiteral() {
+        // tag::map_literal[]
+        def map = [name: 'Gromit', likes: 'cheese', id: 1234]
+        assert map.get('name') == 'Gromit'
+        assert map.get('id') == 1234
+        assert map['name'] == 'Gromit'
+        assert map['id'] == 1234
+        assert map instanceof java.util.Map
+
+        def emptyMap = [:]
+        assert emptyMap.size() == 0
+        emptyMap.put("foo", 5)
+        assert emptyMap.size() == 1
+        assert emptyMap.get("foo") == 5
+        // end::map_literal[]
+    }
+
+    void testMapLiteralUsingEscape() {
+        // tag::map_literal_gotcha[]
+        def a = 'Bob'
+        def ages = [a: 43]
+        assert ages['Bob'] == null // `Bob` is not found
+        assert ages['a'] == 43     // because `a` is a literal!
+
+        ages = [(a): 43]            // now we escape `a` by using parenthesis
+        assert ages['Bob'] == 43   // and the value is found!
+        // end::map_literal_gotcha[]
+    }
+
+    void testMapPropertyNotation() {
+        // tag::map_property[]
+        def map = [name: 'Gromit', likes: 'cheese', id: 1234]
+        assert map.name == 'Gromit'     // can be used instead of map.get('Gromit')
+        assert map.id == 1234
+
+        def emptyMap = [:]
+        assert emptyMap.size() == 0
+        emptyMap.foo = 5
+        assert emptyMap.size() == 1
+        assert emptyMap.foo == 5
+        // end::map_property[]
+    }
+
+    void testMapPropertyGotcha() {
+        // tag::map_property_gotcha[]
+        def map = [name: 'Gromit', likes: 'cheese', id: 1234]
+        assert map.class == null
+        assert map.get('class') == null
+        assert map.getClass() == LinkedHashMap // this is probably what you want
+
+        map = [1      : 'a',
+               (true) : 'p',
+               (false): 'q',
+               (null) : 'x',
+               'null' : 'z']
+        assert map.containsKey(1) // 1 is not an identifier so used as is
+        assert map.true == null
+        assert map.false == null
+        assert map.get(true) == 'p'
+        assert map.get(false) == 'q'
+        assert map.null == 'z'
+        assert map.get(null) == 'x'
+        // end::map_property_gotcha[]
+    }
+
+    void testMapIteration() {
+        // tag::map_iteration[]
+        def map = [
+                Bob  : 42,
+                Alice: 54,
+                Max  : 33
+        ]
+
+        // `entry` is a map entry
+        map.each { entry ->
+            println "Name: $entry.key Age: $entry.value"
+        }
+
+        // `entry` is a map entry, `i` the index in the map
+        map.eachWithIndex { entry, i ->
+            println "$i - Name: $entry.key Age: $entry.value"
+        }
+
+        // Alternatively you can use key and value directly
+        map.each { key, value ->
+            println "Name: $key Age: $value"
+        }
+
+        // Key, value and i as the index in the map
+        map.eachWithIndex { key, value, i ->
+            println "$i - Name: $key Age: $value"
+        }
+        // end::map_iteration[]
+    }
+
+    void testAddElementsToMap() {
+        // tag::map_add[]
+        def defaults = [1: 'a', 2: 'b', 3: 'c', 4: 'd']
+        def overrides = [2: 'z', 5: 'x', 13: 'x']
+
+        def result = new LinkedHashMap(defaults)
+        result.put(15, 't')
+        result[17] = 'u'
+        result.putAll(overrides)
+        assert result == [1: 'a', 2: 'z', 3: 'c', 4: 'd', 5: 'x', 13: 'x', 15: 't', 17: 'u']
+        // end::map_add[]
+    }
+
+    void testMapGDK() {
+        assertScript '''
+            // tag::map_gdk1[]
+            def m = [1:'a', 2:'b']
+            assert m.get(1) == 'a'
+            m.clear()
+            assert m == [:]
+            // end::map_gdk1[]
+        '''
+
+        assertScript '''
+            // tag::map_views[]
+            def map = [1:'a', 2:'b', 3:'c']
+
+            def entries = map.entrySet()
+            entries.each { entry ->
+              assert entry.key in [1,2,3]
+              assert entry.value in ['a','b','c']
+            }
+
+            def keys = map.keySet()
+            assert keys == [1,2,3] as Set
+            // end::map_views[]
+        '''
+
+        assertScript '''
+            // tag::map_gdk2[]
+            def people = [
+                1: [name:'Bob', age: 32, gender: 'M'],
+                2: [name:'Johnny', age: 36, gender: 'M'],
+                3: [name:'Claire', age: 21, gender: 'F'],
+                4: [name:'Amy', age: 54, gender:'F']
+            ]
+
+            def bob = people.find { it.value.name == 'Bob' } // find a single entry
+            def females = people.findAll { it.value.gender == 'F' }
+
+            // both return entries, but you can use collect to retrieve the ages for example
+            def ageOfBob = bob.value.age
+            def agesOfFemales = females.collect {
+                it.value.age
+            }
+
+            assert ageOfBob == 32
+            assert agesOfFemales == [21,54]
+
+            // but you could also use a key/pair value as the parameters of the closures
+            def agesOfMales = people.findAll { id, person ->
+                person.gender == 'M'
+            }.collect { id, person ->
+                person.age
+            }
+            assert agesOfMales == [32, 36]
+
+            // `every` returns true if all entries match the predicate
+            assert people.every { id, person ->
+                person.age > 18
+            }
+
+            // `any` returns true if any entry matches the predicate
+
+            assert people.any { id, person ->
+                person.age == 54
+            }
+            // end::map_gdk2[]
+        '''
+
+        assertScript '''
+            // tag::map_gdk3[]
+            assert ['a', 7, 'b', [2, 3]].groupBy {
+                it.class
+            } == [(String)   : ['a', 'b'],
+                  (Integer)  : [7],
+                  (ArrayList): [[2, 3]]
+            ]
+
+            assert [
+                    [name: 'Clark', city: 'London'], [name: 'Sharma', city: 'London'],
+                    [name: 'Maradona', city: 'LA'], [name: 'Zhang', city: 'HK'],
+                    [name: 'Ali', city: 'HK'], [name: 'Liu', city: 'HK'],
+            ].groupBy { it.city } == [
+                    London: [[name: 'Clark', city: 'London'],
+                             [name: 'Sharma', city: 'London']],
+                    LA    : [[name: 'Maradona', city: 'LA']],
+                    HK    : [[name: 'Zhang', city: 'HK'],
+                             [name: 'Ali', city: 'HK'],
+                             [name: 'Liu', city: 'HK']],
+            ]
+            // end::map_gdk3[]
+        '''
+    }
+
+    void testShouldNotUseGStringAsKey() {
+        assertScript '''
+            // tag::gstring_gotcha[]
+            def key = 'some key'
+            def map = [:]
+            def gstringKey = "${key.toUpperCase()}"
+            map.put(gstringKey,'value')
+            assert map.get('SOME KEY') == null
+            // end::gstring_gotcha[]
+        '''
+    }
+
+    void testMapConstruct() {
+        // tag::map_construct[]
+        def map = [
+                simple : 123,
+                complex: [a: 1, b: 2]
+        ]
+        def map2 = map.clone()
+        assert map2.get('simple') == map.get('simple')
+        assert map2.get('complex') == map.get('complex')
+        map2.get('complex').put('c', 3)
+        assert map.get('complex').get('c') == 3
+        // end::map_construct[]
+    }
+
+    void testGPathSupport() {
+        // tag::gpath_support_1[]
+        def listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22]]
+        assert listOfMaps.a == [11, 21] //GPath notation
+        assert listOfMaps*.a == [11, 21] //spread dot notation
+
+        listOfMaps = [['a': 11, 'b': 12], ['a': 21, 'b': 22], null]
+        assert listOfMaps*.a == [11, 21, null] // caters for null values
+        assert listOfMaps*.a == listOfMaps.collect { it?.a } //equivalent notation
+        // end::gpath_support_1[]
+
+        // tag::gpath_support_2[]
+        // But this will only collect non-null values
+        assert listOfMaps.a == [11,21]
+        // end::gpath_support_2[]
+
+        // tag::gpath_support_3[]
+        assert [ 'z': 900,
+                 *: ['a': 100, 'b': 200], 'a': 300] == ['a': 300, 'b': 200, 'z': 900]
+        //spread map notation in map definition
+        assert [*: [3: 3, *: [5: 5]], 7: 7] == [3: 3, 5: 5, 7: 7]
+
+        def f = { [1: 'u', 2: 'v', 3: 'w'] }
+        assert [*: f(), 10: 'zz'] == [1: 'u', 10: 'zz', 2: 'v', 3: 'w']
+        //spread map notation in function arguments
+        f = { map -> map.c }
+        assert f(*: ['a': 10, 'b': 20, 'c': 30], 'e': 50) == 30
+
+        f = { m, i, j, k -> [m, i, j, k] }
+        //using spread map notation with mixed unnamed and named arguments
+        assert f('e': 100, *[4, 5], *: ['a': 10, 'b': 20, 'c': 30], 6) ==
+                [["e": 100, "b": 20, "c": 30, "a": 10], 4, 5, 6]
+        // end::gpath_support_3[]
+
+    }
+
+    void testStarDot() {
+        // tag::stardot_1[]
+        assert [1, 3, 5] == ['a', 'few', 'words']*.size()
+        // end::stardot_1[]
+        assertScript '''
+            // tag::stardot_2[]
+            class Person {
+                String name
+                int age
+            }
+            def persons = [new Person(name:'Hugo', age:17), new Person(name:'Sandra',age:19)]
+            assert [17, 19] == persons*.age
+            // end::stardot_2[]
+        '''
+    }
+
+    void testSubscriptOperator() {
+        // tag::subscript[]
+        def text = 'nice cheese gromit!'
+        def x = text[2]
+
+        assert x == 'c'
+        assert x.class == String
+
+        def sub = text[5..10]
+        assert sub == 'cheese'
+
+        def list = [10, 11, 12, 13]
+        def answer = list[2,3]
+        assert answer == [12,13]
+        // end::subscript[]
+
+        // tag::subscript_2[]
+        list = 100..200
+        sub = list[1, 3, 20..25, 33]
+        assert sub == [101, 103, 120, 121, 122, 123, 124, 125, 133]
+        // end::subscript_2[]
+
+        // tag::subscript_3[]
+        list = ['a','x','x','d']
+        list[1..2] = ['b','c']
+        assert list == ['a','b','c','d']
+        // end::subscript_3[]
+
+        // tag::subscript_4[]
+        text = "nice cheese gromit!"
+        x = text[-1]
+        assert x == "!"
+
+        def name = text[-7..-2]
+        assert name == "gromit"
+        // end::subscript_4[]
+
+        // tag::subscript_5[]
+        text = "nice cheese gromit!"
+        name = text[3..1]
+        assert name == "eci"
+        // end::subscript_5[]
+    }
+}
diff --git a/src/spec/test/gdk/WorkingWithIOSpecTest.groovy b/src/spec/test/gdk/WorkingWithIOSpecTest.groovy
new file mode 100644
index 0000000..12b4bc1
--- /dev/null
+++ b/src/spec/test/gdk/WorkingWithIOSpecTest.groovy
@@ -0,0 +1,384 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package gdk
+
+import groovy.io.FileType
+import groovy.io.FileVisitResult
+import groovy.transform.CompileStatic
+
+class WorkingWithIOSpecTest extends GroovyTestCase {
+
+    private final static boolean unixlike =
+            System.getProperty('os.name').contains('Linux') ||
+                    System.getProperty('os.name').contains('Mac OS')
+   private final static boolean windoz =
+            System.getProperty('os.name').contains('Windows')
+
+    @CompileStatic
+    private void doInTmpDir(Closure cl) {
+        def baseDir = File.createTempDir()
+        try {
+            cl.call(new FileTreeBuilder(baseDir))
+        } finally {
+            baseDir.deleteDir()
+        }
+    }
+
+    void testFileIntro() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            dir.'haiku.txt'('''Un vieil étang et
+Une grenouille qui plonge,
+Le bruit de l'eau.''')
+            // tag::print_file_lines[]
+            new File(baseDir, 'haiku.txt').eachLine { line ->
+                println line
+            }
+            // end::print_file_lines[]
+
+            // tag::print_file_lines2[]
+            new File(baseDir, 'haiku.txt').eachLine { line, nb ->
+                println "Line $nb: $line"
+            }
+            // end::print_file_lines2[]
+
+            // tag::collect_lines[]
+            def list = new File(baseDir, 'haiku.txt').collect {it}
+            // end::collect_lines[]
+            // tag::lines_as_strings[]
+            def array = new File(baseDir, 'haiku.txt') as String[]
+            // end::lines_as_strings[]
+            assert list.size()==3
+            assert array.length==3
+
+            def file = new File(baseDir, 'haiku.txt')
+            // tag::file_bytes[]
+            byte[] contents = file.bytes
+            // end::file_bytes[]
+            def expectedLength = 64
+            // e with acute accent won't be encoded on some systems -23 vs -61, -87
+            if (System.getProperty('file.encoding').endsWith('1252')) {
+                expectedLength = 63
+            }
+            assert contents.length == expectedLength
+
+        }
+    }
+
+    void testWithReader() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            dir.'haiku.txt'('''Un vieil étang et
+Une grenouille qui plonge,
+Le bruit de l'eau.
+Fin.''')
+            try {
+                // tag::withreader_exception[]
+                def count = 0, MAXSIZE = 3
+                new File(baseDir,"haiku.txt").withReader { reader ->
+                    while (reader.readLine()) {
+                        if (++count > MAXSIZE) {
+                            throw new RuntimeException('Haiku should only have 3 verses')
+                        }
+                    }
+                }
+                // end::withreader_exception[]
+                assert false
+            } catch (RuntimeException e) {
+                assert e.message == 'Haiku should only have 3 verses'
+            }
+        }
+    }
+
+    void testWithWriter() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            // tag::withwriter_example[]
+            new File(baseDir,'haiku.txt').withWriter('utf-8') { writer ->
+                writer.writeLine 'Into the ancient pond'
+                writer.writeLine 'A frog jumps'
+                writer.writeLine 'Water’s sound!'
+            }
+            // end::withwriter_example[]
+        }
+    }
+
+    void testLeftShift() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            // tag::file_leftshift[]
+            new File(baseDir,'haiku.txt') << '''Into the ancient pond
+            A frog jumps
+            Water’s sound!'''
+            // end::file_leftshift[]
+        }
+    }
+
+    void testSetBytes() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            def file = new File(baseDir, 'binary.bin')
+            // tag::file_setbytes[]
+            file.bytes = [66,22,11]
+            // end::file_setbytes[]
+        }
+    }
+
+    void testEachFile() {
+        doInTmpDir { builder ->
+            File dir = builder {
+                'file1.txt'('file 1')
+                'file2.txt'('file 2')
+                'file3.bin'('file 3')
+            }
+            // tag::eachfile[]
+            dir.eachFile { file ->                      // <1>
+                println file.name
+            }
+            dir.eachFileMatch(~/.*\.txt/) { file ->     // <2>
+                println file.name
+            }
+            // end::eachfile[]
+        }
+    }
+
+    void testEachFileRecurse() {
+        doInTmpDir { builder ->
+            File dir = builder {
+                'file1.txt'('file 1')
+                'file2.txt'('file 2')
+                bin {
+                    'file3.bin'('file 3')
+                }
+            }
+            // tag::eachfilerecurse[]
+            dir.eachFileRecurse { file ->                      // <1>
+                println file.name
+            }
+
+            dir.eachFileRecurse(FileType.FILES) { file ->      // <2>
+                println file.name
+            }
+            // end::eachfilerecurse[]
+        }
+    }
+
+    void testTraverse() {
+        doInTmpDir { builder ->
+            File dir = builder {
+                'file1.txt'('file 1')
+                'file2.txt'('file 2')
+                bin {
+                    'file3.bin'('file 3')
+                }
+            }
+            // tag::traverse[]
+            dir.traverse { file ->
+                if (file.directory && file.name=='bin') {
+                    FileVisitResult.TERMINATE                   // <1>
+                } else {
+                    println file.name
+                    FileVisitResult.CONTINUE                    // <2>
+                }
+
+            }
+            // end::traverse[]
+        }
+    }
+
+    void testGetInputStreamFromFile() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            dir.'haiku.txt'('''Un vieil étang et
+Une grenouille qui plonge,
+Le bruit de l'eau.
+Fin.''')
+            // tag::newinputstream[]
+            def is = new File(baseDir,'haiku.txt').newInputStream()
+            // do something ...
+            is.close()
+            // end::newinputstream[]
+
+            // tag::withinputstream[]
+            new File(baseDir,'haiku.txt').withInputStream { stream ->
+                // do something ...
+            }
+            // end::withinputstream[]
+        }
+    }
+
+    void testFileOutputStream() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            // tag::newoutputstream[]
+            def os = new File(baseDir,'data.bin').newOutputStream()
+            // do something ...
+            os.close()
+            // end::newoutputstream[]
+
+            // tag::withoutputstream[]
+            new File(baseDir,'data.bin').withOutputStream { stream ->
+                // do something ...
+            }
+            // end::withoutputstream[]
+        }
+    }
+
+    void testDataInputOutput() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            def file = new File(baseDir, 'data.bin')
+            // tag::data_in_out[]
+            boolean b = true
+            String message = 'Hello from Groovy'
+            // Serialize data into a file
+            file.withDataOutputStream { out ->
+                out.writeBoolean(b)
+                out.writeUTF(message)
+            }
+            // ...
+            // Then read it back
+            file.withDataInputStream { input ->
+                assert input.readBoolean() == b
+                assert input.readUTF() == message
+            }
+            // end::data_in_out[]
+        }
+    }
+
+    void testObjectInputOutput() {
+        doInTmpDir { dir ->
+            File baseDir = dir.baseDir
+            def file = new File(baseDir, 'data.bin')
+            // tag::object_in_out[]
+            Person p = new Person(name:'Bob', age:76)
+            // Serialize data into a file
+            file.withObjectOutputStream { out ->
+                out.writeObject(p)
+            }
+            // ...
+            // Then read it back
+            file.withObjectInputStream { input ->
+                def p2 = input.readObject()
+                assert p2.name == p.name
+                assert p2.age == p.age
+            }
+            // end::object_in_out[]
+        }
+    }
+
+    void testProcess1() {
+        if (unixlike) {
+            // tag::process_list_files[]
+            def process = "ls -l".execute()             // <1>
+            println "Found text ${process.text}"        // <2>
+            // end::process_list_files[]
+            assert process instanceof Process
+        }
+        if (windoz) {
+            try {
+                // tag::dir_windows[]
+                def process = "dir".execute()
+                println "${process.text}"
+                // end::dir_windows[]
+                // we do not check that the expected exception is really thrown,
+                // because the command succeeds if PATH contains cygwin
+            } catch (e) {
+                // tag::dir_windows_fixed[]
+                def process = "cmd /c dir".execute()
+                println "${process.text}"
+                // end::dir_windows_fixed[]
+            }
+        }
+    }
+
+   void testProcess2() {
+        if (unixlike) {
+            // tag::process_list_files_line_by_line[]
+            def process = "ls -l".execute()             // <1>
+            process.in.eachLine { line ->               // <2>
+                println line                            // <3>
+            }
+            // end::process_list_files[]
+            assert process instanceof Process
+        }
+    }
+
+    void testProcessConsumeOutput() {
+        if (unixlike) {
+            doInTmpDir { b ->
+                File file = null
+                def tmpDir = b.tmp {
+                    file = 'foo.tmp'('foo')
+                }
+                assert file.exists()
+                // tag::consumeoutput[]
+                def p = "rm -f foo.tmp".execute([], tmpDir)
+                p.consumeProcessOutput()
+                p.waitFor()
+                // end::consumeoutput[]
+                assert !file.exists()
+            }
+
+        }
+    }
+
+    void testProcessPipe() {
+        if (unixlike) {
+            doInTmpDir { b ->
+                def proc1, proc2, proc3, proc4
+                // tag::pipe_example_1[]
+                proc1 = 'ls'.execute()
+                proc2 = 'tr -d o'.execute()
+                proc3 = 'tr -d e'.execute()
+                proc4 = 'tr -d i'.execute()
+                proc1 | proc2 | proc3 | proc4
+                proc4.waitFor()
+                if (proc4.exitValue()) {
+                    println proc4.err.text
+                } else {
+                    println proc4.text
+                }
+                // end::pipe_example_1[]
+
+                // tag::pipe_example_2[]
+                def sout = new StringBuilder()
+                def serr = new StringBuilder()
+                proc2 = 'tr -d o'.execute()
+                proc3 = 'tr -d e'.execute()
+                proc4 = 'tr -d i'.execute()
+                proc4.consumeProcessOutput(sout, serr)
+                proc2 | proc3 | proc4
+                [proc2, proc3].each { it.consumeProcessErrorStream(serr) }
+                proc2.withWriter { writer ->
+                    writer << 'testfile.groovy'
+                }
+                proc4.waitForOrKill(1000)
+                println "Standard output: $sout"
+                println "Standard error: $serr"
+                // end::pipe_example_2[]
+            }
+        }
+    }
+
+    public static class Person implements Serializable {
+        String name
+        int age
+    }
+}
diff --git a/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy b/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy
new file mode 100644
index 0000000..985b686
--- /dev/null
+++ b/src/spec/test/metaprogramming/ASTXFormSpecTest.groovy
@@ -0,0 +1,314 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metaprogramming
+
+import asciidoctor.Utils
+import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilationUnit
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.CompilerConfiguration
+
+import java.lang.annotation.ElementType
+import java.lang.annotation.Target
+
+class ASTXFormSpecTest extends GroovyTestCase {
+    void testLocalTransform() {
+        def gcl = new GroovyClassLoader()
+        def gse = new GroovyShell(gcl)
+
+        gse.parse '''package gep
+
+            import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+            // tag::withlogging_ann[]
+            import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+            import java.lang.annotation.ElementType
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+            import java.lang.annotation.Target
+
+            @Retention(RetentionPolicy.SOURCE)
+            @Target([ElementType.METHOD])
+            @GroovyASTTransformationClass(["gep.WithLoggingASTTransformation"])
+            public @interface WithLogging {
+            }
+            // end::withlogging_ann[]
+
+            // tag::withlogging_xform[]
+            @CompileStatic                                                                  // <1>
+            @GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)                  // <2>
+            class WithLoggingASTTransformation implements ASTTransformation {               // <3>
+
+                @Override
+                void visit(ASTNode[] nodes, SourceUnit sourceUnit) {                        // <4>
+                    MethodNode method = (MethodNode) nodes[1]                               // <5>
+
+                    def startMessage = createPrintlnAst("Starting $method.name")            // <6>
+                    def endMessage = createPrintlnAst("Ending $method.name")                // <7>
+
+                    def existingStatements = ((BlockStatement)method.code).statements       // <8>
+                    existingStatements.add(0, startMessage)                                 // <9>
+                    existingStatements.add(endMessage)                                      // <10>
+
+                }
+
+                private static Statement createPrintlnAst(String message) {                 // <11>
+                    new ExpressionStatement(
+                        new MethodCallExpression(
+                            new VariableExpression("this"),
+                            new ConstantExpression("println"),
+                            new ArgumentListExpression(
+                                new ConstantExpression(message)
+                            )
+                        )
+                    )
+                }
+            }
+            // end::withlogging_xform[]
+            WithLogging
+        '''
+
+        gse.evaluate '''package gep
+            // tag::withlogging_example[]
+            @WithLogging
+            def greet() {
+                println "Hello World"
+            }
+
+            greet()
+            // end::withlogging_example[]
+        '''
+    }
+
+    void testClassCodeTransformer() {
+        def gcl = new GroovyClassLoader()
+        def gse = new GroovyShell(gcl)
+
+        gse.parse '''package gep
+
+            import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.ClassCodeExpressionTransformer
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+
+            import org.codehaus.groovy.transform.GroovyASTTransformationClass
+
+            import java.lang.annotation.ElementType
+            import java.lang.annotation.Retention
+            import java.lang.annotation.RetentionPolicy
+            import java.lang.annotation.Target
+
+            @Retention(RetentionPolicy.SOURCE)
+            @Target([ElementType.METHOD])
+            @GroovyASTTransformationClass(["gep.ShoutASTTransformation"])
+            public @interface Shout {
+            }
+
+            // tag::shout_xform[]
+            @CompileStatic
+            @GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)
+            class ShoutASTTransformation implements ASTTransformation {
+
+                @Override
+                void visit(ASTNode[] nodes, SourceUnit sourceUnit) {
+                    ClassCodeExpressionTransformer trn = new ClassCodeExpressionTransformer() {         // <1>
+                        private boolean inArgList = false
+                        @Override
+                        protected SourceUnit getSourceUnit() {
+                            sourceUnit                                                                  // <2>
+                        }
+
+                        @Override
+                        Expression transform(final Expression exp) {
+                            if (exp instanceof ArgumentListExpression) {
+                                inArgList = true
+                            } else if (inArgList &&
+                                exp instanceof ConstantExpression && exp.value instanceof String) {
+                                return new ConstantExpression(exp.value.toUpperCase())                  // <3>
+                            }
+                            def trn = super.transform(exp)
+                            inArgList = false
+                            trn
+                        }
+                    }
+                    trn.visitMethod((MethodNode)nodes[1])                                               // <4>
+                }
+            }
+            // end::shout_xform[]
+            Shout
+        '''
+
+        gse.evaluate '''package gep
+            // tag::shout_example[]
+            @Shout
+            def greet() {
+                println "Hello World"
+            }
+
+            greet()
+            // end::shout_example[]
+        '''
+    }
+
+    // tag::breakpoint_missed[]
+    static class Subject {
+        @MyTransformToDebug
+        void methodToBeTested() {}
+    }
+
+    void testMyTransform() {
+        def c = new Subject()
+        c.methodToBeTested()
+    }
+    // end::breakpoint_missed[]
+
+    // tag::breakpoint_hit[]
+    void testMyTransformWithBreakpoint() {
+        assertScript '''
+            import metaprogramming.MyTransformToDebug
+
+            class Subject {
+                @MyTransformToDebug
+                void methodToBeTested() {}
+            }
+            def c = new Subject()
+            c.methodToBeTested()
+        '''
+    }
+    // end::breakpoint_hit[]
+
+    @CompileStatic
+    private void doInTmpDir(Closure cl) {
+        def baseDir = File.createTempDir()
+        try {
+            cl.call(new FileTreeBuilder(baseDir))
+        } finally {
+            baseDir.deleteDir()
+        }
+    }
+
+    void testGlobalTransform() {
+        doInTmpDir { builder ->
+            File dir = builder.baseDir
+            builder {
+                'META-INF' {
+                    services {
+                        'org.codehaus.groovy.transform.ASTTransformation'(Utils.stripAsciidocMarkup('''
+// tag::xform_descriptor_file[]
+gep.WithLoggingASTTransformation
+// end::xform_descriptor_file[]
+'''))
+                    }
+                }
+            }
+            def conf = new CompilerConfiguration()
+            conf.setTargetDirectory(dir)
+            def cu = new CompilationUnit(conf)
+            cu.addSource('WithLoggingASTTransformation.groovy','''package gep
+
+            import groovy.transform.CompileStatic
+import org.codehaus.groovy.ast.ASTNode
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.ArgumentListExpression
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.MethodCallExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.ast.stmt.BlockStatement
+import org.codehaus.groovy.ast.stmt.ExpressionStatement
+import org.codehaus.groovy.ast.stmt.Statement
+import org.codehaus.groovy.control.CompilePhase
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.transform.ASTTransformation
+import org.codehaus.groovy.transform.GroovyASTTransformation
+
+            // tag::withlogging_xform_global[]
+            @CompileStatic                                                                  // <1>
+            @GroovyASTTransformation(phase=CompilePhase.SEMANTIC_ANALYSIS)                  // <2>
+            class WithLoggingASTTransformation implements ASTTransformation {               // <3>
+
+                @Override
+                void visit(ASTNode[] nodes, SourceUnit sourceUnit) {                        // <4>
+                    def methods = sourceUnit.AST.methods                                    // <5>
+                    methods.each { method ->                                                // <6>
+                        def startMessage = createPrintlnAst("Starting $method.name")        // <7>
+                        def endMessage = createPrintlnAst("Ending $method.name")            // <8>
+
+                        def existingStatements = ((BlockStatement)method.code).statements   // <9>
+                        existingStatements.add(0, startMessage)                             // <10>
+                        existingStatements.add(endMessage)                                  // <11>
+                    }
+                }
+
+                private static Statement createPrintlnAst(String message) {                 // <12>
+                    new ExpressionStatement(
+                        new MethodCallExpression(
+                            new VariableExpression("this"),
+                            new ConstantExpression("println"),
+                            new ArgumentListExpression(
+                                new ConstantExpression(message)
+                            )
+                        )
+                    )
+                }
+            }
+            // end::withlogging_xform_global[]
+        ''')
+            cu.compile(CompilePhase.FINALIZATION.phaseNumber)
+
+            def gcl2 = new GroovyClassLoader(new URLClassLoader(
+                    [dir.toURI().toURL()] as URL[]))
+            def shell = new GroovyShell(gcl2)
+            shell.evaluate '''
+            // tag::withlogging_example_global[]
+            def greet() {
+                println "Hello World"
+            }
+
+            greet()
+            // end::withlogging_example_global[]
+        '''
+        }
+
+    }
+}
diff --git a/src/spec/test/metaprogramming/CategoryTest.groovy b/src/spec/test/metaprogramming/CategoryTest.groovy
index eb8b325..9eaba8c 100644
--- a/src/spec/test/metaprogramming/CategoryTest.groovy
+++ b/src/spec/test/metaprogramming/CategoryTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package metaprogramming
 
 import groovy.time.TimeCategory
diff --git a/src/spec/test/metaprogramming/MethodPropertyMissingTest.groovy b/src/spec/test/metaprogramming/MethodPropertyMissingTest.groovy
index a21535b..dc33a68 100644
--- a/src/spec/test/metaprogramming/MethodPropertyMissingTest.groovy
+++ b/src/spec/test/metaprogramming/MethodPropertyMissingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package metaprogramming
 
 class MethodPropertyMissingTest extends GroovyTestCase {
diff --git a/src/spec/test/metaprogramming/MyTransformToDebug.groovy b/src/spec/test/metaprogramming/MyTransformToDebug.groovy
new file mode 100644
index 0000000..b28d3d6
--- /dev/null
+++ b/src/spec/test/metaprogramming/MyTransformToDebug.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package metaprogramming
+
+import java.lang.annotation.ElementType
+import java.lang.annotation.Target
+
+ at Target(ElementType.METHOD)
+ at interface MyTransformToDebug {
+}
diff --git a/src/spec/test/objectorientation/MethodsTest.groovy b/src/spec/test/objectorientation/MethodsTest.groovy
new file mode 100644
index 0000000..e9134d8
--- /dev/null
+++ b/src/spec/test/objectorientation/MethodsTest.groovy
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package objectorientation
+
+class MethodsTests extends GroovyTestCase {
+
+    void testMethodDefinition() {
+        assertScript '''
+            // tag::method_definition[]
+            def someMethod() { 'method called' }                           //<1>
+            String anotherMethod() { 'another method called' }             //<2>
+            def thirdMethod(param1) { "$param1 passed" }                   //<3>
+            static String fourthMethod(String param1) { "$param1 passed" } //<4>
+            // end::method_definition[]
+        '''
+    }
+
+    void testNamedArguments() {
+        assertScript '''
+            // tag::named_arguments[]
+            def foo(Map args) { "${args.name}: ${args.age}" }
+            foo(name: 'Marie', age: 1)
+            // end::named_arguments[]
+        '''
+    }
+
+    void testDefaultArguments() {
+        assertScript '''
+            // tag::default_arguments[]
+            def foo(String par1, Integer par2 = 1) { [name: par1, age: par2] }
+            assert foo('Marie').age == 1
+            // end::default_arguments[]
+        '''
+    }
+
+    void testVarargs() {
+        assertScript '''
+            // tag::varargs_example[]
+            def foo(Object... args) { args.length }
+            assert foo() == 0
+            assert foo(1) == 1
+            assert foo(1, 2) == 2
+            // end::varargs_example[]
+        '''
+    }
+    
+    void testVarargsArrayNotation() {
+        assertScript '''
+            // tag::varargs_array_notation[]
+            def foo(Object[] args) { args.length }
+            assert foo() == 0
+            assert foo(1) == 1
+            assert foo(1, 2) == 2
+            // end::varargs_array_notation[]
+        '''
+    }
+    
+    void testVarargsNullParameter() {
+        assertScript '''
+            // tag::varargs_null_parameter[]
+            def foo(Object... args) { args }
+            assert foo(null) == null
+            // end::varargs_null_parameter[]
+        '''
+    }
+    
+    void testVarargsArrayParameter() {
+        assertScript '''
+            // tag::varargs_array_parameter[]
+            def foo(Object... args) { args }
+            Integer[] ints = [1, 2]
+            assert foo(ints) == [1, 2]
+            // end::varargs_array_parameter[]
+        '''
+    }
+    
+    void testVarargsMethodOverloading() {
+        assertScript '''
+            // tag::varargs_method_overloading[]
+            def foo(Object... args) { 1 }
+            def foo(Object x) { 2 }
+            assert foo() == 1
+            assert foo(1) == 2
+            assert foo(1, 2) == 1
+            // end::varargs_method_overloading[]
+        '''
+    }
+
+}
diff --git a/src/spec/test/semantics/GPathTest.groovy b/src/spec/test/semantics/GPathTest.groovy
new file mode 100644
index 0000000..d690c85
--- /dev/null
+++ b/src/spec/test/semantics/GPathTest.groovy
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package semantics
+
+import asciidoctor.Utils
+
+class GPathTest extends GroovyTestCase {
+
+    //tag::gpath_on_reflection_1[]
+    void aMethodFoo() { println "This is aMethodFoo." } // <0>
+    //end::gpath_on_reflection_1[]
+
+    void testGPathOnReflection() {
+        //tag::gpath_on_reflection_2[]
+        assert ['aMethodFoo'] == this.class.methods.name.grep(~/.*Foo/)
+        //end::gpath_on_reflection_2[]
+    }
+
+    //tag::gpath_on_reflection_3[]
+    void aMethodBar() { println "This is aMethodBar." } // <1>
+    void anotherFooMethod() { println "This is anotherFooMethod." } // <2>
+    void aSecondMethodBar() { println "This is aSecondMethodBar." } // <3>
+    //end::gpath_on_reflection_3[]
+
+    void testGPathOnReflectionWithBarMethods() {
+        //tag::gpath_on_reflection_4[]
+        assert ['aMethodBar', 'aSecondMethodBar'] as Set == this.class.methods.name.grep(~/.*Bar/) as Set
+        //end::gpath_on_reflection_4[]
+    }
+
+    void testGPathArrayAccess() {
+        //tag::gpath_array_access_1[]
+        assert 'aSecondMethodBar' == this.class.methods.name.grep(~/.*Bar/).sort()[1]
+        //end::gpath_array_access_1[]
+    }
+
+    void testGPathOnXml() {
+        //tag::gpath_on_xml_1[]
+        def xmlText = """
+                      | <root>
+                      |   <level>
+                      |      <sublevel id='1'>
+                      |        <keyVal>
+                      |          <key>mykey</key>
+                      |          <value>value 123</value>
+                      |        </keyVal>
+                      |      </sublevel>
+                      |      <sublevel id='2'>
+                      |        <keyVal>
+                      |          <key>anotherKey</key>
+                      |          <value>42</value>
+                      |        </keyVal>
+                      |        <keyVal>
+                      |          <key>mykey</key>
+                      |          <value>fizzbuzz</value>
+                      |        </keyVal>
+                      |      </sublevel>
+                      |   </level>
+                      | </root>
+                      """
+        def root = new XmlSlurper().parseText(xmlText.stripMargin())
+        assert root.level.size() == 1 // <1>
+        assert root.level.sublevel.size() == 2 // <2>
+        assert root.level.sublevel.findAll { it. at id == 1 }.size() == 1 // <3>
+        assert root.level.sublevel[1].keyVal[0].key.text() == 'anotherKey' // <4>
+        //end::gpath_on_xml_1[]
+    }
+
+}
diff --git a/src/spec/test/semantics/LabelsTest.groovy b/src/spec/test/semantics/LabelsTest.groovy
new file mode 100644
index 0000000..1542b26
--- /dev/null
+++ b/src/spec/test/semantics/LabelsTest.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package semantics
+
+class LabelsTest extends GroovyTestCase {
+    void testLabels() {
+        // tag::test_labels[]
+        given:
+            def x = 1
+            def y = 2
+        when:
+            def z = x+y
+        then:
+            assert z == 3
+        // end::test_labels[]
+    }
+
+    void testUseOfLabel() {
+        // tag::label_bad_practice[]
+        for (int i=0;i<10;i++) {
+            for (int j=0;j<i;j++) {
+                println "j=$j"
+                if (j == 5) {
+                    break exit
+                }
+            }
+            exit: println "i=$i"
+        }
+        // end::label_bad_practice[]
+    }
+}
diff --git a/src/spec/test/semantics/OptionalityTest.groovy b/src/spec/test/semantics/OptionalityTest.groovy
new file mode 100644
index 0000000..e749dad
--- /dev/null
+++ b/src/spec/test/semantics/OptionalityTest.groovy
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package semantics
+
+import gls.CompilableTestSupport
+
+class OptionalityTest extends CompilableTestSupport {
+
+    void testOptionalParentheses() {
+        // tag::optional_parentheses[]
+        println 'Hello World'
+        def maximum = Math.max 5, 10
+        // end::optional_parentheses[]
+    }
+    
+    void testRequiredParentheses() {
+        // tag::required_parentheses[]
+        println()
+        println(Math.max(5, 10))
+        // end::required_parentheses[]
+    }
+    
+    void testOptionalSemicolons() {
+        // tag::single_statement_with_semicolon[]
+        assert true;
+        // end::single_statement_with_semicolon[]
+        
+        // tag::single_statement_without_semicolon[]
+        assert true
+        // end::single_statement_without_semicolon[]
+    }
+    
+    void testRequiredSemicolons() {
+        // tag::statements_separated_by_semicolon[]
+        boolean a = true; assert a
+        // end::statements_separated_by_semicolon[]
+    }
+    
+    void testOptionalReturn() {
+        assertScript '''
+            // tag::return_keyword[]
+            int add(int a, int b) {
+                return a+b
+            }
+            assert add(1, 2) == 3
+            // end::return_keyword[]
+        '''
+        assertScript '''
+            // tag::omitted_return_keyword[]
+            int add(int a, int b) {
+                a+b
+            }
+            assert add(1, 2) == 3
+            // end::omitted_return_keyword[]
+        '''
+    }
+    
+    void testOptionalPublic() {
+        shouldCompile '''
+            // tag::public_keyword[]
+            public class Server {
+                public String toString() { "a server" }
+            }
+            // end::public_keyword[]
+        '''
+        shouldCompile '''
+            // tag::omitted_public[]
+            class Server {
+                String toString() { "a server" }
+            }
+            // end::omitted_public[]
+        '''
+    }
+}
diff --git a/src/spec/test/semantics/PowerAssertTest.groovy b/src/spec/test/semantics/PowerAssertTest.groovy
new file mode 100644
index 0000000..84635a3
--- /dev/null
+++ b/src/spec/test/semantics/PowerAssertTest.groovy
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package semantics
+
+import asciidoctor.Utils
+
+class PowerAssertTest extends GroovyTestCase {
+    void testPowerAssert() {
+        def msg = shouldFail {
+            //tag::assert_code_1[]
+            assert 1+1 == 3
+            //end::assert_code_1[]
+        }
+        assert msg == Utils.stripAsciidocMarkup('''
+//tag::assert_error_1[]
+assert 1+1 == 3
+        |  |
+        2  false
+//end::assert_error_1[]
+''')
+    }
+
+    void testPowerAssert2() {
+        def msg = shouldFail {
+            //tag::assert_code_2[]
+            def x = 2
+            def y = 7
+            def z = 5
+            def calc = { a,b -> a*b+1 }
+            assert calc(x,y) == [x,z].sum()
+            //end::assert_code_2[]
+        }
+        assert msg == Utils.stripAsciidocMarkup('''
+//tag::assert_error_2[]
+assert calc(x,y) == [x,z].sum()
+       |    | |  |   | |  |
+       15   2 7  |   2 5  7
+                 false
+//end::assert_error_2[]
+''')
+    }
+
+    void testCustomAssertMessage() {
+        def msg = shouldFail {
+            //tag::assert_code_3[]
+            def x = 2
+            def y = 7
+            def z = 5
+            def calc = { a,b -> a*b+1 }
+            assert calc(x,y) == z*z : 'Incorrect computation result'
+            //end::assert_code_3[]
+        }
+        assert msg == Utils.stripAsciidocMarkup('''
+//tag::assert_error_3[]
+Incorrect computation result. Expression: (calc.call(x, y) == (z * z)). Values: z = 5, z = 5
+//end::assert_error_3[]
+''')
+    }
+}
diff --git a/src/spec/test/semantics/TheGroovyTruthTest.groovy b/src/spec/test/semantics/TheGroovyTruthTest.groovy
new file mode 100644
index 0000000..607a693
--- /dev/null
+++ b/src/spec/test/semantics/TheGroovyTruthTest.groovy
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package semantics
+
+class TheGroovyTruthTest extends GroovyTestCase {
+
+    void testGroovyTruth() {
+        // tag::boolean_truth[]
+        assert true
+        assert !false
+        // end::boolean_truth[]
+        
+        // tag::matcher_truth[]
+        assert ('a' =~ /a/)
+        assert !('a' =~ /b/)
+        // end::matcher_truth[]
+        
+        // tag::collection_truth[]
+        assert [1, 2, 3]
+        assert ![]
+        // end::collection_truth[]
+        
+        // tag::iterator_enumeration_truth[]
+        assert [0].iterator()
+        assert ![].iterator()
+        Vector v = [0] as Vector
+        Enumeration enumeration = v.elements()
+        assert enumeration
+        enumeration.nextElement()
+        assert !enumeration
+        // end::iterator_enumeration_truth[]
+        
+        // tag::map_truth[]
+        assert ['one' : 1]
+        assert ![:]
+        // end::map_truth[]
+        
+        // tag::string_truth[]
+        assert 'a'
+        assert !''
+        def nonEmpty = 'a'
+        assert "$nonEmpty"
+        def empty = ''
+        assert !"$empty"
+        // end::string_truth[]
+        
+        // tag::number_truth[]
+        assert 1
+        assert 3.5
+        assert !0
+        // end::number_truth[]
+        
+        // tag::object_truth[]
+        assert new Object()
+        assert !null
+        // end::object_truth[]
+    }
+    
+    void testAsBoolean() {
+        assertScript '''
+            // tag::asBoolean_object[]
+            class Color {
+                String name
+                
+                boolean asBoolean(){
+                    name == 'green' ? true : false 
+                }
+            }
+            // end::asBoolean_object[]
+            // tag::asBoolean_usage[]
+            assert new Color(name: 'green')
+            assert !new Color(name: 'red')
+            // end::asBoolean_usage[]
+        '''
+    }
+}
diff --git a/src/spec/test/support/MaxRetriesExtension.groovy b/src/spec/test/support/MaxRetriesExtension.groovy
index 766007c..aedbb2b 100644
--- a/src/spec/test/support/MaxRetriesExtension.groovy
+++ b/src/spec/test/support/MaxRetriesExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package support
 
 // tag::instance_extension[]
diff --git a/src/spec/test/thirdpartylib/MultiplyTwo.groovy b/src/spec/test/thirdpartylib/MultiplyTwo.groovy
index 8fefa92..86b099a 100644
--- a/src/spec/test/thirdpartylib/MultiplyTwo.groovy
+++ b/src/spec/test/thirdpartylib/MultiplyTwo.groovy
@@ -1,12 +1,25 @@
-//tag:third_party_lib[]
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// tag::third_party_lib[]
 package thirdpartylib
 
-public class MultiplyTwo
-{
-	def static multiplay(def value)
-	{
-		return value * 3 //intentionally wrong.
-	}
+public class MultiplyTwo {
+    def static multiply(def value) {
+        return value * 3 //intentionally wrong.
+    }
 }
 
-//end:third_party_lib[]
+// end::third_party_lib[]
diff --git a/src/spec/test/typing/PrecompiledExtension.groovy b/src/spec/test/typing/PrecompiledExtension.groovy
new file mode 100644
index 0000000..5d767ce
--- /dev/null
+++ b/src/spec/test/typing/PrecompiledExtension.groovy
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typing
+
+// tag::precompiled_groovy_extension[]
+import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport
+
+class PrecompiledExtension extends GroovyTypeCheckingExtensionSupport.TypeCheckingDSL {     // <1>
+    @Override
+    Object run() {                                                                          // <2>
+        unresolvedVariable { var ->
+            if ('robot'==var.name) {
+                storeType(var, classNodeFor(Robot))                                         // <3>
+                handled = true
+            }
+        }
+    }
+}
+// end::precompiled_groovy_extension[]
\ No newline at end of file
diff --git a/src/spec/test/typing/PrecompiledJavaExtension.java b/src/spec/test/typing/PrecompiledJavaExtension.java
new file mode 100644
index 0000000..77c566e
--- /dev/null
+++ b/src/spec/test/typing/PrecompiledJavaExtension.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typing;
+
+// tag::precompiled_java_extension[]
+import org.codehaus.groovy.ast.ClassHelper;
+import org.codehaus.groovy.ast.expr.VariableExpression;
+import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension;
+
+
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor;
+
+public class PrecompiledJavaExtension extends AbstractTypeCheckingExtension {                   // <1>
+
+    public PrecompiledJavaExtension(final StaticTypeCheckingVisitor typeCheckingVisitor) {
+        super(typeCheckingVisitor);
+    }
+
+    @Override
+    public boolean handleUnresolvedVariableExpression(final VariableExpression vexp) {          // <2>
+        if ("robot".equals(vexp.getName())) {
+            storeType(vexp, ClassHelper.make(Robot.class));
+            setHandled(true);
+            return true;
+        }
+        return false;
+    }
+
+}
+// end::precompiled_java_extension[]
\ No newline at end of file
diff --git a/src/spec/test/typing/Robot.groovy b/src/spec/test/typing/Robot.groovy
new file mode 100644
index 0000000..ca87245
--- /dev/null
+++ b/src/spec/test/typing/Robot.groovy
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typing
+
+// tag::example_robot_classdef[]
+class Robot {
+    Robot move(int qt) { this }
+}
+// end::example_robot_classdef[]
\ No newline at end of file
diff --git a/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy b/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy
new file mode 100644
index 0000000..978a7d9
--- /dev/null
+++ b/src/spec/test/typing/TypeCheckingExtensionSpecTest.groovy
@@ -0,0 +1,467 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package typing
+
+import groovy.$Temp
+import groovy.test.GroovyAssert
+import groovy.transform.TypeChecked
+import groovy.xml.MarkupBuilder
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+
+import static asciidoctor.Utils.stripAsciidocMarkup
+
+class TypeCheckingExtensionSpecTest extends GroovyTestCase {
+
+    void testIntro() {
+        def out = new PrintWriter(new ByteArrayOutputStream())
+        // tag::intro_stc_extensions[]
+        def builder = new MarkupBuilder(out)
+        builder.html {
+            head {
+                // ...
+            }
+            body {
+                p 'Hello, world!'
+            }
+        }
+        // end::intro_stc_extensions[]
+    }
+
+    void testRobotExample() {
+
+        def err = shouldFail(MultipleCompilationErrorsException, '''import groovy.transform.TypeChecked
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+// tag::example_robot_script[]
+robot.move 100
+// end::example_robot_script[]
+"""
+
+// tag::example_robot_setup[]
+def config = new CompilerConfiguration()
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(TypeChecked)            // <1>
+)
+def shell = new GroovyShell(config)                         // <2>
+def robot = new Robot()
+shell.setVariable('robot', robot)
+shell.evaluate(script)                                      // <3>
+// end::example_robot_setup[]
+''')
+        assert err.contains(stripAsciidocMarkup('''
+// tag::example_robot_expected_err[]
+[Static type checking] - The variable [robot] is undeclared.
+// end::example_robot_expected_err[]
+'''))
+    }
+
+    void testRobotExampleFixed() {
+        assertScript '''import groovy.transform.TypeChecked
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+robot.move 100
+"""
+
+def config = new CompilerConfiguration()
+// tag::example_robot_fixed_conf[]
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        TypeChecked,
+        extensions:['robotextension.groovy'])
+)
+// end::example_robot_fixed_conf[]
+def shell = new GroovyShell(config)
+def robot = new Robot()
+shell.setVariable('robot', robot)
+shell.evaluate(script)
+'''
+    }
+
+    void testSetup() {
+        assertScriptWithExtension('setup.groovy', '''
+            1+1
+        ''')
+    }
+
+    void testFinish() {
+        assertScriptWithExtension('finish.groovy', '''
+            1+1
+        ''')
+    }
+
+    void testUnresolvedVariable() {
+        assertScriptWithExtension('unresolvedvariable.groovy', '''
+            assert people.size() == 2
+        ''') {
+            it.setVariable('people', ['John','Meg'])
+        }
+    }
+
+    void testUnresolvedProperty() {
+        use (SpecSupport) {
+            assertScriptWithExtension('unresolvedproperty.groovy', '''
+            assert 'string'.longueur == 6
+        ''')
+        }
+    }
+
+    void testUnresolvedAttribute() {
+        try {
+            assertScriptWithExtension('unresolvedattribute.groovy', '''
+            assert 'string'. at longueur == 6
+        ''')
+            assert false
+        } catch (MissingFieldException mfe) {
+            // ok
+        }
+    }
+
+    void testBeforeMethodCall() {
+        try {
+            assertScriptWithExtension('beforemethodcall.groovy', '''
+            'string'.toUpperCase()
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains('[Static type checking] - Not allowed')
+        }
+    }
+
+    void testAfterMethodCall() {
+        try {
+            assertScriptWithExtension('aftermethodcall.groovy', '''
+            'string'.toUpperCase()
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains('[Static type checking] - Not allowed')
+        }
+    }
+
+    void testOnMethodSelection() {
+        try {
+            assertScriptWithExtension('onmethodselection.groovy', '''
+            'string'.toUpperCase()
+            'string 2'.toLowerCase()
+            'string 3'.length()
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains('[Static type checking] - You can use only 2 calls on String in your source code')
+        }
+    }
+
+    void testMethodNotFound() {
+        use (SpecSupport) {
+            assertScriptWithExtension('methodnotfound.groovy', '''
+            assert 'string'.longueur() == 6
+        ''')
+        }
+    }
+
+    void testBeforeVisitMethod() {
+        use (SpecSupport) {
+            assertScriptWithExtension('beforevisitmethod.groovy', '''
+            void skipIt() {
+                'blah'.doesNotExist()
+            }
+            skipIt()
+        ''')
+        }
+    }
+
+    void testAfterVisitMethod() {
+        try {
+            assertScriptWithExtension('aftervisitmethod.groovy', '''
+            void foo() {
+               'string'.toUpperCase()
+               'string 2'.toLowerCase()
+               'string 3'.length()
+            }
+            foo()
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains('[Static type checking] - Method foo contains more than 2 method calls')
+        }
+    }
+
+    void testBeforeVisitClass() {
+        try {
+            assertScriptWithExtension('beforevisitclass.groovy', '''
+            class someclass {
+            }
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains("[Static type checking] - Class 'someclass' doesn't start with an uppercase letter")
+        }
+    }
+
+    void testAfterVisitClass() {
+        try {
+            assertScriptWithExtension('aftervisitclass.groovy', '''
+            class someclass {
+            }
+        ''')
+            assert false
+        } catch (MultipleCompilationErrorsException err) {
+            assert err.message.contains("[Static type checking] - Class 'someclass' doesn't start with an uppercase letter")
+        }
+    }
+
+    void testIncompatibleAssignment() {
+        use (SpecSupport) {
+            assertScriptWithExtension('incompatibleassignment.groovy', '''import groovy.transform.TypeChecked
+import groovy.transform.TypeCheckingMode
+
+ at TypeChecked(TypeCheckingMode.SKIP)
+class Point {
+    int x, y = 1
+
+    void setProperty(String name, value) {
+        def v = value instanceof Closure ? value() : value
+        this.@"$name" *= v
+    }
+}
+
+def p = new Point(x: 3, y: 4)
+p.x = { 2 }
+assert p.x == 6
+        ''')
+        }
+    }
+
+    void testAmbiguousMethods() {
+        def err = shouldFail {
+            assertScriptWithExtension('ambiguousmethods.groovy', '''
+            int foo(Integer x) { 1 }
+            int foo(String s) { 2 }
+            int foo(Date d) { 3 }
+            assert foo(null) == 2
+        ''')
+        }
+        assert err.contains(/Cannot resolve which method to invoke for [null] due to overlapping prototypes/)
+    }
+
+    void testSupportMethods() {
+        assertScriptWithExtension('selfcheck.groovy','''
+            class Foo {}
+            1+1
+        ''')
+    }
+
+    void testNewMethod() {
+        assertScriptWithExtension('newmethod.groovy','''
+            class Foo {
+                def methodMissing(String name, args) { this }
+            }
+            def f = new Foo()
+            f.foo().bar()
+        ''')
+    }
+
+    void testScopingMethods() {
+        assertScriptWithExtension('scoping.groovy','''
+            1+1
+        ''')
+        assertScriptWithExtension('scoping_alt.groovy','''
+            1+1
+        ''')
+    }
+
+    void testPrecompiledExtensions() {
+        assertScript '''import groovy.transform.TypeChecked
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+robot.move 100
+"""
+
+def config = new CompilerConfiguration()
+// tag::setup_precompiled[]
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        TypeChecked,
+        extensions:['typing.PrecompiledExtension'])
+)
+// end::setup_precompiled[]
+def shell = new GroovyShell(config)
+def robot = new Robot()
+shell.setVariable('robot', robot)
+shell.evaluate(script)
+'''
+
+        assertScript '''import groovy.transform.TypeChecked
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+robot.move 100
+"""
+
+def config = new CompilerConfiguration()
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        TypeChecked,
+        extensions:['typing.PrecompiledJavaExtension'])
+)
+def shell = new GroovyShell(config)
+def robot = new Robot()
+shell.setVariable('robot', robot)
+shell.evaluate(script)
+'''
+    }
+
+    void testRobotExamplePassWithCompileStatic() {
+
+        assertScript '''import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+robot.move 100
+"""
+
+// tag::example_robot_setup_compilestatic[]
+def config = new CompilerConfiguration()
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        CompileStatic,                                      // <1>
+        extensions:['robotextension.groovy'])               // <2>
+)
+def shell = new GroovyShell(config)
+def robot = new Robot()
+shell.setVariable('robot', robot)
+shell.evaluate(script)
+// end::example_robot_setup_compilestatic[]
+'''
+    }
+
+    void testRobotExampleDelegatingScript() {
+
+        assertScript '''import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+// tag::example_robot_script_direct[]
+move 100
+// end::example_robot_script_direct[]
+"""
+
+// tag::example_robot_setup_dynamic[]
+def config = new CompilerConfiguration()
+config.scriptBaseClass = 'groovy.util.DelegatingScript'     // <1>
+def shell = new GroovyShell(config)
+def runner = shell.parse(script)                            // <2>
+runner.setDelegate(new Robot())                             // <3>
+runner.run()                                                // <4>
+// end::example_robot_setup_dynamic[]
+'''
+    }
+
+    void testRobotExampleFailsWithCompileStatic() {
+
+        def err = GroovyAssert.shouldFail '''import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+move 100
+"""
+
+def config = new CompilerConfiguration()
+config.scriptBaseClass = 'groovy.util.DelegatingScript'
+// tag::example_robot_setup_compilestatic2[]
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        CompileStatic,                                      // <1>
+        extensions:['robotextension2.groovy'])              // <2>
+)
+// end::example_robot_setup_compilestatic2[]
+def shell = new GroovyShell(config)
+def runner = shell.parse(script)
+runner.setDelegate(new Robot())
+runner.run()
+'''
+        err = "${err.class.name}: ${err.message}"
+        assert err.contains(stripAsciidocMarkup('''
+// tag::robot_runtime_error_cs[]
+java.lang.NoSuchMethodError: java.lang.Object.move()Ltyping/Robot;
+// end::robot_runtime_error_cs[]
+'''))
+    }
+
+    void testRobotExamplePassesWithCompileStatic() {
+
+        assertScript '''import groovy.transform.CompileStatic
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer
+import typing.Robot
+
+def script = """
+move 100
+"""
+
+def config = new CompilerConfiguration()
+config.scriptBaseClass = 'groovy.util.DelegatingScript'
+config.addCompilationCustomizers(
+    new ASTTransformationCustomizer(
+        CompileStatic,
+        extensions:['robotextension3.groovy'])
+)
+def shell = new GroovyShell(config)
+def runner = shell.parse(script)
+runner.setDelegate(new Robot())
+runner.run()
+'''
+    }
+
+
+    private static class SpecSupport {
+        static int getLongueur(String self) { self.length() }
+        static int longueur(String self) { self.length() }
+        static void doesNotExist(String self) {}
+    }
+
+    private def assertScriptWithExtension(String extensionName, String code, Closure<Void> configurator=null) {
+        def config = new CompilerConfiguration()
+        config.addCompilationCustomizers(
+                new ASTTransformationCustomizer(TypeChecked, extensions:[extensionName]))
+        def binding = new Binding()
+        def shell = new GroovyShell(binding,config)
+        if (configurator) {
+            configurator.call(binding)
+        }
+        shell.evaluate(code)
+    }
+}
diff --git a/src/test/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule b/src/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
similarity index 100%
rename from src/test/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
rename to src/test-resources/META-INF/services/org.codehaus.groovy.runtime.ExtensionModule
diff --git a/src/test/META-INF/services/org.codehaus.groovy.source.Extensions b/src/test-resources/META-INF/services/org.codehaus.groovy.source.Extensions
similarity index 100%
rename from src/test/META-INF/services/org.codehaus.groovy.source.Extensions
rename to src/test-resources/META-INF/services/org.codehaus.groovy.source.Extensions
diff --git a/src/test-resources/groovy/transform/sc/MixedMode.groovy b/src/test-resources/groovy/transform/sc/MixedMode.groovy
index 6ffef08..7958f26 100644
--- a/src/test-resources/groovy/transform/sc/MixedMode.groovy
+++ b/src/test-resources/groovy/transform/sc/MixedMode.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 methodNotFound { receiver, name, argumentList, argTypes, call ->
     return makeDynamic(call, int_TYPE)
 }
diff --git a/src/test-resources/groovy/transform/sc/MixedMode2.groovy b/src/test-resources/groovy/transform/sc/MixedMode2.groovy
index 57184f6..5090f06 100644
--- a/src/test-resources/groovy/transform/sc/MixedMode2.groovy
+++ b/src/test-resources/groovy/transform/sc/MixedMode2.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 methodNotFound { receiver, name, argumentList, argTypes, call ->
     if (isStaticMethodCallOnClass(call, STRING_TYPE)) {
         return makeDynamic(call, buildMapType(STRING_TYPE,Integer_TYPE))
diff --git a/src/test-resources/groovy/transform/sc/MixedModeDynamicBuilder.groovy b/src/test-resources/groovy/transform/sc/MixedModeDynamicBuilder.groovy
index fafb381..c6c8921 100644
--- a/src/test-resources/groovy/transform/sc/MixedModeDynamicBuilder.groovy
+++ b/src/test-resources/groovy/transform/sc/MixedModeDynamicBuilder.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.xml.MarkupBuilder
 
 setup {
diff --git a/src/test-resources/groovy/transform/stc/AnnotatedByTestExtension.groovy b/src/test-resources/groovy/transform/stc/AnnotatedByTestExtension.groovy
index 6e4bba5..b2b9a1e 100644
--- a/src/test-resources/groovy/transform/stc/AnnotatedByTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/AnnotatedByTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.transform.stc.MyType
 import org.codehaus.groovy.transform.stc.StaticTypesMarker
 
diff --git a/src/test-resources/groovy/transform/stc/ArgumentsTestingTestExtension.groovy b/src/test-resources/groovy/transform/stc/ArgumentsTestingTestExtension.groovy
index 8e108f7..781ba59 100644
--- a/src/test-resources/groovy/transform/stc/ArgumentsTestingTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/ArgumentsTestingTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 def expectations = [
         concat: [String],
diff --git a/src/test-resources/groovy/transform/stc/BeforeAfterClassTestExtension.groovy b/src/test-resources/groovy/transform/stc/BeforeAfterClassTestExtension.groovy
index 3094a16..26ef18d 100644
--- a/src/test-resources/groovy/transform/stc/BeforeAfterClassTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/BeforeAfterClassTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 beforeVisitClass { cn ->
     if (cn.name=='B') {
         handled = true // disables visit of this class node
diff --git a/src/test-resources/groovy/transform/stc/DelegatesToTestExtension.groovy b/src/test-resources/groovy/transform/stc/DelegatesToTestExtension.groovy
index 616189e..c482679 100644
--- a/src/test-resources/groovy/transform/stc/DelegatesToTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/DelegatesToTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Dummy extension that removes node metadata on LHS if a method is selected and it's 'toUpperCase'
 onMethodSelection { expr, method ->
     if (method.name=='build') {
diff --git a/src/test-resources/groovy/transform/stc/FinishTestExtension.groovy b/src/test-resources/groovy/transform/stc/FinishTestExtension.groovy
index a4f10d1..5924f58 100644
--- a/src/test-resources/groovy/transform/stc/FinishTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/FinishTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Dummy extension that just puts the "finish" node metadata on the 'A' class node
 finish {
     def cn = context.source.AST.classes.find { it.name == 'A' }
diff --git a/src/test-resources/groovy/transform/stc/FirstArgumentsTestingTestExtension.groovy b/src/test-resources/groovy/transform/stc/FirstArgumentsTestingTestExtension.groovy
index 9cb08b2..e14a09f 100644
--- a/src/test-resources/groovy/transform/stc/FirstArgumentsTestingTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/FirstArgumentsTestingTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 afterMethodCall { call ->
     if (firstArgTypesMatches(call, [String, Integer] as Class[])) {
         addStaticTypeError "Method [${call.methodAsString}] with matching arguments found: ${getArguments(call).expressions.size()}", call
diff --git a/src/test-resources/groovy/transform/stc/Groovy6047Extension.groovy b/src/test-resources/groovy/transform/stc/Groovy6047Extension.groovy
index 678d8e4..51009ba 100644
--- a/src/test-resources/groovy/transform/stc/Groovy6047Extension.groovy
+++ b/src/test-resources/groovy/transform/stc/Groovy6047Extension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Used to check that GROOVY-6047 no longer throws an NPE
 methodNotFound { receiver, name, argumentList, argTypes, call ->
     if (name=='elems') {
diff --git a/src/test-resources/groovy/transform/stc/IncompatibleAssignmentTestExtension.groovy b/src/test-resources/groovy/transform/stc/IncompatibleAssignmentTestExtension.groovy
index 74ce2b2..b61d151 100644
--- a/src/test-resources/groovy/transform/stc/IncompatibleAssignmentTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/IncompatibleAssignmentTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 incompatibleAssignment { lhsType, rhsType, expr ->
     if (lhsType == int_TYPE && rhsType==STRING_TYPE) {
         handled = true
diff --git a/src/test-resources/groovy/transform/stc/IncompatibleReturnTypeTestExtension.groovy b/src/test-resources/groovy/transform/stc/IncompatibleReturnTypeTestExtension.groovy
index ca0dd67..421aac7 100644
--- a/src/test-resources/groovy/transform/stc/IncompatibleReturnTypeTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/IncompatibleReturnTypeTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 incompatibleReturnType { returnStmt, inferredReturnType ->
     if (inferredReturnType==STRING_TYPE) {
         handled = true
diff --git a/src/test-resources/groovy/transform/stc/MissingMethod1TestExtension.groovy b/src/test-resources/groovy/transform/stc/MissingMethod1TestExtension.groovy
index 3fe6595..b6d9d5f 100644
--- a/src/test-resources/groovy/transform/stc/MissingMethod1TestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/MissingMethod1TestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // A simple extension that says that the "TOUPPERCASE" method returns a String
 methodNotFound { receiver, name, argumentList, argTypes, call ->
     if (name=='TOUPPERCASE') {
diff --git a/src/test-resources/groovy/transform/stc/MissingMethod2TestExtension.groovy b/src/test-resources/groovy/transform/stc/MissingMethod2TestExtension.groovy
index 0d1ead0..468ed02 100644
--- a/src/test-resources/groovy/transform/stc/MissingMethod2TestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/MissingMethod2TestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // A simple extension that tries to find a matching method on the same
 // receiver type, but using the lower case version of the method
 methodNotFound { receiver, name, argumentList, argTypes, call ->
diff --git a/src/test-resources/groovy/transform/stc/NewMethodAndIsGeneratedTestExtension.groovy b/src/test-resources/groovy/transform/stc/NewMethodAndIsGeneratedTestExtension.groovy
index b65b35e..bff0a55 100644
--- a/src/test-resources/groovy/transform/stc/NewMethodAndIsGeneratedTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/NewMethodAndIsGeneratedTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 setup {
     newScope()
     currentScope.m1 = newMethod('foo', String)
diff --git a/src/test-resources/groovy/transform/stc/NthArgumentTestingTestExtension.groovy b/src/test-resources/groovy/transform/stc/NthArgumentTestingTestExtension.groovy
index cf30cc5..9a8e842 100644
--- a/src/test-resources/groovy/transform/stc/NthArgumentTestingTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/NthArgumentTestingTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 def expectations = [
         [0, String],
         [1, Integer],
diff --git a/src/test-resources/groovy/transform/stc/OnMethodSelectionTestExtension.groovy b/src/test-resources/groovy/transform/stc/OnMethodSelectionTestExtension.groovy
index 340b257..bcfb3e4 100644
--- a/src/test-resources/groovy/transform/stc/OnMethodSelectionTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/OnMethodSelectionTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Dummy extension that removes node metadata on LHS if a method is selected and it's 'toUpperCase'
 onMethodSelection { expr, method ->
     if (method.name=='toUpperCase' && enclosingBinaryExpression) {
diff --git a/src/test-resources/groovy/transform/stc/PrefixChangerTestExtension.groovy b/src/test-resources/groovy/transform/stc/PrefixChangerTestExtension.groovy
index cb4ec83..1f2eceb 100644
--- a/src/test-resources/groovy/transform/stc/PrefixChangerTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/PrefixChangerTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.control.messages.SyntaxErrorMessage
 import org.codehaus.groovy.syntax.SyntaxException
 
diff --git a/src/test-resources/groovy/transform/stc/RobotMove.groovy b/src/test-resources/groovy/transform/stc/RobotMove.groovy
index 8c09e73..7ea089e 100644
--- a/src/test-resources/groovy/transform/stc/RobotMove.groovy
+++ b/src/test-resources/groovy/transform/stc/RobotMove.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 unresolvedVariable { var ->
     if ('robot' == var.name) {
         def robotClass = lookupClassNodeFor('Robot')
diff --git a/src/test-resources/groovy/transform/stc/ScopeEnterExitTestExtension.groovy b/src/test-resources/groovy/transform/stc/ScopeEnterExitTestExtension.groovy
index 867e8cd..005113c 100644
--- a/src/test-resources/groovy/transform/stc/ScopeEnterExitTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/ScopeEnterExitTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 onMethodSelection { expr, mn ->
     if (mn.name == 'foo') {
         newScope {
diff --git a/src/test-resources/groovy/transform/stc/SetupTestExtension.groovy b/src/test-resources/groovy/transform/stc/SetupTestExtension.groovy
index 287efea..fb7f80f 100644
--- a/src/test-resources/groovy/transform/stc/SetupTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/SetupTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // Dummy extension that just puts the "setup" node metadata on the 'A' class node
 setup {
     def cn = context.source.AST.classes.find { it.name == 'A' }
diff --git a/src/test-resources/groovy/transform/stc/SilentTestExtension.groovy b/src/test-resources/groovy/transform/stc/SilentTestExtension.groovy
index 075e7b8..7a8838e 100644
--- a/src/test-resources/groovy/transform/stc/SilentTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/SilentTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // A very simple extension that will silently drop all errors thrown by the type checker
 setup {
     context.pushErrorCollector()
diff --git a/src/test-resources/groovy/transform/stc/SprintfExtension.groovy b/src/test-resources/groovy/transform/stc/SprintfExtension.groovy
index 72c4e27..fcf9e93 100644
--- a/src/test-resources/groovy/transform/stc/SprintfExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/SprintfExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 afterMethodCall { mc ->
     def method = getTargetMethod(mc)
     if (isExtensionMethod(method) && method.name == 'sprintf') {
diff --git a/src/test-resources/groovy/transform/stc/UndefinedVariableNoHandleTestExtension.groovy b/src/test-resources/groovy/transform/stc/UndefinedVariableNoHandleTestExtension.groovy
index afe4350..98856a6 100644
--- a/src/test-resources/groovy/transform/stc/UndefinedVariableNoHandleTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/UndefinedVariableNoHandleTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // A dummy extension that says that every undefined variable is of type String
 // but doesn't set the handled=true flag
 unresolvedVariable { var ->
diff --git a/src/test-resources/groovy/transform/stc/UndefinedVariableTestExtension.groovy b/src/test-resources/groovy/transform/stc/UndefinedVariableTestExtension.groovy
index 12d00dc..7b2e25b 100644
--- a/src/test-resources/groovy/transform/stc/UndefinedVariableTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/UndefinedVariableTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // A simple extension that says that every dynamic variable is of type String
 unresolvedVariable { var ->
     if (isDynamic(var)) {
diff --git a/src/test-resources/groovy/transform/stc/UnresolvedAttributeTestExtension.groovy b/src/test-resources/groovy/transform/stc/UnresolvedAttributeTestExtension.groovy
index 5585dd3..22a5298 100644
--- a/src/test-resources/groovy/transform/stc/UnresolvedAttributeTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/UnresolvedAttributeTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // this extension will silence all property missing errors
 unresolvedAttribute { attr ->
     handled = true
diff --git a/src/test-resources/groovy/transform/stc/UnresolvedPropertyTestExtension.groovy b/src/test-resources/groovy/transform/stc/UnresolvedPropertyTestExtension.groovy
index 646da06..2cd8225 100644
--- a/src/test-resources/groovy/transform/stc/UnresolvedPropertyTestExtension.groovy
+++ b/src/test-resources/groovy/transform/stc/UnresolvedPropertyTestExtension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // this extension will silence all property missing errors
 unresolvedProperty { pexp ->
     handled = true
diff --git a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest1Extension.groovy b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest1Extension.groovy
index f44ddca..a8ddc70 100644
--- a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest1Extension.groovy
+++ b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest1Extension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // This test extension checks that method calls are not all uppercase
 beforeMethodCall { call ->
     def name = call.methodAsString
diff --git a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest2Extension.groovy b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest2Extension.groovy
index e64a144..4ee78fb 100644
--- a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest2Extension.groovy
+++ b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest2Extension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // This test extension checks that method definitions are not all uppercase
 beforeVisitMethod { mn ->
     def name = mn.name
diff --git a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest3Extension.groovy b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest3Extension.groovy
index b355aa1..7419c24 100644
--- a/src/test-resources/groovy/transform/stc/UpperCaseMethodTest3Extension.groovy
+++ b/src/test-resources/groovy/transform/stc/UpperCaseMethodTest3Extension.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // This test extension checks that method definitions are not all uppercase
 afterVisitMethod { mn ->
     def name = mn.name
diff --git a/src/test-resources/jars/module-test/module-test/1.0.7225-test/module-test-1.0.7225-test.jar b/src/test-resources/jars/module-test/module-test/1.0.7225-test/module-test-1.0.7225-test.jar
new file mode 100644
index 0000000..d08e03c
Binary files /dev/null and b/src/test-resources/jars/module-test/module-test/1.0.7225-test/module-test-1.0.7225-test.jar differ
diff --git a/src/test-resources/jars/module-test/module-test/1.2-test/module-test-1.2-test.jar b/src/test-resources/jars/module-test/module-test/1.2-test/module-test-1.2-test.jar
new file mode 100644
index 0000000..2678d82
Binary files /dev/null and b/src/test-resources/jars/module-test/module-test/1.2-test/module-test-1.2-test.jar differ
diff --git a/src/test-resources/stubgenerator/circularLanguageReference/Rectangle.groovy b/src/test-resources/stubgenerator/circularLanguageReference/Rectangle.groovy
index bd8db38..ea1d987 100644
--- a/src/test-resources/stubgenerator/circularLanguageReference/Rectangle.groovy
+++ b/src/test-resources/stubgenerator/circularLanguageReference/Rectangle.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package stubgenerator.circularLanguageReference;
 
 class Rectangle implements Shape {
diff --git a/src/test-resources/stubgenerator/circularLanguageReference/Shape.java b/src/test-resources/stubgenerator/circularLanguageReference/Shape.java
index 9c5eff6..a99efab 100644
--- a/src/test-resources/stubgenerator/circularLanguageReference/Shape.java
+++ b/src/test-resources/stubgenerator/circularLanguageReference/Shape.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package stubgenerator.circularLanguageReference;
 
 public interface Shape {
diff --git a/src/test-resources/stubgenerator/circularLanguageReference/Square.java b/src/test-resources/stubgenerator/circularLanguageReference/Square.java
index 1a6dff8..7012a9a 100644
--- a/src/test-resources/stubgenerator/circularLanguageReference/Square.java
+++ b/src/test-resources/stubgenerator/circularLanguageReference/Square.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package stubgenerator.circularLanguageReference;
 
 public class Square extends Rectangle {
diff --git a/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/GroovyPogo.groovy b/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/GroovyPogo.groovy
index 7bb178f..7d19933 100644
--- a/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/GroovyPogo.groovy
+++ b/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/GroovyPogo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package stubgenerator.propertyUsageFromJava.somepackage
 
 class GroovyPogo {
diff --git a/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/JavaBean.java b/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/JavaBean.java
index 4d54eef..1974bda 100644
--- a/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/JavaBean.java
+++ b/src/test-resources/stubgenerator/propertyUsageFromJava/somepackage/JavaBean.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package stubgenerator.propertyUsageFromJava.somepackage;
 
 public class JavaBean {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureExhaustiveTestSupport.groovy b/src/test/gls/annotations/closures/AnnotationClosureExhaustiveTestSupport.groovy
index 62552ef..a09147b 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureExhaustiveTestSupport.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureExhaustiveTestSupport.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 abstract class AnnotationClosureExhaustiveTestSupport extends GroovyTestCase {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityParameterizedTest.java b/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityParameterizedTest.java
index 9f2181b..b57a12f 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityParameterizedTest.java
+++ b/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityParameterizedTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures;
 
 // Same as AnnotationClosureCompatibilityTest except that annotation closure's
diff --git a/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityTest.java b/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityTest.java
index 854f25a..d9b799d 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityTest.java
+++ b/src/test/gls/annotations/closures/AnnotationClosureJavaCompatibilityTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures;
 
 import java.lang.reflect.Constructor;
diff --git a/src/test/gls/annotations/closures/AnnotationClosureOwnerCallTest.groovy b/src/test/gls/annotations/closures/AnnotationClosureOwnerCallTest.groovy
index cca1015..7a3c2a3 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureOwnerCallTest.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureOwnerCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 class AnnotationClosureOwnerCallTest extends AnnotationClosureExhaustiveTestSupport {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureThisObjectCallTest.groovy b/src/test/gls/annotations/closures/AnnotationClosureThisObjectCallTest.groovy
index 103c3ff..25cf50e 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureThisObjectCallTest.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureThisObjectCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 class AnnotationClosureThisObjectCallTest extends AnnotationClosureExhaustiveTestSupport {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureUnqualifiedCallTest.groovy b/src/test/gls/annotations/closures/AnnotationClosureUnqualifiedCallTest.groovy
index eb75b89..5032d6b 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureUnqualifiedCallTest.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureUnqualifiedCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 class AnnotationClosureUnqualifiedCallTest extends AnnotationClosureExhaustiveTestSupport {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureWithNonLocalVariable.groovy b/src/test/gls/annotations/closures/AnnotationClosureWithNonLocalVariable.groovy
index eeb445b..8a68544 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureWithNonLocalVariable.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureWithNonLocalVariable.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 class AnnotationClosureWithNonLocalVariable extends GroovyTestCase {
diff --git a/src/test/gls/annotations/closures/AnnotationClosureWithParametersTest.groovy b/src/test/gls/annotations/closures/AnnotationClosureWithParametersTest.groovy
index f9684ba..7898f71 100644
--- a/src/test/gls/annotations/closures/AnnotationClosureWithParametersTest.groovy
+++ b/src/test/gls/annotations/closures/AnnotationClosureWithParametersTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 class AnnotationClosureWithParametersTest extends AnnotationClosureExhaustiveTestSupport {
diff --git a/src/test/gls/annotations/closures/JavaAnnotationWithClassElement.java b/src/test/gls/annotations/closures/JavaAnnotationWithClassElement.java
index d796f22..42ca2ec 100644
--- a/src/test/gls/annotations/closures/JavaAnnotationWithClassElement.java
+++ b/src/test/gls/annotations/closures/JavaAnnotationWithClassElement.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures;
 
 import java.lang.annotation.Retention;
diff --git a/src/test/gls/annotations/closures/JavaAnnotationWithClassElementParameterized.java b/src/test/gls/annotations/closures/JavaAnnotationWithClassElementParameterized.java
index 3312374..958e793 100644
--- a/src/test/gls/annotations/closures/JavaAnnotationWithClassElementParameterized.java
+++ b/src/test/gls/annotations/closures/JavaAnnotationWithClassElementParameterized.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures;
 
 import groovy.lang.Closure;
diff --git a/src/test/gls/annotations/closures/JavaCompatibility.groovy b/src/test/gls/annotations/closures/JavaCompatibility.groovy
index 10fccaa..b1abb9f 100644
--- a/src/test/gls/annotations/closures/JavaCompatibility.groovy
+++ b/src/test/gls/annotations/closures/JavaCompatibility.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 @JavaAnnotationWithClassElement(elem = { 1 + 2 })
diff --git a/src/test/gls/annotations/closures/JavaCompatibilityParameterized.groovy b/src/test/gls/annotations/closures/JavaCompatibilityParameterized.groovy
index 2569207..b220568 100644
--- a/src/test/gls/annotations/closures/JavaCompatibilityParameterized.groovy
+++ b/src/test/gls/annotations/closures/JavaCompatibilityParameterized.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.annotations.closures
 
 @JavaAnnotationWithClassElementParameterized(elem = { 1 + 2 })
diff --git a/src/test/gls/ch06/s05/GName1Test.groovy b/src/test/gls/ch06/s05/GName1Test.groovy
index a3236f1..f0c68ac 100644
--- a/src/test/gls/ch06/s05/GName1Test.groovy
+++ b/src/test/gls/ch06/s05/GName1Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.ch06.s05;
 
 import gls.ch06.s05.testClasses.Tt1cgi;
diff --git a/src/test/gls/ch06/s05/JName1Test.java b/src/test/gls/ch06/s05/JName1Test.java
index 6f8d697..2135041 100644
--- a/src/test/gls/ch06/s05/JName1Test.java
+++ b/src/test/gls/ch06/s05/JName1Test.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.ch06.s05;
 
 
diff --git a/src/test/gls/ch06/s05/testClasses/Tt1.java b/src/test/gls/ch06/s05/testClasses/Tt1.java
index 1e04146..c06c748 100644
--- a/src/test/gls/ch06/s05/testClasses/Tt1.java
+++ b/src/test/gls/ch06/s05/testClasses/Tt1.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /*
 * Copyright 2005 John G. Wilson
 *
diff --git a/src/test/gls/enums/EnumTest.groovy b/src/test/gls/enums/EnumTest.groovy
index 94215e2..a3776ac 100644
--- a/src/test/gls/enums/EnumTest.groovy
+++ b/src/test/gls/enums/EnumTest.groovy
@@ -539,6 +539,20 @@ class EnumTest extends CompilableTestSupport {
             assert MyEnum.ENUM1.accept(new ConcreteVisitor(), null) == 'I have been visited!'
         """
     }
+
+    void testVargsConstructor() {
+        assertScript '''
+            enum Test {
+                TEST1(1, 2, 3)
+                public final info
+
+                Test(Integer... ints) {
+                    info = ints
+                }
+            }
+            println Test.TEST1.info == [1,2,3]
+        '''
+    }
 }
 
 enum UsCoin {
diff --git a/src/test/gls/generics/GenericsTest.groovy b/src/test/gls/generics/GenericsTest.groovy
index 371be6a..09f8f62 100644
--- a/src/test/gls/generics/GenericsTest.groovy
+++ b/src/test/gls/generics/GenericsTest.groovy
@@ -175,6 +175,20 @@ class GenericsTest extends GenericsTestBase {
         ]
     }
 
+    void testwildcardWithBound() {
+        createClassInfo """
+            class Something<T extends Number> {
+                List<? super T> dependency
+            }
+        """
+        assert signatures == [
+                "class":    "<T:Ljava/lang/Number;>Ljava/lang/Object;Lgroovy/lang/GroovyObject;",
+                dependency: "Ljava/util/List<-TT;>;",
+                "setDependency(Ljava/util/List;)V"  : "(Ljava/util/List<-TT;>;)V",
+                "getDependency()Ljava/util/List;"   : "()Ljava/util/List<-TT;>;",
+        ]
+    }
+
     public void testParameterAsParameterForReturnTypeAndFieldClass() {
         createClassInfo """
                public class B<T> {
diff --git a/src/test/gls/generics/GenericsTestBase.java b/src/test/gls/generics/GenericsTestBase.java
index 22d81fa..762b685 100644
--- a/src/test/gls/generics/GenericsTestBase.java
+++ b/src/test/gls/generics/GenericsTestBase.java
@@ -29,7 +29,7 @@ import java.util.Map;
 
 public abstract class GenericsTestBase extends GroovyTestCase {
     MyLoader loader;
-    HashMap signatures = new HashMap();
+    HashMap signatures;
     
     private class MyLoader extends GroovyClassLoader{
         public MyLoader(ClassLoader classLoader) {
@@ -75,6 +75,7 @@ public abstract class GenericsTestBase extends GroovyTestCase {
     
     public void setUp(){
         loader = new MyLoader(this.getClass().getClassLoader());
+        signatures = new HashMap();
     }
     
     public void createClassInfo(String script) {
diff --git a/src/test/gls/innerClass/InnerClassTest.groovy b/src/test/gls/innerClass/InnerClassTest.groovy
index 8b50a5f..1aed15b 100644
--- a/src/test/gls/innerClass/InnerClassTest.groovy
+++ b/src/test/gls/innerClass/InnerClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.innerClass
 
 import gls.CompilableTestSupport
@@ -6,19 +21,19 @@ class InnerClassTest extends CompilableTestSupport {
 
     void testTimerAIC() {
         assertScript """
-            boolean called = false
+            import java.util.concurrent.CountDownLatch
+            import java.util.concurrent.TimeUnit
+
+            CountDownLatch called = new CountDownLatch(1)
 
             Timer timer = new Timer()
             timer.schedule(new TimerTask() {
                 void run() {
-                    called = true
+                    called.countDown()
                 }
             }, 0)
-            for(int i = 0; !called && i < 20; i++) {
-                sleep 50
-            }
 
-            assert called
+            assert called.await(10, TimeUnit.SECONDS)
         """
     }
 
@@ -73,7 +88,7 @@ class InnerClassTest extends CompilableTestSupport {
         """
     }
 
-    void testUsageOfInitializerBlockWithinAnAIC () {
+    void testUsageOfInitializerBlockWithinAnAIC() {
         assertScript """
             Object makeObj2(String name) {
                  new Object() {
@@ -106,7 +121,7 @@ class InnerClassTest extends CompilableTestSupport {
             def mods = A.B.modifiers
             assert Modifier.isPublic(mods)
         """
-        
+
         assertScript """
             class A {
                 static class B{}
@@ -281,7 +296,7 @@ class InnerClassTest extends CompilableTestSupport {
             assert bar.foo() == 2
         """
 
-    //TODO: static part
+        //TODO: static part
 
     }
 
@@ -364,7 +379,7 @@ class InnerClassTest extends CompilableTestSupport {
             assert bar.foo() == 1
         """
     }
-    
+
     void testClassOutputOrdering() {
         // this does actually not do much, but before this
         // change the inner class was tried to be executed
@@ -380,7 +395,7 @@ class InnerClassTest extends CompilableTestSupport {
             }
         """
     }
-    
+
     void testInnerClassDotThisUsage() {
         assertScript """
             class A{
@@ -423,13 +438,13 @@ class InnerClassTest extends CompilableTestSupport {
             assert b.foo() instanceof B
         """
     }
-    
+
     void testImplicitThisPassingWithNamedArguments() {
         def oc = new MyOuterClass4028()
         assert oc.foo().propMap.size() == 2
     }
 
-    void testThis0 () {
+    void testThis0() {
         assertScript """
 class A {
    static def field = 10
@@ -451,7 +466,7 @@ class A {
      def u (i) { println i + s + field }
    }}"""
     }
-    
+
     void testReferencedVariableInAIC() {
         assertScript """
             interface X{}
@@ -480,6 +495,19 @@ class A {
         """
     }
 
+    // GROOVY-5989
+    void testReferenceToOuterClassNestedInterface() {
+        assertScript '''
+            interface Koo { class Inner { } }
+
+            class Usage implements Koo {
+                static class MyInner extends Inner { }
+            }
+
+            assert new Usage() != null
+        '''
+    }
+
     // GROOVY-5679
     // GROOVY-5681
     void testEnclosingMethodIsSet() {
diff --git a/src/test/gls/innerClass/InnerInterfaceTest.groovy b/src/test/gls/innerClass/InnerInterfaceTest.groovy
index ca2ecc1..c807b1e 100644
--- a/src/test/gls/innerClass/InnerInterfaceTest.groovy
+++ b/src/test/gls/innerClass/InnerInterfaceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.innerClass
 
 /**
@@ -52,4 +67,36 @@ class InnerInterfaceTest extends GroovyTestCase {
             assert Foo4422V3.Baz != null
         """
     }
+
+    // GROOVY-5989
+    void testReferenceToInterfaceNestedInterface() {
+        assertScript '''
+            class MyMap extends HashMap {
+                // Entry not just Map.Entry should work on next line
+                Entry firstEntry() { entrySet().iterator().next() }
+                static void main(args) {
+                    def m = new MyMap()
+                    m.a = 42
+                    assert m.firstEntry().toString() == 'a=42'
+                }
+            }
+        '''
+    }
+
+    // GROOVY-5754
+    void testResolveInnerInterface() {
+        assertScript '''
+            class Usage implements Koo {
+              static class MyInner extends Inner {}
+            }
+
+            public interface Koo {
+
+                class Inner {
+                }
+
+            }
+            Koo.Inner
+        '''
+    }
 }
\ No newline at end of file
diff --git a/src/test/gls/invocation/ClassDuplicationTest.groovy b/src/test/gls/invocation/ClassDuplicationTest.groovy
index 52cdd70..c8afd96 100644
--- a/src/test/gls/invocation/ClassDuplicationTest.groovy
+++ b/src/test/gls/invocation/ClassDuplicationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class ClassDuplicationTest extends GroovyTestCase {
     void testDuplicationOnMethodSignatureTest() {
         def shell1 = new GroovyShell(this.class.classLoader)
diff --git a/src/test/gls/invocation/ConstructorDelegationTest.groovy b/src/test/gls/invocation/ConstructorDelegationTest.groovy
index 01e9045..fe4165a 100644
--- a/src/test/gls/invocation/ConstructorDelegationTest.groovy
+++ b/src/test/gls/invocation/ConstructorDelegationTest.groovy
@@ -115,4 +115,40 @@ public class ConstructorDelegationTest extends CompilableTestSupport {
         """
         shouldNotCompile(scriptStr)
     }
+
+    // GROOVY-6618
+    public void testVarsConstructor() {
+        assertScript '''
+            class Foo {
+                public info
+                Foo(String s,Integer[] a){info=a}
+                Foo() {this("foo",1)}
+            }
+            assert new Foo().info == [1]
+        '''
+        assertScript '''
+            class Foo {
+                public info
+                Foo(String s,Integer[] a){info=a}
+                Foo() {this("foo",null)}
+            }
+            assert new Foo().info == null
+        '''
+        assertScript '''
+            class Foo {
+                public info
+                Foo(String s,Integer[] a){info=a}
+                Foo() {this("foo",1,2,3)}
+            }
+            assert new Foo().info == [1,2,3]
+        '''
+        assertScript '''
+            class Foo {
+                public info
+                Foo(String s,Integer[] a){info=a}
+                Foo() {this("foo")}
+            }
+            assert new Foo().info == []
+        '''
+    }
 }
\ No newline at end of file
diff --git a/src/test/gls/property/MetaClassOverridingTest.groovy b/src/test/gls/property/MetaClassOverridingTest.groovy
index ac70654..601c1a1 100644
--- a/src/test/gls/property/MetaClassOverridingTest.groovy
+++ b/src/test/gls/property/MetaClassOverridingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.property
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/scope/ClassVariableHidingTest.groovy b/src/test/gls/scope/ClassVariableHidingTest.groovy
index 15028eb..3dd46aa 100644
--- a/src/test/gls/scope/ClassVariableHidingTest.groovy
+++ b/src/test/gls/scope/ClassVariableHidingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.scope;
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/scope/FinalAccessTest.groovy b/src/test/gls/scope/FinalAccessTest.groovy
index 0bd5ff5..20b869b 100644
--- a/src/test/gls/scope/FinalAccessTest.groovy
+++ b/src/test/gls/scope/FinalAccessTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.scope
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/scope/StaticScopeTest.groovy b/src/test/gls/scope/StaticScopeTest.groovy
index 7c9077b..bbf628c 100644
--- a/src/test/gls/scope/StaticScopeTest.groovy
+++ b/src/test/gls/scope/StaticScopeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.scope
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/scope/VariablePrecedenceTest.groovy b/src/test/gls/scope/VariablePrecedenceTest.groovy
index 6806a8b..ddafb5a 100644
--- a/src/test/gls/scope/VariablePrecedenceTest.groovy
+++ b/src/test/gls/scope/VariablePrecedenceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.scope
 
 /**
diff --git a/src/test/gls/sizelimits/StringSizeTest.groovy b/src/test/gls/sizelimits/StringSizeTest.groovy
index 1e76198..50f1d35 100644
--- a/src/test/gls/sizelimits/StringSizeTest.groovy
+++ b/src/test/gls/sizelimits/StringSizeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.sizelimits
 
 class StringSizeTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/statements/DeclarationTest.groovy b/src/test/gls/statements/DeclarationTest.groovy
index af03d36..b039d0c 100644
--- a/src/test/gls/statements/DeclarationTest.groovy
+++ b/src/test/gls/statements/DeclarationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.statements
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/statements/MultipleAssignmentDeclarationTest.groovy b/src/test/gls/statements/MultipleAssignmentDeclarationTest.groovy
index 5c28e91..9e2c499 100644
--- a/src/test/gls/statements/MultipleAssignmentDeclarationTest.groovy
+++ b/src/test/gls/statements/MultipleAssignmentDeclarationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.statements
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/statements/MultipleAssignmentTest.groovy b/src/test/gls/statements/MultipleAssignmentTest.groovy
index bdda4fa..2d65744 100644
--- a/src/test/gls/statements/MultipleAssignmentTest.groovy
+++ b/src/test/gls/statements/MultipleAssignmentTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.statements
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/statements/ReturnTest.groovy b/src/test/gls/statements/ReturnTest.groovy
index 0cab589..e36be47 100644
--- a/src/test/gls/statements/ReturnTest.groovy
+++ b/src/test/gls/statements/ReturnTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.statements
 
 import gls.CompilableTestSupport
@@ -21,4 +36,24 @@ public class ReturnTest extends CompilableTestSupport {
          assert A.foo==2
       """      
   }
+
+  public void testReturnAdditionInFinally() {
+      //GROOVY-7065
+      assertScript """
+        class CountDown { int counter = 10 }
+
+        CountDown finalCountDown() {
+            def countDown = new CountDown()
+            try {
+                countDown.counter = --countDown.counter
+            } catch (ignored) {
+                countDown.counter = Integer.MIN_VALUE
+            } finally {
+                return countDown
+            }
+        }
+
+        assert finalCountDown().counter == 9
+      """
+  }
 }
\ No newline at end of file
diff --git a/src/test/gls/syntax/AssertTest.groovy b/src/test/gls/syntax/AssertTest.groovy
index 6e08438..72ed0d7 100644
--- a/src/test/gls/syntax/AssertTest.groovy
+++ b/src/test/gls/syntax/AssertTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class AssertTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/BinaryLiteralTest.groovy b/src/test/gls/syntax/BinaryLiteralTest.groovy
index 0a72850..8987ea0 100644
--- a/src/test/gls/syntax/BinaryLiteralTest.groovy
+++ b/src/test/gls/syntax/BinaryLiteralTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/syntax/Gep3OrderDslTest.groovy b/src/test/gls/syntax/Gep3OrderDslTest.groovy
index aed3b02..196e6c1 100644
--- a/src/test/gls/syntax/Gep3OrderDslTest.groovy
+++ b/src/test/gls/syntax/Gep3OrderDslTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/src/test/gls/syntax/Gep3Test.groovy b/src/test/gls/syntax/Gep3Test.groovy
index c18bc21..7079dd0 100644
--- a/src/test/gls/syntax/Gep3Test.groovy
+++ b/src/test/gls/syntax/Gep3Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 import static Container.*
diff --git a/src/test/gls/syntax/NumberLiteralTest.groovy b/src/test/gls/syntax/NumberLiteralTest.groovy
index f2f7034..bb00d89 100644
--- a/src/test/gls/syntax/NumberLiteralTest.groovy
+++ b/src/test/gls/syntax/NumberLiteralTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class NumberLiteralTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy b/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy
index 427c218..cd96c20 100644
--- a/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy
+++ b/src/test/gls/syntax/OldClosureSyntaxRemovalTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class OldClosureSyntaxRemovalTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy b/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy
index 0bc084e..5e8b08f 100644
--- a/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy
+++ b/src/test/gls/syntax/OldPropertySyntaxRemovalTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class OldPropertySyntaxRemovalTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/OldSpreadTest.groovy b/src/test/gls/syntax/OldSpreadTest.groovy
index 817fc9f..b564c41 100644
--- a/src/test/gls/syntax/OldSpreadTest.groovy
+++ b/src/test/gls/syntax/OldSpreadTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class OldSpreadTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/ParsingTest.groovy b/src/test/gls/syntax/ParsingTest.groovy
index a6bd426..bbf6ba6 100644
--- a/src/test/gls/syntax/ParsingTest.groovy
+++ b/src/test/gls/syntax/ParsingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 public class ParsingTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/syntax/UnderscoreInNumbersTest.groovy b/src/test/gls/syntax/UnderscoreInNumbersTest.groovy
index 208075c..6d5249b 100644
--- a/src/test/gls/syntax/UnderscoreInNumbersTest.groovy
+++ b/src/test/gls/syntax/UnderscoreInNumbersTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.syntax
 
 import gls.CompilableTestSupport
diff --git a/src/test/gls/types/BooleanExpressionConversionTest.groovy b/src/test/gls/types/BooleanExpressionConversionTest.groovy
index 01aa2e2..22eaecf 100644
--- a/src/test/gls/types/BooleanExpressionConversionTest.groovy
+++ b/src/test/gls/types/BooleanExpressionConversionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.types
 
 public class BooleanExpressionConversionTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/types/GroovyCastTest.groovy b/src/test/gls/types/GroovyCastTest.groovy
index 697e18d..419af36 100644
--- a/src/test/gls/types/GroovyCastTest.groovy
+++ b/src/test/gls/types/GroovyCastTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.types
 
 public class GroovyCastTest extends gls.CompilableTestSupport {
diff --git a/src/test/gls/types/OperationsResultTypeTest.groovy b/src/test/gls/types/OperationsResultTypeTest.groovy
index 6d48d92..ea68db5 100644
--- a/src/test/gls/types/OperationsResultTypeTest.groovy
+++ b/src/test/gls/types/OperationsResultTypeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package gls.types
 
 public class OperationsResultTypeTest extends gls.CompilableTestSupport {
diff --git a/src/test/groovy/AmbiguousInvocationTest.groovy b/src/test/groovy/AmbiguousInvocationTest.groovy
index 114b7c1..36da67e 100644
--- a/src/test/groovy/AmbiguousInvocationTest.groovy
+++ b/src/test/groovy/AmbiguousInvocationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 /**
  * to prove GROOVY-467 is no longer an issue    
diff --git a/src/test/groovy/ArrayAutoboxingTest.groovy b/src/test/groovy/ArrayAutoboxingTest.groovy
index 179b665..43bba15 100644
--- a/src/test/groovy/ArrayAutoboxingTest.groovy
+++ b/src/test/groovy/ArrayAutoboxingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ArrayAutoboxingTest extends GroovyTestCase {
diff --git a/src/test/groovy/ArrayCoerceTest.groovy b/src/test/groovy/ArrayCoerceTest.groovy
index 2677865..1622f27 100644
--- a/src/test/groovy/ArrayCoerceTest.groovy
+++ b/src/test/groovy/ArrayCoerceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ArrayCoerceTest extends GroovyTestCase {
diff --git a/src/test/groovy/ArrayParamMethodTest.groovy b/src/test/groovy/ArrayParamMethodTest.groovy
index b95c77c..5ba55d6 100644
--- a/src/test/groovy/ArrayParamMethodTest.groovy
+++ b/src/test/groovy/ArrayParamMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ArrayParamMethodTest extends GroovyTestCase implements DummyInterface {
diff --git a/src/test/groovy/ArrayTest.groovy b/src/test/groovy/ArrayTest.groovy
index 9b4c058..2ff6cc9 100644
--- a/src/test/groovy/ArrayTest.groovy
+++ b/src/test/groovy/ArrayTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ArrayTest extends GroovyTestCase {
@@ -441,4 +456,50 @@ class ArrayTest extends GroovyTestCase {
         assert l[0]==1
         assert l[1]==5
     }
+
+    void testJoin() {
+        def a1 = [false, true] as boolean[]
+        def a2 = [1 as byte, 2 as byte] as byte[]
+        def a3 = ["a".charAt(0), "b".charAt(0)] as char[]
+        def a4 = [1 as double, 2 as double] as double[]
+        def a5 = [1 as float, 2 as float] as float[]
+        def a6 = [1 as int, 2 as int] as int[]
+        def a7 = [1 as long, 2 as long] as long[]
+        def a8 = [1 as short, 2 as short] as short[]
+
+        assert "false, true" == a1.join(", ")
+        assert "1, 2" == a2.join(", ")
+        assert "a, b" == a3.join(", ")
+        assert "1.0, 2.0" == a4.join(", ")
+        assert "1.0, 2.0" == a5.join(", ")
+        assert "1, 2" == a6.join(", ")
+        assert "1, 2" == a7.join(", ")
+        assert "1, 2" == a8.join(", ")
+    }
+
+    void testSum() {
+        def a1 = [1, 2, 3] as byte[]
+        def a2 = [1, 2, 3] as short[]
+        def a3 = [1, 2, 3] as int[]
+        def a4 = [1, 2, 3] as long[]
+        def a5 = [1, 2, 3] as char[]
+        def a6 = [1, 2, 3] as float[]
+        def a7 = [1, 2, 3] as double[]
+
+        assert ((byte) 6) == a1.sum()
+        assert ((short) 6) == a2.sum()
+        assert ((int) 6) == a3.sum()
+        assert ((long) 6) == a4.sum()
+        assert ((char) 6) == a5.sum()
+        assert ((float) 6) == a6.sum()
+        assert ((double) 6) == a7.sum()
+
+        assert ((byte) 10) == a1.sum((byte) 4)
+        assert ((short) 10) == a2.sum((short) 4)
+        assert ((int) 10) == a3.sum(4)
+        assert ((long) 10) == a4.sum(4)
+        assert ((char) 10) == a5.sum((char) 4)
+        assert ((float) 10) == a6.sum(4)
+        assert ((double) 10) == a7.sum(4)
+    }
 }
diff --git a/src/test/groovy/ArrayTypeTest.groovy b/src/test/groovy/ArrayTypeTest.groovy
index e783ec5..c868c4d 100644
--- a/src/test/groovy/ArrayTypeTest.groovy
+++ b/src/test/groovy/ArrayTypeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ArrayTypeTest extends GroovyTestCase {
diff --git a/src/test/groovy/AsTest.groovy b/src/test/groovy/AsTest.groovy
index d7f15bd..527858a 100644
--- a/src/test/groovy/AsTest.groovy
+++ b/src/test/groovy/AsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 /**
  * Test case for using the "as" keyword to convert between strings
diff --git a/src/test/groovy/Bar.groovy b/src/test/groovy/Bar.groovy
index 2c308ed..c896cf0 100644
--- a/src/test/groovy/Bar.groovy
+++ b/src/test/groovy/Bar.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import java.util.HashMap as Goober;
diff --git a/src/test/groovy/Base64Test.groovy b/src/test/groovy/Base64Test.groovy
index d202ad9..329658a 100644
--- a/src/test/groovy/Base64Test.groovy
+++ b/src/test/groovy/Base64Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class Base64Test extends GroovyTestCase {
diff --git a/src/test/groovy/BinaryStreamsTest.groovy b/src/test/groovy/BinaryStreamsTest.groovy
index 12f34e3..a4eb791 100755
--- a/src/test/groovy/BinaryStreamsTest.groovy
+++ b/src/test/groovy/BinaryStreamsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Test case for DefaultGroovyMethods involving Object streams and data streams.
  *
diff --git a/src/test/groovy/BreakContinueLabelTest.groovy b/src/test/groovy/BreakContinueLabelTest.groovy
index 41c1a2c..4bb983d 100644
--- a/src/test/groovy/BreakContinueLabelTest.groovy
+++ b/src/test/groovy/BreakContinueLabelTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import gls.CompilableTestSupport
@@ -116,37 +131,21 @@ class BreakContinueLabelTest extends CompilableTestSupport {
         }
     }
 
-    // documents a (minor) limitation of the current implementation compared to Java
-    void testBreakToOtherThanLastLabelCausesSyntaxError() {
-        shouldNotCompile """
-one:
-two:
-three:
-for (i in 1..2) {
-  break one
-}
-            """
-    }
-
-    void testContinueToLastLabelSucceeds() {
-        one:
-        two:
-        three:
-        for (i in 1..2) {
-            continue three
-            fail()
-        }
-    }
-
-    // documents a (minor) limitation of the current implementation compared to Java
-    void testContinueToOtherThanLastLabelCausesSyntaxError() {
-        shouldNotCompile """
-one:
-two:
-three:
-for (i in 1..2) {
-  continue two
-}
+    void testMultipleLabelSupport() {
+        assertScript """
+            def visited = []
+            label1:
+            label2:
+            label3:
+            for (int i = 0; i < 9; i++) {
+              visited << i
+              if (i == 1) continue label1
+              visited << 10 + i
+              if (i == 3) continue label2
+              visited << 100 + i
+              if (i == 5) break label3
+            }
+            assert visited == [0, 10, 100, 1, 2, 12, 102, 3, 13, 4, 14, 104, 5, 15, 105]
         """
     }
 
diff --git a/src/test/groovy/CallInnerClassCtorTest.groovy b/src/test/groovy/CallInnerClassCtorTest.groovy
index 67892a5..52b0fb2 100644
--- a/src/test/groovy/CallInnerClassCtorTest.groovy
+++ b/src/test/groovy/CallInnerClassCtorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/CategoryTest.groovy b/src/test/groovy/CategoryTest.groovy
index 2145ad6..befc53b 100644
--- a/src/test/groovy/CategoryTest.groovy
+++ b/src/test/groovy/CategoryTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class CategoryTest extends GroovyTestCase {
diff --git a/src/test/groovy/ChainedAssignmentTest.groovy b/src/test/groovy/ChainedAssignmentTest.groovy
index 1c0eb64..123f01f 100644
--- a/src/test/groovy/ChainedAssignmentTest.groovy
+++ b/src/test/groovy/ChainedAssignmentTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ChainedAssignmentTest extends GroovyTestCase {
diff --git a/src/test/groovy/ClassExpressionTest.groovy b/src/test/groovy/ClassExpressionTest.groovy
index 7dd2fe5..2ca8c17 100644
--- a/src/test/groovy/ClassExpressionTest.groovy
+++ b/src/test/groovy/ClassExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClassLoaderBug.groovy b/src/test/groovy/ClassLoaderBug.groovy
index 7d2ecf2..3575bc2 100644
--- a/src/test/groovy/ClassLoaderBug.groovy
+++ b/src/test/groovy/ClassLoaderBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ClassLoaderBug extends GroovyTestCase {
diff --git a/src/test/groovy/ClosureCloneTest.groovy b/src/test/groovy/ClosureCloneTest.groovy
index 2b55ae7..ff5ea4f 100644
--- a/src/test/groovy/ClosureCloneTest.groovy
+++ b/src/test/groovy/ClosureCloneTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClosureDefaultParameterTest.groovy b/src/test/groovy/ClosureDefaultParameterTest.groovy
index aaefd03..a601bcc 100644
--- a/src/test/groovy/ClosureDefaultParameterTest.groovy
+++ b/src/test/groovy/ClosureDefaultParameterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClosureInStaticMethodTest.groovy b/src/test/groovy/ClosureInStaticMethodTest.groovy
index 8ffaa05..b0f2da8 100644
--- a/src/test/groovy/ClosureInStaticMethodTest.groovy
+++ b/src/test/groovy/ClosureInStaticMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClosureMethodCallTest.groovy b/src/test/groovy/ClosureMethodCallTest.groovy
index 282ee02..c813386 100644
--- a/src/test/groovy/ClosureMethodCallTest.groovy
+++ b/src/test/groovy/ClosureMethodCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClosureReturnTest.groovy b/src/test/groovy/ClosureReturnTest.groovy
index e12ccde..66bd32a 100644
--- a/src/test/groovy/ClosureReturnTest.groovy
+++ b/src/test/groovy/ClosureReturnTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy b/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy
index 38b0960..90aafff 100644
--- a/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy
+++ b/src/test/groovy/ClosureReturnWithoutReturnStatementTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ClosureReturnWithoutReturnStatementTest extends GroovyTestCase {
diff --git a/src/test/groovy/ClosureSugarTest.groovy b/src/test/groovy/ClosureSugarTest.groovy
index cdb7bea..c4db495 100644
--- a/src/test/groovy/ClosureSugarTest.groovy
+++ b/src/test/groovy/ClosureSugarTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ClosureSugarTest extends GroovyTestCase {
diff --git a/src/test/groovy/ClosureTest.groovy b/src/test/groovy/ClosureTest.groovy
index f3f2f0a..48e55f1 100644
--- a/src/test/groovy/ClosureTest.groovy
+++ b/src/test/groovy/ClosureTest.groovy
@@ -518,6 +518,24 @@ class ClosureTest extends GroovyTestCase {
         }
         assert msg.contains('"methodMissing" implementations are not supported on static inner classes as a synthetic version of "methodMissing" is added during compilation for the purpose of outer class delegation.')
     }
+
+    // GROOVY-6989
+    void testEachCall() {
+        assertScript '''
+            Object[] arr = new Object[1]
+            arr[0] = "1"
+            List list = new ArrayList()
+            list.add(arr)
+
+            list.each { def obj ->
+                assert obj[0] == "1"
+            }
+
+            list.each { Object[] obj ->
+                assert obj[0] == "1"
+            }
+        '''
+    }
 }
 
 public class TinyAgent {
diff --git a/src/test/groovy/ClosureWithEmptyParametersTest.groovy b/src/test/groovy/ClosureWithEmptyParametersTest.groovy
index 2cf8deb..5293eb7 100644
--- a/src/test/groovy/ClosureWithEmptyParametersTest.groovy
+++ b/src/test/groovy/ClosureWithEmptyParametersTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/CollateTest.groovy b/src/test/groovy/CollateTest.groovy
index b52e85e..dd0b509 100644
--- a/src/test/groovy/CollateTest.groovy
+++ b/src/test/groovy/CollateTest.groovy
@@ -20,11 +20,19 @@ class CollateTest extends GroovyTestCase {
   void testSimple() {
     def list = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
     assert list.collate( 3 ) == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]
+
+    int a = 1
+    Iterable iterable = { [ hasNext:{ a <= 10 }, next:{ a++ } ] as Iterator } as Iterable
+    assert iterable.collate( 3 ) == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ], [ 10 ] ]
   }
 
   void testRemain() {
     def list = [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 ]
     assert list.collate( 3, false ) == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
+
+    int a = 1
+    Iterable iterable = { [ hasNext:{ a <= 10 }, next:{ a++ } ] as Iterator } as Iterable
+    assert iterable.collate( 3, false ) == [ [ 1, 2, 3 ], [ 4, 5, 6 ], [ 7, 8, 9 ] ]
   }
 
   void testStepSimple() {
@@ -33,6 +41,10 @@ class CollateTest extends GroovyTestCase {
                      [ 4, 5, 6 ], [ 5, 6, 7 ], [ 6, 7, 8 ],
                      [ 7, 8, 9 ], [ 8, 9, 10 ], [ 9, 10 ], [ 10 ] ]
     assert list.collate( 3, 1 ) == expected
+
+    int a = 1
+    Iterable iterable = { [ hasNext:{ a <= 10 }, next:{ a++ } ] as Iterator } as Iterable
+    assert iterable.collate( 3, 1 ) == expected
   }
 
   void testStepSimpleRemain() {
@@ -41,6 +53,10 @@ class CollateTest extends GroovyTestCase {
                      [ 4, 5, 6 ], [ 5, 6, 7 ], [ 6, 7, 8 ],
                      [ 7, 8, 9 ], [ 8, 9, 10 ] ]
     assert list.collate( 3, 1, false ) == expected
+
+    int a = 1
+    Iterable iterable = { [ hasNext:{ a <= 10 }, next:{ a++ } ] as Iterator } as Iterable
+    assert iterable.collate( 3, 1, false ) == expected
   }
 
   void testTwoDimensions() {
diff --git a/src/test/groovy/CompareEqualsTest.groovy b/src/test/groovy/CompareEqualsTest.groovy
index 65dbcfa..c17a9a9 100644
--- a/src/test/groovy/CompareEqualsTest.groovy
+++ b/src/test/groovy/CompareEqualsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class CompareEqualsTest extends GroovyTestCase {
diff --git a/src/test/groovy/CompareTypesTest.groovy b/src/test/groovy/CompareTypesTest.groovy
index 00550cc..d25625a 100644
--- a/src/test/groovy/CompareTypesTest.groovy
+++ b/src/test/groovy/CompareTypesTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/CompileOrderTest.groovy b/src/test/groovy/CompileOrderTest.groovy
index e963494..56a0e5b 100644
--- a/src/test/groovy/CompileOrderTest.groovy
+++ b/src/test/groovy/CompileOrderTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class CompileOrderTest extends GroovyTestCase {
diff --git a/src/test/groovy/CompilerErrorTest.groovy b/src/test/groovy/CompilerErrorTest.groovy
index d651d55..2a6fef6 100644
--- a/src/test/groovy/CompilerErrorTest.groovy
+++ b/src/test/groovy/CompilerErrorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class CompilerErrorTest extends GroovyTestCase {
diff --git a/src/test/groovy/Constructor2Test.groovy b/src/test/groovy/Constructor2Test.groovy
index 25c027d..d4c91ec 100644
--- a/src/test/groovy/Constructor2Test.groovy
+++ b/src/test/groovy/Constructor2Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class Constructor2Test extends GroovyTestCase {
diff --git a/src/test/groovy/ConstructorTest.groovy b/src/test/groovy/ConstructorTest.groovy
index 723d655..9ebd7d0 100644
--- a/src/test/groovy/ConstructorTest.groovy
+++ b/src/test/groovy/ConstructorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ConstructorTest extends GroovyTestCase {
diff --git a/src/test/groovy/CurlyBracketLayoutTest.groovy b/src/test/groovy/CurlyBracketLayoutTest.groovy
index 1c0e0db..7a6f4d9 100644
--- a/src/test/groovy/CurlyBracketLayoutTest.groovy
+++ b/src/test/groovy/CurlyBracketLayoutTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class CurlyBracketLayoutTest extends GroovyTestCase
diff --git a/src/test/groovy/DoWhileLoopTest.groovy b/src/test/groovy/DoWhileLoopTest.groovy
index 4913bfd..adbe718 100644
--- a/src/test/groovy/DoWhileLoopTest.groovy
+++ b/src/test/groovy/DoWhileLoopTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class DoWhileLoopTest extends GroovyTestCase {
diff --git a/src/test/groovy/DollarEscapingTest.groovy b/src/test/groovy/DollarEscapingTest.groovy
index 6b11cd6..115882a 100644
--- a/src/test/groovy/DollarEscapingTest.groovy
+++ b/src/test/groovy/DollarEscapingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class DollarEscapingTest extends GroovyTestCase {
diff --git a/src/test/groovy/DownUpStepTest.groovy b/src/test/groovy/DownUpStepTest.groovy
index ed997e9..7164e5a 100644
--- a/src/test/groovy/DownUpStepTest.groovy
+++ b/src/test/groovy/DownUpStepTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 public class DownUpStepTest extends GroovyTestCase {
diff --git a/src/test/groovy/DummyInterface.java b/src/test/groovy/DummyInterface.java
index 37f9b3e..a2e3d01 100644
--- a/src/test/groovy/DummyInterface.java
+++ b/src/test/groovy/DummyInterface.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 public interface DummyInterface {
diff --git a/src/test/groovy/DynamicMemberTest.groovy b/src/test/groovy/DynamicMemberTest.groovy
index 08a48bc..01f5b4a 100644
--- a/src/test/groovy/DynamicMemberTest.groovy
+++ b/src/test/groovy/DynamicMemberTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class DynamicMemberTest extends GroovyTestCase {
diff --git a/src/test/groovy/EscapedUnicodeTest.groovy b/src/test/groovy/EscapedUnicodeTest.groovy
index 5b0c8a4..13ae852 100644
--- a/src/test/groovy/EscapedUnicodeTest.groovy
+++ b/src/test/groovy/EscapedUnicodeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 \u0063\u006c\u0061\u0073\u0073\u0020\u0045\u0073\u0063\u0061\u0070\u0065\u0064\u0055\u006e\u0069\u0063\u006f\u0064\u0065\u0054\u0065\u0073\u0074\u0020\u0065\u0078\u0074\u0065\u006e\u0064\u0073\u0020\u0047\u0072\u006f\u006f\u0076\u0079\u0054\u0065\u0073\u0074\u0043\u0061\u0073\u0065\u0020\u007b
 
 \u0020\u0020\u0020\u0020\u0076\u006f\u0069\u0064\u0020\u0074\u0065\u0073\u0074\u0041\u0073\u0073\u0065\u0072\u0074\u0028\u0029\u0020\u007b
diff --git a/src/test/groovy/Foo.groovy b/src/test/groovy/Foo.groovy
index 04e0642..bb75819 100644
--- a/src/test/groovy/Foo.groovy
+++ b/src/test/groovy/Foo.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/GroovyClosureMethodsTest.groovy b/src/test/groovy/GroovyClosureMethodsTest.groovy
index 081b787..bb3c9b8 100644
--- a/src/test/groovy/GroovyClosureMethodsTest.groovy
+++ b/src/test/groovy/GroovyClosureMethodsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/GroovyInterceptableTest.groovy b/src/test/groovy/GroovyInterceptableTest.groovy
index a8ae0ef..b1a45c1 100644
--- a/src/test/groovy/GroovyInterceptableTest.groovy
+++ b/src/test/groovy/GroovyInterceptableTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import org.codehaus.groovy.runtime.ReflectionMethodInvoker
diff --git a/src/test/groovy/GroovyMethodsTest.groovy b/src/test/groovy/GroovyMethodsTest.groovy
index a7fafdf..780482e 100644
--- a/src/test/groovy/GroovyMethodsTest.groovy
+++ b/src/test/groovy/GroovyMethodsTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -30,6 +30,7 @@ import org.codehaus.groovy.util.StringUtil
  * @author Mike Dillon
  * @author Tim Yates
  * @author Dinko Srkoc
+ * @author Yu Kobayashi
  */
 class GroovyMethodsTest extends GroovyTestCase {
     void testCollect() {
@@ -62,11 +63,11 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert animals.elements()*.size() == [3, 3]
     }
 
-    void testCollectAll() {
+    void testCollectNested() {
         def animalLists= [["ant", "mouse", "elephant"], ["deer", "monkey"]]
         assert animalLists*.size() == [3, 2]
         assert animalLists.collect{ it.size() } == [3, 2]
-        assert animalLists.collectAll{ it.size() } == [[3, 5, 8], [4, 6]]
+        assert animalLists.collectNested{ it.size() } == [[3, 5, 8], [4, 6]]
     }
 
     void testAsCoercion() {
@@ -432,13 +433,93 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert !('d' in list)
     }
 
-    void testFirstLastHeadTailForLists() {
+    void testFirstLastHeadTailInitForLists() {
         def list = ['a', 'b', 'c']
         assert 'a' == list.first()
-        assert 'c' == list.last()
         assert 'a' == list.head()
+        assert 'c' == list.last()
         assert ['b', 'c'] == list.tail()
+        assert ['a', 'b'] == list.init()
         assert list.size() == 3
+
+        list = []
+        shouldFail(NoSuchElementException) {
+            list.first()
+        }
+        shouldFail(NoSuchElementException) {
+            list.head()
+        }
+        shouldFail(NoSuchElementException) {
+            list.last()
+        }
+        shouldFail(NoSuchElementException) {
+            list.tail()
+        }
+        shouldFail(NoSuchElementException) {
+            list.init()
+        }
+        assert list.size() == 0
+    }
+
+    void testFirstLastHeadTailInitForIterables() {
+        int a
+        Iterable iterable = { [ hasNext:{ a < 6 }, next:{ a++ } ] as Iterator } as Iterable
+
+        a = 1
+        assert 1 == iterable.first()
+        a = 1
+        assert 1 == iterable.head()
+        a = 1
+        assert 5 == iterable.last()
+        a = 1
+        assert [2, 3, 4, 5] == iterable.tail()
+        a = 1
+        assert [1, 2, 3, 4] == iterable.init()
+
+        iterable = { [ hasNext:{ false }, next:{ 1 } ] as Iterator } as Iterable
+        shouldFail(NoSuchElementException) {
+            iterable.first()
+        }
+        shouldFail(NoSuchElementException) {
+            iterable.head()
+        }
+        shouldFail(NoSuchElementException) {
+            iterable.last()
+        }
+        shouldFail(NoSuchElementException) {
+            iterable.init()
+        }
+        shouldFail(NoSuchElementException) {
+            iterable.tail()
+        }
+    }
+
+    void testFirstLastHeadTailInitForArrays() {
+        String[] ary = ['a', 'b', 'c'] as String[]
+        assert 'a' == ary.first()
+        assert 'a' == ary.head()
+        assert 'c' == ary.last()
+        assert ['b', 'c'] == ary.tail()
+        assert ['a', 'b'] == ary.init()
+        assert ary.length == 3
+
+        ary = [] as String[]
+        shouldFail(NoSuchElementException) {
+            ary.first()
+        }
+        shouldFail(NoSuchElementException) {
+            ary.head()
+        }
+        shouldFail(NoSuchElementException) {
+            ary.last()
+        }
+        shouldFail(NoSuchElementException) {
+            ary.tail()
+        }
+        shouldFail(NoSuchElementException) {
+            ary.init()
+        }
+        assert ary.length == 0
     }
 
     void testPushPopForLists() {
@@ -455,12 +536,30 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert !('d' in array)
     }
 
-    void testMax() {
+    void testMaxForIterable() {
         assert [-5, -3, -1, 0, 2, 4].max {it * it} == -5
-    }
-
-    void testMin() {
+        assert ['be', 'happy', null].max{ it == 'be' ? null : "" + it } == null
+        assert ['be', 'happy', null].max{ it == 'happy' ? null : "" + it } == null
+        assert ['happy', null, 'birthday'].max{ ("" + it).size() } == 'birthday'
+        assert ['be', null].max{ ("" + it).size() } == null
+        assert [null, 'result'].max{ "" + it } == 'result'
+        def nums = [42, 35, 17, 100]
+        assert [].max{ it } == null
+        assert nums.max{ it } == 100
+        assert nums.max{ null } in nums
+        assert nums.max{ it.toString().toList()*.toInteger().sum() } == 35
+    }
+
+    void testMinForIterable() {
         assert [-5, -3, -1, 0, 2, 4].min {it * it} == 0
+        assert ['be', 'happy', null].min{ it == 'happy' ? null : "" + it } == 'happy'
+        assert ['happy', null, 'birthday'].min{ ("" + it).size() } == null
+        assert [null, 'result'].min{ "" + it } == null
+        def nums = [42, 35, 17, 100]
+        assert [].min{ it } == null
+        assert nums.min{ it } == 17
+        assert nums.min{ null } in nums 
+        assert nums.min{ it.toString().toList()*.toInteger().sum() } == 100
     }
 
     void testSort() {
@@ -468,11 +567,11 @@ class GroovyMethodsTest extends GroovyTestCase {
     }
 
     void testMaxForIterator() {
-        assert [-5, -3, -1, 0, 2, 4].collect{ it * it }.iterator().max() == 25
+        assert [-5, -3, -1, 0, 2, 4].collect { it * it }.iterator().max() == 25
     }
 
     void testMinForIterator() {
-        assert [-5, -3, -1, 0, 2, 4].collect{ it * it }.iterator().min() == 0
+        assert [-5, -3, -1, 0, 2, 4].collect { it * it }.iterator().min() == 0
     }
 
     void testMinForObjectArray() {
@@ -577,13 +676,13 @@ class GroovyMethodsTest extends GroovyTestCase {
         def interruptor = new groovy.TestInterruptor(Thread.currentThread())
         new Thread(interruptor).start()
         long start = System.currentTimeMillis()
-        long sleeptime = 1000
+        long sleeptime = 3000
         sleep(sleeptime) {
             log += it.toString()
             false // continue sleeping
         }
         long slept = System.currentTimeMillis() - start
-        short allowedError = 20 // ms
+        short allowedError = 60 // ms
         assert slept + allowedError >= sleeptime, "should have slept for at least $sleeptime ms but only slept for $slept ms"
         assertEquals 'java.lang.InterruptedException: sleep interrupted', log.toString()
     }
@@ -901,7 +1000,7 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert items == [2, 4]
     }
 
-    void testPermutations() {
+    void testPermutationsForLists() {
         def items = [1, 2, 3]
         assert items.permutations() == [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] as Set
         items = "frog".toList()
@@ -937,6 +1036,45 @@ class GroovyMethodsTest extends GroovyTestCase {
         ] as Set
     }
 
+    void testPermutationsForIterables() {
+        int a = 1
+        Iterable items = { [ hasNext:{ a <= 3 }, next:{ a++ } ] as Iterator } as Iterable
+        assert items.permutations() == [[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]] as Set
+
+        a = 0
+        items = { [ hasNext:{ a <= 3 }, next:{ "frog"[a++] } ] as Iterator } as Iterable
+        def ans = [] as Set
+        items.eachPermutation {
+            ans << it
+        }
+        assert ans == [
+                ['f', 'r', 'o', 'g'],
+                ['f', 'r', 'g', 'o'],
+                ['f', 'o', 'r', 'g'],
+                ['f', 'o', 'g', 'r'],
+                ['f', 'g', 'r', 'o'],
+                ['f', 'g', 'o', 'r'],
+                ['r', 'f', 'o', 'g'],
+                ['r', 'f', 'g', 'o'],
+                ['r', 'o', 'f', 'g'],
+                ['r', 'o', 'g', 'f'],
+                ['r', 'g', 'f', 'o'],
+                ['r', 'g', 'o', 'f'],
+                ['o', 'r', 'f', 'g'],
+                ['o', 'r', 'g', 'f'],
+                ['o', 'f', 'r', 'g'],
+                ['o', 'f', 'g', 'r'],
+                ['o', 'g', 'r', 'f'],
+                ['o', 'g', 'f', 'r'],
+                ['g', 'r', 'o', 'f'],
+                ['g', 'r', 'f', 'o'],
+                ['g', 'o', 'r', 'f'],
+                ['g', 'o', 'f', 'r'],
+                ['g', 'f', 'r', 'o'],
+                ['g', 'f', 'o', 'r'],
+        ] as Set
+    }
+
     void testPermutationsWithAction() {
             def items = [1, 2, 3]
             assert items.permutations { it.collect { 2*it } } as Set == [[2, 4, 6], [2, 6, 4], [4, 2, 6], [4, 6, 2], [6, 2, 4], [6, 4, 2]] as Set
@@ -985,6 +1123,11 @@ class GroovyMethodsTest extends GroovyTestCase {
             assert it.take(  0 ) == []
             assert it.take(  2 ) == [ 1, 2 ]
             assert it.take(  4 ) == [ 1, 2, 3 ]
+
+            assert it.takeRight( -1 ) == []
+            assert it.takeRight(  0 ) == []
+            assert it.takeRight(  2 ) == [ 2, 3 ]
+            assert it.takeRight(  4 ) == [ 1, 2, 3 ]
         }
     }
 
@@ -995,6 +1138,11 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert items.take(  0 ) == [] as String[]
         assert items.take(  2 ) == [ 'ant', 'bee' ] as String[]
         assert items.take(  4 ) == [ 'ant', 'bee', 'cat' ] as String[]
+
+        assert items.takeRight( -1 ) == [] as String[]
+        assert items.takeRight(  0 ) == [] as String[]
+        assert items.takeRight(  2 ) == [ 'bee', 'cat' ] as String[]
+        assert items.takeRight(  4 ) == [ 'ant', 'bee', 'cat' ] as String[]
     }
 
     void testMapTake() {
@@ -1021,6 +1169,32 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert items.take(  4 ).collect { it } == [ 3, 4, 5, 6 ]
     }
 
+    void testWellBehavedIteratorsForInfiniteStreams() {
+        int a = 1
+        def infiniterator = [ hasNext:{ true }, next:{ a++ } ] as Iterator
+        assert infiniterator.drop(3).dropWhile{ it < 9 }.toUnique{ it % 100 }.init().tail().take(3).toList() == [10, 11, 12]
+    }
+
+    void testIterableTake() {
+        int a = 1
+        Iterable items = { [ hasNext:{ true }, next:{ a++ } ] as Iterator } as Iterable
+
+        assert items.take( -1 ).collect { it } == []
+        assert items.take(  0 ).collect { it } == []
+        assert items.take(  2 ).collect { it } == [ 1, 2 ]
+        assert items.take(  4 ).collect { it } == [ 3, 4, 5, 6 ]
+
+        items = { [ hasNext:{ a < 6 }, next:{ a++ } ] as Iterator } as Iterable
+
+        assert items.takeRight( -1 ).collect { it } == []
+        a = 1
+        assert items.takeRight(  0 ).collect { it } == []
+        a = 1
+        assert items.takeRight(  2 ).collect { it } == [ 4, 5 ]
+        a = 1
+        assert items.takeRight(  4 ).collect { it } == [ 2, 3, 4, 5 ]
+    }
+
     void testCharSequenceTake() {
         def data = [ 'groovy',      // String
                      "${'groovy'}", // GString
@@ -1049,6 +1223,11 @@ class GroovyMethodsTest extends GroovyTestCase {
             assert it.drop(  0 ) == [ 1, 2, 3 ]
             assert it.drop(  2 ) == [ 3 ]
             assert it.drop(  4 ) == []
+
+            assert it.dropRight( -1 ) == [ 1, 2, 3 ]
+            assert it.dropRight(  0 ) == [ 1, 2, 3 ]
+            assert it.dropRight(  2 ) == [ 1 ]
+            assert it.dropRight(  4 ) == []
         }
     }
 
@@ -1059,6 +1238,11 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert items.drop(  4 ) == [] as String[]
         assert items.drop(  0 ) == [ 'ant', 'bee', 'cat' ] as String[]
         assert items.drop( -1 ) == [ 'ant', 'bee', 'cat' ] as String[]
+
+        assert items.dropRight(  2 ) == [ 'ant' ] as String[]
+        assert items.dropRight(  4 ) == [] as String[]
+        assert items.dropRight(  0 ) == [ 'ant', 'bee', 'cat' ] as String[]
+        assert items.dropRight( -1 ) == [ 'ant', 'bee', 'cat' ] as String[]
     }
 
     void testMapDrop() {
@@ -1088,6 +1272,28 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert items.drop( 5 ).collect { it } == []
     }
 
+    void testIterableDrop() {
+        int a = 1
+        Iterable items = { [ hasNext:{ a < 6 }, next:{ a++ } ] as Iterator } as Iterable
+
+        assert items.drop( 0 ).collect { it } == [ 1, 2, 3, 4, 5 ]
+        a = 1
+        assert items.drop( 2 ).collect { it } == [ 3, 4, 5 ]
+        a = 1
+        assert items.drop( 4 ).collect { it } == [ 5 ]
+        a = 1
+        assert items.drop( 5 ).collect { it } == []
+
+        a = 1
+        assert items.dropRight( 0 ).collect { it } == [ 1, 2, 3, 4, 5 ]
+        a = 1
+        assert items.dropRight( 2 ).collect { it } == [ 1, 2, 3 ]
+        a = 1
+        assert items.dropRight( 4 ).collect { it } == [ 1 ]
+        a = 1
+        assert items.dropRight( 5 ).collect { it } == []
+    }
+
     void testCharSequenceDrop() {
         def data = [ 'groovy',      // String
                      "${'groovy'}", // GString
@@ -1105,6 +1311,7 @@ class GroovyMethodsTest extends GroovyTestCase {
     }
 
     void testTakeDropClassSymmetry() {
+        int a
         // NOTES:
         // - Cannot test plain HashMap, as Groovy will always default to a LinkedHashMap
         //   See org.codehaus.groovy.runtime.DefaultGroovyMethodsSupport.java:183
@@ -1121,14 +1328,34 @@ class GroovyMethodsTest extends GroovyTestCase {
           (java.util.Hashtable)     : new Hashtable( [ a:1, b:2, c:3 ] ),
           // Iterators
           (java.util.Iterator)      : [ hasNext:{ true }, next:{ 'groovy' } ] as Iterator,
+          // Iterables
+          (java.lang.Iterable)      : { [ hasNext:{ a < 6 }, next:{ a++ } ] as Iterator } as Iterable,
           // CharSequences
           (java.lang.String)        : new String( 'groovy' ),
           (java.nio.CharBuffer)     : java.nio.CharBuffer.wrap( 'groovy' ),
         ]
         data.each { Class clazz, object ->
+            a = 1
             assert clazz.isInstance( object.take( 5 ) )
+            a = 1
             assert clazz.isInstance( object.drop( 5 ) )
         }
+
+        data = [
+          // Lists
+          (java.util.ArrayList)     : new ArrayList( [ 1, 2, 3 ] ),
+          (java.util.LinkedList)    : new LinkedList( [ 1, 2, 3 ] ),
+          (java.util.Stack)         : new Stack() {{ addAll( [ 1, 2, 3 ] ) }},
+          (java.util.Vector)        : new Vector( [ 1, 2, 3 ] ),
+          // Iterables
+          (java.lang.Iterable)      : { [ hasNext:{ a < 6 }, next:{ a++ } ] as Iterator } as Iterable,
+        ]
+        data.each { Class clazz, object ->
+            a = 1
+            assert clazz.isInstance( object.takeRight( 5 ) )
+            a = 1
+            assert clazz.isInstance( object.dropRight( 5 ) )
+        }
     }
 
     void testContainsForPrimitiveArrays() {
@@ -1161,6 +1388,53 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert !chars.contains('b' as char)
     }
 
+    void testContainsForArrays() {
+        String[] vowels = ['a', 'e', 'i', 'o', 'u']
+        assert vowels.contains('u')
+        assert !vowels.contains('x')
+    }
+
+    void testContainsForLists() {
+        List vowels = ['a', 'e', 'i', 'o', 'u']
+        assert vowels.contains('u')
+        assert !vowels.contains('x')
+    }
+
+    void testContainsForIterables() {
+        int a
+        Iterable iterable = { [hasNext: { a < 6 }, next: { a++ }] as Iterator } as Iterable
+
+        a = 1
+        assert iterable.contains(5)
+        a = 1
+        assert !iterable.contains(6)
+
+        iterable = { [hasNext: { a < 6 }, next: { a++; null }] as Iterator } as Iterable
+        a = 1
+        assert iterable.contains(null)
+        a = 1
+        assert !iterable.contains("a")
+    }
+
+    void testContainsAllForLists() {
+        List vowels = ['a', 'e', 'i', 'o', 'u']
+        assert vowels.containsAll([] as String[])
+        assert vowels.containsAll(['e', 'u'] as String[])
+        assert !vowels.containsAll(['a', 'x'] as String[])
+    }
+
+    void testContainsAllForIterables() {
+        int a
+        Iterable iterable = { [hasNext: { a < 6 }, next: { a++ }] as Iterator } as Iterable
+
+        a = 1
+        assert iterable.containsAll([] as int[])
+        a = 1
+        assert iterable.containsAll([2, 5] as int[])
+        a = 1
+        assert !iterable.containsAll([1, 6] as int[])
+    }
+
     void testCollectEntriesIterator() {
         def items = ['a', 'bb', 'ccc'].iterator()
         def map = items.collectEntries { [it, it.size()] }
@@ -1173,10 +1447,13 @@ class GroovyMethodsTest extends GroovyTestCase {
         assert map == [a: 'A', b: 'B', c: 'C']
     }
 
-    void testArrayContains() {
-        String[] vowels = ['a', 'e', 'i', 'o', 'u']
-        assert vowels.contains('u')
-        assert !vowels.contains('x')
+    void testCollectEntriesListFallbackCases() {
+        assert [[[1,'a'], [2,'b'], [3]].collectEntries(),
+                [[1,'a'], [2,'b'], []].collectEntries(),
+                [[1,'a'], [2,'b'], [3, 'c', 42]].collectEntries()] == [[1:'a', 2:'b', 3:null], [1:'a', 2:'b', (null):null], [1:'a', 2:'b', 3:'c']]
+        shouldFail(NullPointerException) {
+            [[1, 'a'], [3]].collectEntries(new Hashtable())
+        }
     }
 
     void testListTakeWhile() {
@@ -1222,6 +1499,243 @@ class GroovyMethodsTest extends GroovyTestCase {
             assert it.takeWhile{ it }.toString() == 'groovy'
         }
     }
+
+    void testInjectWithoutIntialValue() {
+        int a = 1
+        def data = [
+                new ArrayList([1, 2, 3]),
+                new LinkedList([1, 2, 3]),
+                new Stack() {{ addAll([1, 2, 3]) }},
+                new Vector([1, 2, 3]),
+                [1, 2, 3] as int[],
+                { [hasNext: { a <= 3 }, next: { a++ }] as Iterator } as Iterable,
+        ]
+        data.each {
+            assert it.inject { int acc, int val -> acc + val } == 6
+        }
+    }
+
+    void testInjectWithIntialValue() {
+        int a = 1
+        def data = [
+                new ArrayList(["a", "aa", "aaa"]),
+                new LinkedList(["a", "aa", "aaa"]),
+                new Stack() {{ addAll(["a", "aa", "aaa"]) }},
+                new Vector(["a", "aa", "aaa"]),
+                ["a", "aa", "aaa"] as String[],
+                { [hasNext: { a <= 3 }, next: { "a" * (a++) }] as Iterator } as Iterable,
+        ]
+        data.each {
+            assert it.inject(10) { int acc, String val -> acc + val.length() } == 16
+        }
+    }
+
+    void testIntersectForLists() {
+        assert [] == [].intersect([4, 5, 6, 7, 8])
+        assert [] == [1, 2, 3, 4, 5].intersect([])
+        assert [4, 5] == [1, 2, 3, 4, 5].intersect([4, 5, 6, 7, 8])
+    }
+
+    void testIntersectForIterables() {
+        int a = 1, b = 4
+        Iterable iterableA = { [ hasNext:{ a <= 5 }, next:{ a++ } ] as Iterator } as Iterable
+        Iterable iterableB = { [ hasNext:{ b <= 8 }, next:{ b++ } ] as Iterator } as Iterable
+        Iterable iterableEmpty = { [ hasNext:{ false }, next:{ 0 } ] as Iterator } as Iterable
+
+        assert [] == iterableEmpty.intersect(iterableB)
+        assert [] == iterableA.intersect(iterableEmpty)
+        a = 1
+        b = 4
+        assert [4, 5] == iterableA.intersect(iterableB)
+    }
+
+    void testDisjointForLists() {
+        assert [].disjoint([])
+        assert [].disjoint([4, 5, 6, 7, 8])
+        assert [1, 2, 3, 4, 5].disjoint([])
+        assert ![1, 2, 3, 4, 5].disjoint([4, 5, 6, 7, 8])
+        assert [1, 2, 3].disjoint([4, 5, 6, 7, 8])
+    }
+
+    void testDisjointForIterables() {
+        int a = 1, b = 4
+        Iterable iterableA = { [ hasNext:{ a <= 5 }, next:{ a++ } ] as Iterator } as Iterable
+        Iterable iterableB = { [ hasNext:{ b <= 8 }, next:{ b++ } ] as Iterator } as Iterable
+        Iterable iterableEmpty = { [ hasNext:{ false }, next:{0 } ] as Iterator } as Iterable
+
+        assert iterableEmpty.disjoint(iterableB)
+        assert iterableA.disjoint(iterableEmpty)
+        a = 1
+        b = 4
+        assert !iterableA.disjoint(iterableB)
+        a = 1
+        b = 6
+        assert iterableA.disjoint(iterableB)
+    }
+
+    void testAsCollectionForIterables() {
+        int a = 1
+        Iterable iterable = { [ hasNext:{ a <= 3 }, next:{ a++ } ] as Iterator } as Iterable
+        assert [1, 2, 3] == iterable.asCollection()
+    }
+
+    void testToSetForIterables() {
+        int a = 1
+        Iterable iterable = { [ hasNext:{ a <= 3 }, next:{ a++ } ] as Iterator } as Iterable
+        assert ([1, 2, 3] as Set) == iterable.toSet()
+    }
+
+    void testToSpreadMapForArrays() {
+        def spreadMap = ([1, 2, 3, 4] as Integer[]).toSpreadMap()
+        assert 2 == spreadMap.size()
+        assert 2 == spreadMap[1]
+        assert 4 == spreadMap[3]
+        assert !spreadMap.containsKey(5)
+    }
+
+    void testToSpreadMapForLists() {
+        def spreadMap = [1, 2, 3, 4].toSpreadMap()
+        assert 2 == spreadMap.size()
+        assert 2 == spreadMap[1]
+        assert 4 == spreadMap[3]
+        assert !spreadMap.containsKey(5)
+    }
+
+    void testToSpreadMapForIterables() {
+        int a = 1
+        Iterable iterable = { [ hasNext:{ a <= 4 }, next:{ a++ } ] as Iterator } as Iterable
+        def spreadMap = iterable.toSpreadMap()
+        assert 2 == spreadMap.size()
+        assert 2 == spreadMap[1]
+        assert 4 == spreadMap[3]
+        assert !spreadMap.containsKey(5)
+    }
+
+    void testPlusMinusClassSymmetryForCollections() {
+        int a
+        def data = [
+                // Lists
+                (java.util.ArrayList)     : new ArrayList( [ 1, 2, 3 ] ),
+                (java.util.LinkedList)    : new LinkedList( [ 1, 2, 3 ] ),
+                (java.util.Stack)         : new Stack() {{ addAll( [ 1, 2, 3 ] ) }},
+                (java.util.Vector)        : new Vector( [ 1, 2, 3 ] ),
+                // Sets
+                (java.util.HashSet)       : new HashSet( [ 1, 2, 3 ] ),
+                // Iterables
+                (java.util.Collection)    : { [ hasNext:{ a <= 3 }, next:{ a++ } ] as Iterator } as Iterable,
+        ]
+        data.each { Class clazz, object ->
+            a = 1
+            assert clazz.isInstance( object + 1 )
+            a = 1
+            assert clazz.isInstance( object - 1 )
+            a = 1
+            assert clazz.isInstance( object + [1, 2] )
+            a = 1
+            assert clazz.isInstance( object - [1, 2] )
+        }
+    }
+
+    void testPlusForLists() {
+        assert [1, 2, 3] == [1, 2] + 3
+
+        int a = 3
+        Iterable iterable = { [ hasNext:{ a <= 4 }, next:{ a++ } ] as Iterator } as Iterable
+        assert [1, 2, 3, 4] == [1, 2] + iterable
+
+        assert [1, 2, 3, 4] == [1, 2] + [3, 4]
+    }
+
+    void testPlusForIterables() {
+        int a, b
+        Iterable iterableA = { [ hasNext:{ a <= 2 }, next:{ a++ } ] as Iterator } as Iterable
+        Iterable iterableB = { [ hasNext:{ b <= 4 }, next:{ b++ } ] as Iterator } as Iterable
+        Iterable iterableEmpty = { [ hasNext:{ false }, next:{ 0 } ] as Iterator } as Iterable
+
+        assert [1] == iterableEmpty + 1
+        a = 1
+        assert [1, 2] == iterableEmpty + iterableA
+        assert [1, 2] == iterableEmpty + [1, 2]
+
+        // Iterable.plus(Object)
+        a = 1
+        assert [1, 2, 3] == iterableA + 3
+
+        // Iterable.plus(Iterable)
+        a = 1
+        b = 3
+        assert [1, 2, 3, 4] == iterableA + iterableB
+
+        // Iterable.plus(List)
+        a = 1
+        assert [1, 2, 3, 4] == iterableA + [3, 4]
+    }
+
+    void testMinusForIterables() {
+        int a, b
+        Iterable iterableA = { [ hasNext:{ a <= 2 }, next:{ a++ } ] as Iterator } as Iterable
+        Iterable iterableB = { [ hasNext:{ b <= 4 }, next:{ b++ } ] as Iterator } as Iterable
+        Iterable iterableEmpty = { [ hasNext:{ false }, next:{ 0 } ] as Iterator } as Iterable
+
+        assert [] == iterableEmpty - 1
+        a =1
+        assert [] == iterableEmpty - iterableA
+        a =1
+        assert [1, 2] ==iterableA - iterableEmpty
+        assert [] == iterableEmpty - [1, 2]
+
+        // Iterable.minus(Object)
+        a = 1
+        assert [2] == iterableA - 1
+
+        // Iterable.minus(Iterable)
+        a = 1
+        b = 3
+        assert [3, 4] == iterableB - iterableA
+
+        // Iterable.minus(List)
+        b = 3
+        assert [3, 4] == iterableB - [1, 2]
+    }
+
+    void testMultiplyForLists() {
+        assert [] == [] * 3
+        assert [1, 2, 1, 2, 1, 2] == [1, 2] * 3
+    }
+
+    void testMultiplyForIterables() {
+        Iterable iterableEmpty = { [ hasNext:{ false }, next:{ 0 } ] as Iterator } as Iterable
+        assert [] == iterableEmpty * 3
+
+        int a = 1
+        Iterable iterable = { [ hasNext:{ a <= 2 }, next:{ a++ } ] as Iterator } as Iterable
+        assert [1, 2, 1, 2, 1, 2] == iterable * 3
+    }
+
+    void testSwap() {
+        assert [1, 2, 3, 4] == [1, 2, 3, 4].swap(0, 0).swap(1, 1)
+
+        assert [1, 3, 4, 2] == [1, 2, 3, 4].swap(1, 2).swap(2, 3)
+        assert (["a", "c", "d", "b"] as String[]) == (["a", "b", "c", "d"] as String[]).swap(1, 2).swap(2, 3)
+        assert ([false, true, true, false] as boolean[]) == ([false, false, true, true] as boolean[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as byte[]) == ([1, 2, 3, 4] as byte[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as char[]) == ([1, 2, 3, 4] as char[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as double[]) == ([1, 2, 3, 4] as double[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as float[]) == ([1, 2, 3, 4] as float[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as int[]) == ([1, 2, 3, 4] as int[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as long[]) == ([1, 2, 3, 4] as long[]).swap(1, 2).swap(2, 3)
+        assert ([1, 3, 4, 2] as short[]) == ([1, 2, 3, 4] as short[]).swap(1, 2).swap(2, 3)
+
+        shouldFail(IndexOutOfBoundsException) {
+            [].swap(1, 2)
+        }
+        shouldFail(ArrayIndexOutOfBoundsException) {
+            ([] as String[]).swap(1, 2)
+        }
+        shouldFail(ArrayIndexOutOfBoundsException) {
+            ([] as int[]).swap(1, 2)
+        }
+    }
 }
 
 class WackyList extends LinkedList {
diff --git a/src/test/groovy/HexTest.groovy b/src/test/groovy/HexTest.groovy
index 90cc049..72f364f 100644
--- a/src/test/groovy/HexTest.groovy
+++ b/src/test/groovy/HexTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/InvokeNormalMethodsFirstTest.groovy b/src/test/groovy/InvokeNormalMethodsFirstTest.groovy
index 9272db2..cc5874d 100644
--- a/src/test/groovy/InvokeNormalMethodsFirstTest.groovy
+++ b/src/test/groovy/InvokeNormalMethodsFirstTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/JavaClass.java b/src/test/groovy/JavaClass.java
index 8464395..8563237 100644
--- a/src/test/groovy/JavaClass.java
+++ b/src/test/groovy/JavaClass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 public class JavaClass {
diff --git a/src/test/groovy/JointGroovy.groovy b/src/test/groovy/JointGroovy.groovy
index e69a6bd..e9f249c 100644
--- a/src/test/groovy/JointGroovy.groovy
+++ b/src/test/groovy/JointGroovy.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class JointGroovy {
diff --git a/src/test/groovy/JointJava.java b/src/test/groovy/JointJava.java
index 693aee8..88cfa82 100644
--- a/src/test/groovy/JointJava.java
+++ b/src/test/groovy/JointJava.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 import groovy.lang.Closure;
diff --git a/src/test/groovy/LeftShiftTest.groovy b/src/test/groovy/LeftShiftTest.groovy
index 0a2586c..16e5486 100644
--- a/src/test/groovy/LeftShiftTest.groovy
+++ b/src/test/groovy/LeftShiftTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class LeftShiftTest extends GroovyTestCase {
diff --git a/src/test/groovy/ListTest.groovy b/src/test/groovy/ListTest.groovy
index 1caf18e..c9135ba 100644
--- a/src/test/groovy/ListTest.groovy
+++ b/src/test/groovy/ListTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,8 @@
  */
 package groovy
 
+import groovy.transform.TypeChecked
+
 class ListTest extends GroovyTestCase {
 
     void testList() {
@@ -289,6 +291,11 @@ class ListTest extends GroovyTestCase {
         }
     }
 
+    void testIndices() {
+        assert 0..2 == [5, 6, 7].indices
+        assert 0..<0 == [].indices
+    }
+
     // see also SubscriptTest
     void testGetAtRange() {
         def list = [0, 1, 2, 3]
@@ -404,6 +411,26 @@ class ListTest extends GroovyTestCase {
         }
     }
 
+    void testWithIndex_indexed_groovy7175() {
+        assert [] == [].withIndex()
+        assert [] == [].withIndex(10)
+        assert [["a", 0], ["b", 1]] == ["a", "b"].withIndex()
+        assert [["a", 5], ["b", 6]] == ["a", "b"].withIndex(5)
+        assert ["0: a", "1: b"] == ["a", "b"].withIndex().collect { str, idx -> "$idx: $str" }
+        assert ["1: a", "2: b"] == ["a", "b"].withIndex(1).collect { str, idx -> "$idx: $str" }
+        assert [:] == [].indexed()
+        assert [:] == [].indexed(10)
+        assert [0: 'a', 1: 'b'] == ["a", "b"].indexed()
+        assert [5: 'a', 6: 'b'] == ["a", "b"].indexed(5)
+        assert ["0: a", "1: b"] == ["a", "b"].indexed().collect { idx, str -> "$idx: $str" }
+        assert ["1: a", "2: b"] == ["a", "b"].indexed(1).collect { idx, str -> "$idx: $str" }
+    }
+
+    @TypeChecked
+    void testWithIndex_indexed_typeChecked_groovy7175() {
+        assert ["A", "BB"] == ["a", "b"].indexed(1).collect { idx, str -> str.toUpperCase() * idx }
+    }
+
     // GROOVY-4946
     void testLazyDefault() {
         def l1 = [].withLazyDefault { 42 }
@@ -776,4 +803,27 @@ class ListTest extends GroovyTestCase {
         def list = new LinkedList([0,1,2,3])
         assert list[0..<0] instanceof LinkedList
     }
+
+    void testRemoveAt() {
+        shouldFail(IndexOutOfBoundsException) {
+            [].removeAt(0)
+        }
+        def list = [1, 2, 3]
+        assert 2 == list.removeAt(1)
+        assert [1, 3] == list
+    }
+
+    void testRemoveElement() {
+        def list = [1, 2, 3, 2]
+        assert list.removeElement(2)
+        assert [1, 3, 2] == list
+        assert !list.removeElement(4)
+        assert [1, 3, 2] == list
+    }
+
+    // GROOVY-7299
+    void testMultipleVeryLongLlists() {
+        def script = "def a = ["+'1000,'*2000+"];def b = ["+'1000,'*2000+"]; def c=(a+b).sum(); assert c==4_000_000";
+        assertScript script
+    }
 }
diff --git a/src/test/groovy/LiteralTypesTest.groovy b/src/test/groovy/LiteralTypesTest.groovy
index 2eff88b..2533754 100644
--- a/src/test/groovy/LiteralTypesTest.groovy
+++ b/src/test/groovy/LiteralTypesTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/LittleClosureTest.groovy b/src/test/groovy/LittleClosureTest.groovy
index c4a9d6c..e356bc7 100644
--- a/src/test/groovy/LittleClosureTest.groovy
+++ b/src/test/groovy/LittleClosureTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class LittleClosureTest extends GroovyTestCase {
diff --git a/src/test/groovy/LocalVariableTest.groovy b/src/test/groovy/LocalVariableTest.groovy
index 1e532d4..266241f 100644
--- a/src/test/groovy/LocalVariableTest.groovy
+++ b/src/test/groovy/LocalVariableTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class LocalVariableTest extends GroovyTestCase {
diff --git a/src/test/groovy/LogicTest.groovy b/src/test/groovy/LogicTest.groovy
index 8bd2a25..4bcb4be 100644
--- a/src/test/groovy/LogicTest.groovy
+++ b/src/test/groovy/LogicTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class LogicTest extends GroovyTestCase {
diff --git a/src/test/groovy/LoopBreakTest.groovy b/src/test/groovy/LoopBreakTest.groovy
index e1c8a71..6054212 100644
--- a/src/test/groovy/LoopBreakTest.groovy
+++ b/src/test/groovy/LoopBreakTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class LoopBreakTest extends GroovyTestCase {
diff --git a/src/test/groovy/MapPropertyTest.groovy b/src/test/groovy/MapPropertyTest.groovy
index e44cf47..ec3f9c3 100644
--- a/src/test/groovy/MapPropertyTest.groovy
+++ b/src/test/groovy/MapPropertyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/MapTest.groovy b/src/test/groovy/MapTest.groovy
index 2ac090d..094d54a 100644
--- a/src/test/groovy/MapTest.groovy
+++ b/src/test/groovy/MapTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MapTest extends GroovyTestCase {
diff --git a/src/test/groovy/MethodCallTest.groovy b/src/test/groovy/MethodCallTest.groovy
index 71bb1e3..fc57007 100644
--- a/src/test/groovy/MethodCallTest.groovy
+++ b/src/test/groovy/MethodCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MethodCallTest extends GroovyTestCase {
diff --git a/src/test/groovy/MethodCallWithoutParenthesisTest.groovy b/src/test/groovy/MethodCallWithoutParenthesisTest.groovy
index a81c3b0..5e2aac7 100644
--- a/src/test/groovy/MethodCallWithoutParenthesisTest.groovy
+++ b/src/test/groovy/MethodCallWithoutParenthesisTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MethodCallWithoutParenthesisTest extends GroovyTestCase {
diff --git a/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy b/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy
index 5b4cfc4..e9ff3ca 100644
--- a/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy
+++ b/src/test/groovy/MethodParameterAccessWithinClosureTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/MinMaxTest.groovy b/src/test/groovy/MinMaxTest.groovy
index 5f048b7..cb03c47 100644
--- a/src/test/groovy/MinMaxTest.groovy
+++ b/src/test/groovy/MinMaxTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/MinusEqualsTest.groovy b/src/test/groovy/MinusEqualsTest.groovy
index e9e1bdd..d0ba030 100644
--- a/src/test/groovy/MinusEqualsTest.groovy
+++ b/src/test/groovy/MinusEqualsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MinusEqualsTest extends GroovyTestCase {
diff --git a/src/test/groovy/ModifiersTest.groovy b/src/test/groovy/ModifiersTest.groovy
index 2a4c945..0d33551 100644
--- a/src/test/groovy/ModifiersTest.groovy
+++ b/src/test/groovy/ModifiersTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/ModuloTest.groovy b/src/test/groovy/ModuloTest.groovy
index 300b652..d503755 100644
--- a/src/test/groovy/ModuloTest.groovy
+++ b/src/test/groovy/ModuloTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ModuloTest extends GroovyTestCase {
diff --git a/src/test/groovy/MultilineStringTest.groovy b/src/test/groovy/MultilineStringTest.groovy
index 692cc5d..e1e89c3 100644
--- a/src/test/groovy/MultilineStringTest.groovy
+++ b/src/test/groovy/MultilineStringTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MultilineStringTest extends GroovyTestCase {
diff --git a/src/test/groovy/MultiplyDivideEqualsTest.groovy b/src/test/groovy/MultiplyDivideEqualsTest.groovy
index e9055f6..e2d12c8 100644
--- a/src/test/groovy/MultiplyDivideEqualsTest.groovy
+++ b/src/test/groovy/MultiplyDivideEqualsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class MultiplyDivideEqualsTest extends GroovyTestCase {
diff --git a/src/test/groovy/NamedParameterTest.groovy b/src/test/groovy/NamedParameterTest.groovy
index f32370f..47e1d3a 100644
--- a/src/test/groovy/NamedParameterTest.groovy
+++ b/src/test/groovy/NamedParameterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class NamedParameterTest extends GroovyTestCase {
diff --git a/src/test/groovy/NestedClassTest.groovy b/src/test/groovy/NestedClassTest.groovy
index 7c337b2..fbf1bc0 100644
--- a/src/test/groovy/NestedClassTest.groovy
+++ b/src/test/groovy/NestedClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class NestedClassTest extends GroovyTestCase {
diff --git a/src/test/groovy/NewExpressionTest.groovy b/src/test/groovy/NewExpressionTest.groovy
index fe38b41..db3ebf4 100644
--- a/src/test/groovy/NewExpressionTest.groovy
+++ b/src/test/groovy/NewExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import org.codehaus.groovy.runtime.DummyBean
diff --git a/src/test/groovy/NoPackageTest.groovy b/src/test/groovy/NoPackageTest.groovy
index eeb0a34..cf05830 100644
--- a/src/test/groovy/NoPackageTest.groovy
+++ b/src/test/groovy/NoPackageTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 class NoPackageTest extends GroovyTestCase {
 
diff --git a/src/test/groovy/NullPropertyTest.groovy b/src/test/groovy/NullPropertyTest.groovy
index d07e73a..085c83f 100644
--- a/src/test/groovy/NullPropertyTest.groovy
+++ b/src/test/groovy/NullPropertyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/NumberMathTest.groovy b/src/test/groovy/NumberMathTest.groovy
index 40e52b2..d2e378b 100644
--- a/src/test/groovy/NumberMathTest.groovy
+++ b/src/test/groovy/NumberMathTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import junit.framework.Assert
diff --git a/src/test/groovy/OuterUser.java b/src/test/groovy/OuterUser.java
index 4bd894e..86b153c 100644
--- a/src/test/groovy/OuterUser.java
+++ b/src/test/groovy/OuterUser.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 /**
diff --git a/src/test/groovy/OverloadInvokeMethodTest.groovy b/src/test/groovy/OverloadInvokeMethodTest.groovy
index 29ac068..48b18dc 100644
--- a/src/test/groovy/OverloadInvokeMethodTest.groovy
+++ b/src/test/groovy/OverloadInvokeMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/OverridePropertyGetterTest.groovy b/src/test/groovy/OverridePropertyGetterTest.groovy
index 8e0d100..2276fca 100644
--- a/src/test/groovy/OverridePropertyGetterTest.groovy
+++ b/src/test/groovy/OverridePropertyGetterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/PlusEqualsTest.groovy b/src/test/groovy/PlusEqualsTest.groovy
index 23a3fa4..4152f39 100644
--- a/src/test/groovy/PlusEqualsTest.groovy
+++ b/src/test/groovy/PlusEqualsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PlusEqualsTest extends GroovyTestCase {
diff --git a/src/test/groovy/PostfixTest.groovy b/src/test/groovy/PostfixTest.groovy
index ff9e61d..6d4ff85 100644
--- a/src/test/groovy/PostfixTest.groovy
+++ b/src/test/groovy/PostfixTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PostfixTest extends GroovyTestCase {
diff --git a/src/test/groovy/PrefixTest.groovy b/src/test/groovy/PrefixTest.groovy
index 6eb2182..440f99a 100644
--- a/src/test/groovy/PrefixTest.groovy
+++ b/src/test/groovy/PrefixTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PrefixTest extends GroovyTestCase {
diff --git a/src/test/groovy/PrimitiveArraysTest.groovy b/src/test/groovy/PrimitiveArraysTest.groovy
index 918622a..54d65f0 100644
--- a/src/test/groovy/PrimitiveArraysTest.groovy
+++ b/src/test/groovy/PrimitiveArraysTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PrimitiveArraysTest extends GroovyTestCase {
diff --git a/src/test/groovy/PrimitiveDefaultValueTest.groovy b/src/test/groovy/PrimitiveDefaultValueTest.groovy
index e614dfb..49f9649 100644
--- a/src/test/groovy/PrimitiveDefaultValueTest.groovy
+++ b/src/test/groovy/PrimitiveDefaultValueTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/PrimitiveTypeFieldTest.groovy b/src/test/groovy/PrimitiveTypeFieldTest.groovy
index 731c6fe..fdd2c29 100644
--- a/src/test/groovy/PrimitiveTypeFieldTest.groovy
+++ b/src/test/groovy/PrimitiveTypeFieldTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PrimitiveTypeFieldTest extends GroovyTestCase {
diff --git a/src/test/groovy/PrintTest.groovy b/src/test/groovy/PrintTest.groovy
index 0060350..d698a86 100644
--- a/src/test/groovy/PrintTest.groovy
+++ b/src/test/groovy/PrintTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 import groovy.io.GroovyPrintStream
diff --git a/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy b/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy
index 760876d..a3009a4 100644
--- a/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy
+++ b/src/test/groovy/PrivateVariableAccessFromAnotherInstanceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/ProcessTest.groovy b/src/test/groovy/ProcessTest.groovy
index cfc1e45..f4cc290 100644
--- a/src/test/groovy/ProcessTest.groovy
+++ b/src/test/groovy/ProcessTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
diff --git a/src/test/groovy/PropertyTest.groovy b/src/test/groovy/PropertyTest.groovy
index a816d4c..36d562c 100644
--- a/src/test/groovy/PropertyTest.groovy
+++ b/src/test/groovy/PropertyTest.groovy
@@ -203,7 +203,51 @@ class PropertyTest extends GroovyTestCase {
             fail("We shouldn't be able to read bean.superThing, but we can: '$bean.superThing'")
         }
     }
-    
+
+    void testPrivatePropertyThroughSubclass() {
+        assertScript '''
+            class A {
+                private getFoo(){1}
+                def bar(){return foo}
+            }
+            class B extends A {}
+
+            def b = new B()
+            assert b.bar()==1
+        '''
+    }
+
+    public void testPropertyWithMultipleSetters() {
+        assertScript '''
+            class A {
+                private field
+                void setX(Integer a) {field=a}
+                void setX(String b) {field=b}
+                def getX(){field}
+            }
+            def a = new A()
+            a.x = 1
+            assert a.x==1
+            a.x = "3"
+            assert a.x == "3"
+        '''
+    }
+
+    void testOverrideMultiSetterThroughMetaClass() {
+        assertScript '''
+        class A {
+            private String field
+            void setConstraints(Closure cl) {}
+            void setConstraints(String s) {}
+            String getField() { field }
+        }
+
+        A.metaClass.setConstraints = { delegate.field = it+it }
+        def a = new A()
+        a.constraints = '100'
+        assert a.field == '100100'
+        '''
+    }
 }
 
 class Base {
diff --git a/src/test/groovy/PropertyWithoutDotTest.groovy b/src/test/groovy/PropertyWithoutDotTest.groovy
index c26b0d0..3be9e24 100644
--- a/src/test/groovy/PropertyWithoutDotTest.groovy
+++ b/src/test/groovy/PropertyWithoutDotTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class PropertyWithoutDotTest extends GroovyTestCase {
diff --git a/src/test/groovy/ReadLineTest.groovy b/src/test/groovy/ReadLineTest.groovy
index 0087321..9703cde 100644
--- a/src/test/groovy/ReadLineTest.groovy
+++ b/src/test/groovy/ReadLineTest.groovy
@@ -1,4 +1,19 @@
 // Do not remove this line: it is used in test below
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /**
@@ -20,9 +35,9 @@ class ReadLineTest extends GroovyTestCase {
         assert line == "// Do not remove this line: it is used in test below"
     }
     
-    static testString = " �\n �\n\n �\r\n 5\r\r 7\n\r 9"
-    static expectedLines = [ " �", " �", "", " �", " 5", "", " 7", "", " 9" ]
-    static String[] expectedLinesSlow = [ " �", " �", " �", " 5", " 7" ]
+    static testString = " �\n �\n\n �\r\n 5\r\r 7\n\r 9"
+    static expectedLines = [ " �", " �", "", " �", " 5", "", " 7", "", " 9" ]
+    static String[] expectedLinesSlow = [ " �", " �", " �", " 5", " 7" ]
     static int[] expectedChars = [' ', '9', -1];
 
     void readFromReader(Reader reader) throws IOException {
diff --git a/src/test/groovy/ReturnTest.groovy b/src/test/groovy/ReturnTest.groovy
index 9abc849..5ae687a 100644
--- a/src/test/groovy/ReturnTest.groovy
+++ b/src/test/groovy/ReturnTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/SafeNavigationTest.groovy b/src/test/groovy/SafeNavigationTest.groovy
index 7a6b8bb..3d029ca 100644
--- a/src/test/groovy/SafeNavigationTest.groovy
+++ b/src/test/groovy/SafeNavigationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SafeNavigationTest extends GroovyTestCase {
diff --git a/src/test/groovy/SampleMain.groovy b/src/test/groovy/SampleMain.groovy
index 5a4f2c7..2b5ea40 100644
--- a/src/test/groovy/SampleMain.groovy
+++ b/src/test/groovy/SampleMain.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SampleMain {
diff --git a/src/test/groovy/SetTest.groovy b/src/test/groovy/SetTest.groovy
index 8dd0fe0..f534cc9 100644
--- a/src/test/groovy/SetTest.groovy
+++ b/src/test/groovy/SetTest.groovy
@@ -34,13 +34,15 @@ class SetTest extends GroovyTestCase {
 
     void testSetFlatten() {
         Set orig = [[[4, 5, 6, [46, 7, "erer"] as Set] as Set, 4, [3, 6, 78] as Set] as Set, 4]
-        Set flat = orig.flatten()
+        def flat = orig.flatten()
+        assert flat instanceof Set
         assert flat == [3, 4, 5, 6, 7, 46, 78, "erer"] as Set
     }
 
     void testFlattenSetOfMapsWithClosure() {
         Set orig = [[a:1, b:2], [c:3, d:4]] as Set
-        Set flat = orig.flatten{ it instanceof Map ? it.values() : it }
+        def flat = orig.flatten{ it instanceof Map ? it.values() : it }
+        assert flat instanceof Set
         assert flat == [1, 2, 3 ,4] as Set
         flat = orig.flatten{ it instanceof Map ? it.keySet() : it }
         assert flat == ["a", "b", "c", "d"] as Set
diff --git a/src/test/groovy/SimplePostfixTest.groovy b/src/test/groovy/SimplePostfixTest.groovy
index 4604dbf..b453c32 100644
--- a/src/test/groovy/SimplePostfixTest.groovy
+++ b/src/test/groovy/SimplePostfixTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SimplePostfixTest extends GroovyTestCase {
diff --git a/src/test/groovy/SingletonBugTest.groovy b/src/test/groovy/SingletonBugTest.groovy
index 05caca1..488415d 100644
--- a/src/test/groovy/SingletonBugTest.groovy
+++ b/src/test/groovy/SingletonBugTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 // TODO: GROOVY-435
 
diff --git a/src/test/groovy/SliceTest.groovy b/src/test/groovy/SliceTest.groovy
index 6bc0d96..b9f5231 100644
--- a/src/test/groovy/SliceTest.groovy
+++ b/src/test/groovy/SliceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SliceTest extends GroovyTestCase {
diff --git a/src/test/groovy/SomeClass.java b/src/test/groovy/SomeClass.java
index 72764bd..c81827d 100644
--- a/src/test/groovy/SomeClass.java
+++ b/src/test/groovy/SomeClass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 /**
diff --git a/src/test/groovy/SortTest.groovy b/src/test/groovy/SortTest.groovy
index 08029e3..c95f1b6 100644
--- a/src/test/groovy/SortTest.groovy
+++ b/src/test/groovy/SortTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/SqlDateTest.groovy b/src/test/groovy/SqlDateTest.groovy
index 039698b..f1a6f56 100644
--- a/src/test/groovy/SqlDateTest.groovy
+++ b/src/test/groovy/SqlDateTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 import groovy.time.TimeCategory
diff --git a/src/test/groovy/StaticImportTarget.groovy b/src/test/groovy/StaticImportTarget.groovy
index 102cb86..fec714f 100644
--- a/src/test/groovy/StaticImportTarget.groovy
+++ b/src/test/groovy/StaticImportTarget.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class StaticImportTarget {
diff --git a/src/test/groovy/StaticMessageTest.groovy b/src/test/groovy/StaticMessageTest.groovy
index bb4c9cd..30dec54 100755
--- a/src/test/groovy/StaticMessageTest.groovy
+++ b/src/test/groovy/StaticMessageTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class StaticMessageTest extends GroovyTestCase {
diff --git a/src/test/groovy/StaticThisTest.groovy b/src/test/groovy/StaticThisTest.groovy
index 4521f6f..d1eaa29 100644
--- a/src/test/groovy/StaticThisTest.groovy
+++ b/src/test/groovy/StaticThisTest.groovy
@@ -128,4 +128,17 @@ class StaticThisTest extends CompilableTestSupport {
             """
     }
 
+    /**
+     * GROOVY-7047: Static inner class crashes compiler when it references parent's this
+     */
+    void testParentThisShouldNotBeReferredInsideStaticClass() {
+        shouldNotCompile """
+            class Foo {
+                static class Bar {
+                    def parent = Foo.this
+                }
+            }
+        """
+    }
+
 }
diff --git a/src/test/groovy/StringBufferTest.groovy b/src/test/groovy/StringBufferTest.groovy
index ce57b85..2d9ccab 100644
--- a/src/test/groovy/StringBufferTest.groovy
+++ b/src/test/groovy/StringBufferTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class StringBufferTest extends GroovyTestCase {
diff --git a/src/test/groovy/StringTest.groovy b/src/test/groovy/StringTest.groovy
index 39a2ea7..7c8abee 100644
--- a/src/test/groovy/StringTest.groovy
+++ b/src/test/groovy/StringTest.groovy
@@ -172,6 +172,16 @@ foo
         assert out == 'groovy.codehaus.org[19] and www.aboutgroovy.com[19]'
     }
 
+    void testDollarSlashyFirstCharEscaping() {
+        def VAR = 'foo'
+        def result = $/$/VAR/$
+        assert result == '/VAR'
+        result = $/$$VAR/$
+        assert result == '$VAR'
+        result = $/$VAR/$
+        assert result == 'foo'
+    }
+
     void testMultilineDollarSlashyRegexpEscaping() {
         def str = 'groovy.codehaus.org and www.aboutgroovy.com'
         def re = $/(?x)  # to enable whitespace and comments
diff --git a/src/test/groovy/SubscriptTest.groovy b/src/test/groovy/SubscriptTest.groovy
index c154a31..5b0a0a1 100644
--- a/src/test/groovy/SubscriptTest.groovy
+++ b/src/test/groovy/SubscriptTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SubscriptTest extends GroovyTestCase {
@@ -196,7 +211,22 @@ class SubscriptTest extends GroovyTestCase {
         
         assert map.getClass() == sub.getClass()
     }
-    
+
+    void testSubMapWithNonExistentKey() {
+        def map = ['a':123, 'b':456, 'c':789]
+
+        def keys = ['b', 'a', 'd']
+        def sub = map.subMap(keys)
+
+        assert sub.size() == 2
+        assert sub['a'] == 123
+        assert sub['b'] == 456
+        assert ! sub.containsKey('c')
+        assert ! sub.containsKey('d')
+
+        assert map.getClass() == sub.getClass()
+    }
+
     void testListWithinAListSyntax() {
         def list = [1, 2, 3, 4..10, 5, 6]
         
diff --git a/src/test/groovy/SwitchTest.groovy b/src/test/groovy/SwitchTest.groovy
index b35e560..9d0c352 100644
--- a/src/test/groovy/SwitchTest.groovy
+++ b/src/test/groovy/SwitchTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class SwitchTest extends GroovyTestCase {
diff --git a/src/test/groovy/SwitchWithDifferentTypesTest.groovy b/src/test/groovy/SwitchWithDifferentTypesTest.groovy
index c0394b7..c7f9e7f 100644
--- a/src/test/groovy/SwitchWithDifferentTypesTest.groovy
+++ b/src/test/groovy/SwitchWithDifferentTypesTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/TestInterruptor.java b/src/test/groovy/TestInterruptor.java
index 1102423..8a55832 100644
--- a/src/test/groovy/TestInterruptor.java
+++ b/src/test/groovy/TestInterruptor.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 public class TestInterruptor implements Runnable {
diff --git a/src/test/groovy/TextPropertyTest.groovy b/src/test/groovy/TextPropertyTest.groovy
index 19a990e..50ac172 100644
--- a/src/test/groovy/TextPropertyTest.groovy
+++ b/src/test/groovy/TextPropertyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 /**
  * check that text def is available on...
diff --git a/src/test/groovy/ToArrayBugTest.groovy b/src/test/groovy/ToArrayBugTest.groovy
index 59f9c66..daa4e5f 100644
--- a/src/test/groovy/ToArrayBugTest.groovy
+++ b/src/test/groovy/ToArrayBugTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ToArrayBugTest extends GroovyTestCase {
diff --git a/src/test/groovy/TripleQuotedStringTest.groovy b/src/test/groovy/TripleQuotedStringTest.groovy
index 1e2a934..df9cbc2 100644
--- a/src/test/groovy/TripleQuotedStringTest.groovy
+++ b/src/test/groovy/TripleQuotedStringTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class TripleQuotedStringTest extends GroovyTestCase {
diff --git a/src/test/groovy/TypesafeMethodTest.groovy b/src/test/groovy/TypesafeMethodTest.groovy
index e23c989..c00ea48 100644
--- a/src/test/groovy/TypesafeMethodTest.groovy
+++ b/src/test/groovy/TypesafeMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class TypesafeMethodTest extends GroovyTestCase {
diff --git a/src/test/groovy/UnitTestAsScriptTest.groovy b/src/test/groovy/UnitTestAsScriptTest.groovy
index bf0f93a..8fdaa0f 100644
--- a/src/test/groovy/UnitTestAsScriptTest.groovy
+++ b/src/test/groovy/UnitTestAsScriptTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 a = 123
 a *= 2
 println "Running unit test with a = ${a}"
diff --git a/src/test/groovy/UnsafeNavigationTest.groovy b/src/test/groovy/UnsafeNavigationTest.groovy
index ba122e5..9b7511e 100644
--- a/src/test/groovy/UnsafeNavigationTest.groovy
+++ b/src/test/groovy/UnsafeNavigationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class UnsafeNavigationTest extends GroovyTestCase {
diff --git a/src/test/groovy/VArgsTest.groovy b/src/test/groovy/VArgsTest.groovy
index b32483e..2f6a6e9 100644
--- a/src/test/groovy/VArgsTest.groovy
+++ b/src/test/groovy/VArgsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class VArgsTest extends GroovyTestCase {
diff --git a/src/test/groovy/ValidNameTest.groovy b/src/test/groovy/ValidNameTest.groovy
index 5cd8aab..215c0de 100644
--- a/src/test/groovy/ValidNameTest.groovy
+++ b/src/test/groovy/ValidNameTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class ValidNameTest extends GroovyTestCase {
diff --git a/src/test/groovy/VarargsMethodTest.groovy b/src/test/groovy/VarargsMethodTest.groovy
index 6453c96..68c5648 100644
--- a/src/test/groovy/VarargsMethodTest.groovy
+++ b/src/test/groovy/VarargsMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 /** 
diff --git a/src/test/groovy/VerbatimGStringTest.groovy b/src/test/groovy/VerbatimGStringTest.groovy
index d5adca7..b7ef04f 100644
--- a/src/test/groovy/VerbatimGStringTest.groovy
+++ b/src/test/groovy/VerbatimGStringTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class VerbatimGStringTest extends GroovyTestCase {
diff --git a/src/test/groovy/WhileLoopTest.groovy b/src/test/groovy/WhileLoopTest.groovy
index 42ae4fd..8b96d24 100644
--- a/src/test/groovy/WhileLoopTest.groovy
+++ b/src/test/groovy/WhileLoopTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy
 
 class WhileLoopTest extends GroovyTestCase {
diff --git a/src/test/groovy/annotations/MyClass.groovy b/src/test/groovy/annotations/MyClass.groovy
index 5fa7b5f..14e75ab 100644
--- a/src/test/groovy/annotations/MyClass.groovy
+++ b/src/test/groovy/annotations/MyClass.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 @MyIntegerAnno(40) // ignored at runtime
 package groovy.annotations
 
diff --git a/src/test/groovy/annotations/ParameterAnnotationTest.groovy b/src/test/groovy/annotations/ParameterAnnotationTest.groovy
index 8a21e6d..2970485 100644
--- a/src/test/groovy/annotations/ParameterAnnotationTest.groovy
+++ b/src/test/groovy/annotations/ParameterAnnotationTest.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
 * Copyright 2003-2011 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/test/groovy/annotations/package-info.groovy b/src/test/groovy/annotations/package-info.groovy
index 4485f14..3bafa02 100644
--- a/src/test/groovy/annotations/package-info.groovy
+++ b/src/test/groovy/annotations/package-info.groovy
@@ -1,2 +1,17 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 @MyIntegerAnno(30)
 package groovy.annotations
\ No newline at end of file
diff --git a/src/test/groovy/beans/BindableTest.groovy b/src/test/groovy/beans/BindableTest.groovy
index 688f03b..0307a85 100644
--- a/src/test/groovy/beans/BindableTest.groovy
+++ b/src/test/groovy/beans/BindableTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2012 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -18,6 +18,11 @@ package groovy.beans
 
 import org.codehaus.groovy.control.CompilationFailedException
 
+import java.beans.PropertyChangeListener
+
+import static java.lang.reflect.Modifier.isPublic
+import static java.lang.reflect.Modifier.isSynthetic
+
 /**
  * @author Danno Ferrin (shemnon)
  */
@@ -346,6 +351,13 @@ class BindableTest extends GroovyTestCase {
         """
     }
 
+    void testPropertyChangeMethodsNotSynthetic() {
+        def clazz = new GroovyClassLoader().parseClass('class MyBean { @groovy.beans.Bindable String dummy }', 'dummyName')
+        def modifiers = clazz.getMethod('addPropertyChangeListener', PropertyChangeListener).modifiers
+        assert isPublic(modifiers)
+        assert !isSynthetic(modifiers)
+    }
+
     void testPropertyChangeMethodWithCompileStatic() {
         assertScript """
             import groovy.beans.Bindable
@@ -358,4 +370,4 @@ class BindableTest extends GroovyTestCase {
             assert new MyBean()
         """
     }
-}
+}
\ No newline at end of file
diff --git a/src/test/groovy/beans/ListenerListHelper.groovy b/src/test/groovy/beans/ListenerListHelper.groovy
index 9887932..fe4e7dd 100644
--- a/src/test/groovy/beans/ListenerListHelper.groovy
+++ b/src/test/groovy/beans/ListenerListHelper.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.beans
 
 
diff --git a/src/test/groovy/benchmarks/createLoop.groovy b/src/test/groovy/benchmarks/createLoop.groovy
index b467d28..b07b904 100644
--- a/src/test/groovy/benchmarks/createLoop.groovy
+++ b/src/test/groovy/benchmarks/createLoop.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 c = {
   for (i in 1..it){
     x = new Object()
diff --git a/src/test/groovy/benchmarks/loop.groovy b/src/test/groovy/benchmarks/loop.groovy
index ee30b72..d58a457 100644
--- a/src/test/groovy/benchmarks/loop.groovy
+++ b/src/test/groovy/benchmarks/loop.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.benchmarks
 
 class Loop {
diff --git a/src/test/groovy/benchmarks/loop2.groovy b/src/test/groovy/benchmarks/loop2.groovy
index 8d38360..4e4efb0 100644
--- a/src/test/groovy/benchmarks/loop2.groovy
+++ b/src/test/groovy/benchmarks/loop2.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.benchmarks
 
 class Loop2 {
diff --git a/src/test/groovy/bugs/AmbiguousListOrMethodTest.groovy b/src/test/groovy/bugs/AmbiguousListOrMethodTest.groovy
index 1bea765..6841bda 100644
--- a/src/test/groovy/bugs/AmbiguousListOrMethodTest.groovy
+++ b/src/test/groovy/bugs/AmbiguousListOrMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class AmbiguousListOrMethodTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/ArrayMethodCallBug.groovy b/src/test/groovy/bugs/ArrayMethodCallBug.groovy
index b8b31b6..9bb113b 100644
--- a/src/test/groovy/bugs/ArrayMethodCallBug.groovy
+++ b/src/test/groovy/bugs/ArrayMethodCallBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class ArrayMethodCallBug extends TestSupport {
diff --git a/src/test/groovy/bugs/AsBoolBug.groovy b/src/test/groovy/bugs/AsBoolBug.groovy
index 61dfa84..52e134a 100644
--- a/src/test/groovy/bugs/AsBoolBug.groovy
+++ b/src/test/groovy/bugs/AsBoolBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy b/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy
index a5735d4..0baae96 100644
--- a/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy
+++ b/src/test/groovy/bugs/AssignmentInsideExpressionBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/AttributeSetExpressionBug.groovy b/src/test/groovy/bugs/AttributeSetExpressionBug.groovy
index 0d84f51..21a0091 100644
--- a/src/test/groovy/bugs/AttributeSetExpressionBug.groovy
+++ b/src/test/groovy/bugs/AttributeSetExpressionBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * @author Pilho Kim
  * @version $Revision$
diff --git a/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy b/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy
index b68ebaf..36749e9 100644
--- a/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy
+++ b/src/test/groovy/bugs/AutoboxingOfComparisonsBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class AutoboxingOfComparisonsBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/BadLineNumberOnExceptionBugTest.groovy b/src/test/groovy/bugs/BadLineNumberOnExceptionBugTest.groovy
index 8c05a3e..1acbf68 100644
--- a/src/test/groovy/bugs/BadLineNumberOnExceptionBugTest.groovy
+++ b/src/test/groovy/bugs/BadLineNumberOnExceptionBugTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/BenchmarkBug.groovy b/src/test/groovy/bugs/BenchmarkBug.groovy
index 135339f..bb3a9ff 100644
--- a/src/test/groovy/bugs/BenchmarkBug.groovy
+++ b/src/test/groovy/bugs/BenchmarkBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/BooleanBug.groovy b/src/test/groovy/bugs/BooleanBug.groovy
index 7c4a240..6065523 100644
--- a/src/test/groovy/bugs/BooleanBug.groovy
+++ b/src/test/groovy/bugs/BooleanBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ByteIndexBug.groovy b/src/test/groovy/bugs/ByteIndexBug.groovy
index 7922c82..2e90d5d 100644
--- a/src/test/groovy/bugs/ByteIndexBug.groovy
+++ b/src/test/groovy/bugs/ByteIndexBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode2Bug.groovy b/src/test/groovy/bugs/Bytecode2Bug.groovy
index b8ac503..341a4c8 100644
--- a/src/test/groovy/bugs/Bytecode2Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode2Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode3Bug.groovy b/src/test/groovy/bugs/Bytecode3Bug.groovy
index 01bb4c1..4a13366 100644
--- a/src/test/groovy/bugs/Bytecode3Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode3Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode4Bug.groovy b/src/test/groovy/bugs/Bytecode4Bug.groovy
index 089caaf..2477ff4 100644
--- a/src/test/groovy/bugs/Bytecode4Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode4Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode5Bug.groovy b/src/test/groovy/bugs/Bytecode5Bug.groovy
index 675eed8..0d99c46 100644
--- a/src/test/groovy/bugs/Bytecode5Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode5Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode6Bug.groovy b/src/test/groovy/bugs/Bytecode6Bug.groovy
index e9259f5..71bfc7c 100644
--- a/src/test/groovy/bugs/Bytecode6Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode6Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Bytecode7Bug.groovy b/src/test/groovy/bugs/Bytecode7Bug.groovy
index cad9e5d..675f2c8 100644
--- a/src/test/groovy/bugs/Bytecode7Bug.groovy
+++ b/src/test/groovy/bugs/Bytecode7Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/BytecodeBug.groovy b/src/test/groovy/bugs/BytecodeBug.groovy
index f43ca19..9592f0b 100644
--- a/src/test/groovy/bugs/BytecodeBug.groovy
+++ b/src/test/groovy/bugs/BytecodeBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy b/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy
index 99f25b2..a4b9d74 100644
--- a/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy
+++ b/src/test/groovy/bugs/CallingClosuresWithClosuresBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy b/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy
index 107d982..bd5dac5 100644
--- a/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy
+++ b/src/test/groovy/bugs/CastWhenUsingClosuresBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy b/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy
index 15ebe55..031a764 100644
--- a/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy
+++ b/src/test/groovy/bugs/ClassGeneratorFixesTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 
diff --git a/src/test/groovy/bugs/ClassInNamedParamsBug.groovy b/src/test/groovy/bugs/ClassInNamedParamsBug.groovy
index 9854e29..e9e9eb2 100644
--- a/src/test/groovy/bugs/ClassInNamedParamsBug.groovy
+++ b/src/test/groovy/bugs/ClassInNamedParamsBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class ClassInNamedParamsBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/ClosureInClosureBug.groovy b/src/test/groovy/bugs/ClosureInClosureBug.groovy
index 1cbd865..1281313 100644
--- a/src/test/groovy/bugs/ClosureInClosureBug.groovy
+++ b/src/test/groovy/bugs/ClosureInClosureBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ClosureParameterPassingBug.groovy b/src/test/groovy/bugs/ClosureParameterPassingBug.groovy
index ca72750..4e7d280 100644
--- a/src/test/groovy/bugs/ClosureParameterPassingBug.groovy
+++ b/src/test/groovy/bugs/ClosureParameterPassingBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.classgen.TestSupport
diff --git a/src/test/groovy/bugs/ClosureTypedVariableBug.groovy b/src/test/groovy/bugs/ClosureTypedVariableBug.groovy
index cdc614f..d848dc6 100644
--- a/src/test/groovy/bugs/ClosureTypedVariableBug.groovy
+++ b/src/test/groovy/bugs/ClosureTypedVariableBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ClosureVariableBug.groovy b/src/test/groovy/bugs/ClosureVariableBug.groovy
index 72814b2..d29b4d8 100644
--- a/src/test/groovy/bugs/ClosureVariableBug.groovy
+++ b/src/test/groovy/bugs/ClosureVariableBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy b/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy
index 21bc8ce..8b560c6 100644
--- a/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy
+++ b/src/test/groovy/bugs/ClosureWithBitwiseDefaultParamTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class ClosureWithBitwiseDefaultParamTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy b/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy
index 5da8b5a..8bd9967 100644
--- a/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy
+++ b/src/test/groovy/bugs/ClosureWithStaticVariablesBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ConstructorBug.groovy b/src/test/groovy/bugs/ConstructorBug.groovy
index f71c548..3912763 100644
--- a/src/test/groovy/bugs/ConstructorBug.groovy
+++ b/src/test/groovy/bugs/ConstructorBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.runtime.InvokerHelper
diff --git a/src/test/groovy/bugs/ConstructorThisCallBug.groovy b/src/test/groovy/bugs/ConstructorThisCallBug.groovy
index 683e35e..828516c 100644
--- a/src/test/groovy/bugs/ConstructorThisCallBug.groovy
+++ b/src/test/groovy/bugs/ConstructorThisCallBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * ConstructorThisCallBug.groovy
  *
diff --git a/src/test/groovy/bugs/DefVariableBug.groovy b/src/test/groovy/bugs/DefVariableBug.groovy
index 3b7545e..8667de6 100644
--- a/src/test/groovy/bugs/DefVariableBug.groovy
+++ b/src/test/groovy/bugs/DefVariableBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy b/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
index caa0904..0067a9f 100644
--- a/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
+++ b/src/test/groovy/bugs/DirectMethodCallWithVargsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.ast.ClassCodeVisitorSupport
diff --git a/src/test/groovy/bugs/FullyQualifiedClassBug.groovy b/src/test/groovy/bugs/FullyQualifiedClassBug.groovy
index 5af8f9f..2c8079f 100644
--- a/src/test/groovy/bugs/FullyQualifiedClassBug.groovy
+++ b/src/test/groovy/bugs/FullyQualifiedClassBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy b/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy
index fd78741..ab09160 100644
--- a/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy
+++ b/src/test/groovy/bugs/FullyQualifiedMethodReturnTypeBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy b/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy
index a919176..828ad74 100644
--- a/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy
+++ b/src/test/groovy/bugs/FullyQualifiedVariableTypeBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/G3839A1.java b/src/test/groovy/bugs/G3839A1.java
index 924222b..f0e68f0 100644
--- a/src/test/groovy/bugs/G3839A1.java
+++ b/src/test/groovy/bugs/G3839A1.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
diff --git a/src/test/groovy/bugs/G3839A2.java b/src/test/groovy/bugs/G3839A2.java
index 5a31fc3..5265e3e 100644
--- a/src/test/groovy/bugs/G3839A2.java
+++ b/src/test/groovy/bugs/G3839A2.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
diff --git a/src/test/groovy/bugs/G3839A3.java b/src/test/groovy/bugs/G3839A3.java
index f6c63d5..e1eca52 100644
--- a/src/test/groovy/bugs/G3839A3.java
+++ b/src/test/groovy/bugs/G3839A3.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
diff --git a/src/test/groovy/bugs/G3839A4.java b/src/test/groovy/bugs/G3839A4.java
index 9d4a7f0..a7b3134 100644
--- a/src/test/groovy/bugs/G3839A4.java
+++ b/src/test/groovy/bugs/G3839A4.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.transform.GroovyASTTransformationClass;
diff --git a/src/test/groovy/bugs/G3839Transform1.java b/src/test/groovy/bugs/G3839Transform1.java
index cb01e87..24578a9 100644
--- a/src/test/groovy/bugs/G3839Transform1.java
+++ b/src/test/groovy/bugs/G3839Transform1.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.objectweb.asm.Opcodes;
diff --git a/src/test/groovy/bugs/G3839Transform2.java b/src/test/groovy/bugs/G3839Transform2.java
index 39761c1..b8ea061 100644
--- a/src/test/groovy/bugs/G3839Transform2.java
+++ b/src/test/groovy/bugs/G3839Transform2.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.objectweb.asm.Opcodes;
diff --git a/src/test/groovy/bugs/G3839Transform3.java b/src/test/groovy/bugs/G3839Transform3.java
index f1e704e..e4885af 100644
--- a/src/test/groovy/bugs/G3839Transform3.java
+++ b/src/test/groovy/bugs/G3839Transform3.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.objectweb.asm.Opcodes;
diff --git a/src/test/groovy/bugs/GROOVY3934Helper.groovy b/src/test/groovy/bugs/GROOVY3934Helper.groovy
index ff04e0d..5a9f860 100644
--- a/src/test/groovy/bugs/GROOVY3934Helper.groovy
+++ b/src/test/groovy/bugs/GROOVY3934Helper.groovy
@@ -1 +1,16 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 return 'GROOVY3934Helper script called'
\ No newline at end of file
diff --git a/src/test/groovy/bugs/Groovy1018_Bug.groovy b/src/test/groovy/bugs/Groovy1018_Bug.groovy
index b63abed..7fa2a21 100644
--- a/src/test/groovy/bugs/Groovy1018_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1018_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy1059_Bug.groovy b/src/test/groovy/bugs/Groovy1059_Bug.groovy
index 5608d02..86c4ff6 100644
--- a/src/test/groovy/bugs/Groovy1059_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1059_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy1407_Bug.groovy b/src/test/groovy/bugs/Groovy1407_Bug.groovy
index 0425f3c..13b2ba1 100644
--- a/src/test/groovy/bugs/Groovy1407_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1407_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy1407_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy1462_Bug.groovy b/src/test/groovy/bugs/Groovy1462_Bug.groovy
index 0bc069f..7ba20b2 100644
--- a/src/test/groovy/bugs/Groovy1462_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1462_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy1465Bug.groovy b/src/test/groovy/bugs/Groovy1465Bug.groovy
index ec5cff1..5918d11 100644
--- a/src/test/groovy/bugs/Groovy1465Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1465Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
diff --git a/src/test/groovy/bugs/Groovy1593.groovy b/src/test/groovy/bugs/Groovy1593.groovy
index 1e110f5..859c560 100644
--- a/src/test/groovy/bugs/Groovy1593.groovy
+++ b/src/test/groovy/bugs/Groovy1593.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy1593 extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy1617_Bug.groovy b/src/test/groovy/bugs/Groovy1617_Bug.groovy
index 5c24d67..7873744 100644
--- a/src/test/groovy/bugs/Groovy1617_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1617_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy1617_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy1706_Bug.groovy b/src/test/groovy/bugs/Groovy1706_Bug.groovy
index 3440e12..63115f3 100644
--- a/src/test/groovy/bugs/Groovy1706_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1706_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy1706_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy1759_Bug.groovy b/src/test/groovy/bugs/Groovy1759_Bug.groovy
index ffb5808..5c98327 100644
--- a/src/test/groovy/bugs/Groovy1759_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy1759_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class Groovy1759_Bug extends GroovyTestCase {
    void testInterception() {
       def benchmarkInterceptor = new BenchmarkInterceptor()
diff --git a/src/test/groovy/bugs/Groovy2348Bug.groovy b/src/test/groovy/bugs/Groovy2348Bug.groovy
index 15f395c..b77b3b3 100644
--- a/src/test/groovy/bugs/Groovy2348Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2348Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2348Bug extends GroovyTestCase{
diff --git a/src/test/groovy/bugs/Groovy2350Bug.groovy b/src/test/groovy/bugs/Groovy2350Bug.groovy
index 31865f1..251161f 100644
--- a/src/test/groovy/bugs/Groovy2350Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2350Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2350Bug extends GroovyTestCase{
diff --git a/src/test/groovy/bugs/Groovy2351Bug.groovy b/src/test/groovy/bugs/Groovy2351Bug.groovy
index feabb7a..94071fd 100644
--- a/src/test/groovy/bugs/Groovy2351Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2351Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2351Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy2365Base.groovy b/src/test/groovy/bugs/Groovy2365Base.groovy
index 68bd6c1..0713a12 100644
--- a/src/test/groovy/bugs/Groovy2365Base.groovy
+++ b/src/test/groovy/bugs/Groovy2365Base.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * Created by IntelliJ IDEA.
  * User: applerestore
diff --git a/src/test/groovy/bugs/Groovy2365Bug.java b/src/test/groovy/bugs/Groovy2365Bug.java
index fd2649e..5fdeb64 100644
--- a/src/test/groovy/bugs/Groovy2365Bug.java
+++ b/src/test/groovy/bugs/Groovy2365Bug.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import groovy.lang.GroovyClassLoader;
diff --git a/src/test/groovy/bugs/Groovy2391Bug.groovy b/src/test/groovy/bugs/Groovy2391Bug.groovy
index 478cdc3..d5a53d0 100644
--- a/src/test/groovy/bugs/Groovy2391Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2391Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2391Bug extends GroovyTestCase{
diff --git a/src/test/groovy/bugs/Groovy239_Bug.groovy b/src/test/groovy/bugs/Groovy239_Bug.groovy
index 246a06d..a92800c 100644
--- a/src/test/groovy/bugs/Groovy239_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy239_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy2432Bug.groovy b/src/test/groovy/bugs/Groovy2432Bug.groovy
index e6d555f..2eadd65 100644
--- a/src/test/groovy/bugs/Groovy2432Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2432Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import java.util.logging.Level
diff --git a/src/test/groovy/bugs/Groovy2490Bug.groovy b/src/test/groovy/bugs/Groovy2490Bug.groovy
index 66d327c..80b2f03 100644
--- a/src/test/groovy/bugs/Groovy2490Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2490Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2490Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy252_Bug.groovy b/src/test/groovy/bugs/Groovy252_Bug.groovy
index af87240..e12ee30 100644
--- a/src/test/groovy/bugs/Groovy252_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy252_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy2553Bug.java b/src/test/groovy/bugs/Groovy2553Bug.java
index a05cae3..976acfe 100644
--- a/src/test/groovy/bugs/Groovy2553Bug.java
+++ b/src/test/groovy/bugs/Groovy2553Bug.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import groovy.lang.GroovyShell;
diff --git a/src/test/groovy/bugs/Groovy2556Bug.groovy b/src/test/groovy/bugs/Groovy2556Bug.groovy
index 6d6843a..1e19749 100644
--- a/src/test/groovy/bugs/Groovy2556Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2556Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2556Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy2557Bug.groovy b/src/test/groovy/bugs/Groovy2557Bug.groovy
index 10e647c..d626647 100644
--- a/src/test/groovy/bugs/Groovy2557Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2557Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2557Bug extends GroovyTestCase{
diff --git a/src/test/groovy/bugs/Groovy2558Bug.groovy b/src/test/groovy/bugs/Groovy2558Bug.groovy
index 99319c3..6aab1fc 100644
--- a/src/test/groovy/bugs/Groovy2558Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2558Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2558Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy2666Bug.groovy b/src/test/groovy/bugs/Groovy2666Bug.groovy
index 645304b..ae628e3 100644
--- a/src/test/groovy/bugs/Groovy2666Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2666Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.GroovyBugError
diff --git a/src/test/groovy/bugs/Groovy2706Bug.groovy b/src/test/groovy/bugs/Groovy2706Bug.groovy
index 9f128ba..e09a00a 100644
--- a/src/test/groovy/bugs/Groovy2706Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2706Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.util.GroovyTestCase
diff --git a/src/test/groovy/bugs/Groovy278_Bug.groovy b/src/test/groovy/bugs/Groovy278_Bug.groovy
index 2861e47..08b8ed8 100644
--- a/src/test/groovy/bugs/Groovy278_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy278_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy2801Bug.groovy b/src/test/groovy/bugs/Groovy2801Bug.groovy
index f0e2e72..3e103f7 100644
--- a/src/test/groovy/bugs/Groovy2801Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2801Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2801Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy2816Bug.groovy b/src/test/groovy/bugs/Groovy2816Bug.groovy
index be5237a..ae491a9 100644
--- a/src/test/groovy/bugs/Groovy2816Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2816Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2816Bug extends GroovyTestCase{
diff --git a/src/test/groovy/bugs/Groovy2849Bug.groovy b/src/test/groovy/bugs/Groovy2849Bug.groovy
index edb7585..528be69 100644
--- a/src/test/groovy/bugs/Groovy2849Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2849Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2849Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy2949Bug.groovy b/src/test/groovy/bugs/Groovy2949Bug.groovy
index 6b45c65..1b2d47c 100644
--- a/src/test/groovy/bugs/Groovy2949Bug.groovy
+++ b/src/test/groovy/bugs/Groovy2949Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy2949Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3069Bug.groovy b/src/test/groovy/bugs/Groovy3069Bug.groovy
index 6dc8993..55696f9 100644
--- a/src/test/groovy/bugs/Groovy3069Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3069Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3069Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3135Bug.groovy b/src/test/groovy/bugs/Groovy3135Bug.groovy
index 7dd2747..539f8b0 100644
--- a/src/test/groovy/bugs/Groovy3135Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3135Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3135Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3139Bug.groovy b/src/test/groovy/bugs/Groovy3139Bug.groovy
index b1c8133..492be0c 100644
--- a/src/test/groovy/bugs/Groovy3139Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3139Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.mock.interceptor.StubFor
diff --git a/src/test/groovy/bugs/Groovy3156And2621Bug.groovy b/src/test/groovy/bugs/Groovy3156And2621Bug.groovy
index 3abe3d1..00e572e 100644
--- a/src/test/groovy/bugs/Groovy3156And2621Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3156And2621Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3156And2621Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3163Bug.groovy b/src/test/groovy/bugs/Groovy3163Bug.groovy
index d98c686..b05e3dc 100644
--- a/src/test/groovy/bugs/Groovy3163Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3163Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import java.math.BigInteger;
diff --git a/src/test/groovy/bugs/Groovy3175_Bug.groovy b/src/test/groovy/bugs/Groovy3175_Bug.groovy
index 7761e00..4c87283 100644
--- a/src/test/groovy/bugs/Groovy3175_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3175_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 public class Groovy3175_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3205Bug.groovy b/src/test/groovy/bugs/Groovy3205Bug.groovy
index f55f47a..b0a1a45 100644
--- a/src/test/groovy/bugs/Groovy3205Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3205Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3205Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3208Bug.groovy b/src/test/groovy/bugs/Groovy3208Bug.groovy
index 2374e70..40efd8c 100644
--- a/src/test/groovy/bugs/Groovy3208Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3208Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 public class Groovy3208Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3235Bug.groovy b/src/test/groovy/bugs/Groovy3235Bug.groovy
index 191bf55..ccb4056 100644
--- a/src/test/groovy/bugs/Groovy3235Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3235Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 public class Groovy3235Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3238Bug.groovy b/src/test/groovy/bugs/Groovy3238Bug.groovy
index c87e527..f34110d 100644
--- a/src/test/groovy/bugs/Groovy3238Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3238Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3238Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy325_Bug.groovy b/src/test/groovy/bugs/Groovy325_Bug.groovy
index b3a1454..c05c7c0 100644
--- a/src/test/groovy/bugs/Groovy325_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy325_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy325_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3304Bug.groovy b/src/test/groovy/bugs/Groovy3304Bug.groovy
index ab68c74..42b0c15 100644
--- a/src/test/groovy/bugs/Groovy3304Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3304Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
diff --git a/src/test/groovy/bugs/Groovy3305Bug.groovy b/src/test/groovy/bugs/Groovy3305Bug.groovy
index 4a5aff6..12cf531 100644
--- a/src/test/groovy/bugs/Groovy3305Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3305Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3305Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3335Bug.groovy b/src/test/groovy/bugs/Groovy3335Bug.groovy
index a0b6b60..0a33ca9 100644
--- a/src/test/groovy/bugs/Groovy3335Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3335Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3335Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3389Bug.groovy b/src/test/groovy/bugs/Groovy3389Bug.groovy
index 342a092..745862d 100644
--- a/src/test/groovy/bugs/Groovy3389Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3389Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3389Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3403Bug.groovy b/src/test/groovy/bugs/Groovy3403Bug.groovy
index ec47953..5b4ab47 100644
--- a/src/test/groovy/bugs/Groovy3403Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3403Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.mock.interceptor.StubFor
diff --git a/src/test/groovy/bugs/Groovy3405Bug.groovy b/src/test/groovy/bugs/Groovy3405Bug.groovy
index 65089df..1d871ae 100644
--- a/src/test/groovy/bugs/Groovy3405Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3405Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3405Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3410Bug.groovy b/src/test/groovy/bugs/Groovy3410Bug.groovy
index 31e6196..4c3a1cc 100644
--- a/src/test/groovy/bugs/Groovy3410Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3410Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3410Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3424Bug.groovy b/src/test/groovy/bugs/Groovy3424Bug.groovy
index 1c8dd58..6916819 100644
--- a/src/test/groovy/bugs/Groovy3424Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3424Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3424Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3426Bug.groovy b/src/test/groovy/bugs/Groovy3426Bug.groovy
index 8ceeee7..9e941a3 100644
--- a/src/test/groovy/bugs/Groovy3426Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3426Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3426Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3462Bug.groovy b/src/test/groovy/bugs/Groovy3462Bug.groovy
index 7cde866..8544c42 100644
--- a/src/test/groovy/bugs/Groovy3462Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3462Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3462Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3464Bug.groovy b/src/test/groovy/bugs/Groovy3464Bug.groovy
index a9aef7b..624af01 100644
--- a/src/test/groovy/bugs/Groovy3464Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3464Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit
diff --git a/src/test/groovy/bugs/Groovy3465Helper.groovy b/src/test/groovy/bugs/Groovy3465Helper.groovy
index ae100cb..8769d04 100644
--- a/src/test/groovy/bugs/Groovy3465Helper.groovy
+++ b/src/test/groovy/bugs/Groovy3465Helper.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 public class Groovy3465Helper {
diff --git a/src/test/groovy/bugs/Groovy3498Bug.groovy b/src/test/groovy/bugs/Groovy3498Bug.groovy
index 10cd6c9..59e0f2a 100644
--- a/src/test/groovy/bugs/Groovy3498Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3498Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3498Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3509Bug.groovy b/src/test/groovy/bugs/Groovy3509Bug.groovy
index 64243c3..8b33284 100644
--- a/src/test/groovy/bugs/Groovy3509Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3509Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3509Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3511Bug.groovy b/src/test/groovy/bugs/Groovy3511Bug.groovy
index 8755126..30a3605 100644
--- a/src/test/groovy/bugs/Groovy3511Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3511Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.runtime.typehandling.DefaultTypeTransformation
diff --git a/src/test/groovy/bugs/Groovy3519Bug.groovy b/src/test/groovy/bugs/Groovy3519Bug.groovy
new file mode 100644
index 0000000..180a329
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy3519Bug.groovy
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.bugs
+
+class Groovy3519Bug extends GroovyTestCase {
+
+    void testShouldSkipPrivateMethodsFromCovariantReturnTypeChecks() {
+        assertScript '''
+            class A {
+                private String foo() { "1" }
+                def bar() { foo() }
+            }
+            def a = new A()
+            assert a.bar() == "1"
+            class B extends A {
+                Integer foo() {2}
+            }
+            def b = new B()
+            assert b.bar()=="1"
+        '''
+    }
+
+    void testShouldSkipPrivateMethodsFromCovariantReturnTypeChecksCS() {
+        assertScript '''import groovy.transform.CompileStatic
+
+            @CompileStatic
+            class A {
+                private String foo() { "1" }
+                def bar() { foo() }
+            }
+            def a = new A()
+            assert a.bar() == "1"
+            @CompileStatic
+            class B extends A {
+                Integer foo() {2}
+            }
+            def b = new B()
+            assert b.bar()=="1"
+        '''
+    }
+
+}
+
+
+
+
diff --git a/src/test/groovy/bugs/Groovy3574Bug.groovy b/src/test/groovy/bugs/Groovy3574Bug.groovy
index 93c5e62..984301b 100644
--- a/src/test/groovy/bugs/Groovy3574Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3574Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3574Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3645Bug.groovy b/src/test/groovy/bugs/Groovy3645Bug.groovy
index a7855d6..3f6ffcb 100644
--- a/src/test/groovy/bugs/Groovy3645Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3645Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3645Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3719Bug.groovy b/src/test/groovy/bugs/Groovy3719Bug.groovy
index dc2bc93..963c3af 100644
--- a/src/test/groovy/bugs/Groovy3719Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3719Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3719Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3719Bug_script.groovy b/src/test/groovy/bugs/Groovy3719Bug_script.groovy
index 8dae523..45712ed 100644
--- a/src/test/groovy/bugs/Groovy3719Bug_script.groovy
+++ b/src/test/groovy/bugs/Groovy3719Bug_script.groovy
@@ -1,2 +1,17 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 println "YES I CAN!"
 throw new NoSuchMethodException()
\ No newline at end of file
diff --git a/src/test/groovy/bugs/Groovy3720Bug.groovy b/src/test/groovy/bugs/Groovy3720Bug.groovy
index c8cc11e..bdd7de4 100644
--- a/src/test/groovy/bugs/Groovy3720Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3720Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.mock.interceptor.*
diff --git a/src/test/groovy/bugs/Groovy3723Bug.groovy b/src/test/groovy/bugs/Groovy3723Bug.groovy
index b53f3cf..856ac3b 100644
--- a/src/test/groovy/bugs/Groovy3723Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3723Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3723Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3749Bug.groovy b/src/test/groovy/bugs/Groovy3749Bug.groovy
index 36c6bf4..ff11e21 100644
--- a/src/test/groovy/bugs/Groovy3749Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3749Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3749Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3770Bug.groovy b/src/test/groovy/bugs/Groovy3770Bug.groovy
index 797220d..8d97eec 100644
--- a/src/test/groovy/bugs/Groovy3770Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3770Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3770Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3776Bug.groovy b/src/test/groovy/bugs/Groovy3776Bug.groovy
index c91bb12..9e44b88 100644
--- a/src/test/groovy/bugs/Groovy3776Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3776Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import java.lang.reflect.*
diff --git a/src/test/groovy/bugs/Groovy3784Bug.groovy b/src/test/groovy/bugs/Groovy3784Bug.groovy
index 003d457..205a29a 100644
--- a/src/test/groovy/bugs/Groovy3784Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3784Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3784Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3789Bug.groovy b/src/test/groovy/bugs/Groovy3789Bug.groovy
index b897eda..590127e 100644
--- a/src/test/groovy/bugs/Groovy3789Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3789Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3789Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3801Bug.groovy b/src/test/groovy/bugs/Groovy3801Bug.groovy
index 29f5093..d2739fa 100644
--- a/src/test/groovy/bugs/Groovy3801Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3801Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3801Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3817Bug.groovy b/src/test/groovy/bugs/Groovy3817Bug.groovy
index 5d35e32..c49ed3b 100644
--- a/src/test/groovy/bugs/Groovy3817Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3817Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy3818Bug.groovy b/src/test/groovy/bugs/Groovy3818Bug.groovy
index 27a3291..4277add 100644
--- a/src/test/groovy/bugs/Groovy3818Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3818Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3818Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3827Bug.groovy b/src/test/groovy/bugs/Groovy3827Bug.groovy
index 2340820..1ebd7c2 100644
--- a/src/test/groovy/bugs/Groovy3827Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3827Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
diff --git a/src/test/groovy/bugs/Groovy3830Bug.groovy b/src/test/groovy/bugs/Groovy3830Bug.groovy
index 9b11098..572e353 100644
--- a/src/test/groovy/bugs/Groovy3830Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3830Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3830Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3831Bug.groovy b/src/test/groovy/bugs/Groovy3831Bug.groovy
index 111a7d8..9d64183 100644
--- a/src/test/groovy/bugs/Groovy3831Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3831Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3831Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3834Bug.groovy b/src/test/groovy/bugs/Groovy3834Bug.groovy
index ccf8b8a..c66cf4b 100644
--- a/src/test/groovy/bugs/Groovy3834Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3834Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3834Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3839Bug.groovy b/src/test/groovy/bugs/Groovy3839Bug.groovy
index ea91abf..ba4ba98 100644
--- a/src/test/groovy/bugs/Groovy3839Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3839Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3839Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3852Bug.groovy b/src/test/groovy/bugs/Groovy3852Bug.groovy
index 33908fd..dd4710a 100644
--- a/src/test/groovy/bugs/Groovy3852Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3852Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy3857Bug.groovy b/src/test/groovy/bugs/Groovy3857Bug.groovy
index ee28b14..e118715 100644
--- a/src/test/groovy/bugs/Groovy3857Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3857Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy3863Bug.groovy b/src/test/groovy/bugs/Groovy3863Bug.groovy
index e05c2a9..c9a82cf 100644
--- a/src/test/groovy/bugs/Groovy3863Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3863Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3863Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3868Bug.groovy b/src/test/groovy/bugs/Groovy3868Bug.groovy
index 5a73aa5..30ef764 100644
--- a/src/test/groovy/bugs/Groovy3868Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3868Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3868Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3871Bug.groovy b/src/test/groovy/bugs/Groovy3871Bug.groovy
index fdd1cca..e86e0f5 100644
--- a/src/test/groovy/bugs/Groovy3871Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3871Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy3873Bug.groovy b/src/test/groovy/bugs/Groovy3873Bug.groovy
index 13b0214..b364b7c 100644
--- a/src/test/groovy/bugs/Groovy3873Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3873Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3873Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3876Bug.groovy b/src/test/groovy/bugs/Groovy3876Bug.groovy
index d3bba2f..258e808 100644
--- a/src/test/groovy/bugs/Groovy3876Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3876Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.runtime.typehandling.GroovyCastException
diff --git a/src/test/groovy/bugs/Groovy3894Bug.groovy b/src/test/groovy/bugs/Groovy3894Bug.groovy
index 43a44dd..c1c024f 100644
--- a/src/test/groovy/bugs/Groovy3894Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3894Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3894Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy389_Bug.groovy b/src/test/groovy/bugs/Groovy389_Bug.groovy
index 88275b2..b637436 100644
--- a/src/test/groovy/bugs/Groovy389_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy389_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy3904Bug.groovy b/src/test/groovy/bugs/Groovy3904Bug.groovy
index ba25a51..e433f64 100644
--- a/src/test/groovy/bugs/Groovy3904Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3904Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
diff --git a/src/test/groovy/bugs/Groovy3949Bug.groovy b/src/test/groovy/bugs/Groovy3949Bug.groovy
index ad1ce1e..443845e 100644
--- a/src/test/groovy/bugs/Groovy3949Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3949Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy3949Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy3989Bug.groovy b/src/test/groovy/bugs/Groovy3989Bug.groovy
index 817d23d..a2b6ee2 100644
--- a/src/test/groovy/bugs/Groovy3989Bug.groovy
+++ b/src/test/groovy/bugs/Groovy3989Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy4025Bug.groovy b/src/test/groovy/bugs/Groovy4025Bug.groovy
index d02b776..ea84d25 100644
--- a/src/test/groovy/bugs/Groovy4025Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4025Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy4035Bug.groovy b/src/test/groovy/bugs/Groovy4035Bug.groovy
index 5123a5a..c7ac824 100644
--- a/src/test/groovy/bugs/Groovy4035Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4035Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4035Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4038Bug.groovy b/src/test/groovy/bugs/Groovy4038Bug.groovy
index f2d2862..29a64d3 100644
--- a/src/test/groovy/bugs/Groovy4038Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4038Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4038Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4043Bug.groovy b/src/test/groovy/bugs/Groovy4043Bug.groovy
index ec2157c..0690fba 100644
--- a/src/test/groovy/bugs/Groovy4043Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4043Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy4046Bug.groovy b/src/test/groovy/bugs/Groovy4046Bug.groovy
index 180f3cf..8d660db 100644
--- a/src/test/groovy/bugs/Groovy4046Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4046Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4046Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4069Bug.groovy b/src/test/groovy/bugs/Groovy4069Bug.groovy
index 6217e78..e48b800 100644
--- a/src/test/groovy/bugs/Groovy4069Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4069Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4069Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4075Bug.groovy b/src/test/groovy/bugs/Groovy4075Bug.groovy
index 6c56498..69f3706 100644
--- a/src/test/groovy/bugs/Groovy4075Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4075Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4075Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4078Bug.groovy b/src/test/groovy/bugs/Groovy4078Bug.groovy
index 0aa170d..2a45976 100644
--- a/src/test/groovy/bugs/Groovy4078Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4078Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4078Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4080Bug.groovy b/src/test/groovy/bugs/Groovy4080Bug.groovy
index 42415f6..633510b 100644
--- a/src/test/groovy/bugs/Groovy4080Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4080Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4080Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4081Bug.groovy b/src/test/groovy/bugs/Groovy4081Bug.groovy
index 711dffa..f519f0f 100644
--- a/src/test/groovy/bugs/Groovy4081Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4081Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import gls.CompilableTestSupport
diff --git a/src/test/groovy/bugs/Groovy4145.groovy b/src/test/groovy/bugs/Groovy4145.groovy
index e55bbf8..375c75d 100644
--- a/src/test/groovy/bugs/Groovy4145.groovy
+++ b/src/test/groovy/bugs/Groovy4145.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4145 {
diff --git a/src/test/groovy/bugs/Groovy4206Bug.groovy b/src/test/groovy/bugs/Groovy4206Bug.groovy
index e29e66d..4d65c2a 100644
--- a/src/test/groovy/bugs/Groovy4206Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4206Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4206Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4243Bug.groovy b/src/test/groovy/bugs/Groovy4243Bug.groovy
index fc14e46..14a0418 100644
--- a/src/test/groovy/bugs/Groovy4243Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4243Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.*
diff --git a/src/test/groovy/bugs/Groovy4247Bug.groovy b/src/test/groovy/bugs/Groovy4247Bug.groovy
index 3d896c2..ade6204 100644
--- a/src/test/groovy/bugs/Groovy4247Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4247Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4247Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4257Bug.groovy b/src/test/groovy/bugs/Groovy4257Bug.groovy
index 4221f11..5857329 100644
--- a/src/test/groovy/bugs/Groovy4257Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4257Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4257Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4386_Bug.groovy b/src/test/groovy/bugs/Groovy4386_Bug.groovy
index 9706689..12ce856 100644
--- a/src/test/groovy/bugs/Groovy4386_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4386_Bug.groovy
@@ -29,19 +29,18 @@ class Groovy4386_Bug extends GroovyTestCase {
             static final TWOPI = 6.28
         }
     """
-    File dir = null
-    File file = null
+    File tmpDir
 
     @Override protected void setUp() {
-        dir = new File("foo")
+        tmpDir = File.createTempDir()
+        File dir = new File(tmpDir, 'foo')
         dir.mkdir()
-        file = new File(dir, "Constants.groovy")
+        File file = new File(dir, "Constants.groovy")
         DefaultGroovyMethods.setText(file, scriptSource);
     }
 
     @Override protected void tearDown() {
-        file.delete()
-        dir.delete()
+        tmpDir.deleteDir()
     }
 
     void testAccessPublicStaticField() {
@@ -81,7 +80,7 @@ class Groovy4386_Bug extends GroovyTestCase {
     }
 
     void assertScript(String script) {
-        GroovyShell shell = new GroovyShell(new CompilerConfiguration(classpath:'.'))
+        GroovyShell shell = new GroovyShell(new CompilerConfiguration(classpath: tmpDir.path))
         shell.evaluate(script, getTestClassName())
     }
 }
diff --git a/src/test/groovy/bugs/Groovy4415Bug.groovy b/src/test/groovy/bugs/Groovy4415Bug.groovy
index 910fa8c..a2b4937 100644
--- a/src/test/groovy/bugs/Groovy4415Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4415Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4415Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy4457GenericTypeDeclarationLeakTest.groovy b/src/test/groovy/bugs/Groovy4457GenericTypeDeclarationLeakTest.groovy
index 1595b9d..3d35c74 100644
--- a/src/test/groovy/bugs/Groovy4457GenericTypeDeclarationLeakTest.groovy
+++ b/src/test/groovy/bugs/Groovy4457GenericTypeDeclarationLeakTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy4471Bug.groovy b/src/test/groovy/bugs/Groovy4471Bug.groovy
index e5a8fb9..d98e11b 100644
--- a/src/test/groovy/bugs/Groovy4471Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4471Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 
diff --git a/src/test/groovy/bugs/Groovy4861Bug.groovy b/src/test/groovy/bugs/Groovy4861Bug.groovy
index 6da8d40..7c200bb 100644
--- a/src/test/groovy/bugs/Groovy4861Bug.groovy
+++ b/src/test/groovy/bugs/Groovy4861Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy4861Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5025Bug.groovy b/src/test/groovy/bugs/Groovy5025Bug.groovy
index 4cc97f0..fdb0aba 100644
--- a/src/test/groovy/bugs/Groovy5025Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5025Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5025Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5061.groovy b/src/test/groovy/bugs/Groovy5061.groovy
index 1764ec5..306f5d0 100644
--- a/src/test/groovy/bugs/Groovy5061.groovy
+++ b/src/test/groovy/bugs/Groovy5061.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/src/test/groovy/bugs/Groovy5101Test.groovy b/src/test/groovy/bugs/Groovy5101Test.groovy
index df2ce20..38c919c 100644
--- a/src/test/groovy/bugs/Groovy5101Test.groovy
+++ b/src/test/groovy/bugs/Groovy5101Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5101Test extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5109Bug.groovy b/src/test/groovy/bugs/Groovy5109Bug.groovy
index 97d964d..5099b17 100644
--- a/src/test/groovy/bugs/Groovy5109Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5109Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5109Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5122Bug.groovy b/src/test/groovy/bugs/Groovy5122Bug.groovy
index 1417997..27c57c5 100644
--- a/src/test/groovy/bugs/Groovy5122Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5122Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5122Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5137Bug.groovy b/src/test/groovy/bugs/Groovy5137Bug.groovy
index 6a538a0..69f66a5 100644
--- a/src/test/groovy/bugs/Groovy5137Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5137Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5137Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5150Bug.groovy b/src/test/groovy/bugs/Groovy5150Bug.groovy
index 967710f..bc9d380 100644
--- a/src/test/groovy/bugs/Groovy5150Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5150Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/src/test/groovy/bugs/Groovy5152Bug.groovy b/src/test/groovy/bugs/Groovy5152Bug.groovy
index 3952131..4b5ba80 100644
--- a/src/test/groovy/bugs/Groovy5152Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5152Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5152Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5185Bug.groovy b/src/test/groovy/bugs/Groovy5185Bug.groovy
index 828fe4c..11499cb 100644
--- a/src/test/groovy/bugs/Groovy5185Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5185Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5185Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5193Bug.groovy b/src/test/groovy/bugs/Groovy5193Bug.groovy
index 14bdb12..2c670b1 100644
--- a/src/test/groovy/bugs/Groovy5193Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5193Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
diff --git a/src/test/groovy/bugs/Groovy5210Bug.groovy b/src/test/groovy/bugs/Groovy5210Bug.groovy
index 74d0d87..22f72be 100644
--- a/src/test/groovy/bugs/Groovy5210Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5210Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5210Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5212Bug.groovy b/src/test/groovy/bugs/Groovy5212Bug.groovy
index ce791be..d256748 100644
--- a/src/test/groovy/bugs/Groovy5212Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5212Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.ast.ClassNode
diff --git a/src/test/groovy/bugs/Groovy5259Bug.groovy b/src/test/groovy/bugs/Groovy5259Bug.groovy
index 4891260..dd0c206 100644
--- a/src/test/groovy/bugs/Groovy5259Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5259Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5259Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5260Bug.groovy b/src/test/groovy/bugs/Groovy5260Bug.groovy
index 0d471b4..8d992c6 100644
--- a/src/test/groovy/bugs/Groovy5260Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5260Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.ast.ClassNode
diff --git a/src/test/groovy/bugs/Groovy5267Bug.groovy b/src/test/groovy/bugs/Groovy5267Bug.groovy
index 8968705..175c226 100644
--- a/src/test/groovy/bugs/Groovy5267Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5267Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/groovy/bugs/Groovy5272Bug.groovy b/src/test/groovy/bugs/Groovy5272Bug.groovy
index 5c5a890..a008f13 100644
--- a/src/test/groovy/bugs/Groovy5272Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5272Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5272Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy5285Bug.groovy b/src/test/groovy/bugs/Groovy5285Bug.groovy
index 32064c0..b151c97 100644
--- a/src/test/groovy/bugs/Groovy5285Bug.groovy
+++ b/src/test/groovy/bugs/Groovy5285Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy5285Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy6374Bug.groovy b/src/test/groovy/bugs/Groovy6374Bug.groovy
index 64c893a..df80cbe 100644
--- a/src/test/groovy/bugs/Groovy6374Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6374Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy6374Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy6508Bug.groovy b/src/test/groovy/bugs/Groovy6508Bug.groovy
index 7eaf7a3..ed0d1b0 100644
--- a/src/test/groovy/bugs/Groovy6508Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6508Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import java.util.concurrent.Callable
diff --git a/src/test/groovy/bugs/Groovy662Bug.groovy b/src/test/groovy/bugs/Groovy662Bug.groovy
index d29cd9e..55780d5 100644
--- a/src/test/groovy/bugs/Groovy662Bug.groovy
+++ b/src/test/groovy/bugs/Groovy662Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 //  The order of the classes is crucial, the first must be the GroovyTestCase.  Its name doesn't
diff --git a/src/test/groovy/bugs/Groovy662_JavaClass.java b/src/test/groovy/bugs/Groovy662_JavaClass.java
index 0dce3fc..d67730d 100644
--- a/src/test/groovy/bugs/Groovy662_JavaClass.java
+++ b/src/test/groovy/bugs/Groovy662_JavaClass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import java.util.HashMap;
diff --git a/src/test/groovy/bugs/Groovy666_Bug.groovy b/src/test/groovy/bugs/Groovy666_Bug.groovy
index 8b21520..d84c06b 100644
--- a/src/test/groovy/bugs/Groovy666_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy666_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy674_Bug.groovy b/src/test/groovy/bugs/Groovy674_Bug.groovy
index ca6b551..b834063 100644
--- a/src/test/groovy/bugs/Groovy674_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy674_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy6755Bug.groovy b/src/test/groovy/bugs/Groovy6755Bug.groovy
index 3e98206..7cb0ce6 100644
--- a/src/test/groovy/bugs/Groovy6755Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6755Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/src/test/groovy/bugs/Groovy6786Bug.groovy b/src/test/groovy/bugs/Groovy6786Bug.groovy
index df98985..46d7ef7 100644
--- a/src/test/groovy/bugs/Groovy6786Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6786Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.transform.NotYetImplemented
diff --git a/src/test/groovy/bugs/Groovy6804Bug.groovy b/src/test/groovy/bugs/Groovy6804Bug.groovy
index 54546ab..5085afc 100644
--- a/src/test/groovy/bugs/Groovy6804Bug.groovy
+++ b/src/test/groovy/bugs/Groovy6804Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.transform.NotYetImplemented
diff --git a/src/test/groovy/bugs/Groovy6841Bug.groovy b/src/test/groovy/bugs/Groovy6841Bug.groovy
new file mode 100644
index 0000000..8bfec44
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy6841Bug.groovy
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.bugs
+
+class Groovy6841Bug extends GroovyTestCase {
+    void testShouldNotThrowNPEduringCompilation() {
+        assertScript '''
+ at groovy.transform.InheritConstructors
+class Tuple<E> extends ArrayList<E> {
+
+   public ListIterator<E> listIterator(final int index) {
+        return new ListIterator<E>() {
+            private final ListIterator<? extends E> i = Tuple.super.listIterator(index)
+
+            public boolean hasNext()     {return i.hasNext();}
+            public E next()              {return i.next();}
+            public boolean hasPrevious() {return i.hasPrevious();}
+            public E previous()          {return i.previous();}
+            public int nextIndex()       {return i.nextIndex();}
+            public int previousIndex()   {return i.previousIndex();}
+
+            public void remove() {
+                throw new UnsupportedOperationException();
+            }
+            public void set(E e) {
+                throw new UnsupportedOperationException();
+            }
+            public void add(E e) {
+                throw new UnsupportedOperationException();
+            }
+        };
+    }
+}
+Tuple
+'''
+    }
+}
diff --git a/src/test/groovy/bugs/Groovy7081Bug.groovy b/src/test/groovy/bugs/Groovy7081Bug.groovy
new file mode 100644
index 0000000..d69fe0a
--- /dev/null
+++ b/src/test/groovy/bugs/Groovy7081Bug.groovy
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package groovy.bugs
+
+import org.codehaus.groovy.control.MultipleCompilationErrorsException
+
+class Groovy7081Bug extends GroovyTestCase {
+    void testShouldSeeThatMethodIsNotImplemented() {
+        def msg = shouldFail '''
+            interface DefinesProperty {
+                String getName()
+            }
+            class Foo implements DefinesProperty {
+                static String name = 'Foo'
+            }
+            new Foo().name
+            '''
+
+        assert msg.contains("Method 'getName' is already defined in class 'Foo'")
+    }
+
+    void testShouldSeeConflictInTypeSignature() {
+        def msg = shouldFail '''
+            interface DefinesProperty {
+                String getName()
+            }
+            class Foo implements DefinesProperty {
+                static int name = 666
+            }
+            new Foo().name
+            '''
+
+        assert msg.contains("Abstract method 'java.lang.String getName()' is not implemented but a method of the same name but different return type is defined: static method 'int getName()'")
+    }
+
+    void testShouldSeeConflictUsingTrait() {
+        def msg = shouldFail '''
+            trait SomeTrait {
+                int getMagicNumber() {
+                    42
+                }
+            }
+            class SomeClass implements SomeTrait {
+                static magicNumber = 'Forty Two'
+            }
+        '''
+        assert msg.contains("Abstract method 'int getMagicNumber()' is not implemented but a method of the same name but different return type is defined: static method 'java.lang.Object getMagicNumber()'")
+    }
+}
diff --git a/src/test/groovy/bugs/Groovy770_Bug.groovy b/src/test/groovy/bugs/Groovy770_Bug.groovy
index 76718a1..576729e 100644
--- a/src/test/groovy/bugs/Groovy770_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy770_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /**
  * @version $Revision$
  */
diff --git a/src/test/groovy/bugs/Groovy831_Bug.groovy b/src/test/groovy/bugs/Groovy831_Bug.groovy
index f87fe69..381e367 100644
--- a/src/test/groovy/bugs/Groovy831_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy831_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy872Bug.groovy b/src/test/groovy/bugs/Groovy872Bug.groovy
index d6abf16..64cc340 100644
--- a/src/test/groovy/bugs/Groovy872Bug.groovy
+++ b/src/test/groovy/bugs/Groovy872Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy872 extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/Groovy965_Bug.groovy b/src/test/groovy/bugs/Groovy965_Bug.groovy
index 49c0c49..d9bc50b 100644
--- a/src/test/groovy/bugs/Groovy965_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy965_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/Groovy996_Bug.groovy b/src/test/groovy/bugs/Groovy996_Bug.groovy
index e160738..ad687df 100644
--- a/src/test/groovy/bugs/Groovy996_Bug.groovy
+++ b/src/test/groovy/bugs/Groovy996_Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class Groovy996_Bug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/GroovyInnerEnumBug.groovy b/src/test/groovy/bugs/GroovyInnerEnumBug.groovy
index 15853d3..0574d61 100644
--- a/src/test/groovy/bugs/GroovyInnerEnumBug.groovy
+++ b/src/test/groovy/bugs/GroovyInnerEnumBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class GroovyInnerEnumBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/GuillaumesBug.groovy b/src/test/groovy/bugs/GuillaumesBug.groovy
index 3e8750e..912a604 100644
--- a/src/test/groovy/bugs/GuillaumesBug.groovy
+++ b/src/test/groovy/bugs/GuillaumesBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/GuillaumesMapBug.groovy b/src/test/groovy/bugs/GuillaumesMapBug.groovy
index d5a956d..2862611 100644
--- a/src/test/groovy/bugs/GuillaumesMapBug.groovy
+++ b/src/test/groovy/bugs/GuillaumesMapBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/InconsistentStackHeightBug.groovy b/src/test/groovy/bugs/InconsistentStackHeightBug.groovy
index c9a34b2..9783a69 100644
--- a/src/test/groovy/bugs/InconsistentStackHeightBug.groovy
+++ b/src/test/groovy/bugs/InconsistentStackHeightBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/InterfaceImplBug.groovy b/src/test/groovy/bugs/InterfaceImplBug.groovy
index 99eabc0..0f57c62 100644
--- a/src/test/groovy/bugs/InterfaceImplBug.groovy
+++ b/src/test/groovy/bugs/InterfaceImplBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import java.io.Reader
diff --git a/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Groovy657Bug.groovy b/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Groovy657Bug.groovy
index 0c2c515..263536e 100644
--- a/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Groovy657Bug.groovy
+++ b/src/test/groovy/bugs/InvokeNormalMethodFromBuilder_Groovy657Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy b/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy
index 61d0d7f..294d792 100644
--- a/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy
+++ b/src/test/groovy/bugs/IterateOverCustomTypeBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/MarkupAndMethodBug.groovy b/src/test/groovy/bugs/MarkupAndMethodBug.groovy
index fd03943..795f9f2 100644
--- a/src/test/groovy/bugs/MarkupAndMethodBug.groovy
+++ b/src/test/groovy/bugs/MarkupAndMethodBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy b/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy
index be118e2..cb09288 100644
--- a/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy
+++ b/src/test/groovy/bugs/MethodCallWithoutParensInStaticMethodBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class MethodCallWithoutParensInStaticMethodBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/MethodClosureTest.groovy b/src/test/groovy/bugs/MethodClosureTest.groovy
index 0be871d..6319a2d 100644
--- a/src/test/groovy/bugs/MethodClosureTest.groovy
+++ b/src/test/groovy/bugs/MethodClosureTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.codehaus.groovy.runtime.MethodClosure
diff --git a/src/test/groovy/bugs/MethodDispatchBug.groovy b/src/test/groovy/bugs/MethodDispatchBug.groovy
index 68f8147..868ca0a 100644
--- a/src/test/groovy/bugs/MethodDispatchBug.groovy
+++ b/src/test/groovy/bugs/MethodDispatchBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class MethodDispatchBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/MethodPointerBug.groovy b/src/test/groovy/bugs/MethodPointerBug.groovy
index bcc3e12..7bb2124 100644
--- a/src/test/groovy/bugs/MethodPointerBug.groovy
+++ b/src/test/groovy/bugs/MethodPointerBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/MorgansBug.groovy b/src/test/groovy/bugs/MorgansBug.groovy
index d2a7403..ae6fc8f 100644
--- a/src/test/groovy/bugs/MorgansBug.groovy
+++ b/src/test/groovy/bugs/MorgansBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/MyConstants4272.java b/src/test/groovy/bugs/MyConstants4272.java
index 048a7e0..b1d9504 100644
--- a/src/test/groovy/bugs/MyConstants4272.java
+++ b/src/test/groovy/bugs/MyConstants4272.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import java.lang.annotation.ElementType;
diff --git a/src/test/groovy/bugs/MyConstantsASTTransformation4272.groovy b/src/test/groovy/bugs/MyConstantsASTTransformation4272.groovy
index 9d36eb3..f612f88 100644
--- a/src/test/groovy/bugs/MyConstantsASTTransformation4272.groovy
+++ b/src/test/groovy/bugs/MyConstantsASTTransformation4272.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import org.objectweb.asm.Opcodes
diff --git a/src/test/groovy/bugs/NullAsBooleanCoercionTest.groovy b/src/test/groovy/bugs/NullAsBooleanCoercionTest.groovy
index 2ef2337..b3535cd 100644
--- a/src/test/groovy/bugs/NullAsBooleanCoercionTest.groovy
+++ b/src/test/groovy/bugs/NullAsBooleanCoercionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/NullCompareBug.groovy b/src/test/groovy/bugs/NullCompareBug.groovy
index ec12f2a..3649a04 100644
--- a/src/test/groovy/bugs/NullCompareBug.groovy
+++ b/src/test/groovy/bugs/NullCompareBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/POJOCallSiteBug.groovy b/src/test/groovy/bugs/POJOCallSiteBug.groovy
index eb29b0a..e01f28a 100644
--- a/src/test/groovy/bugs/POJOCallSiteBug.groovy
+++ b/src/test/groovy/bugs/POJOCallSiteBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class POJOCallSiteBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/POJOCallSiteBugFoo.java b/src/test/groovy/bugs/POJOCallSiteBugFoo.java
index 706558a..0f899ea 100644
--- a/src/test/groovy/bugs/POJOCallSiteBugFoo.java
+++ b/src/test/groovy/bugs/POJOCallSiteBugFoo.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 public class POJOCallSiteBugFoo {
diff --git a/src/test/groovy/bugs/PrimitivePropertyBug.groovy b/src/test/groovy/bugs/PrimitivePropertyBug.groovy
index 6b2db6f..6c7e4fc 100644
--- a/src/test/groovy/bugs/PrimitivePropertyBug.groovy
+++ b/src/test/groovy/bugs/PrimitivePropertyBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/PrintlnWithNewBug.groovy b/src/test/groovy/bugs/PrintlnWithNewBug.groovy
index 02b1624..a27cc96 100644
--- a/src/test/groovy/bugs/PrintlnWithNewBug.groovy
+++ b/src/test/groovy/bugs/PrintlnWithNewBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.Foo
diff --git a/src/test/groovy/bugs/PropertyNameBug.groovy b/src/test/groovy/bugs/PropertyNameBug.groovy
index 630f9b0..8ac497a 100644
--- a/src/test/groovy/bugs/PropertyNameBug.groovy
+++ b/src/test/groovy/bugs/PropertyNameBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/RodsBooleanBug.groovy b/src/test/groovy/bugs/RodsBooleanBug.groovy
index 1319b6c..0e4ecf3 100644
--- a/src/test/groovy/bugs/RodsBooleanBug.groovy
+++ b/src/test/groovy/bugs/RodsBooleanBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/RodsBug.groovy b/src/test/groovy/bugs/RodsBug.groovy
index bf76fb5..beaf3f5 100644
--- a/src/test/groovy/bugs/RodsBug.groovy
+++ b/src/test/groovy/bugs/RodsBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/RussellsOptionalParenTest.groovy b/src/test/groovy/bugs/RussellsOptionalParenTest.groovy
index 2b62796..990128c 100644
--- a/src/test/groovy/bugs/RussellsOptionalParenTest.groovy
+++ b/src/test/groovy/bugs/RussellsOptionalParenTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class RussellsOptionalParenTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/SingleEvalTest.groovy b/src/test/groovy/bugs/SingleEvalTest.groovy
index d540ac2..c121dc4 100644
--- a/src/test/groovy/bugs/SingleEvalTest.groovy
+++ b/src/test/groovy/bugs/SingleEvalTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class SingleEvalTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/StaticClosurePropertyBug.groovy b/src/test/groovy/bugs/StaticClosurePropertyBug.groovy
index 2d23b54..143ddd8 100644
--- a/src/test/groovy/bugs/StaticClosurePropertyBug.groovy
+++ b/src/test/groovy/bugs/StaticClosurePropertyBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /** 
diff --git a/src/test/groovy/bugs/StaticMethodCallBug.groovy b/src/test/groovy/bugs/StaticMethodCallBug.groovy
index e85c377..edf5bf4 100644
--- a/src/test/groovy/bugs/StaticMethodCallBug.groovy
+++ b/src/test/groovy/bugs/StaticMethodCallBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /** 
diff --git a/src/test/groovy/bugs/StaticMethodImportBug.groovy b/src/test/groovy/bugs/StaticMethodImportBug.groovy
index ee2540b..ed4e3c0 100644
--- a/src/test/groovy/bugs/StaticMethodImportBug.groovy
+++ b/src/test/groovy/bugs/StaticMethodImportBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.dummy.*
diff --git a/src/test/groovy/bugs/StaticMethodImportGroovy935Bug.groovy b/src/test/groovy/bugs/StaticMethodImportGroovy935Bug.groovy
index 11205ed..b02cbb5 100644
--- a/src/test/groovy/bugs/StaticMethodImportGroovy935Bug.groovy
+++ b/src/test/groovy/bugs/StaticMethodImportGroovy935Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs;
 
 import org.codehaus.groovy.dummy.ClassWithStaticMethod
diff --git a/src/test/groovy/bugs/StaticPropertyBug.groovy b/src/test/groovy/bugs/StaticPropertyBug.groovy
index 10e3423..866153f 100644
--- a/src/test/groovy/bugs/StaticPropertyBug.groovy
+++ b/src/test/groovy/bugs/StaticPropertyBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class StaticPropertyBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy b/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy
index 48b8866..ea79864 100644
--- a/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy
+++ b/src/test/groovy/bugs/SubscriptAndExpressionBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class SubscriptAndExpressionBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy b/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy
index 31630c0..7fdcf9e 100644
--- a/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy
+++ b/src/test/groovy/bugs/SubscriptOnPrimitiveTypeArrayBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class SubscriptOnPrimitiveTypeArrayBug extends TestSupport {
diff --git a/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy b/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy
index b8fa0c8..dea1522 100644
--- a/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy
+++ b/src/test/groovy/bugs/SubscriptOnStringArrayBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class SubscriptOnStringArrayBug extends TestSupport {
diff --git a/src/test/groovy/bugs/TernaryOperatorTest.groovy b/src/test/groovy/bugs/TernaryOperatorTest.groovy
index 7acdd59..8a42f33 100644
--- a/src/test/groovy/bugs/TernaryOperatorTest.groovy
+++ b/src/test/groovy/bugs/TernaryOperatorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class TernaryOperatorBugTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/TryCatch2Bug.groovy b/src/test/groovy/bugs/TryCatch2Bug.groovy
index 57101ea..93a3e16 100644
--- a/src/test/groovy/bugs/TryCatch2Bug.groovy
+++ b/src/test/groovy/bugs/TryCatch2Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/TryCatchBug.groovy b/src/test/groovy/bugs/TryCatchBug.groovy
index 9619a30..9f793a5 100644
--- a/src/test/groovy/bugs/TryCatchBug.groovy
+++ b/src/test/groovy/bugs/TryCatchBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/UnknownVariableBug.groovy b/src/test/groovy/bugs/UnknownVariableBug.groovy
index 85ed923..1cd2ff8 100644
--- a/src/test/groovy/bugs/UnknownVariableBug.groovy
+++ b/src/test/groovy/bugs/UnknownVariableBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/UseClosureInClosureBug.groovy b/src/test/groovy/bugs/UseClosureInClosureBug.groovy
index 0343668..720b85b 100644
--- a/src/test/groovy/bugs/UseClosureInClosureBug.groovy
+++ b/src/test/groovy/bugs/UseClosureInClosureBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/UseStaticInClosureBug.groovy b/src/test/groovy/bugs/UseStaticInClosureBug.groovy
index 560d745..08eafc6 100644
--- a/src/test/groovy/bugs/UseStaticInClosureBug.groovy
+++ b/src/test/groovy/bugs/UseStaticInClosureBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/VariablePrecedence.groovy b/src/test/groovy/bugs/VariablePrecedence.groovy
index 795b9c0..1c21e71 100644
--- a/src/test/groovy/bugs/VariablePrecedence.groovy
+++ b/src/test/groovy/bugs/VariablePrecedence.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/VariablePrecedenceTest.groovy b/src/test/groovy/bugs/VariablePrecedenceTest.groovy
index 03900ef..0a8cb37 100644
--- a/src/test/groovy/bugs/VariablePrecedenceTest.groovy
+++ b/src/test/groovy/bugs/VariablePrecedenceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class VariablePrecedenceTest extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/VariableScopingBug.groovy b/src/test/groovy/bugs/VariableScopingBug.groovy
index 86ade01..24e8797 100644
--- a/src/test/groovy/bugs/VariableScopingBug.groovy
+++ b/src/test/groovy/bugs/VariableScopingBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/VerifyErrorBug.groovy b/src/test/groovy/bugs/VerifyErrorBug.groovy
index 3897cf5..57874f3 100644
--- a/src/test/groovy/bugs/VerifyErrorBug.groovy
+++ b/src/test/groovy/bugs/VerifyErrorBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 class VerifyErrorBug extends GroovyTestCase {
diff --git a/src/test/groovy/bugs/WriteOnlyPropertyBug.groovy b/src/test/groovy/bugs/WriteOnlyPropertyBug.groovy
index 7e43737..af51796 100644
--- a/src/test/groovy/bugs/WriteOnlyPropertyBug.groovy
+++ b/src/test/groovy/bugs/WriteOnlyPropertyBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/ZoharsBug.groovy b/src/test/groovy/bugs/ZoharsBug.groovy
index 4d27aa7..c2909a0 100644
--- a/src/test/groovy/bugs/ZoharsBug.groovy
+++ b/src/test/groovy/bugs/ZoharsBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 /**
diff --git a/src/test/groovy/bugs/bug1567_script.groovy b/src/test/groovy/bugs/bug1567_script.groovy
index 5151bb1..e8c6d5d 100644
--- a/src/test/groovy/bugs/bug1567_script.groovy
+++ b/src/test/groovy/bugs/bug1567_script.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 t = new Thread({ println "Groovy" })
diff --git a/src/test/groovy/execute/ExecuteTest_LinuxSolaris.groovy b/src/test/groovy/execute/ExecuteTest_LinuxSolaris.groovy
index e455806..b0618b7 100644
--- a/src/test/groovy/execute/ExecuteTest_LinuxSolaris.groovy
+++ b/src/test/groovy/execute/ExecuteTest_LinuxSolaris.groovy
@@ -1,4 +1,19 @@
-#! /usr/bin/env groovy 
+#! /usr/bin/env groovy
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 package groovy.execute
 
diff --git a/src/test/groovy/gpath/NodeGPathTest.groovy b/src/test/groovy/gpath/NodeGPathTest.groovy
index f4cf9d6..a307e5e 100644
--- a/src/test/groovy/gpath/NodeGPathTest.groovy
+++ b/src/test/groovy/gpath/NodeGPathTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.gpath
 
 /**
diff --git a/src/test/groovy/grape/GrapeClassLoaderTest.groovy b/src/test/groovy/grape/GrapeClassLoaderTest.groovy
index 4947a65..a2eb91a 100644
--- a/src/test/groovy/grape/GrapeClassLoaderTest.groovy
+++ b/src/test/groovy/grape/GrapeClassLoaderTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.grape
 /**
  * Created by IntelliJ IDEA.
diff --git a/src/test/groovy/io/PlatformLineWriterTest.java b/src/test/groovy/io/PlatformLineWriterTest.java
index 07cfa6d..afc69f2 100644
--- a/src/test/groovy/io/PlatformLineWriterTest.java
+++ b/src/test/groovy/io/PlatformLineWriterTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.io;
 
 import groovy.lang.Binding;
diff --git a/src/test/groovy/lang/BenchmarkInterceptorTest.groovy b/src/test/groovy/lang/BenchmarkInterceptorTest.groovy
index 6e212bd..dd258ab 100644
--- a/src/test/groovy/lang/BenchmarkInterceptorTest.groovy
+++ b/src/test/groovy/lang/BenchmarkInterceptorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 /**
diff --git a/src/test/groovy/lang/CharacterRangeTest.java b/src/test/groovy/lang/CharacterRangeTest.java
index 2baad29..d1f503d 100644
--- a/src/test/groovy/lang/CharacterRangeTest.java
+++ b/src/test/groovy/lang/CharacterRangeTest.java
@@ -1,4 +1,19 @@
 /**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
  *
  */
 package groovy.lang;
diff --git a/src/test/groovy/lang/ClassReloadingTest.groovy b/src/test/groovy/lang/ClassReloadingTest.groovy
index 151f7ea..92acfcd 100644
--- a/src/test/groovy/lang/ClassReloadingTest.groovy
+++ b/src/test/groovy/lang/ClassReloadingTest.groovy
@@ -1,5 +1,22 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
+import org.codehaus.groovy.control.CompilerConfiguration
+
 class ClassReloadingTest extends GroovyTestCase {
 
     public void testReloading() {
@@ -68,4 +85,59 @@ class ClassReloadingTest extends GroovyTestCase {
         message = groovyClass.newInstance().greeting
         assert "goodbye" == message
     }
+
+
+    public void testReloadingIfInitialFileMissesTimestamp() {
+        def parent = File.createTempDir("reload","test")
+        def file = File.createTempFile("TestReload", ".groovy", parent)
+        file.deleteOnExit()
+        def className = file.name - ".groovy"
+        def cc = new CompilerConfiguration()
+        def currentDir = file.parentFile.absolutePath
+//        cc.targetDirectory = parent
+        def cl = new GroovyClassLoader(this.class.classLoader, cc)
+        cl.addClasspath(currentDir)
+        cl.shouldRecompile = false
+
+        try {
+            file.write """
+              class $className {
+                def greeting = "hello"
+              }
+            """
+            def groovyClass = cl.loadClass(className, true, false)
+            println System.identityHashCode(groovyClass)
+            assert !groovyClass.declaredFields.any { it.name.contains('__timeStamp') }
+            def message = groovyClass.newInstance().greeting
+            assert "hello" == message
+
+            cl = new GroovyClassLoader(this.class.classLoader, cc)
+            cl.addClasspath(currentDir)
+            cl.shouldRecompile = true
+
+            sleep 1500
+
+            // change class
+            file.write """
+              class $className {
+                def greeting = "goodbye"
+              }
+            """
+            def success = file.setLastModified(System.currentTimeMillis())
+            assert success
+            sleep 500
+
+            // reload
+            groovyClass = cl.loadClass(className, true, false)
+            println System.identityHashCode(groovyClass)
+            assert groovyClass.declaredFields.any { it.name.contains('__timeStamp') }
+            message = groovyClass.newInstance().greeting
+            assert "goodbye" == message
+        } finally {
+            println parent.listFiles()
+            parent.eachFile {it.delete()}
+            parent.delete()
+        }
+    }
+
 }
\ No newline at end of file
diff --git a/src/test/groovy/lang/DelegatingMetaClassTest.groovy b/src/test/groovy/lang/DelegatingMetaClassTest.groovy
index da32764..44557bb 100644
--- a/src/test/groovy/lang/DelegatingMetaClassTest.groovy
+++ b/src/test/groovy/lang/DelegatingMetaClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 
diff --git a/src/test/groovy/lang/EmptyRangeTest.java b/src/test/groovy/lang/EmptyRangeTest.java
index 0ee010b..69d189e 100644
--- a/src/test/groovy/lang/EmptyRangeTest.java
+++ b/src/test/groovy/lang/EmptyRangeTest.java
@@ -1,4 +1,19 @@
 /**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
  *
  */
 package groovy.lang;
diff --git a/src/test/groovy/lang/ExceptionTest.groovy b/src/test/groovy/lang/ExceptionTest.groovy
index e996400..1413587 100644
--- a/src/test/groovy/lang/ExceptionTest.groovy
+++ b/src/test/groovy/lang/ExceptionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 public class ExceptionTest extends GroovyTestCase {
diff --git a/src/test/groovy/lang/Groovy3406Test.groovy b/src/test/groovy/lang/Groovy3406Test.groovy
index 5e95269..3694f8f 100644
--- a/src/test/groovy/lang/Groovy3406Test.groovy
+++ b/src/test/groovy/lang/Groovy3406Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class Groovy3406Test extends GroovyTestCase {
     void testBug() {    
         def str = 'hello'
diff --git a/src/test/groovy/lang/GroovyClassLoaderTest.groovy b/src/test/groovy/lang/GroovyClassLoaderTest.groovy
index 7e27252..2f26329 100644
--- a/src/test/groovy/lang/GroovyClassLoaderTest.groovy
+++ b/src/test/groovy/lang/GroovyClassLoaderTest.groovy
@@ -74,6 +74,17 @@ public class GroovyClassLoaderTest extends GroovyTestCase implements Opcodes {
     }
 
 
+    public void testParseThenLoadByName() {
+        def loader = new GroovyClassLoader()
+        def clazz = loader.parseClass("println 'howdy'")
+        assert clazz == loader.loadClass(clazz.name)
+    }
+
+    public void testParseThenLoadByNameWeak() {
+        def loader = new GroovyClassLoader()
+        assert null != loader.loadClass(loader.parseClass("println 'howdy'").name)
+    }
+
     public void testClassNotFoundIsNotHidden() {
         def paths = []
         def loader = this.class.classLoader
diff --git a/src/test/groovy/lang/GroovyShellTest2.groovy b/src/test/groovy/lang/GroovyShellTest2.groovy
new file mode 100644
index 0000000..2281fa0
--- /dev/null
+++ b/src/test/groovy/lang/GroovyShellTest2.groovy
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.lang
+
+/**
+ * Created by jim on 8/14/14.
+ */
+class GroovyShellTest2 extends GroovyTestCase {
+    void testBindingsInBaseScriptInitializers() {
+        def shell = new GroovyShell();
+        def scriptText = '''
+        @groovy.transform.BaseScript CustomBaseScript baseScript
+
+        abstract class CustomBaseScript extends Script {
+            CustomBaseScript() { this(new Binding()) }
+            public CustomBaseScript(Binding b) { super(b) }
+
+            def script_args = getProperty('args')
+        }
+
+        assert script_args[0] == 'Hello Groovy'
+        script_args[0]
+'''
+
+        def arg0 = 'Hello Groovy'
+        def result = shell.run scriptText, 'TestBindingsInBaseScriptInitializers.groovy', [arg0]
+        assert result == arg0
+    }
+
+    void testBindingsInScriptFieldInitializers() {
+        def shell = new GroovyShell();
+        def scriptText = '''
+        @groovy.transform.Field def script_args = getProperty('args')
+
+        assert script_args[0] == 'Rehi Groovy'
+        script_args[0]
+'''
+
+        def arg0 = 'Rehi Groovy'
+        def result = shell.run scriptText, 'TestBindingsInScriptFieldInitializers.groovy', [arg0]
+        assert result == arg0
+    }
+
+    void testEvalBindingsInBaseScriptInitializers() {
+        def context = new Binding()
+        def arg0 = 'Hello Groovy Eval'
+        context.setProperty("args", [arg0] as String[])
+        def shell = new GroovyShell(context);
+        def scriptText = '''
+        @groovy.transform.BaseScript CustomBaseScript baseScript
+
+        abstract class CustomBaseScript extends Script {
+            CustomBaseScript() { this(new Binding()) }
+            public CustomBaseScript(Binding b) { super(b) }
+
+            def script_args = getProperty('args')
+        }
+
+        assert script_args[0] == 'Hello Groovy Eval'
+        script_args[0]
+'''
+        def result = shell.evaluate scriptText
+        assert result == arg0
+    }
+
+    void testEvalBindingsInScriptFieldInitializers() {
+        def context = new Binding()
+        def arg0 = 'Rehi Groovy Eval'
+        context.setProperty("args", [arg0] as String[])
+        def shell = new GroovyShell(context);
+        def scriptText = '''
+        @groovy.transform.Field def script_args = getProperty('args')
+        assert script_args[0] == 'Rehi Groovy Eval'
+        script_args[0]
+'''
+
+        def result = shell.evaluate scriptText
+        assert result == arg0
+    }
+}
diff --git a/src/test/groovy/lang/GroovySystemTest.groovy b/src/test/groovy/lang/GroovySystemTest.groovy
index c23284d..fd9e2bd 100644
--- a/src/test/groovy/lang/GroovySystemTest.groovy
+++ b/src/test/groovy/lang/GroovySystemTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 import java.util.logging.*
diff --git a/src/test/groovy/lang/InnerClassResolvingTest.groovy b/src/test/groovy/lang/InnerClassResolvingTest.groovy
index 4b72eeb..8c47f53 100644
--- a/src/test/groovy/lang/InnerClassResolvingTest.groovy
+++ b/src/test/groovy/lang/InnerClassResolvingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 class InnerClassResolvingTest extends GroovyTestCase {
diff --git a/src/test/groovy/lang/MetaClassRegistryTest.groovy b/src/test/groovy/lang/MetaClassRegistryTest.groovy
index b1aa750..3ed6368 100644
--- a/src/test/groovy/lang/MetaClassRegistryTest.groovy
+++ b/src/test/groovy/lang/MetaClassRegistryTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 /**
diff --git a/src/test/groovy/lang/MixinTest.groovy b/src/test/groovy/lang/MixinTest.groovy
index 62b6296..f8143ee 100644
--- a/src/test/groovy/lang/MixinTest.groovy
+++ b/src/test/groovy/lang/MixinTest.groovy
@@ -20,6 +20,7 @@ import org.codehaus.groovy.reflection.ClassInfo
 
 class MixinTest extends GroovyTestCase {
 
+    @groovy.transform.CompileStatic
     protected void setUp() {
         ClassInfo.clearModifiedExpandos()
     }
@@ -27,6 +28,7 @@ class MixinTest extends GroovyTestCase {
     protected void tearDown() {
         ArrayList.metaClass = null
         List.metaClass = null
+        ObjToTest.metaClass = null
     }
 
     void testOneClass() {
diff --git a/src/test/groovy/lang/ReferenceSerializationTest.groovy b/src/test/groovy/lang/ReferenceSerializationTest.groovy
index d90a532..cb32376 100644
--- a/src/test/groovy/lang/ReferenceSerializationTest.groovy
+++ b/src/test/groovy/lang/ReferenceSerializationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 /**
diff --git a/src/test/groovy/lang/ScriptCacheTest.groovy b/src/test/groovy/lang/ScriptCacheTest.groovy
index 8e8ce26..97c223e 100644
--- a/src/test/groovy/lang/ScriptCacheTest.groovy
+++ b/src/test/groovy/lang/ScriptCacheTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 class ScriptCacheTest extends GroovyTestCase {
diff --git a/src/test/groovy/lang/ScriptIntegerDivideTest.java b/src/test/groovy/lang/ScriptIntegerDivideTest.java
index cdfd820..410c5af 100644
--- a/src/test/groovy/lang/ScriptIntegerDivideTest.java
+++ b/src/test/groovy/lang/ScriptIntegerDivideTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang;
 
 import org.codehaus.groovy.classgen.TestSupport;
diff --git a/src/test/groovy/lang/ScriptSourcePositionInAstTest.groovy b/src/test/groovy/lang/ScriptSourcePositionInAstTest.groovy
index 1920b00..022c7a1 100644
--- a/src/test/groovy/lang/ScriptSourcePositionInAstTest.groovy
+++ b/src/test/groovy/lang/ScriptSourcePositionInAstTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 import org.codehaus.groovy.control.CompilationUnit
diff --git a/src/test/groovy/lang/ScriptTest.java b/src/test/groovy/lang/ScriptTest.java
index 327d019..5c953fe 100644
--- a/src/test/groovy/lang/ScriptTest.java
+++ b/src/test/groovy/lang/ScriptTest.java
@@ -78,4 +78,12 @@ public class ScriptTest extends TestSupport {
         shell.evaluate(script);
     }
 
+    // GROOVY-6344
+    public void testScriptNameMangling() {
+        String script = "this.getClass().getName()";
+        GroovyShell shell = new GroovyShell();
+        String name = (String) shell.evaluate(script,"a!b");
+        assertEquals("a_b", name);
+    }
+
 }
diff --git a/src/test/groovy/lang/StringConcatTest.groovy b/src/test/groovy/lang/StringConcatTest.groovy
index d7a1e5a..fbaf701 100644
--- a/src/test/groovy/lang/StringConcatTest.groovy
+++ b/src/test/groovy/lang/StringConcatTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 class StringConcatTest extends GroovyTestCase{
diff --git a/src/test/groovy/lang/StripMarginTest.groovy b/src/test/groovy/lang/StripMarginTest.groovy
index b251270..30fe7b7 100644
--- a/src/test/groovy/lang/StripMarginTest.groovy
+++ b/src/test/groovy/lang/StripMarginTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 class StripMarginTest extends GroovyTestCase {
diff --git a/src/test/groovy/lang/SyntheticReturnTest.groovy b/src/test/groovy/lang/SyntheticReturnTest.groovy
index e1865e9..60976ab 100644
--- a/src/test/groovy/lang/SyntheticReturnTest.groovy
+++ b/src/test/groovy/lang/SyntheticReturnTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 class SyntheticReturnTest extends GroovyShellTestCase{
diff --git a/src/test/groovy/lang/TupleTest.java b/src/test/groovy/lang/TupleTest.java
index ee5218c..43f8b41 100644
--- a/src/test/groovy/lang/TupleTest.java
+++ b/src/test/groovy/lang/TupleTest.java
@@ -70,12 +70,22 @@ public class TupleTest extends TestCase {
         Tuple a = new Tuple(new Object[]{"a", "b", "c"});
         Tuple b = new Tuple(new Object[]{"a", "b", "c"});
         Tuple c = new Tuple(new Object[]{"d", "b", "c"});
+        Tuple d = new Tuple(new Object[]{"a", "b"});
+        Tuple2<String, String> e = new Tuple2<String, String>("a", "b");
+        Tuple2<String, String> f = new Tuple2<String, String>("a", "c");
 
         assertEquals("hashcode", a.hashCode(), b.hashCode());
         assertTrue("hashcode", a.hashCode() != c.hashCode());
 
         assertEquals("a and b", a, b);
         assertFalse("a != c", a.equals(c));
+
+        assertFalse("!a.equals(null)", a.equals(null));
+
+        assertTrue("d.equals(e)", d.equals(e));
+        assertTrue("e.equals(d)", e.equals(d));
+        assertFalse("!e.equals(f)", e.equals(f));
+        assertFalse("!f.equals(e)", f.equals(e));
     }
 
     public void testIterator() {
diff --git a/src/test/groovy/lang/gcldeadlock/DeadlockBugUtil.groovy b/src/test/groovy/lang/gcldeadlock/DeadlockBugUtil.groovy
index 01112b6..9b68db9 100644
--- a/src/test/groovy/lang/gcldeadlock/DeadlockBugUtil.groovy
+++ b/src/test/groovy/lang/gcldeadlock/DeadlockBugUtil.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class DeadlockBugUtil {
   def plus(a, b){ return a + b }
 }
diff --git a/src/test/groovy/lang/gcldeadlock/GroovyClassLoaderDeadlockTest.java b/src/test/groovy/lang/gcldeadlock/GroovyClassLoaderDeadlockTest.java
index 5f7f3b2..34b9c37 100644
--- a/src/test/groovy/lang/gcldeadlock/GroovyClassLoaderDeadlockTest.java
+++ b/src/test/groovy/lang/gcldeadlock/GroovyClassLoaderDeadlockTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang.gcldeadlock;
 
 import groovy.lang.Binding;
diff --git a/src/test/groovy/lang/gcldeadlock/script0.groovy b/src/test/groovy/lang/gcldeadlock/script0.groovy
index 03e4d37..612d1de 100644
--- a/src/test/groovy/lang/gcldeadlock/script0.groovy
+++ b/src/test/groovy/lang/gcldeadlock/script0.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 def plus(a, b){ return a + b }
 
 number + "+" + number + "=" + plus(number, number)
diff --git a/src/test/groovy/lang/gcldeadlock/script1.groovy b/src/test/groovy/lang/gcldeadlock/script1.groovy
index b982e27..d715ba1 100644
--- a/src/test/groovy/lang/gcldeadlock/script1.groovy
+++ b/src/test/groovy/lang/gcldeadlock/script1.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 def util = new DeadlockBugUtil()
 
 number + "+" + number + "=" + util.plus(number, number)
diff --git a/src/test/groovy/mock/example/CheeseSlicer.groovy b/src/test/groovy/mock/example/CheeseSlicer.groovy
index 528e348..fdbe25a 100644
--- a/src/test/groovy/mock/example/CheeseSlicer.groovy
+++ b/src/test/groovy/mock/example/CheeseSlicer.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.example
 
 class CheeseSlicer {
diff --git a/src/test/groovy/mock/example/SandwichMaker.groovy b/src/test/groovy/mock/example/SandwichMaker.groovy
index 1ce5c93..70b3e13 100644
--- a/src/test/groovy/mock/example/SandwichMaker.groovy
+++ b/src/test/groovy/mock/example/SandwichMaker.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.example
 
 class SandwichMaker {
diff --git a/src/test/groovy/mock/example/SandwichMakerTest.groovy b/src/test/groovy/mock/example/SandwichMakerTest.groovy
index fc0ae8f..b8fc03c 100644
--- a/src/test/groovy/mock/example/SandwichMakerTest.groovy
+++ b/src/test/groovy/mock/example/SandwichMakerTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.example
 
 import groovy.mock.interceptor.MockFor
diff --git a/src/test/groovy/mock/interceptor/Caller.groovy b/src/test/groovy/mock/interceptor/Caller.groovy
index ae9b94f..1f563a4 100644
--- a/src/test/groovy/mock/interceptor/Caller.groovy
+++ b/src/test/groovy/mock/interceptor/Caller.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 /**
diff --git a/src/test/groovy/mock/interceptor/Collaborator.groovy b/src/test/groovy/mock/interceptor/Collaborator.groovy
index cba77f3..ce21442 100644
--- a/src/test/groovy/mock/interceptor/Collaborator.groovy
+++ b/src/test/groovy/mock/interceptor/Collaborator.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 /**
diff --git a/src/test/groovy/mock/interceptor/HalfMockTest.groovy b/src/test/groovy/mock/interceptor/HalfMockTest.groovy
index 9b84551..9d86225 100644
--- a/src/test/groovy/mock/interceptor/HalfMockTest.groovy
+++ b/src/test/groovy/mock/interceptor/HalfMockTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 class HalfMockTest extends GroovyTestCase {
diff --git a/src/test/groovy/mock/interceptor/IteratorCounter.java b/src/test/groovy/mock/interceptor/IteratorCounter.java
index dd2a5c7..174548e 100644
--- a/src/test/groovy/mock/interceptor/IteratorCounter.java
+++ b/src/test/groovy/mock/interceptor/IteratorCounter.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor;
 
 public class IteratorCounter {
diff --git a/src/test/groovy/mock/interceptor/MockForJavaTest.groovy b/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
index 7869545..1891063 100644
--- a/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
+++ b/src/test/groovy/mock/interceptor/MockForJavaTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 class MockForJavaTest extends GroovyTestCase {
diff --git a/src/test/groovy/mock/interceptor/MockNestedCallTest.groovy b/src/test/groovy/mock/interceptor/MockNestedCallTest.groovy
index 11b9a3c..b57d732 100644
--- a/src/test/groovy/mock/interceptor/MockNestedCallTest.groovy
+++ b/src/test/groovy/mock/interceptor/MockNestedCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 class MockNestedCallTest extends GroovyTestCase {
diff --git a/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy b/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy
index 2496cb7..692d994 100644
--- a/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy
+++ b/src/test/groovy/mock/interceptor/MockSingleCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 import junit.framework.AssertionFailedError
diff --git a/src/test/groovy/mock/interceptor/MockWithZeroRangeTest.groovy b/src/test/groovy/mock/interceptor/MockWithZeroRangeTest.groovy
index e98c897..17b44e5 100644
--- a/src/test/groovy/mock/interceptor/MockWithZeroRangeTest.groovy
+++ b/src/test/groovy/mock/interceptor/MockWithZeroRangeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 import groovy.mock.interceptor.MockFor
diff --git a/src/test/groovy/mock/interceptor/StubForJavaTest.groovy b/src/test/groovy/mock/interceptor/StubForJavaTest.groovy
index a3e55e5..1841fd7 100644
--- a/src/test/groovy/mock/interceptor/StubForJavaTest.groovy
+++ b/src/test/groovy/mock/interceptor/StubForJavaTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 class StubForJavaTest extends GroovyTestCase {
diff --git a/src/test/groovy/mock/interceptor/StubTest.groovy b/src/test/groovy/mock/interceptor/StubTest.groovy
index fb82947..38e24b0 100644
--- a/src/test/groovy/mock/interceptor/StubTest.groovy
+++ b/src/test/groovy/mock/interceptor/StubTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.mock.interceptor
 
 class StubTest extends GroovyTestCase {
diff --git a/src/test/groovy/operator/BitwiseOperatorsTest.groovy b/src/test/groovy/operator/BitwiseOperatorsTest.groovy
index 8a10709..197e1c9 100644
--- a/src/test/groovy/operator/BitwiseOperatorsTest.groovy
+++ b/src/test/groovy/operator/BitwiseOperatorsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 /** 
diff --git a/src/test/groovy/operator/IntegerOperatorsTest.groovy b/src/test/groovy/operator/IntegerOperatorsTest.groovy
index 1f77bf8..10210d0 100644
--- a/src/test/groovy/operator/IntegerOperatorsTest.groovy
+++ b/src/test/groovy/operator/IntegerOperatorsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 class IntegerOperatorsTest extends GroovyTestCase {
diff --git a/src/test/groovy/operator/MyColor.groovy b/src/test/groovy/operator/MyColor.groovy
index d340a9b..29e1575 100644
--- a/src/test/groovy/operator/MyColor.groovy
+++ b/src/test/groovy/operator/MyColor.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 import java.awt.Color
diff --git a/src/test/groovy/operator/MyColorCategory.groovy b/src/test/groovy/operator/MyColorCategory.groovy
index 06a45bd..7a420ea 100644
--- a/src/test/groovy/operator/MyColorCategory.groovy
+++ b/src/test/groovy/operator/MyColorCategory.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 class MyColorCategory {
diff --git a/src/test/groovy/operator/MyColorOperatorOverloadingTest.groovy b/src/test/groovy/operator/MyColorOperatorOverloadingTest.groovy
index 5076a10..9649cd7 100644
--- a/src/test/groovy/operator/MyColorOperatorOverloadingTest.groovy
+++ b/src/test/groovy/operator/MyColorOperatorOverloadingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 import static java.awt.Color.*
diff --git a/src/test/groovy/operator/NegateListsTest.groovy b/src/test/groovy/operator/NegateListsTest.groovy
index 6a8d0c1..24d10c9 100644
--- a/src/test/groovy/operator/NegateListsTest.groovy
+++ b/src/test/groovy/operator/NegateListsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 /** 
diff --git a/src/test/groovy/operator/PowerOperatorsTest.groovy b/src/test/groovy/operator/PowerOperatorsTest.groovy
index db8fd46..5aa1b7a 100644
--- a/src/test/groovy/operator/PowerOperatorsTest.groovy
+++ b/src/test/groovy/operator/PowerOperatorsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 /** 
diff --git a/src/test/groovy/operator/SpreadListOperatorTest.groovy b/src/test/groovy/operator/SpreadListOperatorTest.groovy
index a0ea9b5..91bc114 100644
--- a/src/test/groovy/operator/SpreadListOperatorTest.groovy
+++ b/src/test/groovy/operator/SpreadListOperatorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 /**
diff --git a/src/test/groovy/operator/SpreadMapOperatorTest.groovy b/src/test/groovy/operator/SpreadMapOperatorTest.groovy
index fedac6d..3fbd9fb 100644
--- a/src/test/groovy/operator/SpreadMapOperatorTest.groovy
+++ b/src/test/groovy/operator/SpreadMapOperatorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 /**
diff --git a/src/test/groovy/operator/TernaryOperatorsTest.groovy b/src/test/groovy/operator/TernaryOperatorsTest.groovy
index db233fb..e591ef5 100644
--- a/src/test/groovy/operator/TernaryOperatorsTest.groovy
+++ b/src/test/groovy/operator/TernaryOperatorsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 class TernaryOperatorsTest extends GroovyTestCase {
diff --git a/src/test/groovy/operator/UnaryMinusNumberTests.groovy b/src/test/groovy/operator/UnaryMinusNumberTests.groovy
index 58625a7..3b01665 100644
--- a/src/test/groovy/operator/UnaryMinusNumberTests.groovy
+++ b/src/test/groovy/operator/UnaryMinusNumberTests.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 class UnaryMinusNumberTests extends GroovyTestCase {
diff --git a/src/test/groovy/operator/UnaryMinusOperatorTest.groovy b/src/test/groovy/operator/UnaryMinusOperatorTest.groovy
index 978d4a8..d5aeb7d 100644
--- a/src/test/groovy/operator/UnaryMinusOperatorTest.groovy
+++ b/src/test/groovy/operator/UnaryMinusOperatorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.operator
 
 class UnaryMinusOperatorTest extends GroovyTestCase {
diff --git a/src/test/groovy/runtime/metaclass/groovy/bugs/CustomMetaClassTestMetaClass.groovy b/src/test/groovy/runtime/metaclass/groovy/bugs/CustomMetaClassTestMetaClass.groovy
index d3c072e..9acebc5 100644
--- a/src/test/groovy/runtime/metaclass/groovy/bugs/CustomMetaClassTestMetaClass.groovy
+++ b/src/test/groovy/runtime/metaclass/groovy/bugs/CustomMetaClassTestMetaClass.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.runtime.metaclass.groovy.bugs
 
 class CustomMetaClassTestMetaClass extends groovy.lang.DelegatingMetaClass {
diff --git a/src/test/groovy/script/CallAnotherScript.groovy b/src/test/groovy/script/CallAnotherScript.groovy
index 207cff1..d44509e 100644
--- a/src/test/groovy/script/CallAnotherScript.groovy
+++ b/src/test/groovy/script/CallAnotherScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 println("About to call another script")
 
diff --git a/src/test/groovy/script/ClassWithScript.groovy b/src/test/groovy/script/ClassWithScript.groovy
index 60798ba..52ecf5f 100644
--- a/src/test/groovy/script/ClassWithScript.groovy
+++ b/src/test/groovy/script/ClassWithScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class X {}
 x = new X()
 println(x)
\ No newline at end of file
diff --git a/src/test/groovy/script/EvalInScript.groovy b/src/test/groovy/script/EvalInScript.groovy
index f251fe1..5caeb67 100644
--- a/src/test/groovy/script/EvalInScript.groovy
+++ b/src/test/groovy/script/EvalInScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 a = 1
 evaluate("a = 3")
diff --git a/src/test/groovy/script/HelloWorld.groovy b/src/test/groovy/script/HelloWorld.groovy
index 4f813ab..21be7b3 100644
--- a/src/test/groovy/script/HelloWorld.groovy
+++ b/src/test/groovy/script/HelloWorld.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 println "Hello world"
 
diff --git a/src/test/groovy/script/HelloWorld2.groovy b/src/test/groovy/script/HelloWorld2.groovy
index 9056ef0..efb1393 100644
--- a/src/test/groovy/script/HelloWorld2.groovy
+++ b/src/test/groovy/script/HelloWorld2.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 x = ['James', 'Bob', 'Brian']
 x.each { println("hello " + it) }
diff --git a/src/test/groovy/script/MethodTestScript.groovy b/src/test/groovy/script/MethodTestScript.groovy
index 2bdf017..c27b18d 100644
--- a/src/test/groovy/script/MethodTestScript.groovy
+++ b/src/test/groovy/script/MethodTestScript.groovy
@@ -1 +1,16 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 GString.methods.each { println it.name }
diff --git a/src/test/groovy/script/PackageScript.groovy b/src/test/groovy/script/PackageScript.groovy
index 1e57436..2449749 100644
--- a/src/test/groovy/script/PackageScript.groovy
+++ b/src/test/groovy/script/PackageScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.script
 
 println("Hello world")
diff --git a/src/test/groovy/script/ScriptWithFunctions.groovy b/src/test/groovy/script/ScriptWithFunctions.groovy
index bb04b78..46a0f78 100644
--- a/src/test/groovy/script/ScriptWithFunctions.groovy
+++ b/src/test/groovy/script/ScriptWithFunctions.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 def foo(list, value) {
     println "Calling function foo() with param ${value}"
     list << value
diff --git a/src/test/groovy/script/ShowArgs.groovy b/src/test/groovy/script/ShowArgs.groovy
index b3d0578..69689b7 100644
--- a/src/test/groovy/script/ShowArgs.groovy
+++ b/src/test/groovy/script/ShowArgs.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 
 for (a in args) {
     println("Argument: " + a)
diff --git a/src/test/groovy/script/StreamClassloaderInScriptTest.groovy b/src/test/groovy/script/StreamClassloaderInScriptTest.groovy
index a86f8cd..6e6fd27 100644
--- a/src/test/groovy/script/StreamClassloaderInScriptTest.groovy
+++ b/src/test/groovy/script/StreamClassloaderInScriptTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.script
 
 class StreamClassloaderInScriptTest extends GroovyShellTestCase {
diff --git a/src/test/groovy/script/UseClosureInScript.groovy b/src/test/groovy/script/UseClosureInScript.groovy
index 9769195..7c661cf 100644
--- a/src/test/groovy/script/UseClosureInScript.groovy
+++ b/src/test/groovy/script/UseClosureInScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 a = 1
 [1].each { 
     a = it 
diff --git a/src/test/groovy/security/RunOneGroovyScript.java b/src/test/groovy/security/RunOneGroovyScript.java
index 717924d..bf89960 100644
--- a/src/test/groovy/security/RunOneGroovyScript.java
+++ b/src/test/groovy/security/RunOneGroovyScript.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.security;
 
 import junit.framework.Test;
diff --git a/src/test/groovy/security/SecurityTest.java b/src/test/groovy/security/SecurityTest.java
index 7f2a838..173599b 100644
--- a/src/test/groovy/security/SecurityTest.java
+++ b/src/test/groovy/security/SecurityTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.security;
 
 import groovy.lang.GroovyCodeSource;
diff --git a/src/test/groovy/security/SecurityTestSupport.java b/src/test/groovy/security/SecurityTestSupport.java
index c29e2f4..13ea809 100644
--- a/src/test/groovy/security/SecurityTestSupport.java
+++ b/src/test/groovy/security/SecurityTestSupport.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.security;
 
 import groovy.lang.Binding;
diff --git a/src/test/groovy/security/SignedJarTest.java b/src/test/groovy/security/SignedJarTest.java
index 638c87d..de9604d 100644
--- a/src/test/groovy/security/SignedJarTest.java
+++ b/src/test/groovy/security/SignedJarTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.security;
 
 import junit.framework.Test;
diff --git a/src/test/groovy/time/DurationTest.groovy b/src/test/groovy/time/DurationTest.groovy
index 223de0f..3f4f047 100644
--- a/src/test/groovy/time/DurationTest.groovy
+++ b/src/test/groovy/time/DurationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.time
 
 import static java.util.Calendar.*
diff --git a/src/test/groovy/transform/AnnotationCollectorTest.groovy b/src/test/groovy/transform/AnnotationCollectorTest.groovy
index af25730..28ab3bb 100644
--- a/src/test/groovy/transform/AnnotationCollectorTest.groovy
+++ b/src/test/groovy/transform/AnnotationCollectorTest.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
 * Copyright 2003-2012 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/src/test/groovy/transform/LazyTest.groovy b/src/test/groovy/transform/LazyTest.groovy
index 376be0c..8b2bcfb 100644
--- a/src/test/groovy/transform/LazyTest.groovy
+++ b/src/test/groovy/transform/LazyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.transform
 
 import java.lang.ref.SoftReference
diff --git a/src/test/groovy/transform/ReadWriteLockTest.groovy b/src/test/groovy/transform/ReadWriteLockTest.groovy
index decea95..daed551 100644
--- a/src/test/groovy/transform/ReadWriteLockTest.groovy
+++ b/src/test/groovy/transform/ReadWriteLockTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.transform
 
 import java.util.concurrent.locks.ReentrantReadWriteLock
diff --git a/src/test/groovy/transform/ThreadInterruptTest.groovy b/src/test/groovy/transform/ThreadInterruptTest.groovy
index fb6d7c7..bc37c5e 100644
--- a/src/test/groovy/transform/ThreadInterruptTest.groovy
+++ b/src/test/groovy/transform/ThreadInterruptTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2008-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.transform
 
 import groovy.mock.interceptor.StubFor
@@ -308,7 +323,7 @@ class ThreadInterruptTest extends GroovyTestCase {
         mocker.use {
             new GroovyShell().evaluate(script)
         }
-        // 2 is once for run() and once for scriptMethod()
+        // 4 is once for run() plus 3 for times loop
         assert 4 == counter.interruptedCheckCount
     }
 
diff --git a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
index cebe4c6..51a1af7 100644
--- a/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ArraysAndCollectionsSTCTest.groovy
@@ -542,5 +542,17 @@ class ArraysAndCollectionsSTCTest extends StaticTypeCheckingTestCase {
             assert foo==[]
         """
     }
+
+    // GROOVY-7122
+    void testIterableLoop() {
+        assertScript '''
+            int countIt(Iterable<Integer> list) {
+                int count = 0
+                for (Integer obj : list) {count ++}
+                return count
+            }
+            countIt([1,2,3])==3
+        '''
+    }
 }
 
diff --git a/src/test/groovy/transform/stc/BugsSTCTest.groovy b/src/test/groovy/transform/stc/BugsSTCTest.groovy
index 54d59d5..ac834c4 100644
--- a/src/test/groovy/transform/stc/BugsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/BugsSTCTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.transform.stc
 
 /**
diff --git a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
index 081c6e6..2d115ec 100644
--- a/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ClosuresSTCTest.groovy
@@ -84,7 +84,7 @@ class ClosuresSTCTest extends StaticTypeCheckingTestCase {
                 }
             }
             byte res = cl(0) // should throw an error because return type inference should be a long
-        ''', 'Possible loose of precision from long to byte'
+        ''', 'Possible loss of precision from long to byte'
     }
 
     void testClosureWithoutParam() {
diff --git a/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy b/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy
index 3714b87..2977aa5 100644
--- a/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy
+++ b/src/test/groovy/transform/stc/ConstructorsSTCTest.groovy
@@ -350,5 +350,20 @@ class ConstructorsSTCTest extends StaticTypeCheckingTestCase {
             assert b.toString() == 'Test'
         '''
     }
+
+    void testMapStyleConstructorShouldNotCarrySetterInfoToOuterBinExp() {
+        assertScript '''
+            class Blah {
+                void setA(String a) {}
+            }
+
+            void blah(Map attrs) {
+               Closure c = {
+                  def blah = new Blah(a:attrs.a as String)
+               }
+            }
+            blah(a:'foo')
+        '''
+    }
 }
 
diff --git a/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy b/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
index b774dd9..166a042 100644
--- a/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
+++ b/src/test/groovy/transform/stc/DelegatesToSTCTest.groovy
@@ -81,6 +81,7 @@ class DelegatesToSTCTest extends StaticTypeCheckingTestCase {
             assert o.test() == 2
         '''
     }
+
     void testShouldAcceptMethodCall() {
         assertScript '''
             class ExecSpec {
@@ -401,6 +402,7 @@ class DelegatesToSTCTest extends StaticTypeCheckingTestCase {
             persons = Person.findBy { name == 'Cedric' }
         '''
     }
+
     void testDelegatesToInStaticContext2() {
         assertScript '''
             class QueryBuilder {
@@ -750,4 +752,58 @@ class DelegatesToSTCTest extends StaticTypeCheckingTestCase {
             foo()
         '''
     }
+
+    void testDelegatesToNestedGenericType() {
+        assertScript '''
+            trait Configurable<ConfigObject> {
+                ConfigObject configObject
+
+                void configure(Closure<Void> configSpec) {
+                    configSpec.resolveStrategy = Closure.DELEGATE_FIRST
+                    configSpec.delegate = configObject
+                    configSpec()
+                }
+            }
+            public <T,U extends Configurable<T>> U configure(Class<U> clazz, @DelegatesTo(type="T") Closure configSpec) {
+                Configurable<T> obj = (Configurable<T>) clazz.newInstance()
+                obj.configure(configSpec)
+                obj
+            }
+            class Module implements Configurable<ModuleConfig> {
+                String value
+
+                 Module(){
+                    configObject = new ModuleConfig()
+                 }
+
+                 @Override
+                 void configure(Closure<Void> configSpec) {
+                    Configurable.super.configure(configSpec)
+                    value = "${configObject.name}-${configObject.version}"
+                 }
+            }
+            class ModuleConfig {
+                String name
+                String version
+            }
+            def module = configure(Module) {
+                name = 'test'
+                version = '1.0'
+            }
+            assert module.value == 'test-1.0'
+        '''
+    }
+
+    void testDelegatesToWithType2() {
+        assertScript '''
+            public <T> boolean evalAsSet(List<T> list, @DelegatesTo(type="Set<T>") Closure<Boolean> cl) {
+                cl.delegate = list as Set
+                cl()
+            }
+            assert evalAsSet([1,1,2,3]) {
+                size() == 3
+            }
+        '''
+    }
 }
+
diff --git a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
index 0e90422..42ca0ef 100644
--- a/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
+++ b/src/test/groovy/transform/stc/FieldsAndPropertiesSTCTest.groovy
@@ -15,6 +15,8 @@
  */
 package groovy.transform.stc
 
+import org.codehaus.groovy.ast.ASTNode
+
 /**
  * Unit tests for static type checking : fields and properties.
  *
@@ -575,6 +577,157 @@ new FooWorker().doSomething()''', 'Incompatible generic argument types. Cannot a
         '''
     }
 
+    public void testPropertyWithMultipleSetters() {
+        assertScript '''import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.BooleanExpression
+import org.codehaus.groovy.ast.stmt.AssertStatement
+            class A {
+                private field
+                void setX(Integer a) {field=a}
+                void setX(String b) {field=b}
+                def getX(){field}
+            }
+
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                lookup('test1').each { stmt ->
+                    def exp = stmt.expression
+                    assert exp instanceof BinaryExpression
+                    def left = exp.leftExpression
+                    def md = left.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
+                    assert md
+                    assert md.name == 'setX'
+                    assert md.parameters[0].originType == Integer_TYPE
+                }
+                lookup('test2').each { stmt ->
+                    def exp = stmt.expression
+                    assert exp instanceof BinaryExpression
+                    def left = exp.leftExpression
+                    def md = left.getNodeMetaData(DIRECT_METHOD_CALL_TARGET)
+                    assert md
+                    assert md.name == 'setX'
+                    assert md.parameters[0].originType == STRING_TYPE
+                }
+            })
+            void testBody() {
+                def a = new A()
+                test1:
+                a.x = 1
+                assert a.x==1
+                test2:
+                a.x = "3"
+                assert a.x == "3"
+            }
+            testBody()
+        '''
+    }
+
+    void testPropertyAssignmentAsExpression() {
+        assertScript '''
+            class Foo {
+                int x = 2
+            }
+            def f = new Foo()
+            def v = f.x = 3
+            assert v == 3
+'''
+    }
+
+    void testPropertyAssignmentInSubClassAndMultiSetter() {
+        10.times {
+            assertScript '''import org.codehaus.groovy.ast.PropertyNode
+
+            public class Activity {
+                int debug
+
+                Activity() {
+                    contentView = 1
+                }
+
+                public void setContentView(Date layoutResID) { debug = 2 }
+                public void setContentView(int layoutResID) { debug = 3 }
+            }
+
+            class MyActivity extends Activity {
+                void foo() {
+                    contentView = 1
+                    assert debug == 3
+                    contentView = new Date()
+                    assert debug == 2
+                }
+            }
+            new MyActivity().foo()
+        '''
+        }
+    }
+
+    void testPropertyAssignmentInSubClassAndMultiSetterThroughDelegation() {
+        10.times {
+            assertScript '''import org.codehaus.groovy.ast.PropertyNode
+
+            public class Activity {
+                int debug
+
+                Activity() {
+                    contentView = 1
+                }
+
+                public void setContentView(Date layoutResID) { debug = 2 }
+                public void setContentView(int layoutResID) { debug = 3 }
+            }
+
+            class MyActivity extends Activity {
+            }
+            def activity = new  MyActivity()
+            activity.with {
+                 contentView = 1
+                 assert debug == 3
+                 contentView = new Date()
+                 assert debug == 2
+            }
+        '''
+        }
+    }
+
+    void testShouldAcceptPropertyAssignmentEvenIfSetterOnlyBecauseOfSpecialType() {
+        assertScript '''
+            class BooleanSetterOnly {
+                void setFlag(boolean b) {}
+            }
+
+            def b = new BooleanSetterOnly()
+            b.flag = 'foo'
+        '''
+        assertScript '''
+            class StringSetterOnly {
+                void setFlag(String b) {}
+            }
+
+            def b = new StringSetterOnly()
+            b.flag = false
+        '''
+        assertScript '''
+            class ClassSetterOnly {
+                void setFlag(Class b) {}
+            }
+
+            def b = new ClassSetterOnly()
+            b.flag = 'java.lang.String'
+        '''
+    }
+
+    // GROOVY-6590
+    void testShouldFindStaticPropertyOnPrimitiveType() {
+        assertScript '''
+            int i=1
+            i.MAX_VALUE
+        '''
+        assertScript '''
+            def i="d"
+            i=1
+            i.MAX_VALUE
+        '''
+    }
+
     public static interface InterfaceWithField {
         String boo = "I don't fancy fields in interfaces"
     }
diff --git a/src/test/groovy/transform/stc/Groovy7184Bug.groovy b/src/test/groovy/transform/stc/Groovy7184Bug.groovy
new file mode 100644
index 0000000..fcf08a8
--- /dev/null
+++ b/src/test/groovy/transform/stc/Groovy7184Bug.groovy
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.transform.stc
+
+class Groovy7184Bug extends StaticTypeCheckingTestCase {
+    void testShouldNotAllowDirectAssignmentToInterface() {
+        shouldFailWithMessages '''
+            interface Config {}
+
+            class Holders {
+                static setConfig(Config cfg) {}
+            }
+
+            Config config = new ConfigObject()
+        ''', 'Cannot assign value of type groovy.util.ConfigObject to variable of type Config'
+    }
+}
diff --git a/src/test/groovy/transform/stc/PrecompiledExtensionNotExtendingDSL.groovy b/src/test/groovy/transform/stc/PrecompiledExtensionNotExtendingDSL.groovy
new file mode 100644
index 0000000..da174aa
--- /dev/null
+++ b/src/test/groovy/transform/stc/PrecompiledExtensionNotExtendingDSL.groovy
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.transform.stc
+
+import org.codehaus.groovy.ast.MethodNode
+import org.codehaus.groovy.ast.expr.Expression
+import org.codehaus.groovy.transform.stc.AbstractTypeCheckingExtension
+import org.codehaus.groovy.transform.stc.StaticTypeCheckingVisitor
+
+class PrecompiledExtensionNotExtendingDSL extends AbstractTypeCheckingExtension {
+
+
+    PrecompiledExtensionNotExtendingDSL(
+            final StaticTypeCheckingVisitor typeCheckingVisitor) {
+        super(typeCheckingVisitor)
+    }
+
+    @Override
+    void setup() {
+        addStaticTypeError('Error thrown from extension in setup', context.enclosingClassNode)
+    }
+
+    @Override
+    void onMethodSelection(final Expression expression, final MethodNode target) {
+        if (target.name=='println') {
+            addStaticTypeError('Error thrown from extension in onMethodSelection', expression.parameters[0])
+        }
+    }
+}
\ No newline at end of file
diff --git a/src/test/groovy/transform/stc/STCAssignmentTest.groovy b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
index 4a0ea3a..e676620 100644
--- a/src/test/groovy/transform/stc/STCAssignmentTest.groovy
+++ b/src/test/groovy/transform/stc/STCAssignmentTest.groovy
@@ -141,7 +141,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
         shouldFailWithMessages '''
             long a = Long.MAX_VALUE
             int b = a
-        ''', 'Possible loose of precision from long to int'
+        ''', 'Possible loss of precision from long to int'
     }
 
     void testPossibleLooseOfPrecision2() {
@@ -159,7 +159,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
     void testPossibleLooseOfPrecision4() {
         shouldFailWithMessages '''
             byte b = 128 // will not fit in a byte
-        ''', 'Possible loose of precision from int to byte'
+        ''', 'Possible loss of precision from int to byte'
     }
 
     void testPossibleLooseOfPrecision5() {
@@ -171,7 +171,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
     void testPossibleLooseOfPrecision6() {
         shouldFailWithMessages '''
             short b = 32768 // will not fit in a short
-        ''', 'Possible loose of precision from int to short'
+        ''', 'Possible loss of precision from int to short'
     }
 
     void testPossibleLooseOfPrecision7() {
@@ -195,7 +195,7 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
     void testPossibleLooseOfPrecision10() {
         shouldFailWithMessages '''
             int b = 32768.1d
-        ''', 'Possible loose of precision from double to int'
+        ''', 'Possible loss of precision from double to int'
     }
 
     void testCastIntToShort() {
@@ -806,5 +806,26 @@ class STCAssignmentTest extends StaticTypeCheckingTestCase {
             int[] array = o
         ''', 'Cannot assign value of type java.lang.Object to variable of type int[]'
     }
+
+    // GROOVY-7015
+    void testAssingmentToSuperclassFieldWithDifferingGenerics() {
+        assertScript '''
+            class Base {}
+            class Derived extends Base {
+                public String sayHello() { "hello"}
+            }
+
+            class GBase<T extends Base> {
+                T myVar;
+            }
+            class GDerived extends GBase<Derived> {
+                GDerived() { myVar = new Derived(); }
+                public String method() {myVar.sayHello()}
+            }
+
+            GDerived d = new GDerived();
+            assert d.method() == "hello"
+        '''
+    }
 }
 
diff --git a/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy b/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
index 83ba071..ecdec90 100644
--- a/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
+++ b/src/test/groovy/transform/stc/TypeCheckingExtensionsTest.groovy
@@ -491,4 +491,16 @@ class TypeCheckingExtensionsTest extends StaticTypeCheckingTestCase {
         ''', 'Error thrown from extension'
 
     }
+
+    void testPrecompiledExtensionNotExtendingTypeCheckingDSL() {
+        extension = null
+        assertScript '''
+            println 'Everything is ok'
+        '''
+        extension = 'groovy.transform.stc.PrecompiledExtensionNotExtendingDSL'
+        shouldFailWithMessages '''
+            println 'Everything is ok'
+        ''', 'Error thrown from extension in setup', 'Error thrown from extension in onMethodSelection'
+
+    }
 }
diff --git a/src/test/groovy/transform/stc/package.html b/src/test/groovy/transform/stc/package.html
index 1664ea2..e401128 100644
--- a/src/test/groovy/transform/stc/package.html
+++ b/src/test/groovy/transform/stc/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.transform.stc.*</title>
diff --git a/src/test/groovy/tree/ClosureClassLoaderBug.groovy b/src/test/groovy/tree/ClosureClassLoaderBug.groovy
index 15eba51..f10e838 100644
--- a/src/test/groovy/tree/ClosureClassLoaderBug.groovy
+++ b/src/test/groovy/tree/ClosureClassLoaderBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 class ClosureClassLoaderBug extends GroovyTestCase {
diff --git a/src/test/groovy/tree/NavigationTest.groovy b/src/test/groovy/tree/NavigationTest.groovy
index bd4ec66..40ee56d 100644
--- a/src/test/groovy/tree/NavigationTest.groovy
+++ b/src/test/groovy/tree/NavigationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 /**
diff --git a/src/test/groovy/tree/NestedClosureBugTest.groovy b/src/test/groovy/tree/NestedClosureBugTest.groovy
index f5d9543..fc62c09 100644
--- a/src/test/groovy/tree/NestedClosureBugTest.groovy
+++ b/src/test/groovy/tree/NestedClosureBugTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 /**
diff --git a/src/test/groovy/tree/SmallTreeTest.groovy b/src/test/groovy/tree/SmallTreeTest.groovy
index 18750ce..9d582c6 100644
--- a/src/test/groovy/tree/SmallTreeTest.groovy
+++ b/src/test/groovy/tree/SmallTreeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 class SmallTreeTest extends GroovyTestCase {
diff --git a/src/test/groovy/tree/TreeTest.groovy b/src/test/groovy/tree/TreeTest.groovy
index f8dd6a1..3515093 100644
--- a/src/test/groovy/tree/TreeTest.groovy
+++ b/src/test/groovy/tree/TreeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 /**
diff --git a/src/test/groovy/tree/VerboseTreeTest.groovy b/src/test/groovy/tree/VerboseTreeTest.groovy
index 5054589..dba0e28 100644
--- a/src/test/groovy/tree/VerboseTreeTest.groovy
+++ b/src/test/groovy/tree/VerboseTreeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.tree
 
 /**
diff --git a/src/test/groovy/txn/TransactionBean.java b/src/test/groovy/txn/TransactionBean.java
index 60e5fac..2c03c3f 100644
--- a/src/test/groovy/txn/TransactionBean.java
+++ b/src/test/groovy/txn/TransactionBean.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.txn;
 
 import groovy.lang.Closure;
diff --git a/src/test/groovy/txn/TransactionBuilder.java b/src/test/groovy/txn/TransactionBuilder.java
index 4dad74c..7873306 100644
--- a/src/test/groovy/txn/TransactionBuilder.java
+++ b/src/test/groovy/txn/TransactionBuilder.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.txn;
 
 import groovy.lang.Closure;
diff --git a/src/test/groovy/ui/GroovyMainTest.groovy b/src/test/groovy/ui/GroovyMainTest.groovy
index c7b8d5f..f0e4419 100644
--- a/src/test/groovy/ui/GroovyMainTest.groovy
+++ b/src/test/groovy/ui/GroovyMainTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.ui
 
 class GroovyMainTest extends GroovyTestCase {
diff --git a/src/test/groovy/util/BuilderSupportTest.groovy b/src/test/groovy/util/BuilderSupportTest.groovy
index 3ab2c7f..e4dd89c 100644
--- a/src/test/groovy/util/BuilderSupportTest.groovy
+++ b/src/test/groovy/util/BuilderSupportTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 /**
diff --git a/src/test/groovy/util/ConfigObjectTest.groovy b/src/test/groovy/util/ConfigObjectTest.groovy
index e1018ee..8f1c6ae 100644
--- a/src/test/groovy/util/ConfigObjectTest.groovy
+++ b/src/test/groovy/util/ConfigObjectTest.groovy
@@ -66,4 +66,17 @@ class ConfigObjectTest extends GroovyTestCase {
         def config = new ConfigSlurper().parse('foo { emptyNestedBlock { } }')
         assert config.foo.isSet('emptyNestedBlock') == false
     }
+
+    void test_prettyPrint() {
+        def configString = '''\
+development {
+    rabbitmq {
+        active=true
+        hostname='localhost'
+    }
+}'''
+
+        def config = new ConfigSlurper().parse(configString)
+        assert config == new ConfigSlurper().parse(config.prettyPrint())
+    }
 }
diff --git a/src/test/groovy/util/EvalTest.java b/src/test/groovy/util/EvalTest.java
index 397fe3a..e24d45c 100644
--- a/src/test/groovy/util/EvalTest.java
+++ b/src/test/groovy/util/EvalTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 import junit.framework.TestCase;
diff --git a/src/test/groovy/util/FileTreeBuilderTest.groovy b/src/test/groovy/util/FileTreeBuilderTest.groovy
new file mode 100644
index 0000000..62a43ab
--- /dev/null
+++ b/src/test/groovy/util/FileTreeBuilderTest.groovy
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.util
+
+class FileTreeBuilderTest extends GroovyTestCase {
+    File tmpDir
+    FileTreeBuilder builder
+
+    void setUp() {
+        super.setUp()
+        tmpDir = File.createTempDir()
+        builder = new FileTreeBuilder(tmpDir)
+    }
+
+    void tearDown() {
+        tmpDir.deleteDir()
+        builder = null
+        tmpDir = null
+    }
+
+    void testFileWithText() {
+        def file = builder.file('foo.txt','foo')
+        assert file.exists()
+        assert file.text == 'foo'
+    }
+
+    void testFileWithBytes() {
+        def file = builder.file('foo.txt','foo'.getBytes('utf-8'))
+        assert file.exists()
+        assert file.getText('utf-8') == 'foo'
+    }
+
+    void testFileWithFile() {
+        def f1 = builder.file('foo.txt', 'foo')
+        def f2 = builder.file('bar.txt', f1)
+        assert f2.exists()
+        assert f2.text == 'foo'
+    }
+
+    void testFileWithClosureSpec() {
+        def file = builder.file('foo.txt') { file ->
+            file << 'foo'
+        }
+        assert file.exists()
+        assert file.text == 'foo'
+        def file2 = builder.file('foo.txt') {
+            withWriter('utf-8') {
+                it.write('foo')
+            }
+        }
+        assert file2.exists()
+        assert file2.text == 'foo'
+    }
+
+    void testDir() {
+        def dir = builder.dir('sub')
+        assert dir.directory
+        assert dir.parentFile == builder.baseDir
+    }
+
+    void testDirWithClosure() {
+        File f = null
+        def dir = builder.dir('sub') {
+            f = file('foo.txt','foo')
+        }
+        assert dir.directory
+        assert dir.parentFile == builder.baseDir
+        assert f.text == 'foo'
+        assert f.parentFile == dir
+    }
+
+    void testCall() {
+        File s1=null,s2=null,f1=null,f2=null
+        builder {
+            s1=dir('sub1') {
+                f1=file('foo.txt','foo')
+            }
+            s2=dir('sub2') {
+                f2=file('bar.txt', 'bar')
+            }
+        }
+        assert f1.text == 'foo'
+        assert f2.text == 'bar'
+        assert f1.parentFile == s1
+        assert f2.parentFile == s2
+        assert s1.parentFile == builder.baseDir
+        assert s2.parentFile == builder.baseDir
+    }
+
+    void testCreateDirWithMethodMissing() {
+        File dir = builder.dir {}
+        assert dir.directory
+        assert dir.name == 'dir'
+        assert dir.parentFile == builder.baseDir
+    }
+
+    void testCreateFileWithMethodMissing() {
+        File f1 = builder.'foo.txt'('foo')
+        File f2 = builder.'bar.txt'('foo'.getBytes('utf-8'))
+        File f3 = builder.'baz.txt'(f2)
+        [f1,f2,f3].each {
+            assert it.exists()
+            assert it.getText('utf-8') == 'foo'
+        }
+    }
+}
diff --git a/src/test/groovy/util/GroovyCollectionsTest.groovy b/src/test/groovy/util/GroovyCollectionsTest.groovy
index 554a8d4..09453fe 100644
--- a/src/test/groovy/util/GroovyCollectionsTest.groovy
+++ b/src/test/groovy/util/GroovyCollectionsTest.groovy
@@ -107,4 +107,8 @@ public class GroovyCollectionsTest extends GroovyTestCase {
         assert sum([1, 2, 3]) == 6
     }
 
+    // GROOVY-7267
+    void testHashCodeCollisionInMinus() {
+        assert ([[1:2],[2:3]]-[["b":"a"]]) == [[1:2],[2:3]]
+    }
 }
\ No newline at end of file
diff --git a/src/test/groovy/util/GroovyScriptEngineReloadingTest.groovy b/src/test/groovy/util/GroovyScriptEngineReloadingTest.groovy
index 0a81da5..b66e0d0 100644
--- a/src/test/groovy/util/GroovyScriptEngineReloadingTest.groovy
+++ b/src/test/groovy/util/GroovyScriptEngineReloadingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 import java.util.concurrent.ConcurrentHashMap
diff --git a/src/test/groovy/util/IndentPrinterTest.groovy b/src/test/groovy/util/IndentPrinterTest.groovy
index 87d2f9b..52b1472 100644
--- a/src/test/groovy/util/IndentPrinterTest.groovy
+++ b/src/test/groovy/util/IndentPrinterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 /**
diff --git a/src/test/groovy/util/ObjectGraphBuilderTest.groovy b/src/test/groovy/util/ObjectGraphBuilderTest.groovy
index 71f54b5..915dfc4 100644
--- a/src/test/groovy/util/ObjectGraphBuilderTest.groovy
+++ b/src/test/groovy/util/ObjectGraphBuilderTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 class ObjectGraphBuilderTest extends GroovyTestCase {
diff --git a/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy b/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy
index 35fa70d..6e94569 100644
--- a/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy
+++ b/src/test/groovy/util/ProxyGeneratorAdapterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 import org.codehaus.groovy.runtime.ProxyGeneratorAdapter
@@ -138,6 +153,19 @@ class ProxyGeneratorAdapterTest extends GroovyTestCase {
         '''
     }
 
+    // GROOVY-7146
+    void testShouldNotThrowVerifyErrorBecauseOfStackSize() {
+        assertScript '''
+            interface DoStuff {
+            }
+            class Foo {
+               void foo(double a, int b) {} // first a parameter that requires 2 slots, then one that requires only 1
+            }
+
+            def gp=new Foo() as DoStuff
+            '''
+    }
+
     void testGetTypeArgsRegisterLength() {
         def types = { list -> list as org.objectweb.asm.Type[] }
         def proxyGeneratorAdapter = new ProxyGeneratorAdapter([:], Object, [] as Class[], null, false, Object)
diff --git a/src/test/groovy/util/ProxyTest.groovy b/src/test/groovy/util/ProxyTest.groovy
index 50a2afc..bf67eba 100644
--- a/src/test/groovy/util/ProxyTest.groovy
+++ b/src/test/groovy/util/ProxyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 /**
diff --git a/src/test/groovy/util/ResourceBundleTest.groovy b/src/test/groovy/util/ResourceBundleTest.groovy
index 1945b8f..eec9859 100644
--- a/src/test/groovy/util/ResourceBundleTest.groovy
+++ b/src/test/groovy/util/ResourceBundleTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 public class ResourceBundleTest extends GroovyTestCase {
diff --git a/src/test/groovy/util/i18n.properties b/src/test/groovy/util/i18n.properties
index f071cfb..f669773 100644
--- a/src/test/groovy/util/i18n.properties
+++ b/src/test/groovy/util/i18n.properties
@@ -1 +1,17 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 upvote=+1
diff --git a/src/test/groovy/util/i18n_en.properties b/src/test/groovy/util/i18n_en.properties
index fb967af..824fca0 100644
--- a/src/test/groovy/util/i18n_en.properties
+++ b/src/test/groovy/util/i18n_en.properties
@@ -1 +1,17 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 yes=yes
\ No newline at end of file
diff --git a/src/test/groovy/util/i18n_fr.properties b/src/test/groovy/util/i18n_fr.properties
index a47234d..a5c2c06 100644
--- a/src/test/groovy/util/i18n_fr.properties
+++ b/src/test/groovy/util/i18n_fr.properties
@@ -1 +1,17 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 yes=oui
diff --git a/src/test/groovy/util/logging/CommonsTest.groovy b/src/test/groovy/util/logging/CommonsTest.groovy
index a211b89..39031a7 100644
--- a/src/test/groovy/util/logging/CommonsTest.groovy
+++ b/src/test/groovy/util/logging/CommonsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util.logging
 
 import java.lang.reflect.Field
diff --git a/src/test/groovy/util/logging/Log4j2Test.groovy b/src/test/groovy/util/logging/Log4j2Test.groovy
index f3e7a88..6e858ed 100644
--- a/src/test/groovy/util/logging/Log4j2Test.groovy
+++ b/src/test/groovy/util/logging/Log4j2Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util.logging
 
 import java.lang.reflect.Field
@@ -13,6 +28,8 @@ import org.apache.logging.log4j.core.layout.PatternLayout
 import org.apache.logging.log4j.Level
 import org.apache.logging.log4j.Logger
 
+import java.nio.charset.Charset
+
 class Log4j2Test extends GroovyTestCase {
 
     class Log4j2InterceptingAppender extends AbstractAppender {
@@ -31,12 +48,12 @@ class Log4j2Test extends GroovyTestCase {
     }
 
     Log4j2InterceptingAppender appender
-    def logger
+    Logger logger
 
     protected void setUp() {
         super.setUp()
 
-        PatternLayout layout = PatternLayout.createLayout("%m", null, null, "UTF-8", "true", "false")
+        PatternLayout layout = PatternLayout.createLayout('%m', null, null, Charset.forName('UTF-8'), true, false, '', '')
         appender = new Log4j2InterceptingAppender('MyAppender', null, layout)
         logger = LogManager.getLogger('MyClass')
         logger.addAppender(appender)
@@ -216,7 +233,7 @@ class Log4j2Test extends GroovyTestCase {
     }
 
     void testCustomCategory() {
-        PatternLayout layout = PatternLayout.createLayout("%m", null, null, "UTF-8", "true", "false")
+        PatternLayout layout = PatternLayout.createLayout('%m', null, null, Charset.forName('UTF-8'), true, false, '', '')
         Log4j2InterceptingAppender appenderForCustomCategory = new Log4j2InterceptingAppender('Appender4CustomCategory', null, layout)
         def loggerForCustomCategory = LogManager.getLogger('customCategory')
         loggerForCustomCategory.addAppender(appenderForCustomCategory)
diff --git a/src/test/groovy/util/logging/Log4jTest.groovy b/src/test/groovy/util/logging/Log4jTest.groovy
index c822d11..ce7ad01 100644
--- a/src/test/groovy/util/logging/Log4jTest.groovy
+++ b/src/test/groovy/util/logging/Log4jTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util.logging
 
 import java.lang.reflect.*
diff --git a/src/test/groovy/util/logging/LogTest.groovy b/src/test/groovy/util/logging/LogTest.groovy
index dd9fbea..58e7b5d 100644
--- a/src/test/groovy/util/logging/LogTest.groovy
+++ b/src/test/groovy/util/logging/LogTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util.logging
 
 import java.lang.reflect.Field
diff --git a/src/test/groovy/util/logging/Slf4jTest.groovy b/src/test/groovy/util/logging/Slf4jTest.groovy
index b53e265..306a920 100644
--- a/src/test/groovy/util/logging/Slf4jTest.groovy
+++ b/src/test/groovy/util/logging/Slf4jTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util.logging
 
 import ch.qos.logback.classic.Level
diff --git a/src/test/groovy/util/system.properties b/src/test/groovy/util/system.properties
index 9f60a8c..4bdcddb 100644
--- a/src/test/groovy/util/system.properties
+++ b/src/test/groovy/util/system.properties
@@ -1,2 +1,18 @@
+#
+# Copyright 2003-2015 the original author or authors.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
 catalog.prov = false
 catalog.prov.db.user = sa
\ No newline at end of file
diff --git a/src/test/groovy/xml/XmlAssert.java b/src/test/groovy/xml/XmlAssert.java
index b8f1247..c048956 100644
--- a/src/test/groovy/xml/XmlAssert.java
+++ b/src/test/groovy/xml/XmlAssert.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml;
 
 import org.custommonkey.xmlunit.Diff;
diff --git a/src/test/indy/IndyUsageTest.groovy b/src/test/indy/IndyUsageTest.groovy
index b5069eb..15173e1 100644
--- a/src/test/indy/IndyUsageTest.groovy
+++ b/src/test/indy/IndyUsageTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 class IndyUsageTest extends GroovyTestCase {
   void testIndyIsUsedNested() {
     assertScript """
diff --git a/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy b/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
index 99310e4..3872bb1 100644
--- a/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
+++ b/src/test/org/codehaus/groovy/ClosureAndInnerClassNodeStructureTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy
 
 import org.codehaus.groovy.control.CompilationUnit
@@ -22,13 +37,13 @@ class ClosureAndInnerClassNodeStructureTest extends GroovyTestCase {
         def cu = new CompilationUnit()
         cu.addSource("t.groovy", '''
             exec {                               // t$_run_closure1
-                def d = {                        // t$_run_closure1_closure3
+                def d = {                        // t$_run_closure1$_closure3
                     def o = new Object() {       // t$1
                         void run() {             //
-                            def f = {}           // t$_1_run_closure1
+                            def f = {}           // t$1$_run_closure1
                         }                        //
                     }                            //
-                    def e = {}                   // t$_run_closure1_closure3_closure4
+                    def e = {}                   // t$_run_closure1$_closure3$_closure4
                 }                                //
             }                                    //
             def g = {}                           // t$_run_closure2
@@ -57,11 +72,41 @@ class ClosureAndInnerClassNodeStructureTest extends GroovyTestCase {
             }]
         }
 
-        assertParentOf 't$1'                               isClass 't'
-        assertParentOf 't$_1_run_closure1'                 isClass 't$1'
-        assertParentOf 't$_run_closure1'                   isClass 't'
-        assertParentOf 't$_run_closure2'                   isClass 't'
-        assertParentOf 't$_run_closure1_closure3'          isClass 't$_run_closure1'
-        assertParentOf 't$_run_closure1_closure3_closure4' isClass 't$_run_closure1_closure3'
+        assertParentOf 't$1'                                 isClass 't'
+        assertParentOf 't$1$_run_closure1'                   isClass 't$1'
+        assertParentOf 't$_run_closure1'                     isClass 't'
+        assertParentOf 't$_run_closure2'                     isClass 't'
+        assertParentOf 't$_run_closure1$_closure3'           isClass 't$_run_closure1'
+        assertParentOf 't$_run_closure1$_closure3$_closure4' isClass 't$_run_closure1$_closure3'
+    }
+
+    // GROOVY-5351
+    void testGetSimpleName() {
+        assertScript '''
+            class X {
+                static class Y {
+                    def foo() {
+                        def cl = {return{}}
+                        def cl2 = cl()
+                        [cl.getClass().getSimpleName(), cl2.getClass().getSimpleName()]
+                    }
+                }
+            }
+            def simpleNames = new X.Y().foo()
+            assert simpleNames == ['_foo_closure1', '_closure2']
+        '''
+    }
+
+    //GROOVY-7119 && GROOVY-7120
+    void testIrregularMethodName() {
+        assertScript '''
+            class X {
+                def 'foo!bar'() {
+                    return {}
+                }
+            }
+            def str = new X().'foo!bar'().getClass().getName()
+            assert str == 'X$_foo_bar_closure1'
+        '''
     }
 }
diff --git a/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java b/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java
index 8525661..ef7c904 100644
--- a/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java
+++ b/src/test/org/codehaus/groovy/antlr/treewalker/Java2GroovyTest.java
@@ -18,7 +18,7 @@
 package org.codehaus.groovy.antlr.treewalker;
 
 import groovy.util.GroovyTestCase;
-import org.codehaus.groovy.antlr.java.Java2GroovyMain;
+import org.codehaus.groovy.antlr.java.Java2GroovyProcessor;
 
 public class Java2GroovyTest extends GroovyTestCase {
 
@@ -32,15 +32,15 @@ public class Java2GroovyTest extends GroovyTestCase {
     }
 
     private String convert(String input) throws Exception {
-        return Java2GroovyMain.convert("Java2GroovyTest.java", input);
+        return Java2GroovyProcessor.convert("Java2GroovyTest.java", input);
     }
 
     private String mindmap(String input) throws Exception {
-        return Java2GroovyMain.mindmap(input);
+        return Java2GroovyProcessor.mindmap(input);
     }
 
     private String nodePrinter(String input) throws Exception {
-        return Java2GroovyMain.nodePrinter(input);
+        return Java2GroovyProcessor.nodePrinter(input);
     }
 }
 
diff --git a/src/test/org/codehaus/groovy/ast/ASTTest.java b/src/test/org/codehaus/groovy/ast/ASTTest.java
index 8558597..4e5f60e 100644
--- a/src/test/org/codehaus/groovy/ast/ASTTest.java
+++ b/src/test/org/codehaus/groovy/ast/ASTTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast;
 
 import junit.framework.TestCase;
diff --git a/src/test/org/codehaus/groovy/ast/CodeVisitorSupportTest.groovy b/src/test/org/codehaus/groovy/ast/CodeVisitorSupportTest.groovy
index fa3932b..f936f4d 100644
--- a/src/test/org/codehaus/groovy/ast/CodeVisitorSupportTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/CodeVisitorSupportTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast;
 
 
diff --git a/src/test/org/codehaus/groovy/ast/LazyInitOnClassNodeTest.groovy b/src/test/org/codehaus/groovy/ast/LazyInitOnClassNodeTest.groovy
index 638cc9c..7fc493c 100644
--- a/src/test/org/codehaus/groovy/ast/LazyInitOnClassNodeTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/LazyInitOnClassNodeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import org.codehaus.groovy.ast.*
 
 class LazyInitOnClassNodeTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/ast/LineColumnChecker.java b/src/test/org/codehaus/groovy/ast/LineColumnChecker.java
index 58f4c8b..4513583 100644
--- a/src/test/org/codehaus/groovy/ast/LineColumnChecker.java
+++ b/src/test/org/codehaus/groovy/ast/LineColumnChecker.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast;
 
 import java.util.List;
diff --git a/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy b/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
index 8c7dceb..665fb97 100644
--- a/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/MethodNodeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast;
 
 import org.codehaus.groovy.ast.builder.AstBuilder;
diff --git a/src/test/org/codehaus/groovy/ast/VariableExpressionTest.java b/src/test/org/codehaus/groovy/ast/VariableExpressionTest.java
index 862dc0e..dbb4123 100644
--- a/src/test/org/codehaus/groovy/ast/VariableExpressionTest.java
+++ b/src/test/org/codehaus/groovy/ast/VariableExpressionTest.java
@@ -1,4 +1,19 @@
 /**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/**
  * 
  */
 package org.codehaus.groovy.ast;
diff --git a/src/test/org/codehaus/groovy/ast/builder/AstBuilderFromSpecificationTest.groovy b/src/test/org/codehaus/groovy/ast/builder/AstBuilderFromSpecificationTest.groovy
index f0749de..7ece6c9 100644
--- a/src/test/org/codehaus/groovy/ast/builder/AstBuilderFromSpecificationTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/builder/AstBuilderFromSpecificationTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -102,7 +102,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testArgumentListExpression_NoArgs() {
 
         def result = new AstBuilder().buildFromSpec {
@@ -113,7 +112,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testArgumentListExpression_OneListArg() {
 
         def result = new AstBuilder().buildFromSpec {
@@ -135,7 +133,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testAttributeExpression() {
 
         // represents foo.bar attribute invocation
@@ -153,7 +150,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     /**
      * Test for code:
      * if (foo == bar) println "Hello" else println "World"
@@ -222,7 +218,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testDeclarationAndListExpression() {
 
         // represents def foo = [1, 2, 3]
@@ -250,7 +245,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testArrayExpression() {
 
         // new Integer[]{1, 2, 3}
@@ -272,7 +266,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testBitwiseNegationExpression() {
         def result = new AstBuilder().buildFromSpec {
             bitwiseNegation {
@@ -344,7 +337,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testClosureExpression_MultipleParameters() {
 
         // { x,y,z -> println z }
@@ -412,7 +404,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testNotExpression() {
         // !true
         def result = new AstBuilder().buildFromSpec {
@@ -428,7 +419,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testPostfixExpression() {
         // 1++
         def result = new AstBuilder().buildFromSpec {
@@ -446,7 +436,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testPrefixExpression() {
         // ++1
         def result = new AstBuilder().buildFromSpec {
@@ -479,7 +468,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testUnaryPlusExpression() {
         // (+foo)
         def result = new AstBuilder().buildFromSpec {
@@ -515,31 +503,32 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testFieldExpression() {
         // public static String foo = "a value"
         def result = new AstBuilder().buildFromSpec {
             field {
                 fieldNode "foo", ACC_PUBLIC | ACC_STATIC, String, this.class, {
                     constant "a value"
+                    annotations {
+                        annotation Deprecated
+                    }
                 }
             }
         }
 
-        def expected = new FieldExpression(
-                new FieldNode(
-                        "foo",
-                        ACC_PUBLIC | ACC_STATIC,
-                        ClassHelper.make(String, false),
-                        ClassHelper.make(this.class, false),
-                        new ConstantExpression("a value")
-                )
+        def fieldNode = new FieldNode(
+                "foo",
+                ACC_PUBLIC | ACC_STATIC,
+                ClassHelper.make(String, false),
+                ClassHelper.make(this.class, false),
+                new ConstantExpression("a value")
         )
+        fieldNode.addAnnotation(new AnnotationNode(ClassHelper.make(Deprecated, false)))
+        def expected = new FieldExpression(fieldNode)
 
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testMapAndMapEntryExpression() {
 
         // [foo: 'bar', baz: 'buz']
@@ -556,18 +545,10 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
             }
         }
 
-        def expected = new MapExpression(
-                [
-                        new MapEntryExpression(
-                                new ConstantExpression('foo'),
-                                new ConstantExpression('bar')
-                        ),
-                        new MapEntryExpression(
-                                new ConstantExpression('baz'),
-                                new ConstantExpression('buz')
-                        ),
-                ]
-        )
+        def expected = new MapExpression([
+                new MapEntryExpression(new ConstantExpression('foo'), new ConstantExpression('bar')),
+                new MapEntryExpression(new ConstantExpression('baz'), new ConstantExpression('buz')),
+        ])
 
         AstAssert.assertSyntaxTree([expected], result)
     }
@@ -583,31 +564,16 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
             }
         }
 
-        def expected = new MapExpression(
-                [
-                        new MapEntryExpression(
-                                new ConstantExpression('foo'),
-                                new ConstantExpression('bar')
-                        ),
-                        new MapEntryExpression(
-                                new ConstantExpression('baz'),
-                                new ConstantExpression('buz')
-                        ),
-                        new MapEntryExpression(
-                                new ConstantExpression('qux'),
-                                new ConstantExpression('quux')
-                        ),
-                        new MapEntryExpression(
-                                new ConstantExpression('corge'),
-                                new ConstantExpression('grault')
-                        ),
-                ]
-        )
+        def expected = new MapExpression([
+                new MapEntryExpression(new ConstantExpression('foo'), new ConstantExpression('bar')),
+                new MapEntryExpression(new ConstantExpression('baz'), new ConstantExpression('buz')),
+                new MapEntryExpression(new ConstantExpression('qux'), new ConstantExpression('quux')),
+                new MapEntryExpression(new ConstantExpression('corge'), new ConstantExpression('grault')),
+        ])
 
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testGStringExpression() {
         // "$foo"
         def result = new AstBuilder().buildFromSpec {
@@ -632,7 +598,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testMethodPointerExpression() {
         // Integer.&toString
         def result = new AstBuilder().buildFromSpec {
@@ -650,7 +615,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testRangeExpression() {
         // (0..10)
         def result = new AstBuilder().buildFromSpec {
@@ -721,7 +685,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testSwitchAndCaseAndBreakStatements() {
         /*
                   switch (foo) {
@@ -820,7 +783,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testAssertStatement() {
         /*
                   assert true : "should always be true"
@@ -901,7 +863,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testTryCatchAndCatchAndThrowStatements() {
         /*
                   try {
@@ -954,7 +915,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testFinallyStatement() {
         /*
                   try {
@@ -1011,7 +971,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testForStatementAndClosureListExpression() {
         /*
               for (int x = 0; x < 10; x++) {
@@ -1091,7 +1050,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testStaticMethodCallExpression_MethodAsString() {
         // Math.min(1,2)
         def result = new AstBuilder().buildFromSpec {
@@ -1138,7 +1096,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testSpreadExpression() {
         // ['foo', *['bar','baz']]
         def result = new AstBuilder().buildFromSpec {
@@ -1166,7 +1123,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testSpreadMapExpression() {
         // func (*:m)
         def result = new AstBuilder().buildFromSpec {
@@ -1186,9 +1142,7 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
                 new VariableExpression('this', ClassHelper.make(Object, false)),
                 'func',
                 new MapEntryExpression(
-                        new SpreadMapExpression(
-                                new VariableExpression('m', ClassHelper.make(Object, false))
-                        ),
+                        new SpreadMapExpression(new VariableExpression('m', ClassHelper.make(Object, false))),
                         new VariableExpression('m', ClassHelper.make(Object, false))
                 )
 
@@ -1197,7 +1151,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testTernaryExpression() {
         // true ? "male" : "female"
         def result = new AstBuilder().buildFromSpec {
@@ -1211,9 +1164,7 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         }
 
         def expected = new TernaryExpression(
-                new BooleanExpression(
-                        new ConstantExpression(true)
-                ),
+                new BooleanExpression(new ConstantExpression(true)),
                 new ConstantExpression('male'),
                 new ConstantExpression('female')
         )
@@ -1221,7 +1172,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testDoWhileStatement() {
         // DoWhileStatement doesn't seemed to be used, and the do/while source doesn't compile either
     }
@@ -1322,7 +1272,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testElvisOperatorExpression() {
         // name ?: 'Anonymous'
         def result = new AstBuilder().buildFromSpec {
@@ -1340,7 +1289,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testNamedArgumentListExpression() {
         // new String(foo: 'bar')
 
@@ -1564,6 +1512,84 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
+    public void testClassWithMethods() {
+        // class MyClass {
+        //   String myProp = 'foo'
+        //   String myMethod(String parameter) throws IOException { 'some result' }
+        //   String myOtherMethod() { 'some other result' }
+        // }
+
+        def result = new AstBuilder().buildFromSpec {
+            classNode 'MyClass', ACC_PUBLIC, {
+                classNode Object        //superclass
+                interfaces {
+                    classNode GroovyObject
+                }
+                mixins {}
+                methods {
+                    method('myMethod', ACC_PUBLIC, String) {
+                        parameters {
+                            parameter 'parameter': String
+                        }
+                        exceptions {
+                            classNode IOException
+                        }
+                        block {
+                            returnStatement {
+                                constant 'some result'
+                            }
+                        }
+                    }
+                    method('myOtherMethod', ACC_PUBLIC, String) {
+                        parameters {}
+                        exceptions {}
+                        block {
+                            returnStatement {
+                                constant 'some other result'
+                            }
+                        }
+                    }
+                }
+                properties {
+                    propertyNode "myProp", ACC_PUBLIC, String, this.class, {
+                        constant "foo"
+                        annotations {
+                            annotation Deprecated
+                        }
+                    }
+                }
+                annotations {
+                    annotation Deprecated
+                }
+            }
+        }
+
+        def expected = new ClassNode("MyClass", ACC_PUBLIC, ClassHelper.make(Object, false))
+        expected.addAnnotation(new AnnotationNode(ClassHelper.make(Deprecated, false)))
+        def pNode = new PropertyNode("myProp", ACC_PUBLIC, ClassHelper.make(String, false),
+                ClassHelper.make(this.class, false), new ConstantExpression("foo"), null, null)
+        pNode.addAnnotation(new AnnotationNode(ClassHelper.make(Deprecated, false)))
+        expected.addProperty(pNode)
+        expected.addMethod(new MethodNode(
+                "myMethod",
+                ACC_PUBLIC,
+                ClassHelper.make(String, false),
+                [new Parameter(ClassHelper.make(String, false), "parameter")] as Parameter[],
+                [ClassHelper.make(IOException, false)] as ClassNode[],
+                new BlockStatement(
+                        [new ReturnStatement(new ConstantExpression('some result'))], new VariableScope()
+                )))
+        expected.addMethod(new MethodNode(
+                "myOtherMethod",
+                ACC_PUBLIC,
+                ClassHelper.make(String, false),
+                [] as Parameter[],
+                [] as ClassNode[],
+                new BlockStatement(
+                        [new ReturnStatement(new ConstantExpression('some other result'))], new VariableScope()
+                )))
+        AstAssert.assertSyntaxTree([expected], result)
+    }
 
     public void testGenericsType_WithLowerBounds() {
         // class MyClass<T, U extends Number> {}
@@ -1663,7 +1689,6 @@ public class AstBuilderFromSpecificationTest extends GroovyTestCase {
         AstAssert.assertSyntaxTree([expected], result)
     }
 
-
     public void testAnnotation_WithParameter() {
         // @org.junit.Test(timeout=50L) def myMethod() {}
         def result = new AstBuilder().buildFromSpec {
diff --git a/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy b/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
index b30af97..347052a 100644
--- a/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/expr/ClosureExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.expr
 
 import org.codehaus.groovy.ast.builder.AstBuilder
diff --git a/src/test/org/codehaus/groovy/ast/expr/MapExpressionTest.groovy b/src/test/org/codehaus/groovy/ast/expr/MapExpressionTest.groovy
index ea8a263..4ef972d 100644
--- a/src/test/org/codehaus/groovy/ast/expr/MapExpressionTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/expr/MapExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.expr
 
 import org.codehaus.groovy.ast.builder.AstBuilder
diff --git a/src/test/org/codehaus/groovy/ast/expr/MethodCallExpressionTest.groovy b/src/test/org/codehaus/groovy/ast/expr/MethodCallExpressionTest.groovy
index 7027cec..91b3042 100644
--- a/src/test/org/codehaus/groovy/ast/expr/MethodCallExpressionTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/expr/MethodCallExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.expr
 
 /**
diff --git a/src/test/org/codehaus/groovy/ast/expr/PropertyExpressionTest.groovy b/src/test/org/codehaus/groovy/ast/expr/PropertyExpressionTest.groovy
index 086a42a..1724a9b 100644
--- a/src/test/org/codehaus/groovy/ast/expr/PropertyExpressionTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/expr/PropertyExpressionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.expr
 
 /**
diff --git a/src/test/org/codehaus/groovy/ast/source/Groovy3049Test.groovy b/src/test/org/codehaus/groovy/ast/source/Groovy3049Test.groovy
index c04db16..f401324 100644
--- a/src/test/org/codehaus/groovy/ast/source/Groovy3049Test.groovy
+++ b/src/test/org/codehaus/groovy/ast/source/Groovy3049Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.source
 
 
diff --git a/src/test/org/codehaus/groovy/ast/source/Groovy3050Test.groovy b/src/test/org/codehaus/groovy/ast/source/Groovy3050Test.groovy
index 7a1c11f..94eb8d7 100644
--- a/src/test/org/codehaus/groovy/ast/source/Groovy3050Test.groovy
+++ b/src/test/org/codehaus/groovy/ast/source/Groovy3050Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.source
 
 
diff --git a/src/test/org/codehaus/groovy/ast/source/Groovy3051Test.groovy b/src/test/org/codehaus/groovy/ast/source/Groovy3051Test.groovy
index 40dac26..668262e 100644
--- a/src/test/org/codehaus/groovy/ast/source/Groovy3051Test.groovy
+++ b/src/test/org/codehaus/groovy/ast/source/Groovy3051Test.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.source
 
 
diff --git a/src/test/org/codehaus/groovy/ast/source/SourceBaseTestCase.groovy b/src/test/org/codehaus/groovy/ast/source/SourceBaseTestCase.groovy
index c37aaa3..c3b6e3c 100644
--- a/src/test/org/codehaus/groovy/ast/source/SourceBaseTestCase.groovy
+++ b/src/test/org/codehaus/groovy/ast/source/SourceBaseTestCase.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ast.source
 
 import org.codehaus.groovy.control.*
diff --git a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
index e1260bd..178669e 100644
--- a/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
+++ b/src/test/org/codehaus/groovy/ast/tools/WideningCategoriesTest.groovy
@@ -326,6 +326,15 @@ class WideningCategoriesTest extends GenericsTestCase {
 
     }
 
+    void testLUBOfArrayTypes() {
+        def typeA = extractTypesFromCode('Number[] type').type
+        def typeB = extractTypesFromCode('Integer[] type').type
+        def superType = lowestUpperBound(typeA, typeB)
+        assert superType.isArray()
+        def component = superType.getComponentType()
+        assert component == make(Number)
+    }
+
     // ---------- Classes and Interfaces used in this unit test ----------------
     private static interface InterfaceA {}
     private static interface InterfaceB {}
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/binarytrees.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/binarytrees.groovy
index 0b8a56d..136c3f9 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/binarytrees.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/binarytrees.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /* The Computer Language Benchmarks Game
    http://shootout.alioth.debian.org/
    contributed by Jochen Hinrichsen.
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/fannkuch.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/fannkuch.groovy
index a014567..68ee747 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/fannkuch.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/fannkuch.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 /* The Computer Language Benchmarks Game
    http://shootout.alioth.debian.org/
    contributed by Brian Schlining
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/partialsums.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/partialsums.groovy
index 2ac2f7b..371b4c8 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/partialsums.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/partialsums.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import java.text.DecimalFormat
 
 // ---------------------------------------------------------------------
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/rayTracer.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/rayTracer.groovy
index 45c3088..c2397d2 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/rayTracer.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/rayTracer.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // translated from http://www.ffconsultancy.com/languages/ray_tracer/code/1/ray.java
 // by Derek Young -  Sep 6, 07
 
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/recursive.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/recursive.groovy
index 333b1da..29fd8af 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/recursive.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/recursive.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // ---------------------------------------------------------------------
 // The Great Computer Language Shootout
 // http://shootout.alioth.debian.org/
diff --git a/src/test/org/codehaus/groovy/benchmarks/alioth/spectralnorm.groovy b/src/test/org/codehaus/groovy/benchmarks/alioth/spectralnorm.groovy
index c9c574c..2c03514 100644
--- a/src/test/org/codehaus/groovy/benchmarks/alioth/spectralnorm.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/alioth/spectralnorm.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
     The Computer Language Shootout
     http://shootout.alioth.debian.org/
 
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Builder.java b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Builder.java
index 534a4af..86ac0d0 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Builder.java
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Builder.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.benchmarks.vm5.b2394;
 
 public class Builder
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Main.java b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Main.java
index 46d0b0b..c8d6e03 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Main.java
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/Main.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.benchmarks.vm5.b2394;
 
 import groovy.lang.GroovyClassLoader;
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/ScriptLauncher.java b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/ScriptLauncher.java
index 68000fc..7f2b77e 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/ScriptLauncher.java
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/ScriptLauncher.java
@@ -1,7 +1,23 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.benchmarks.vm5.b2394;
 
 import groovy.lang.Binding;
 import groovy.lang.Script;
+import org.codehaus.groovy.runtime.InvokerHelper;
 
 import java.util.concurrent.CountDownLatch;
 
@@ -34,18 +50,10 @@ public class ScriptLauncher extends Thread
         {
             Builder builder = new Builder();
 
-            try
-            {
-                script = (Script)scriptClass.newInstance();
-            }
-            catch (Exception e)
-            {
-                e.printStackTrace();
-            }
-
             Binding binding = new Binding();
             binding.setVariable("builder", builder);
-            script.setBinding(binding);
+
+            script = InvokerHelper.createScript(scriptClass, binding);
 
             script.run();
         }
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script120.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script120.groovy
index 8d8b293..fb641e2 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script120.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script120.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 builder.add("3", "1")
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script240.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script240.groovy
index f722689..87b992e 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script240.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script240.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 builder.add("3", "1")
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script30.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script30.groovy
index 1e139b9..46b609c 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script30.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script30.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 builder.add("3", "1")
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300.groovy
index ca954e3..4b2506f 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 builder.add("3", "1")
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300WithCategory.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300WithCategory.groovy
index 9d19250..d6ba274 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300WithCategory.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script300WithCategory.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 use (Object) {
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script60.groovy b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script60.groovy
index c7d041a..520e9da 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script60.groovy
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/b2394/script60.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 builder.add("3", "1")
 builder.add("3", "1")
 builder.add("3", "1")
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/psum.java b/src/test/org/codehaus/groovy/benchmarks/vm5/psum.java
index 009073b..7d1759d 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/psum.java
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/psum.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.benchmarks.vm5;
 
 class psum {
diff --git a/src/test/org/codehaus/groovy/benchmarks/vm5/spectralnorm.java b/src/test/org/codehaus/groovy/benchmarks/vm5/spectralnorm.java
index 15dfac7..1e0a653 100644
--- a/src/test/org/codehaus/groovy/benchmarks/vm5/spectralnorm.java
+++ b/src/test/org/codehaus/groovy/benchmarks/vm5/spectralnorm.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.benchmarks.vm5;
 /*
  The Great Computer Language Shootout
diff --git a/src/test/org/codehaus/groovy/classgen/GenericsGenTest.groovy b/src/test/org/codehaus/groovy/classgen/GenericsGenTest.groovy
index 51e93e8..34d69de 100644
--- a/src/test/org/codehaus/groovy/classgen/GenericsGenTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/GenericsGenTest.groovy
@@ -71,7 +71,7 @@ class GenericsGenTest extends GroovyTestCase {
         config.targetDirectory = createTempDir("groovy-target-", "-target")
         config.jointCompilationOptions = [
                 "stubDir": createTempDir("groovy-stub-", "-stub"),
-                "namedValues": ["target", "1.5", "source", "1.5"] as String[]
+                "namedValues": ["target", "1.6", "source", "1.6"] as String[]
         ]
         config.classpath = "target/classes"
         FileSystemCompiler compiler = new FileSystemCompiler(config)
diff --git a/src/test/org/codehaus/groovy/classgen/asm/AbstractBytecodeTestCase.groovy b/src/test/org/codehaus/groovy/classgen/asm/AbstractBytecodeTestCase.groovy
index c14bf37..c989ae9 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/AbstractBytecodeTestCase.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/AbstractBytecodeTestCase.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 import org.codehaus.groovy.control.CompilationUnit
diff --git a/src/test/org/codehaus/groovy/classgen/asm/BinaryOperationsTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/BinaryOperationsTest.groovy
index f9d72bf..feaf766 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/BinaryOperationsTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/BinaryOperationsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 import static org.codehaus.groovy.control.CompilerConfiguration.DEFAULT as config
diff --git a/src/test/org/codehaus/groovy/classgen/asm/DirectMethodCallTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/DirectMethodCallTest.groovy
index c4a3480..c4cb359 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/DirectMethodCallTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/DirectMethodCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 import org.codehaus.groovy.ast.ClassHelper
diff --git a/src/test/org/codehaus/groovy/classgen/asm/HotSwapTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/HotSwapTest.groovy
index 8004429..d168269 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/HotSwapTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/HotSwapTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 import static org.codehaus.groovy.control.CompilerConfiguration.DEFAULT as config
@@ -10,7 +25,7 @@ class HotSwapTest extends AbstractBytecodeTestCase {
     void testHotSwapMethodExistsAndCallsGetCallSiteArray() {
         if (config.optimizationOptions.indy) return;
         assert compile(method: '__$swapInit', '''
-            double d = 1d
+            Long d = 123456L
         ''').hasSequence([
                 'ACONST_NULL',
                 'PUTSTATIC script.$callSiteArray : Ljava/lang/ref/SoftReference;'
@@ -19,7 +34,7 @@ class HotSwapTest extends AbstractBytecodeTestCase {
     
     void testClinitCallingHotSwapMethod() {
         assert compile(method: '<clinit>', '''
-            double d = 1d
+             Long d = 123456L
         ''').hasSequence([
                 'INVOKESTATIC script.__$swapInit ()V'
         ])
diff --git a/src/test/org/codehaus/groovy/classgen/asm/InstructionSequenceHelperClassTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/InstructionSequenceHelperClassTest.groovy
index 9e9fa98..0d01f28 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/InstructionSequenceHelperClassTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/InstructionSequenceHelperClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 /**
diff --git a/src/test/org/codehaus/groovy/classgen/asm/MethodPatternsTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/MethodPatternsTest.groovy
index 73b952b..cc5b287 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/MethodPatternsTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/MethodPatternsTest.groovy
@@ -347,6 +347,15 @@ class MethodPatternsTest extends AbstractBytecodeTestCase {
             'IADD',
             'IRETURN'
         ])
+
+        // check that there is no fastpath for this method, since n is Object
+        def seq = compile(method: "fib", """
+            def fib(n) {
+                n<=2L?n:fib(n-1L)+fib(n-2L)
+            }
+        """).toSequence()
+        // isOrigXY is used for the fastpath guards
+        assert !seq.contains("isOrig")
     }
 
     void testNoBoxUnbox() {
diff --git a/src/test/org/codehaus/groovy/classgen/asm/PrintlnLoadsAConstantTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/PrintlnLoadsAConstantTest.groovy
index 47e1d97..3158e25 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/PrintlnLoadsAConstantTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/PrintlnLoadsAConstantTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm
 
 /**
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
index 74ab852..3148691 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/ArraysAndCollectionsStaticCompileTest.groovy
@@ -76,5 +76,14 @@ class ArraysAndCollectionsStaticCompileTest extends ArraysAndCollectionsSTCTest
             assert map['bytes'] == 'TEST'
         '''
     }
+
+    @Override
+    void testForInLoop() {
+        try {
+            super.testForInLoop()
+        } finally {
+            println astTrees
+        }
+    }
 }
 
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
index 6b76666..a1da36d 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/FieldsAndPropertiesStaticCompileTest.groovy
@@ -179,7 +179,7 @@ class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCTest im
                 assert b.isSetterCalled() == true
                 assert b.x == 2
             '''
-        assert astTrees['B'][1].contains('INVOKEVIRTUAL A.setX')
+        assert astTrees['B'][1].contains('INVOKEVIRTUAL B.setX')
     }
 
     void testDirectReadFieldFromSameClass() {
@@ -257,7 +257,7 @@ class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCTest im
                     b.usingGetter()
                     assert b.isGetterCalled() == true
                 '''
-        assert astTrees['B'][1].contains('INVOKEVIRTUAL A.getX')
+        assert astTrees['B'][1].contains('INVOKEVIRTUAL B.getX')
     }
 
     void testUseAttributeExternal() {
@@ -429,4 +429,90 @@ class FieldsAndPropertiesStaticCompileTest extends FieldsAndPropertiesSTCTest im
         '''
     }
 
+    @Override
+    void testPropertyWithMultipleSetters() {
+        // we need to override the test because the AST is going to be changed
+        assertScript '''import org.codehaus.groovy.ast.expr.BinaryExpression
+import org.codehaus.groovy.ast.expr.BooleanExpression
+import org.codehaus.groovy.ast.stmt.AssertStatement
+import org.codehaus.groovy.transform.sc.ListOfExpressionsExpression
+            class A {
+                private field
+                void setX(Integer a) {field=a}
+                void setX(String b) {field=b}
+                def getX(){field}
+            }
+
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                lookup('test1').each { stmt ->
+                    def exp = stmt.expression
+                    assert exp instanceof ListOfExpressionsExpression
+                }
+                lookup('test2').each { stmt ->
+                    def exp = stmt.expression
+                    assert exp instanceof ListOfExpressionsExpression
+                }
+            })
+            void testBody() {
+                def a = new A()
+                test1:
+                a.x = 1
+                assert a.x==1
+                test2:
+                a.x = "3"
+                assert a.x == "3"
+            }
+            testBody()
+            '''
+    }
+
+    void testCallSetterAsPropertyWithinFinallyBlockShouldNotThrowVerifyError() {
+        try {
+            assertScript '''
+            class Multi {
+               void setOut(int a) {}
+            }
+
+            void foo() {
+               def m = new Multi()
+               try {
+               } finally {
+                  m.out = 1
+               }
+            }
+            foo()
+            '''
+        } finally {
+            assert astTrees.values().any {
+                it.toString().contains 'INVOKEVIRTUAL Multi.setOut (I)V'
+            }
+        }
+    }
+
+    void testCallMultiSetterAsPropertyWithinFinallyBlockShouldNotThrowVerifyError() {
+        try {
+            assertScript '''
+            class Multi {
+               void setOut(int a) {}
+               void setOut(String a) {}
+            }
+
+            void foo() {
+               def m = new Multi()
+               try {
+               } finally {
+                  m.out = 1
+                  m.out = 'foo'
+               }
+            }
+            foo()
+            '''
+        } finally {
+            assert astTrees.values().any {
+                def code = it.toString()
+                code.contains('INVOKEVIRTUAL Multi.setOut (I)V') &&
+                        code.contains('INVOKEVIRTUAL Multi.setOut (Ljava/lang/String;)V')
+            }
+        }
+    }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/Groovy7222OptimizationsTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/Groovy7222OptimizationsTest.groovy
new file mode 100644
index 0000000..44b6597
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/Groovy7222OptimizationsTest.groovy
@@ -0,0 +1,108 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.classgen.asm.sc
+
+import com.sun.xml.internal.ws.org.objectweb.asm.Opcodes
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.expr.ConstantExpression
+import org.codehaus.groovy.ast.expr.DeclarationExpression
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.control.ErrorCollector
+import org.codehaus.groovy.control.SourceUnit
+import org.codehaus.groovy.syntax.Token
+import org.codehaus.groovy.syntax.Types
+import org.codehaus.groovy.transform.sc.StaticCompilationVisitor
+import org.codehaus.groovy.transform.sc.transformers.StaticCompilationTransformer
+
+class Groovy7222OptimizationsTest extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport  {
+    void testShouldOptimizeConstantInitialization() {
+        def values = [
+                (short) 2,
+                (byte) 2,
+                2i,
+                2.0G,
+                2.5G,
+                2.0f,
+                2.5f,
+                2.5d,
+                2L
+        ]
+        def types = [
+                ClassHelper.byte_TYPE,
+                ClassHelper.short_TYPE,
+                ClassHelper.int_TYPE,
+                ClassHelper.long_TYPE,
+                ClassHelper.float_TYPE,
+                ClassHelper.double_TYPE,
+
+                ClassHelper.Byte_TYPE,
+                ClassHelper.Short_TYPE,
+                ClassHelper.Integer_TYPE,
+                ClassHelper.Long_TYPE,
+                ClassHelper.Float_TYPE,
+                ClassHelper.Double_TYPE,
+
+                ClassHelper.BigInteger_TYPE,
+                ClassHelper.BigDecimal_TYPE
+        ]
+        // dummy source setup
+        ClassNode cn = new ClassNode('Foo', Opcodes.ACC_PUBLIC, ClassHelper.OBJECT_TYPE)
+        CompilerConfiguration conf = new CompilerConfiguration()
+        SourceUnit su = new SourceUnit('Foo.groovy', '', conf, new GroovyClassLoader(), new ErrorCollector(conf))
+        StaticCompilationTransformer transformer = new StaticCompilationTransformer(su, new StaticCompilationVisitor(su, cn))
+        [types,values].combinations { declarationType, value ->
+            DeclarationExpression dex = new DeclarationExpression(
+                    new VariableExpression("x", declarationType),
+                    Token.newSymbol(Types.EQUAL, -1, -1),
+                    new ConstantExpression(value,true)
+            )
+            def optimized = transformer.transform(dex)
+            assert optimized instanceof DeclarationExpression
+            def varType = optimized.leftExpression.originType
+            def constantType = optimized.rightExpression.type
+            assert varType == constantType
+        }
+
+    }
+
+    void testShouldNotContainBigDecimalInBytecode() {
+        try {
+            assertScript '''
+                double d = 2.5 // forgot to add the 'd' so normally implies new BigDecimal
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /BigDecimal/ }.value[1]
+            assert bytecode.contains('LDC 2.5')
+            assert bytecode.contains('DSTORE')
+            assert !bytecode.contains('java/math/BigDecimal')
+        }
+    }
+
+    void testShouldNotThrowNPE() {
+        assertScript '''
+            @groovy.transform.CompileStatic
+            void foo() {
+              Double d = null
+            }
+
+            foo()
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/MethodCallsStaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/MethodCallsStaticCompilationTest.groovy
index dd42929..69e78da 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/MethodCallsStaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/MethodCallsStaticCompilationTest.groovy
@@ -177,4 +177,52 @@ import groovy.transform.TypeCheckingMode//import org.codehaus.groovy.classgen.as
         ''', 'Cannot call private constructor'
     }
 
+    // GROOVY-7063
+    void testCallToProtectedMethodFromClosureInSubclassAndDifferentPackage() {
+        assertScript ''' import org.codehaus.groovy.classgen.asm.sc.MethodCallsStaticCompilationTest.Base
+
+        class Ext extends Base {
+
+            int doSomething() {
+                def c = {
+                    foo()
+                }
+                c.call()
+            }
+        }
+        def ext = new Ext()
+        assert ext.doSomething() == 123
+        '''
+    }
+
+    // GROOVY-7264
+    void testCallProtectedMethodWithGenericTypes() {
+        assertScript '''
+            import org.codehaus.groovy.classgen.asm.sc.MethodCallsStaticCompilationTest.BaseGeneric
+
+            class Ext extends BaseGeneric<Integer> {
+
+                int doSomething() {
+                    def c = {
+                        foo(123)
+                    }
+                    c.call()?1:0
+                }
+            }
+            def ext = new Ext()
+            assert ext.doSomething() == 1
+        '''
+    }
+
+    public static class Base {
+        protected int foo() {
+            123
+        }
+    }
+
+    public static class BaseGeneric<T> {
+        protected boolean foo(T t) {
+            true
+        }
+    }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
index e20a137..f312f90 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTest.groovy
@@ -1,6 +1,23 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
+import org.codehaus.groovy.control.CompilerConfiguration
+import org.codehaus.groovy.transform.stc.GroovyTypeCheckingExtensionSupport
 
 class StaticCompilationTest extends AbstractBytecodeTestCase {
     void testEmptyMethod() {
@@ -363,7 +380,307 @@ assert o.blah() == 'outer'
 ''').hasStrictSequence([
         'GETFIELD Outer$Inner.this$0',
         'INVOKEVIRTUAL Outer.getOuterProperty',
+        'DUP',
+        'ASTORE',
+        'ALOAD',
+        'ALOAD',
         'INVOKEVIRTUAL Holder.setValue'
 ])
     }
+
+    void testShouldOptimizeBytecodeByAvoidingCreationOfMopMethods() {
+        def shell = new GroovyShell()
+        def clazz = shell.evaluate '''
+            import groovy.transform.TypeCheckingMode
+            import groovy.transform.CompileStatic
+
+            @CompileStatic
+            class A {
+                def doSomething() { 'A' }
+            }
+
+            @CompileStatic
+            class B extends A {
+                def doSomething() { 'B' + super.doSomething() }
+            }
+
+            B
+        '''
+        assert clazz instanceof Class
+        assert clazz.name == 'B'
+        def mopMethods = clazz.declaredMethods.findAll { it.name =~ /(super|this)\$/ }
+        assert mopMethods.empty
+    }
+
+    void testShouldNotOptimizeBytecodeForMopMethodsBecauseOfSkip() {
+        def shell = new GroovyShell()
+        def clazz = shell.evaluate '''
+            import groovy.transform.TypeCheckingMode
+            import groovy.transform.CompileStatic
+
+            @CompileStatic
+            class A {
+                def doSomething() { 'A' }
+            }
+
+            @CompileStatic
+            class B extends A {
+                @CompileStatic(TypeCheckingMode.SKIP)
+                def doSomething() { 'B' + super.doSomething() }
+            }
+
+            B
+        '''
+        assert clazz instanceof Class
+        assert clazz.name == 'B'
+        def mopMethods = clazz.declaredMethods.findAll { it.name =~ /(super|this)\$/ }
+        assert !mopMethods.empty
+    }
+
+    // GROOVY-7124
+    void testUseInvokeVirtualPreferredOverInvokeInterface() {
+        assert compile([method: 'foo',classNamePattern:'B'], '''
+        interface A { void m() }
+        class B implements A {
+            void m() {}
+            @groovy.transform.CompileStatic
+            void foo() {
+                m()
+            }
+        }
+
+        ''').hasStrictSequence(['INVOKEVIRTUAL B.m'])
+    }
+
+    void testShouldNotTryToCastToSupposedDelegateType() {
+        assertScript '''
+            @groovy.transform.CompileStatic
+            class ClassCastOhNoes {
+               def foo(def o) {
+                   def cl = {
+                       delegate.getClass()
+                   }
+                   cl.delegate = o
+                   cl()
+               }
+            }
+            new ClassCastOhNoes().foo(100)
+        '''
+    }
+
+    void testShouldOptimizeCharInit() {
+        assert compile([method:'m'],'''
+        @groovy.transform.CompileStatic
+        void m() {
+            char c = 'x'
+        }
+        ''').hasStrictSequence([
+                'LINENUMBER 4',
+                'BIPUSH 120',
+                'ISTORE'
+        ])
+    }
+
+    void testShouldOptimizeCharComparison() {
+        assert compile([method:'m'],'''
+        @groovy.transform.CompileStatic
+        void m() {
+            char c1 = 'x'
+            char c2 = 'x'
+            boolean b = c1==c2
+        }
+        ''').hasSequence([
+                'LINENUMBER 4',
+                'BIPUSH 120',
+                'ISTORE',
+                'BIPUSH 120',
+                'ISTORE',
+                'ILOAD',
+                'ILOAD',
+                'IF_ICMPNE',
+        ])
+
+        // make sure the code passes
+        assertScript '''
+            @groovy.transform.CompileStatic
+            void m() {
+                char c1 = 'x'
+                char c2 = 'x'
+                boolean b = c1==c2
+                assert b
+                char c3 = 'z'
+                b = c1==c3
+                assert !b
+            }
+            m()
+        '''
+    }
+
+    void testForEachLoopOptimization() {
+        def loop_init = [
+                'ALOAD', // load array (might be more complex than just ALOAD in general case)
+                'DUP',
+                'ASTORE', // store array to local var
+                'ARRAYLENGTH', // get array len
+                'ISTORE', // store it to local var
+                'ICONST_0',
+                'ISTORE', // initialize loop index
+                'ILOAD', // load loop index
+                'ILOAD', // load array length
+                'IF_ICMPGE' // if greater or equal, end of loop
+        ]
+
+        // int[]
+        def intExample = '''
+        @groovy.transform.CompileStatic
+        void m(int[] arr) {
+            for (int i: arr) {
+               println(i)
+            }
+        }
+        m([1,2] as int[])
+        '''
+        assert compile([method:'m'], intExample).hasSequence([*loop_init,'IALOAD','ISTORE'])
+
+        // short[]
+        def shortExample = '''
+        @groovy.transform.CompileStatic
+        void m(short[] arr) {
+            for (short i: arr) {
+               println(i)
+            }
+        }
+        m([1,2] as short[])
+        '''
+        assert compile([method:'m'], shortExample).hasSequence([*loop_init,'SALOAD','ISTORE'])
+
+        // byte[]
+        def byteExample = '''
+        @groovy.transform.CompileStatic
+        void m(byte[] arr) {
+            for (byte i: arr) {
+               println(i)
+            }
+        }
+        m([1,2] as byte[])
+        '''
+        assert compile([method:'m'], byteExample).hasSequence([*loop_init,'BALOAD','ISTORE'])
+
+        // long[]
+        def longExample = '''
+        @groovy.transform.CompileStatic
+        void m(long[] arr) {
+            for (long i: arr) {
+               println(i)
+            }
+        }
+        m([1,2] as long[])
+        '''
+        assert compile([method:'m'], longExample).hasSequence([*loop_init,'LALOAD','LSTORE'])
+
+       // char[]
+        def charExample = '''
+        @groovy.transform.CompileStatic
+        void m(char[] arr) {
+            for (char i: arr) {
+               println(i)
+            }
+        }
+        m('foo'.toCharArray())
+        '''
+        assert compile([method:'m'], charExample).hasSequence([*loop_init,'CALOAD','ISTORE'])
+
+       // boolean[]
+        def boolExample = '''
+        @groovy.transform.CompileStatic
+        void m(boolean[] arr) {
+            for (boolean i: arr) {
+               println(i)
+            }
+        }
+        m([true,false] as boolean[])
+        '''
+        assert compile([method:'m'], boolExample).hasSequence([*loop_init,'BALOAD','ISTORE'])
+
+        // float[]
+        def floatExample = '''
+        @groovy.transform.CompileStatic
+        void m(float[] arr) {
+            for (float i: arr) {
+               println(i)
+            }
+        }
+        m([1.5f,2.0f] as float[])
+        '''
+        assert compile([method:'m'], floatExample).hasSequence([*loop_init,'FALOAD','FSTORE'])
+
+        // double[]
+        def doubleExample = '''
+        @groovy.transform.CompileStatic
+        void m(double[] arr) {
+            for (double i: arr) {
+               println(i)
+            }
+        }
+        m([1.1,2.2] as double[])
+        '''
+        assert compile([method:'m'], doubleExample).hasSequence([*loop_init,'DALOAD','DSTORE'])
+
+        // Any[]
+        def anyExample = '''
+        @groovy.transform.CompileStatic
+        void m(String[] arr) {
+            for (String i: arr) {
+               println(i)
+            }
+        }
+        m(['a','b'] as String[])
+        '''
+        assert compile([method:'m'], anyExample).hasSequence([*loop_init,'AALOAD','ASTORE'])
+
+        // now check that everything runs fine
+        [byteExample,shortExample, intExample, charExample, boolExample,
+         longExample, floatExample, doubleExample, anyExample].each { script ->
+            assertScript(script)
+        }
+    }
+
+    void testCompareWithCharOptimization() {
+        String code = '''
+        @groovy.transform.CompileStatic
+        boolean m(char[] arr) {
+            char c = arr[0]
+            ' '==c
+        }
+        assert m(' abc '.toCharArray()) == true
+        '''
+        assert compile([method:'m'],code).hasSequence(['BIPUSH','ILOAD','IF_ICMPNE'])
+        assertScript(code)
+
+        code = '''
+        @groovy.transform.CompileStatic
+        boolean m(char[] arr) {
+            char c = arr[0]
+            c==' '
+        }
+        assert m(' abc '.toCharArray()) == true
+        '''
+        assert compile([method:'m'],code).hasSequence(['ILOAD','BIPUSH','IF_ICMPNE'])
+        assertScript(code)
+    }
+
+    void testShouldRemoveUnnecessaryCast() {
+        assert compile([method:'m'],'''
+        @groovy.transform.CompileStatic
+        void m() {
+            char c = (char) 'x'
+        }
+        ''').hasStrictSequence([
+                'LINENUMBER 4',
+                'BIPUSH 120',
+                // No checkcast, but the idea is to check that further optimization was done
+                // because the RHS is no longer a CastExpression but a ConstantExpression
+                'ISTORE'
+        ])
+    }
 }
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
index c0a7e9c..c0da39a 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilationTestSupport.groovy
@@ -43,8 +43,7 @@ import org.codehaus.groovy.tools.GroovyClass
  *
  * @author Cedric Champeau
  */
- at Trait
-class StaticCompilationTestSupport {
+trait StaticCompilationTestSupport {
     Map<String, Object[]> astTrees
     CustomCompilationUnit compilationUnit
 
@@ -67,6 +66,12 @@ class StaticCompilationTestSupport {
         shell.loader = new CompilationUnitAwareGroovyClassLoader(this.getClass().classLoader, config, this)
     }
 
+    void tearDown() {
+        astTrees = null
+        compilationUnit = null
+        super.tearDown()
+    }
+
     void assertAndDump(String script) {
         try {
             assertScript(script)
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileArrayLengthAndGet.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileArrayLengthAndGet.groovy
index 40ac4ea..29ce9d0 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileArrayLengthAndGet.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileArrayLengthAndGet.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileCastOptimizationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileCastOptimizationTest.groovy
new file mode 100644
index 0000000..1128c42
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileCastOptimizationTest.groovy
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.classgen.asm.sc
+
+import groovy.transform.stc.DefaultGroovyMethodsSTCTest
+
+/**
+ * Unit tests for static compilation: DGM method calls.
+ *
+ * @author Cedric Champeau
+ */
+class StaticCompileCastOptimizationTest extends DefaultGroovyMethodsSTCTest implements StaticCompilationTestSupport {
+
+    void testShouldOptimizeAsTypeToSimpleCast() {
+        try {
+            assertScript '''
+                int x = 2
+                long y = x as long // asType, where it could be a cast
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('I2L')
+        }
+    }
+
+    void testShouldOptimizeCharToLongAsTypeToSimpleCast() {
+        try {
+            assertScript '''
+                char x = 2
+                long y = x as long // asType, where it could be a cast
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('I2L')
+        }
+    }
+
+    void testShouldOptimizeLongToCharAsTypeToSimpleCast() {
+        try {
+            assertScript '''
+                long x = 2L
+                char y = x as char // asType, where it could be a cast
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('L2I') && bytecode.contains('I2C')
+        }
+    }
+
+    void testShouldOptimizeListLiteralToArrayCast() {
+        try {
+            assertScript '''
+                def x = ['a','b','c'] as String[]
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('ANEWARRAY java/lang/String')
+        }
+    }
+
+    void testShouldOptimizeListLiteralToArrayCastWithIncompatibleElementType() {
+        try {
+            assertScript '''
+                def x = ['a','b',new Date()] as String[]
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('ANEWARRAY java/lang/String')
+        }
+    }
+
+    void testShouldOptimizeListLiteralToArrayCastThroughParameter() {
+        try {
+            assertScript '''
+                int foo(String[] args) {
+                    args.length
+                }
+                assert foo(['a','b',new Date()] as String[]) == 3
+            '''
+        } finally {
+            def bytecode = astTrees.entrySet().find { it.key =~ /ShouldOptimize/ }.value[1]
+            assert bytecode.contains('ANEWARRAY java/lang/String')
+        }
+    }
+}
+
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureCallTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureCallTest.groovy
index 695bd91..81b6dd2 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureCallTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileClosureCallTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileComparisonTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileComparisonTest.groovy
index 2895642..27ff558 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileComparisonTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileComparisonTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileDGMMethodTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileDGMMethodTest.groovy
index 66e6364..cae856c 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileDGMMethodTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileDGMMethodTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFieldAccessTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFieldAccessTest.groovy
index b10b448..2257970 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFieldAccessTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFieldAccessTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFlowTypingTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFlowTypingTest.groovy
index 47d0b29..5d662f6 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFlowTypingTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileFlowTypingTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileInnerClassTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileInnerClassTest.groovy
index e81546d..4ba7b6b 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileInnerClassTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileInnerClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileMathTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileMathTest.groovy
index 2cc231e..4a992ed 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileMathTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileMathTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileNullCompareOptimizationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileNullCompareOptimizationTest.groovy
index 598662e..8d7c647 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileNullCompareOptimizationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompileNullCompareOptimizationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilePostfixPrefixTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilePostfixPrefixTest.groovy
index 60d8278..6755c44 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilePostfixPrefixTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/StaticCompilePostfixPrefixTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/TupleConstructorStaticCompilationTest.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/TupleConstructorStaticCompilationTest.groovy
index 6938b45..d3f74d3 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/TupleConstructorStaticCompilationTest.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/TupleConstructorStaticCompilationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc
 
 import org.codehaus.groovy.classgen.asm.AbstractBytecodeTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6240Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6240Bug.groovy
new file mode 100644
index 0000000..f35ce04
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6240Bug.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy6240Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testGroovyAllowsIteratingOnMapDirectlyWithForEachLoop() {
+        assertScript '''
+            Map<String, Integer> map = [foo: 123, bar: 456]
+            for (entry in map) {
+                assert entry.key.reverse() in ['oof','rab']
+                assert entry.value * 2 in [246, 912]
+            }
+        '''
+    }
+
+    void testGroovyAllowsIteratingOnMapDirectlyWithForEachLoopCustomMapType() {
+        assertScript '''
+            class MyMap extends LinkedHashMap<String,Integer>{}
+            def map = new MyMap([foo: 123, bar: 456])
+            for (entry in map) {
+                assert entry.key.reverse() in ['oof','rab']
+                assert entry.value * 2 in [246, 912]
+            }
+        '''
+    }
+
+    // GROOVY-6123
+    void testGroovyAllowsIteratingOnEnumerationDirectlyWithForEachLoop() {
+        assertScript '''
+            Vector<String> v = new Vector<>()
+            v.add('ooo')
+            def en = v.elements()
+            for (e in en) {
+                assert e.toUpperCase() == 'OOO'
+            }
+            v.add('groovy')
+            en = v.elements()
+            for (e in en) {
+                assert e.toUpperCase() == 'OOO'
+                break
+            }
+
+            en = v.elements()
+            for (e in en) {
+                assert e.toUpperCase() in ['OOO','GROOVY']
+                if (e=='ooo') continue
+            }
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6411Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6411Bug.groovy
index 85096a4..9d81672 100644
--- a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6411Bug.groovy
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6411Bug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.classgen.asm.sc.bugs
 
 import groovy.transform.stc.StaticTypeCheckingTestCase
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6757Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6757Bug.groovy
new file mode 100644
index 0000000..1ea0957
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy6757Bug.groovy
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy6757Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testExplicitTypeHint() {
+        assertScript '''
+            @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                def ift = node.getNodeMetaData(INFERRED_TYPE)
+                assert ift == make(List)
+                def gt = ift.genericsTypes[0]
+                assert gt.type == STRING_TYPE
+            })
+            def list = Collections.<String>emptyList()
+            if (list) {
+              list.get(0).toUpperCase()
+            }
+        '''
+    }
+
+    void testExplicitTypeHintWithBoundedGenerics() {
+        // example from GROOVY-7307
+        assertScript '''
+            class A {
+                static <T extends Number> T id(T value) {
+                    value
+                }
+
+                // Narrower generic type: doesn't compile
+                static <U extends Integer> U id2(U value) {
+                    A.<U>id(value)
+                }
+            }
+            A
+        '''
+    }
+
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7039Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7039Bug.groovy
new file mode 100644
index 0000000..db5ac3a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7039Bug.groovy
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7039Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testAccessToPublicStaticFieldOfInterfaceFromClass() {
+        assertScript '''
+            interface Intf {
+                public static final int TRUTH = 42
+            }
+
+            class A implements Intf {}
+
+            int truth() { A.TRUTH }
+
+            assert truth() == 42
+
+        '''
+    }
+
+    void testAccessToPublicStaticFieldOfInterfaceFromSubClass() {
+        assertScript '''
+            interface Intf {
+                public static final int TRUTH = 42
+            }
+
+            class A implements Intf {}
+            class B extends A {}
+
+            int truth() { B.TRUTH }
+
+            assert truth() == 42
+
+        '''
+    }
+
+    void testAccessToPublicStaticFieldOfInterfaceFromSuperInterface() {
+        assertScript '''
+            interface Intf {
+                public static final int TRUTH = 42
+            }
+            interface SubIntf extends Intf {}
+
+            class A implements SubIntf {}
+            class B extends A {}
+
+            int truth() { B.TRUTH }
+
+            assert truth() == 42
+
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7041Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7041Bug.groovy
new file mode 100644
index 0000000..edd5276
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7041Bug.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7041Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldHandleSpreadOperatorInBinaryExpression() {
+        assertScript '''
+            List<String> myList = [ ]
+            if (myList*.isEmpty().any() && true) {
+                println 'hello'
+            }
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7042Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7042Bug.groovy
new file mode 100644
index 0000000..80985fe
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7042Bug.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7042Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testDoExtendTraitsShouldNotCreatePropertiesTwice() {
+        assertScript '''import org.codehaus.groovy.transform.trait.TraitComposer
+
+            trait MagicTrait {
+                int age
+            }
+            @ASTTest(phase=SEMANTIC_ANALYSIS,value={
+                node.addInterface(sourceUnit.AST.classes.find { it.name == 'MagicTrait' } )
+                TraitComposer.doExtendTraits(node, sourceUnit, compilationUnit)
+            })
+            class Magic {
+
+            }
+            def m = new Magic()
+            m.age = 35
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7072Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7072Bug.groovy
new file mode 100644
index 0000000..2e3df28
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7072Bug.groovy
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7072Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testSpreadSafeOperatorOnArray() {
+            assertScript '''
+                new File(System.getProperty('java.io.tmpdir','/tmp')).listFiles()*.name
+        '''
+    }
+
+
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7075Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7075Bug.groovy
new file mode 100644
index 0000000..d4b3307
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7075Bug.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7075Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotLooseSafeNavigationFlag() {
+            assertScript '''interface Y extends YParent {}
+
+interface YParent {
+    Integer getValue()
+}
+
+Y y = null
+def v = y?.value
+assert v == null
+        '''
+    }
+
+    void testShouldNotLooseSaveNavigationFlagWithDGM() {
+        assertScript '''
+            URL url = null
+            String text = url?.text
+            assert text==null
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7093Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7093Bug.groovy
new file mode 100644
index 0000000..14bd50f
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7093Bug.groovy
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7093Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testAssignmentOperatorShouldLeaveRHSOnStack() {
+        assertScript '''
+             def map = [:]
+             assert (map[0] = 1) == 1
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7098Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7098Bug.groovy
new file mode 100644
index 0000000..d90ba07
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7098Bug.groovy
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7098Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testForEachLoopWithIterable() {
+        assertScript '''
+Iterable<Object> toIterable(List list) {
+    return new Iterable<Object>() {
+        Iterator iterator() {
+            list.iterator()
+        }
+    }
+}
+
+List loopDirect(List list) {
+    List result = new ArrayList()
+    for (Object o : list) {
+        result.add(o)
+        result.add(o)
+    }
+    result
+}
+
+List loopIterable(List list) {
+    List result = new ArrayList()
+    for (Object o : toIterable(list)) {
+        result.add(o)
+        result.add(o)
+    }
+    result
+}
+
+def list = ['a','b']
+assert loopDirect(list) == ['a','a','b','b']
+assert loopIterable(list) == ['a','a','b','b']
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7133Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7133Bug.groovy
new file mode 100644
index 0000000..07a404b
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7133Bug.groovy
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7133Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldHandleArrayAsComponentType() {
+        try {
+            assertScript '''import org.codehaus.groovy.classgen.asm.sc.bugs.support.Groovy7133Support
+        def list = Groovy7133Support.list()
+        for (def ary : list) {
+            //assert ary.length == 1
+        }
+        '''
+        } finally {
+            println astTrees
+        }
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7138Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7138Bug.groovy
new file mode 100644
index 0000000..209f12b
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7138Bug.groovy
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7138Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testCallSuperFromAClosure() {
+        assertScript '''
+            class Top {
+               int x() { 3 }
+            }
+
+            class Bottom extends Top {
+               int x() {
+                  int y = 0
+                  def t = Thread.start { y=2*super.x() }
+                  t.join()
+                  y
+               }
+            }
+
+            assert new Bottom().x() == 6
+        '''
+    }
+
+    void testCallSuperFromAClosureWithParameter() {
+        assertScript '''
+            class Top {
+               int x(int y) { 3+y }
+            }
+
+            class Bottom extends Top {
+               int x(int d) {
+                  int y = 0
+                  def t = Thread.start { y=2*super.x(d) }
+                  t.join()
+                  y
+               }
+            }
+
+            assert new Bottom().x(4) == 14
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7145Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7145Bug.groovy
new file mode 100644
index 0000000..280994a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7145Bug.groovy
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7145Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldHandlerNullSafeOperatorOnPublicField() {
+        assertScript '''
+class SafeNavigation {
+
+    String name1
+    public String name2
+
+    public static void main(String[] args) {
+        SafeNavigation test
+
+        println test?.name1 // 'null'
+        println test?.name2 // NullPointerException
+    }
+}
+'''
+    }
+
+    void testShouldHandlerNullSafeOperatorOnPublicFieldOfPrimitiveType() {
+        assertScript '''
+class SafeNavigation {
+
+    int name1
+    public int name2
+
+    public static void main(String[] args) {
+        SafeNavigation test
+
+        println test?.name1 // 'null'
+        println test?.name2 // NullPointerException
+    }
+}
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7149Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7149Bug.groovy
new file mode 100644
index 0000000..7cb8a4c
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7149Bug.groovy
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7149Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldFindGetterFromInterface() {
+        assertScript '''
+            def test() {
+              I x = new ConcreteA()
+              I y = new ConcreteB()
+
+              assert "X is called $x.name" == 'X is called ConcreteA'
+              assert "Y is called $y.name" == 'Y is called ConcreteB'
+            }
+
+            public class ConcreteA extends Abstract {
+              String name = 'ConcreteA'
+            }
+
+            public class ConcreteB extends Abstract {
+              String name= 'ConcreteB'
+            }
+
+            abstract class Abstract implements I {
+              //abstract String getName()
+            }
+
+            interface I {
+              String getName()
+            }
+            test()
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7169Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7169Bug.groovy
new file mode 100644
index 0000000..6738dd4
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7169Bug.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7169Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotThrowIllegalAccessException() {
+        assertScript '''
+             Number[] ary
+             ary = [1] as Integer[]
+             ary[0] = 2
+             ary = [1] as Number[] // this line is responsible for an error thrown at the previous one!
+        '''
+    }
+
+    void testShouldAllowStoringNullInArray() {
+        assertScript '''
+             Number[] ary
+             ary = [1] as Integer[]
+             ary[0] = null
+             ary = [1] as Number[] // this line is responsible for an error thrown at the previous one!
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7210Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7210Bug.groovy
new file mode 100644
index 0000000..806d7cb
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7210Bug.groovy
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7210Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldPassCompilationEvenIfUsingBoxing() {
+        assertScript '''
+            Integer i = 0
+            int[] a = [0]
+            a[i] = 1
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7211Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7211Bug.groovy
new file mode 100644
index 0000000..61bff40
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7211Bug.groovy
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7211Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testIncorrectGenericTypeError() {
+        assertScript '''
+class Bug1Base<T> {
+    T t
+
+    T get(a, b=0) {
+        return t
+    }
+}
+
+Bug1Base<Integer> bug = new Bug1Base<Integer>(t:1)
+ at ASTTest(phase=INSTRUCTION_SELECTION,value={
+    assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
+})
+Integer t = bug.get(1)
+println t
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy
new file mode 100644
index 0000000..4112166
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7242Bug.groovy
@@ -0,0 +1,81 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7242Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testCallMethodOfTraitInsideClosure() {
+        assertScript '''
+            trait MyTrait {
+                def f() {
+                    ['a'].collect {String it -> f2(it)}
+                }
+
+                def f2(String s) {
+                    s.toUpperCase()
+                }
+            }
+
+            class A implements MyTrait {}
+            def a = new A()
+            assert a.f() == ['A']
+        '''
+    }
+
+    void testCallMethodOfTraitInsideClosureAndClosureParamTypeInference() {
+        assertScript '''
+            trait MyTrait {
+                def f() {
+                    ['a'].collect {f2(it)}
+                }
+
+                def f2(String s) {
+                    s.toUpperCase()
+                }
+            }
+
+            class A implements MyTrait {}
+            def a = new A()
+            assert a.f() == ['A']
+        '''
+    }
+
+    void testAccessTraitPropertyFromClosureInTrait() {
+        assertScript '''
+            trait MyTrait {
+                int x
+                def f() {
+                    [1].each { x = it }
+                }
+            }
+            class A implements MyTrait {}
+            def a = new A()
+            a.f()
+            assert a.x == 1
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7276Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7276Bug.groovy
new file mode 100644
index 0000000..f0337aa
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7276Bug.groovy
@@ -0,0 +1,92 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.NotYetImplemented
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7276Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldGoThroughPrivateBridgeAccessor() {
+            assertScript '''
+                class Foo {
+                    private i = 1
+                    def m() { new String().with {i}}
+                }
+                assert new Foo().m() == 1
+                class Bar extends Foo {}
+                assert new Bar().m() == 1
+        '''
+    }
+
+    void testShouldGoThroughPrivateBridgeMethod() {
+            assertScript '''
+                class Foo {
+                    private i = 1
+                    private def pvI() { i }
+                    def m() { new String().with {pvI()}}
+                }
+                assert new Foo().m() == 1
+                class Bar extends Foo {}
+                assert new Bar().m() == 1
+        '''
+    }
+
+    void testPrivateAccessInInnerClass() {
+        assertScript '''import groovy.transform.CompileStatic
+
+class Outer {
+    private static class Inner {
+
+        private Set<String> variablesToCheck = []
+
+        private void checkAssertions(String name) {
+            Runnable r = {
+                def candidates = variablesToCheck.findAll { it == name }
+            }
+            r.run()
+        }
+    }
+
+    static void test() {
+        new Inner().checkAssertions('name')
+    }
+}
+
+Outer.test()'''
+    }
+
+    @NotYetImplemented
+    // GROOVY-7304
+    void testShouldGoThroughPrivateBridgeAccessorWithWriteAccess() {
+            assertScript '''
+                class Foo {
+                    private int i = 1
+                    def m() { new String().with {++i}}
+                }
+                assert new Foo().m() == 2
+                class Bar extends Foo {}
+                assert new Bar().m() == 2
+        '''
+    }
+
+
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7298Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7298Bug.groovy
new file mode 100644
index 0000000..f6d15e1
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7298Bug.groovy
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7298Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotThrowNPEInTypeResolver() {
+            assertScript '''
+
+public <T> T tryToExecuteWithFreePort(Closure<T> closure) {
+    [1].each {
+        return executeLogicForAvailablePort(closure)
+    }
+}
+
+private <T> T executeLogicForAvailablePort(Closure<T> closure) {
+    return closure.call()
+}
+
+executeLogicForAvailablePort {}
+
+
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy
new file mode 100644
index 0000000..eba0a20
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7300Bug.groovy
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7300Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotThrowStackOverflow() {
+        assertScript '''
+class A {
+    private String field1 = 'test'
+
+    String getField1() {
+        return this.field1
+   }
+}
+
+class B extends A {
+    @Override
+    String getField1() {
+        super.field1
+    }
+}
+
+B b = new B()
+
+assert b.field1 == 'test'
+'''
+    }
+
+    void testShouldNotThrowStackOverflowWithSuper() {
+        assertScript '''
+class A {
+    private String field1 = 'test'
+
+    void setField1(String val) { field1 = val }
+
+    String getField1() {
+        return this.field1
+   }
+}
+
+class B extends A {
+    @Override
+    String getField1() {
+        super.field1 = 'test 2'
+        super.field1
+    }
+}
+
+B b = new B()
+
+assert b.field1 == 'test 2'
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7307Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7307Bug.groovy
new file mode 100644
index 0000000..22040e2
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7307Bug.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7307Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testIncorrectInstanceOfInference() {
+        assertScript '''
+            static <T extends Number> T id(T value) {
+                value
+            }
+
+            // Narrower generic type: doesn't compile
+            static <U extends Integer> U id2(U value) {
+                id(value)
+            }
+
+            // Fixed type: compiles
+            static Integer id4(Integer value) {
+                id(value)
+            }
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7316Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7316Bug.groovy
new file mode 100644
index 0000000..549afe2
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7316Bug.groovy
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7316Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+
+    void testTypeCheckingBypass() {
+        assertScript '''
+            public <T> T getSomething() { null }
+
+            public List getList() { getSomething() }
+        '''
+    }
+
+    void testTypeCheckingBypassUsingExplicitTypeHint() {
+        assertScript '''
+            public <T> T getSomething() { null }
+
+            public List getList() {
+                @ASTTest(phase=INSTRUCTION_SELECTION,value={
+                    def ift = node.getNodeMetaData(INFERRED_TYPE)
+                    assert ift == make(List)
+                })
+                def list = this.<List>getSomething()
+            }
+        '''
+    }
+
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy
new file mode 100644
index 0000000..4bd2f2d
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7322Bug.groovy
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7322Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testCallStaticTraitMethodFromTraitItself() {
+        assertScript '''
+            trait SomeTrait {
+
+                static someMethod() {
+                    List theNames = getNames()
+                    theNames
+                }
+
+                static List getNames() {
+                    ['Jeff', 'Betsy', 'Jake', 'Zack']
+                }
+            }
+
+            class SomeClass implements SomeTrait {}
+            assert SomeClass.someMethod() == ['Jeff', 'Betsy', 'Jake', 'Zack']
+        '''
+    }
+
+    // GROOVY-7191
+    void testCallStaticMethodFromInstanceMethodInTrait() {
+        assertScript '''
+            trait SomeTrait {
+                static int someStaticMethod(){ 1 }
+
+                int someInstanceMethod() {
+                    someStaticMethod()
+                }
+            }
+            class SomeClass implements SomeTrait {}
+            def o = new SomeClass()
+            assert o.someInstanceMethod() == 1
+        '''
+    }
+
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7324Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7324Bug.groovy
new file mode 100644
index 0000000..f12fdaf
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7324Bug.groovy
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7324Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testInferenceOfListDotOperator() {
+        assertScript '''class Account {
+    String id
+}
+
+class GCAccount {
+    List<Account> sfAccounts
+}
+
+class User {
+    List<GCAccount> gcAccounts
+}
+
+void foo() {
+    def accounts = (1..10).collect { new Account(id: "Id $it") }
+    def user1 = new User(gcAccounts: [new GCAccount(sfAccounts: accounts[0..2]), new GCAccount(sfAccounts: accounts[3..4])])
+    def user2 = new User(gcAccounts: [new GCAccount(sfAccounts: accounts[5..7]), new GCAccount(sfAccounts: accounts[8..9])])
+    def users = [user1,user2]
+    def ids = users.gcAccounts.sfAccounts.id.flatten()
+    println ids
+}
+
+foo()
+        '''
+    }
+
+    void testInferenceOfSpreadDotOperator() {
+        assertScript '''class Account {
+    String id
+}
+
+class GCAccount {
+    List<Account> sfAccounts
+}
+
+class User {
+    List<GCAccount> gcAccounts
+}
+
+void foo() {
+    def accounts = (1..10).collect { new Account(id: "Id $it") }
+    def user = new User(gcAccounts: [new GCAccount(sfAccounts: accounts[0..2]), new GCAccount(sfAccounts: accounts[3..4])])
+    def ids = user.gcAccounts*.sfAccounts*.id.flatten()
+    println ids
+}
+
+foo()
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy
new file mode 100644
index 0000000..ba1fe97
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7325Bug.groovy
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7325Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testGenericIdentityWithClosure() {
+        assertScript '''
+public static <T> T identity(T self) { self }
+
+ at ASTTest(phase=INSTRUCTION_SELECTION,value={
+    assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == Integer_TYPE
+})
+Integer i = identity(2)
+
+ at ASTTest(phase=INSTRUCTION_SELECTION,value={
+    assert node.rightExpression.getNodeMetaData(INFERRED_TYPE) == CLOSURE_TYPE
+})
+Closure c = identity {'foo'}
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7327Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7327Bug.groovy
new file mode 100644
index 0000000..379f2d9
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7327Bug.groovy
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7327Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testReturnTypeInferenceWithJavaEnum() {
+        assertScript '''import org.codehaus.groovy.control.CompilePhase
+
+            public static <T> List<T> randomSample(T[] sequence) {
+                Arrays.asList(sequence)[0..1]
+            }
+
+            assert randomSample(CompilePhase.values()).size() == 2
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy
new file mode 100644
index 0000000..dfcbdc1
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7333Bug.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7333Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testIncorrectInstanceOfInference() {
+        assertScript '''
+            int len(byte[] arr) { arr.length }
+            def foo(arg) {
+               if (arg instanceof byte[]) {
+                  len(arg)
+               }
+            }
+            assert foo(new byte[3]) == 3
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7343Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7343Bug.groovy
new file mode 100644
index 0000000..a9566ed
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7343Bug.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7343Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testIncorrectInstanceOfInference() {
+        assertScript '''
+            class Test {
+                 static private String str = "My String"
+
+                 static def test() {
+                     myStr
+                 }
+
+                 static String getMyStr() {
+                     return "${str.replace(" ", "")}"
+                 }
+            }
+
+            assert Test.test() == 'MyString'
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7355Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7355Bug.groovy
new file mode 100644
index 0000000..59e4d11
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7355Bug.groovy
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7355Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotThrowVerifyError() {
+        assertScript '''
+            private void foo(String[] arr) {
+                for (String s in arr) {
+                    { -> println(s)}.call()
+                }
+            }
+
+            foo(['a','b'] as String[])
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7356Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7356Bug.groovy
new file mode 100644
index 0000000..8b4836f
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7356Bug.groovy
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7356Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotFailCompilationBecauseOfForEachAndTry() {
+        assertScript '''
+
+            private void foo(String[] arr) {
+
+                for (String s in arr.iterator()) {
+                    try {
+                        println(s)
+                    } catch (e) {
+                    }
+                }
+
+            }
+
+            foo(['a', 'b'] as String[])
+        '''
+    }
+
+    void testShouldNotFailCompilationBecauseOfForEachAndTryDirectArray() {
+        assertScript '''
+
+            private void foo(String[] arr) {
+
+                for (String s in arr) {
+                    try {
+                        println(s)
+                    } catch (e) {
+                    }
+                }
+
+            }
+
+            foo(['a', 'b'] as String[])
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7357Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7357Bug.groovy
new file mode 100644
index 0000000..7818ba7
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7357Bug.groovy
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7357Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+        void testOptimizedArrayForLoopShouldPerformImplicitNullCheck() {
+        assertScript '''
+
+            private void foo(String[] arr) {
+                for (String s in arr) {
+                    println(s)
+                }
+            }
+
+            foo(null)
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7358Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7358Bug.groovy
new file mode 100644
index 0000000..9824f6a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7358Bug.groovy
@@ -0,0 +1,54 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7358Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+        void testShouldHandleContinuePropertyInOptimizedLoop() {
+        assertScript '''
+
+            private int foo(String[] arr) {
+               int counter=0
+               for (String s in arr) {
+                  if(counter++ > 100) break
+                  println(s)
+                  if(s == 'b') continue
+               }
+               counter
+            }
+
+            assert foo(['a','b','c'] as String[])==3
+
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7361Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7361Bug.groovy
new file mode 100644
index 0000000..4107ed1
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7361Bug.groovy
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7361Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testShouldNotThrowVerifyError() {
+        assertScript '''
+                class TaskManager {
+                    private final Map<Long, String> map = [1L:'a',2L:'b']
+                    void doh() {
+                        def list = [1L]
+                        list.each {
+                            synchronized (map) {
+                                map.remove(it)
+                            }
+                        }
+                    }
+                }
+                new TaskManager().doh()
+            '''
+    }
+
+    void testShouldNotThrowClassCastException() {
+        assertScript '''
+            class A {
+                private final Map map = [:]
+                Map foo() {
+                    new Runnable() {
+                        @Override
+                        void run(){
+                            { -> map['a']='b'}.call()
+                        }
+                    }.run()
+                    map
+                }
+            }
+            def a = new A()
+            assert a.foo() == [a:'b']
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7364Bug.groovy b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7364Bug.groovy
new file mode 100644
index 0000000..0f34be2
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/Groovy7364Bug.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.classgen.asm.sc.bugs
+
+import groovy.transform.stc.StaticTypeCheckingTestCase
+import org.codehaus.groovy.classgen.asm.sc.StaticCompilationTestSupport
+
+class Groovy7364Bug extends StaticTypeCheckingTestCase implements StaticCompilationTestSupport {
+    void testGenericReturnTypeInferenceWithMethodHavingDefaultParams() {
+        assertScript '''
+
+                public <T> T f(T value, int param = 0) {
+                    value
+                }
+
+                def s = f('42')
+                s.length()
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/support/Groovy7133Support.java b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/support/Groovy7133Support.java
new file mode 100644
index 0000000..33883e2
--- /dev/null
+++ b/src/test/org/codehaus/groovy/classgen/asm/sc/bugs/support/Groovy7133Support.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.classgen.asm.sc.bugs.support;
+
+import java.util.Arrays;
+import java.util.List;
+
+public class Groovy7133Support {
+    public static List<int[]> list() {
+        return Arrays.asList(new int[1]);
+    }
+}
diff --git a/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy b/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
index 5445d6a..cdd9dfd 100644
--- a/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
+++ b/src/test/org/codehaus/groovy/control/customizers/ASTTransformationCustomizerTest.groovy
@@ -190,7 +190,7 @@ class ASTTransformationCustomizerTest extends GroovyTestCase {
 
 boolean interrupted = false
 try {
-    25.times {
+    50.times {
         Thread.sleep(100)
     }
 } catch (TimeoutException e) {
diff --git a/src/test/org/codehaus/groovy/control/io/FileReaderTest.groovy b/src/test/org/codehaus/groovy/control/io/FileReaderTest.groovy
index 3488d51..f38613a 100644
--- a/src/test/org/codehaus/groovy/control/io/FileReaderTest.groovy
+++ b/src/test/org/codehaus/groovy/control/io/FileReaderTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.control.io
 
 
diff --git a/src/test/org/codehaus/groovy/control/io/NullWriterTest.groovy b/src/test/org/codehaus/groovy/control/io/NullWriterTest.groovy
index a11419c..5c838cd 100644
--- a/src/test/org/codehaus/groovy/control/io/NullWriterTest.groovy
+++ b/src/test/org/codehaus/groovy/control/io/NullWriterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.control.io
 
 class NullWriterTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/control/io/StringReaderSourceTest.groovy b/src/test/org/codehaus/groovy/control/io/StringReaderSourceTest.groovy
index 47d1442..e84e650 100644
--- a/src/test/org/codehaus/groovy/control/io/StringReaderSourceTest.groovy
+++ b/src/test/org/codehaus/groovy/control/io/StringReaderSourceTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.control.io
 
 import org.codehaus.groovy.control.CompilerConfiguration
diff --git a/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy b/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy
index 3b24e66..0d9beee 100644
--- a/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy
+++ b/src/test/org/codehaus/groovy/dummy/ClassWithStaticMethod.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.dummy;
 
 /**
diff --git a/src/test/org/codehaus/groovy/dummy/FooHandler.java b/src/test/org/codehaus/groovy/dummy/FooHandler.java
index df47e38..b79e183 100644
--- a/src/test/org/codehaus/groovy/dummy/FooHandler.java
+++ b/src/test/org/codehaus/groovy/dummy/FooHandler.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.dummy;
 
 import java.io.Reader;
diff --git a/src/test/org/codehaus/groovy/reflection/GroovyClassValueFactoryTest.groovy b/src/test/org/codehaus/groovy/reflection/GroovyClassValueFactoryTest.groovy
new file mode 100644
index 0000000..79c2479
--- /dev/null
+++ b/src/test/org/codehaus/groovy/reflection/GroovyClassValueFactoryTest.groovy
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.reflection
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+import groovy.util.GroovyTestCase;
+
+import org.codehaus.groovy.reflection.GroovyClassValue.ComputeValue
+
+class GroovyClassValueFactoryTest extends GroovyTestCase {
+	public void testCreateGroovyClassValue(){
+		final AtomicInteger counter = new AtomicInteger();
+		GroovyClassValue<String> classValue = GroovyClassValueFactory.createGroovyClassValue(new ComputeValue<String>(){
+			String computeValue(Class<?> type){
+				counter.incrementAndGet()
+				return type.name;
+			}
+		});
+		assertEquals("retrieved String class value", String.class.getName(), classValue.get(String.class))
+		assertEquals("computeValue correctly invoked 1 time", 1, counter.value)
+		assertEquals("retrieved String class value", String.class.getName(), classValue.get(String.class))
+		assertEquals("computeValue correctly invoked 1 time", 1, counter.value)
+		assertEquals("retrieved Integer class value", Integer.class.getName(), classValue.get(Integer.class))
+		assertEquals("computeValue correctly invoked 2 times", 2, counter.value)
+		classValue.remove(String.class)
+		assertEquals("retrieved String class value", String.class.getName(), classValue.get(String.class))
+		assertEquals("computeValue correctly invoked 3 times", 3, counter.value)
+	}
+}
diff --git a/src/test/org/codehaus/groovy/reflection/WeakMapTest.groovy b/src/test/org/codehaus/groovy/reflection/WeakMapTest.groovy
index 9858c4f..4a61a6d 100644
--- a/src/test/org/codehaus/groovy/reflection/WeakMapTest.groovy
+++ b/src/test/org/codehaus/groovy/reflection/WeakMapTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.reflection
 
 class WeakMapTest extends GroovyTestCase{
diff --git a/src/test/org/codehaus/groovy/runtime/AppendableDgmMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/AppendableDgmMethodsTest.groovy
index c04eaa6..5110077 100644
--- a/src/test/org/codehaus/groovy/runtime/AppendableDgmMethodsTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/AppendableDgmMethodsTest.groovy
@@ -23,9 +23,9 @@ package org.codehaus.groovy.runtime
 class AppendableDgmMethodsTest extends GroovyTestCase {
     List<String> store = []
     Appendable app = new Appendable() {
-        Appendable append(char c) { null }
+        Appendable append(char c) { store+="$c"; this }
         Appendable append(CharSequence cs) { store += cs; this }
-        Appendable append(CharSequence cs, int i1, int i2) { null }
+        Appendable append(CharSequence cs, int i1, int i2) { store += cs.subSequence(i1,i2); this }
     }
 
     void testFoo() {
diff --git a/src/test/org/codehaus/groovy/runtime/CustomBooleanCoercionTest.groovy b/src/test/org/codehaus/groovy/runtime/CustomBooleanCoercionTest.groovy
index 8dbeeac..ec9811b 100644
--- a/src/test/org/codehaus/groovy/runtime/CustomBooleanCoercionTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/CustomBooleanCoercionTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy b/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
index a68e25a..54d4322 100644
--- a/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/DateGDKTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -54,6 +54,17 @@ class DateGDKTest extends GroovyTestCase {
         TimeZone.setDefault defaultTZ
     }
 
+    void testParseWithTimeZone() {
+        TimeZone defaultTZ = TimeZone.default
+
+        TimeZone.default = TimeZone.getTimeZone("GMT+05")
+        def tz = TimeZone.getTimeZone("GMT+03")
+        def newYear = Date.parse('yyyy-MM-dd', "2015-01-01", tz)
+        assert newYear.toString() == 'Thu Jan 01 02:00:00 GMT+05:00 2015'
+
+        TimeZone.default = defaultTZ
+    }
+
     void testRoundTrip() {
         Date d = new Date()
         String pattern = 'dd MMM yyyy, hh:mm:ss,SSS a z'
diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy
new file mode 100644
index 0000000..7cebc39
--- /dev/null
+++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.groovy
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import java.util.*;
+
+/**
+ * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
+ * @author Marc Guillemot
+ * @author Brad Long
+ */
+public class DefaultGroovyMethodsTest extends GroovyTestCase {
+
+    public void testPrint() throws Exception {
+        Map<String, String> map = new LinkedHashMap<String, String>();
+        map.put("bob", "drools");
+        map.put("james", "geronimo");
+        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
+        list.add(map);
+        assertEquals("[[bob:drools, james:geronimo]]", InvokerHelper.toString(list));
+    }
+
+    public void testFloatRounding() throws Exception {
+        Float f = 1000.123456f;
+
+        assertEquals(DefaultGroovyMethods.round(f), 1000);
+        assertEquals(DefaultGroovyMethods.round(f, 0), 1000.0f);
+        assertEquals(DefaultGroovyMethods.round(f, 1), 1000.1f);
+        assertEquals(DefaultGroovyMethods.round(f, 2), 1000.12f);
+        assertEquals(DefaultGroovyMethods.round(f, 3), 1000.123f);
+        assertEquals(DefaultGroovyMethods.round(f, 4), 1000.1235f);
+        assertEquals(DefaultGroovyMethods.round(f, 5), 1000.12346f);
+        assertEquals(DefaultGroovyMethods.round(f, 6), 1000.123456f);
+    }
+
+    public void testDoubleRounding() throws Exception {
+        Double d = 1000.123456;
+
+        assertEquals(DefaultGroovyMethods.round(d), 1000L);
+        assertEquals(DefaultGroovyMethods.round(d, 0), 1000.0);
+        assertEquals(DefaultGroovyMethods.round(d, 1), 1000.1);
+        assertEquals(DefaultGroovyMethods.round(d, 2), 1000.12);
+        assertEquals(DefaultGroovyMethods.round(d, 3), 1000.123);
+        assertEquals(DefaultGroovyMethods.round(d, 4), 1000.1235);
+        assertEquals(DefaultGroovyMethods.round(d, 5), 1000.12346);
+        assertEquals(DefaultGroovyMethods.round(d, 6), 1000.123456);
+    }
+
+    public void testFloatTruncate() throws Exception {
+        Float f = 1000.123456f;
+
+        assertEquals(DefaultGroovyMethods.trunc(f), 1000.0f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 0), 1000.0f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 1), 1000.1f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 2), 1000.12f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 3), 1000.123f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 4), 1000.1234f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 5), 1000.12345f);
+        assertEquals(DefaultGroovyMethods.trunc(f, 6), 1000.123456f);
+    }
+
+    public void testDoubleTruncate() throws Exception {
+        Double d = 1000.123456;
+
+        assertEquals(DefaultGroovyMethods.trunc(d), 1000.0);
+        assertEquals(DefaultGroovyMethods.trunc(d, 0), 1000.0);
+        assertEquals(DefaultGroovyMethods.trunc(d, 1), 1000.1);
+        assertEquals(DefaultGroovyMethods.trunc(d, 2), 1000.12);
+        assertEquals(DefaultGroovyMethods.trunc(d, 3), 1000.123);
+        assertEquals(DefaultGroovyMethods.trunc(d, 4), 1000.1234);
+        assertEquals(DefaultGroovyMethods.trunc(d, 5), 1000.12345);
+        assertEquals(DefaultGroovyMethods.trunc(d, 6), 1000.123456);
+    }
+
+    // GROOVY-6626
+    void testBigIntegerPower() {
+        assert DefaultGroovyMethods.power(2G, 63G) == DefaultGroovyMethods.power(2G, 63)
+        assert DefaultGroovyMethods.power(13G, 15G) == DefaultGroovyMethods.power(13G, 15)
+    }
+
+    public void testToMethods() throws Exception {
+        Number n = 7L;
+        assertEquals(DefaultGroovyMethods.toInteger(n), new Integer(7));
+        assertEquals(DefaultGroovyMethods.toLong(n), new Long(7));
+        assertEquals(DefaultGroovyMethods.toFloat(n), new Float(7));
+        assertEquals(DefaultGroovyMethods.toDouble(n), new Double(7));
+        assertEquals(DefaultGroovyMethods.toBigInteger(n), new BigInteger("7"));
+        assertEquals(DefaultGroovyMethods.toBigDecimal(n), new BigDecimal("7"));
+        // The following is true starting with 1.6 (GROOVY-3171):
+        assertEquals(new BigDecimal("0.1"), DefaultGroovyMethods.toBigDecimal(0.1));
+        assertEquals(ResourceGroovyMethods.toURL("http://example.org/"), new URL("http://example.org/"));
+        assertEquals(ResourceGroovyMethods.toURI("http://example.org/"), new URI("http://example.org/"));
+        assertEquals(DefaultGroovyMethods.toBoolean(Boolean.FALSE), Boolean.FALSE);
+        assertEquals(DefaultGroovyMethods.toBoolean(Boolean.TRUE), Boolean.TRUE);
+    }
+
+    public void testGetBytes() {
+        byte[] bytes = [42,45,47,14,10,84] as byte[]
+        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
+        try {
+            byte[] answer = IOGroovyMethods.getBytes(is);
+            assertEquals(bytes.length, answer.length);
+            for (int i = 0; i < bytes.length; i++) {
+                assertEquals(bytes[i], answer[i]);       
+            }
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    public void testSetBytes() {
+        byte[] bytes = [42,45,47,14,10,84] as byte[]
+        ByteArrayOutputStream os = new ByteArrayOutputStream();
+        try {
+            IOGroovyMethods.setBytes(os, bytes);
+            byte[] answer = os.toByteArray();
+            assertEquals(bytes.length, answer.length);
+            for (int i = 0; i < bytes.length; i++) {
+                assertEquals(bytes[i], answer[i]);
+            }
+        } catch (IOException e) {
+            fail();
+        }
+    }
+
+    public void testDownto() {
+        final int[] count = [0] as int[]
+        final Closure closure = new Closure(null) {
+            public Object doCall(final Object params) {
+                count[0]++;
+                return null;
+            }
+        };
+
+        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0"), closure);
+        assertEquals(count[0], 2);
+
+        count[0] = 0;
+
+        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0.123"), closure);
+        assertEquals(count[0], 1);
+    }
+
+    public void testBulkCollectionForArrayOperations() {
+        List<String> list = new ArrayList<String>();
+        assertTrue(DefaultGroovyMethods.addAll(list, "abcd".split("")));
+        assertTrue(DefaultGroovyMethods.removeAll(list, "def".split("")));
+        assertTrue(DefaultGroovyMethods.retainAll(list, "bcd".split("")));
+        List<String> bAndC = Arrays.asList("b", "c");
+        assertTrue(DefaultGroovyMethods.containsAll(list, bAndC.toArray(new String[2])));
+        assertEquals(list, bAndC);
+        assertTrue(DefaultGroovyMethods.addAll(list, 1, Arrays.asList("a", "s", "i").toArray(new String[3])));
+        assertEquals(list, Arrays.asList("b", "a", "s", "i", "c"));
+    }
+
+    /**
+     * Tests that a List subclass without a constructor for Collections is still coerced
+     * into the correct list type. 
+     */
+    public void testCollectionTypeConstructors() {
+        MyList list = DefaultGroovyMethods.asType(Arrays.asList(1, 2, 3), MyList.class);
+        assertEquals(3, list.size());
+        assertEquals(1, list.get(0));
+        assertEquals(2, list.get(1));
+        assertEquals(3, list.get(2));
+    }
+
+    private static class MyList extends ArrayList {
+        public MyList() {}
+    }
+}
diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java b/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java
deleted file mode 100644
index be65a09..0000000
--- a/src/test/org/codehaus/groovy/runtime/DefaultGroovyMethodsTest.java
+++ /dev/null
@@ -1,188 +0,0 @@
-/*
- * Copyright 2003-2013 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package org.codehaus.groovy.runtime;
-
-import groovy.lang.Closure;
-import groovy.util.GroovyTestCase;
-
-import java.io.ByteArrayInputStream;
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.math.BigDecimal;
-import java.math.BigInteger;
-import java.net.URI;
-import java.net.URL;
-import java.util.*;
-
-/**
- * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
- * @author Marc Guillemot
- * @author Brad Long
- */
-public class DefaultGroovyMethodsTest extends GroovyTestCase {
-
-    public void testPrint() throws Exception {
-        Map<String, String> map = new LinkedHashMap<String, String>();
-        map.put("bob", "drools");
-        map.put("james", "geronimo");
-        List<Map<String, String>> list = new ArrayList<Map<String, String>>();
-        list.add(map);
-        assertEquals("[[bob:drools, james:geronimo]]", InvokerHelper.toString(list));
-    }
-
-    public void testFloatRounding() throws Exception {
-        Float f = 1000.123456f;
-
-        assertEquals(DefaultGroovyMethods.round(f), 1000);
-        assertEquals(DefaultGroovyMethods.round(f, 0), 1000.0f);
-        assertEquals(DefaultGroovyMethods.round(f, 1), 1000.1f);
-        assertEquals(DefaultGroovyMethods.round(f, 2), 1000.12f);
-        assertEquals(DefaultGroovyMethods.round(f, 3), 1000.123f);
-        assertEquals(DefaultGroovyMethods.round(f, 4), 1000.1235f);
-        assertEquals(DefaultGroovyMethods.round(f, 5), 1000.12346f);
-        assertEquals(DefaultGroovyMethods.round(f, 6), 1000.123456f);
-    }
-
-    public void testDoubleRounding() throws Exception {
-        Double d = 1000.123456;
-
-        assertEquals(DefaultGroovyMethods.round(d), 1000L);
-        assertEquals(DefaultGroovyMethods.round(d, 0), 1000.0);
-        assertEquals(DefaultGroovyMethods.round(d, 1), 1000.1);
-        assertEquals(DefaultGroovyMethods.round(d, 2), 1000.12);
-        assertEquals(DefaultGroovyMethods.round(d, 3), 1000.123);
-        assertEquals(DefaultGroovyMethods.round(d, 4), 1000.1235);
-        assertEquals(DefaultGroovyMethods.round(d, 5), 1000.12346);
-        assertEquals(DefaultGroovyMethods.round(d, 6), 1000.123456);
-    }
-
-    public void testFloatTruncate() throws Exception {
-        Float f = 1000.123456f;
-
-        assertEquals(DefaultGroovyMethods.trunc(f), 1000.0f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 0), 1000.0f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 1), 1000.1f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 2), 1000.12f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 3), 1000.123f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 4), 1000.1234f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 5), 1000.12345f);
-        assertEquals(DefaultGroovyMethods.trunc(f, 6), 1000.123456f);
-    }
-
-    public void testDoubleTruncate() throws Exception {
-        Double d = 1000.123456;
-
-        assertEquals(DefaultGroovyMethods.trunc(d), 1000.0);
-        assertEquals(DefaultGroovyMethods.trunc(d, 0), 1000.0);
-        assertEquals(DefaultGroovyMethods.trunc(d, 1), 1000.1);
-        assertEquals(DefaultGroovyMethods.trunc(d, 2), 1000.12);
-        assertEquals(DefaultGroovyMethods.trunc(d, 3), 1000.123);
-        assertEquals(DefaultGroovyMethods.trunc(d, 4), 1000.1234);
-        assertEquals(DefaultGroovyMethods.trunc(d, 5), 1000.12345);
-        assertEquals(DefaultGroovyMethods.trunc(d, 6), 1000.123456);
-    }
-
-    public void testToMethods() throws Exception {
-        Number n = 7L;
-        assertEquals(DefaultGroovyMethods.toInteger(n), new Integer(7));
-        assertEquals(DefaultGroovyMethods.toLong(n), new Long(7));
-        assertEquals(DefaultGroovyMethods.toFloat(n), new Float(7));
-        assertEquals(DefaultGroovyMethods.toDouble(n), new Double(7));
-        assertEquals(DefaultGroovyMethods.toBigInteger(n), new BigInteger("7"));
-        assertEquals(DefaultGroovyMethods.toBigDecimal(n), new BigDecimal("7"));
-        // The following is true starting with 1.6 (GROOVY-3171):
-        assertEquals(new BigDecimal("0.1"), DefaultGroovyMethods.toBigDecimal(0.1));
-        assertEquals(ResourceGroovyMethods.toURL("http://example.org/"), new URL("http://example.org/"));
-        assertEquals(ResourceGroovyMethods.toURI("http://example.org/"), new URI("http://example.org/"));
-        assertEquals(DefaultGroovyMethods.toBoolean(Boolean.FALSE), Boolean.FALSE);
-        assertEquals(DefaultGroovyMethods.toBoolean(Boolean.TRUE), Boolean.TRUE);
-    }
-
-    public void testGetBytes() {
-        byte[] bytes = {42,45,47,14,10,84};
-        ByteArrayInputStream is = new ByteArrayInputStream(bytes);
-        try {
-            byte[] answer = IOGroovyMethods.getBytes(is);
-            assertEquals(bytes.length, answer.length);
-            for (int i = 0; i < bytes.length; i++) {
-                assertEquals(bytes[i], answer[i]);       
-            }
-        } catch (IOException e) {
-            fail();
-        }
-    }
-
-    public void testSetBytes() {
-        byte[] bytes = {42,45,47,14,10,84};
-        ByteArrayOutputStream os = new ByteArrayOutputStream();
-        try {
-            IOGroovyMethods.setBytes(os, bytes);
-            byte[] answer = os.toByteArray();
-            assertEquals(bytes.length, answer.length);
-            for (int i = 0; i < bytes.length; i++) {
-                assertEquals(bytes[i], answer[i]);
-            }
-        } catch (IOException e) {
-            fail();
-        }
-    }
-
-    public void testDownto() {
-        final int[] count = new int[]{0};
-        final Closure closure = new Closure(null) {
-            public Object doCall(final Object params) {
-                count[0]++;
-                return null;
-            }
-        };
-
-        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0"), closure);
-        assertEquals(count[0], 2);
-
-        count[0] = 0;
-
-        DefaultGroovyMethods.downto(new BigInteger("1"), new BigDecimal("0.123"), closure);
-        assertEquals(count[0], 1);
-    }
-
-    public void testBulkCollectionForArrayOperations() {
-        List<String> list = new ArrayList<String>();
-        assertTrue(DefaultGroovyMethods.addAll(list, "abcd".split("")));
-        assertTrue(DefaultGroovyMethods.removeAll(list, "def".split("")));
-        assertTrue(DefaultGroovyMethods.retainAll(list, "bcd".split("")));
-        List<String> bAndC = Arrays.asList("b", "c");
-        assertTrue(DefaultGroovyMethods.containsAll(list, bAndC.toArray(new String[2])));
-        assertEquals(list, bAndC);
-        assertTrue(DefaultGroovyMethods.addAll(list, 1, Arrays.asList("a", "s", "i").toArray(new String[3])));
-        assertEquals(list, Arrays.asList("b", "a", "s", "i", "c"));
-    }
-
-    /**
-     * Tests that a List subclass without a constructor for Collections is still coerced
-     * into the correct list type. 
-     */
-    public void testCollectionTypeConstructors() {
-        MyList list = DefaultGroovyMethods.asType(Arrays.asList(1, 2, 3), MyList.class);
-        assertEquals(3, list.size());
-        assertEquals(1, list.get(0));
-        assertEquals(2, list.get(1));
-        assertEquals(3, list.get(2));
-    }
-
-    private static class MyList extends ArrayList {
-        public MyList() {}
-    }
-}
diff --git a/src/test/org/codehaus/groovy/runtime/DefaultGroovyStaticMethodsTest.java b/src/test/org/codehaus/groovy/runtime/DefaultGroovyStaticMethodsTest.java
new file mode 100644
index 0000000..0dfc74f
--- /dev/null
+++ b/src/test/org/codehaus/groovy/runtime/DefaultGroovyStaticMethodsTest.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.runtime;
+
+import groovy.util.GroovyTestCase;
+
+/**
+ * @author Kent Inge Fagerland Simonsen
+ */
+public class DefaultGroovyStaticMethodsTest extends GroovyTestCase {
+
+    /**
+     *Tests System.currentTimeSeconds()
+     */
+    public void testCurrentTimeSeconds() {
+	long timeMillis = System.currentTimeMillis();
+        long timeSeconds = DefaultGroovyStaticMethods.currentTimeSeconds(null);
+        long timeMillis2 = System.currentTimeMillis();
+        assertTrue(timeMillis/1000 <= timeSeconds);
+        assertTrue(timeMillis2/1000 >= timeSeconds);
+    }
+}
diff --git a/src/test/org/codehaus/groovy/runtime/DirectoryDeleteTest.groovy b/src/test/org/codehaus/groovy/runtime/DirectoryDeleteTest.groovy
index 7cfa7e3..5c80f85 100644
--- a/src/test/org/codehaus/groovy/runtime/DirectoryDeleteTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/DirectoryDeleteTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime;
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/EachLineTest.groovy b/src/test/org/codehaus/groovy/runtime/EachLineTest.groovy
index a996a39..6723241 100644
--- a/src/test/org/codehaus/groovy/runtime/EachLineTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/EachLineTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime;
 
 class EachLineTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy b/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy
index fa6db01..e3c3cf4 100644
--- a/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/FileLeftShiftTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 class FileLeftShiftTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy b/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy
index 75d9436..d0d5af9 100644
--- a/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/GroovyCategoryTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 class GroovyCategoryTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy b/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy
index 3c4dcf6..04e3a4d 100644
--- a/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/InterfaceConversionTest.groovy
@@ -22,8 +22,8 @@ class InterfaceConversionTest extends GroovyTestCase {
         def c2 = c1 as InterfaceConversionTestFoo
         assert !(c1 instanceof InterfaceConversionTestFoo)
         assert c2 instanceof InterfaceConversionTestFoo
-        assert c2.a() == null
-        assert c2.b(null) == 1
+        assert c2.a() == 0
+        assert c2.b(null) == null
     }
 
     void testMapConversion() {
@@ -35,6 +35,20 @@ class InterfaceConversionTest extends GroovyTestCase {
         assert m2.a() == 1
         assert m2.b(null) == 2
     }
+
+    //GROOVY-7104
+    void testDefaultInterfaceMethodCallOnProxy() {
+        try {
+            // checks for Java 8
+            Class.forName("java.util.function.Consumer", false, this.class.classLoader);
+        } catch (e) {
+            return
+        }
+        Comparator c1 = {a,b -> a<=>b}
+        assert c1.compare("a","b") == -1
+        def c2 = c1.reversed()
+        assert c2.compare("a","b") == 1
+    }
 }
 
 interface InterfaceConversionTestFoo {
diff --git a/src/test/org/codehaus/groovy/runtime/InvokerHelperTest.java b/src/test/org/codehaus/groovy/runtime/InvokerHelperTest.java
index f3bbe2c..adc3e02 100644
--- a/src/test/org/codehaus/groovy/runtime/InvokerHelperTest.java
+++ b/src/test/org/codehaus/groovy/runtime/InvokerHelperTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime;
 
 import java.util.HashMap;
diff --git a/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java b/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java
index 3b8a600..3047cf9 100644
--- a/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java
+++ b/src/test/org/codehaus/groovy/runtime/MetaClassHelperTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime;
 
 import junit.framework.TestCase;
diff --git a/src/test/org/codehaus/groovy/runtime/MinusTest.groovy b/src/test/org/codehaus/groovy/runtime/MinusTest.groovy
index d5656ba..f2f8f74 100644
--- a/src/test/org/codehaus/groovy/runtime/MinusTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/MinusTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 class MinusTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy b/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy
index 4dd1cc4..186e8e7 100644
--- a/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/NullObjectTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 class NullObjectTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/runtime/PerInstanceMetaClassTest.groovy b/src/test/org/codehaus/groovy/runtime/PerInstanceMetaClassTest.groovy
index 482166e..8364c90 100644
--- a/src/test/org/codehaus/groovy/runtime/PerInstanceMetaClassTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/PerInstanceMetaClassTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime
 
 class PerInstanceMetaClassTest extends GroovyTestCase{
diff --git a/src/test/org/codehaus/groovy/runtime/StaticInitTest.java b/src/test/org/codehaus/groovy/runtime/StaticInitTest.java
index 71b1f2e..3a780ae 100644
--- a/src/test/org/codehaus/groovy/runtime/StaticInitTest.java
+++ b/src/test/org/codehaus/groovy/runtime/StaticInitTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime;
 
 import groovy.lang.GroovyClassLoader;
diff --git a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
index 4ab5e7c..1ad93fe 100644
--- a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
+++ b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleHelperForTests.groovy
@@ -42,8 +42,9 @@ public class ExtensionModuleHelperForTests {
                 throw new RuntimeException("Unable to find class loader")
             }
         }
-        def cp = ((URLClassLoader)cl).URLs.collect{ new File(it.toURI()).absolutePath}
+        Set<String> cp = ((URLClassLoader)cl).URLs.collect{ new File(it.toURI()).absolutePath}
         cp << baseDir.absolutePath
+
         def ant = new AntBuilder()
         try {
             ant.with {
@@ -63,10 +64,13 @@ public class ExtensionModuleHelperForTests {
                 )
             }
         } finally {
+            String out = ant.project.properties.out
             String err = ant.project.properties.err
             baseDir.deleteDir()
             if (err) {
-                throw new RuntimeException(err)
+                throw new RuntimeException("$err\nClasspath: ${cp.join('\n')}")
+            } else if ( ! out.contains("OK")) {
+                throw new RuntimeException("$out\nClasspath: ${cp.join('\n')}")
             }
         }
     }
diff --git a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleTest.groovy b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleTest.groovy
index b7e21ad..7403e04 100644
--- a/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/m12n/ExtensionModuleTest.groovy
@@ -87,4 +87,28 @@ class ExtensionModuleTest extends GroovyTestCase {
             """
         '''
     }
+
+    /**
+     * Test case that reproduces GROOVY-7225.
+     */
+    void testExtensionModuleUsingGrabAndClosure() {
+        ExtensionModuleHelperForTests.doInFork '''
+            ExtensionModuleRegistry registry = GroovySystem.metaClassRegistry.moduleRegistry
+            // ensure that the module isn't loaded
+            assert !registry.modules.any { it.name == 'Groovy Test 7225' && it.version == '1.0.7225-test' }
+
+            // find jar resource
+            def jarURL = this.class.getResource("/jars")
+            assert jarURL
+
+            assertScript """
+            @GrabResolver('$jarURL')
+            @Grab(value='module-test:module-test:1.0.7225-test', changing='true')
+            import org.codehaus.groovy.runtime.m12n.*
+
+            assert 'test'.groovy7225() == 'test: ok'
+            assert {->}.groovy7225() == '{"field":"value"}'
+            """
+        '''
+    }
 }
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/AbstractMemoizeTestCase.groovy b/src/test/org/codehaus/groovy/runtime/memoize/AbstractMemoizeTestCase.groovy
index ba8a4c3..7838336 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/AbstractMemoizeTestCase.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/AbstractMemoizeTestCase.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupTest.groovy
index 48c18e9..590ed31 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/CacheCleanupTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 import java.lang.ref.SoftReference
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/LRUProtectionStorageTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/LRUProtectionStorageTest.groovy
index 51ec854..ccf940b 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/LRUProtectionStorageTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/LRUProtectionStorageTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtLeastTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtLeastTest.groovy
index 014acda..caf7b1e 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtLeastTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtLeastTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtMostTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtMostTest.groovy
index 499214f..8abf325 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtMostTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeAtMostTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeBetweenTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeBetweenTest.groovy
index 41f1443..f883d44 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeBetweenTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeBetweenTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeTest.groovy
index 40db48a..45d8a42 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/MemoizeTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/MemoizeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
@@ -5,7 +20,29 @@ package org.codehaus.groovy.runtime.memoize
  */
 
 public class MemoizeTest extends AbstractMemoizeTestCase {
+
     Closure buildMemoizeClosure(Closure cl) {
         cl.memoize()
     }
+
+    void testMemoizeWithInject() {
+        int maxExecutionCount = 0
+        Closure max = { int a, int b ->
+            maxExecutionCount++
+            Math.max(a, b)
+        }.memoize()
+        int minExecutionCount = 0
+        Closure min = { int a, int b ->
+            minExecutionCount++
+            Math.min(a, b)
+        }.memoize()
+        100.times {
+            max.call(max.call(1, 2), 3)
+        }
+        100.times {
+            [1, 2, 3].inject(min)
+        }
+        assert maxExecutionCount == 2
+        assert minExecutionCount == 2
+    }
 }
diff --git a/src/test/org/codehaus/groovy/runtime/memoize/NullValueTest.groovy b/src/test/org/codehaus/groovy/runtime/memoize/NullValueTest.groovy
index 42b14da..0b8b2c2 100644
--- a/src/test/org/codehaus/groovy/runtime/memoize/NullValueTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/memoize/NullValueTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.memoize
 
 /**
diff --git a/src/test/org/codehaus/groovy/runtime/trampoline/TrampolineTest.groovy b/src/test/org/codehaus/groovy/runtime/trampoline/TrampolineTest.groovy
index 6bdf05d..a96cacc 100644
--- a/src/test/org/codehaus/groovy/runtime/trampoline/TrampolineTest.groovy
+++ b/src/test/org/codehaus/groovy/runtime/trampoline/TrampolineTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.runtime.trampoline
 
 /**
diff --git a/src/test/org/codehaus/groovy/syntax/TokenTest.java b/src/test/org/codehaus/groovy/syntax/TokenTest.java
index 2f10a75..764109d 100644
--- a/src/test/org/codehaus/groovy/syntax/TokenTest.java
+++ b/src/test/org/codehaus/groovy/syntax/TokenTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.syntax;
 
 
diff --git a/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java b/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java
index b28baa0..5d9c066 100644
--- a/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java
+++ b/src/test/org/codehaus/groovy/tools/DocGeneratorMain.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools;
 
 import groovy.lang.GroovyShell;
diff --git a/src/test/org/codehaus/groovy/tools/LoaderConfigurationTest.groovy b/src/test/org/codehaus/groovy/tools/LoaderConfigurationTest.groovy
index 7f20854..228ba93 100644
--- a/src/test/org/codehaus/groovy/tools/LoaderConfigurationTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/LoaderConfigurationTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools
 
 class LoaderConfigurationTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/tools/MetaBuilderTest.groovy b/src/test/org/codehaus/groovy/tools/MetaBuilderTest.groovy
index 2a72c58..07cbbeb 100644
--- a/src/test/org/codehaus/groovy/tools/MetaBuilderTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/MetaBuilderTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools
 
 import java.lang.reflect.Modifier
diff --git a/src/test/org/codehaus/groovy/tools/StringHelperTest.groovy b/src/test/org/codehaus/groovy/tools/StringHelperTest.groovy
index 8573a4c..77e2516 100644
--- a/src/test/org/codehaus/groovy/tools/StringHelperTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/StringHelperTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools
 
 import static org.codehaus.groovy.tools.StringHelper.*
diff --git a/src/test/org/codehaus/groovy/tools/TestDgmConverter.java b/src/test/org/codehaus/groovy/tools/TestDgmConverter.java
index c3f83c1..9aacfb9 100644
--- a/src/test/org/codehaus/groovy/tools/TestDgmConverter.java
+++ b/src/test/org/codehaus/groovy/tools/TestDgmConverter.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools;
 
 import groovy.lang.MetaMethod;
diff --git a/src/test/org/codehaus/groovy/tools/UtilitiesTest.groovy b/src/test/org/codehaus/groovy/tools/UtilitiesTest.groovy
index 63384b7..643369d 100644
--- a/src/test/org/codehaus/groovy/tools/UtilitiesTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/UtilitiesTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools
 
 class UtilitiesTest extends GroovyTestCase {
diff --git a/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java b/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
index b7187dd..ccc9add 100644
--- a/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
+++ b/src/test/org/codehaus/groovy/tools/gse/DependencyTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.gse;
 
 import java.io.StringBufferInputStream;
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGenericGroovySuperclass.groovy b/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGenericGroovySuperclass.groovy
index 3f275ca..924a144 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGenericGroovySuperclass.groovy
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGenericGroovySuperclass.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync
 
 public abstract class AbstractGenericGroovySuperclass<T> {
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGroovySuperclass.groovy b/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGroovySuperclass.groovy
index 1a893ab..4fe9afe 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGroovySuperclass.groovy
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/AbstractGroovySuperclass.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync
 
 abstract class AbstractGroovySuperclass {
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteGenericJavaSubclass.java b/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteGenericJavaSubclass.java
index f891f7d..1d66bb1 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteGenericJavaSubclass.java
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteGenericJavaSubclass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync;
 
 import java.util.Set;
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteJavaSubclass.java b/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteJavaSubclass.java
index 3ddd727..679b0b6 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteJavaSubclass.java
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/ConcreteJavaSubclass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync;
 
 public class ConcreteJavaSubclass extends AbstractGroovySuperclass {
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteGenericJavaSubclass.java b/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteGenericJavaSubclass.java
index f08c550..12bc806 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteGenericJavaSubclass.java
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteGenericJavaSubclass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync;
 
 import java.util.Set;
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteJavaSubclass.java b/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteJavaSubclass.java
index 4dd2ff4..3277a0b 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteJavaSubclass.java
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/OtherConcreteJavaSubclass.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync;
 
 public class OtherConcreteJavaSubclass extends AbstractGroovySuperclass {
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInGroovyTest.groovy b/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInGroovyTest.groovy
index 2f15081..20c6896 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInGroovyTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInGroovyTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync
 
 import static junit.framework.Assert.assertEquals
diff --git a/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInJavaTest.java b/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInJavaTest.java
index 9a8cab6..2da2082 100644
--- a/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInJavaTest.java
+++ b/src/test/org/codehaus/groovy/tools/rootloadersync/SubclassingInJavaTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.rootloadersync;
 
 import org.junit.Test;
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationCollectorStubTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationCollectorStubTest.groovy
new file mode 100644
index 0000000..7de417b
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/AnnotationCollectorStubTest.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.stubgenerator
+
+import groovy.transform.AnnotationCollector
+
+import java.lang.annotation.Retention
+import java.lang.annotation.RetentionPolicy
+
+class AnnotationCollectorStubTest extends StringSourcesStubTestCase {
+
+    Map<String, String> provideSources() {
+        [
+                'foo/Main.java'    : '''
+                    package foo;
+
+                    public class Main {}
+                ''',
+                'bar/GroovyClass.groovy': '''
+                    package bar
+                    import org.codehaus.groovy.tools.stubgenerator.*
+
+                    @TheSuperGroovyHeroes
+                    class GroovyClass {}
+                '''
+        ]
+    }
+
+    void verifyStubs() {
+        def stubSource = stubJavaSourceFor('bar.GroovyClass')
+        assert !stubSource.contains('AnnotationCollector')
+    }
+}
+
+ at Retention(RetentionPolicy.RUNTIME)
+ at interface GroovyCoreTeam {
+    GroovyDeveloper[] value()
+}
+
+ at Retention(RetentionPolicy.RUNTIME)
+ at interface GroovyDeveloper {
+    String value() default "";
+}
+
+ at GroovyCoreTeam([
+        @GroovyDeveloper('Paul'),
+        @GroovyDeveloper('Cedric'),
+        @GroovyDeveloper('Jochen'),
+        @GroovyDeveloper('Guillaume')
+])
+ at AnnotationCollector
+ at interface TheSuperGroovyHeroes {}
+
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/BadGenericsExpansionOnInnerClassStubsTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/BadGenericsExpansionOnInnerClassStubsTest.groovy
index f5379e6..6079ee0 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/BadGenericsExpansionOnInnerClassStubsTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/BadGenericsExpansionOnInnerClassStubsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.stubgenerator
 
 /**
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/DefaultValueReturnTypeShouldUseGenericsStubsTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/DefaultValueReturnTypeShouldUseGenericsStubsTest.groovy
index 39936c9..1f81ea7 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/DefaultValueReturnTypeShouldUseGenericsStubsTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/DefaultValueReturnTypeShouldUseGenericsStubsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.stubgenerator
 
 /**
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/EnsureClassAnnotationPresentInStubTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/EnsureClassAnnotationPresentInStubTest.groovy
index 147b785..21e823e 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/EnsureClassAnnotationPresentInStubTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/EnsureClassAnnotationPresentInStubTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.stubgenerator
 
 /**
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7052Bug.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7052Bug.groovy
new file mode 100644
index 0000000..9a7671a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7052Bug.groovy
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.tools.stubgenerator
+
+/**
+ * Test that traits do not mess up with stub generation.
+ *
+ * @author Cedric Champeau
+ */
+class Groovy7052Bug extends StringSourcesStubTestCase {
+
+    Map<String, String> provideSources() {
+        [
+                'Foo.groovy': '''
+                    trait Foo {}
+                ''',
+                'Bar.java': '''
+                    class Bar implements Foo {}
+                ''',
+                'Baz.groovy': '''
+                    class Baz implements Foo {}
+                '''
+        ]
+    }
+
+    void verifyStubs() {
+        def stubSource = stubJavaSourceFor('Foo')
+        assert stubSource.contains('interface Foo')
+    }
+}
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7113Bug.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7113Bug.groovy
new file mode 100644
index 0000000..d4e1fab
--- /dev/null
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/Groovy7113Bug.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.tools.stubgenerator
+
+/**
+ * Test that traits do not mess up with stub generation.
+ *
+ * @author Cedric Champeau
+ */
+class Groovy7113Bug extends StringSourcesStubTestCase {
+
+    Map<String, String> provideSources() {
+        [
+                'Foo.groovy': '''
+                    trait Foo {
+                        int foo() { 1 }
+                        void bar(int x) {}
+                        void baz(int y) { }
+                    }
+                ''',
+                'Bar.java': '''
+                    class Bar extends Baz {  }
+                ''',
+                'Baz.groovy': '''
+                    class Baz implements Foo { void bar(int x) {} }
+                ''',
+                'AbstractFoo.groovy':'''
+                    abstract class AbstractFoo implements Foo {}
+                ''',
+                'ConcreteBar.java': '''
+                    public class ConcreteBar extends AbstractFoo {}
+                '''
+        ]
+    }
+
+    void verifyStubs() {
+        def stubSource = stubJavaSourceFor('Foo')
+        assert stubSource.contains('interface Foo')
+        assert stubSource.contains('int foo()')
+        assert stubSource.contains('void baz(int y)')
+        assert stubSource.contains('void bar(int x)')
+
+        stubSource = stubJavaSourceFor('Baz')
+        assert stubSource.contains('class Baz')
+        assert stubSource.contains('int foo()')
+        assert stubSource.contains('void baz(int y)')
+        assert stubSource.contains('void bar(int x)')
+    }
+}
diff --git a/src/test/org/codehaus/groovy/tools/stubgenerator/WrongCastForGenericReturnValueOfMethodStubsTest.groovy b/src/test/org/codehaus/groovy/tools/stubgenerator/WrongCastForGenericReturnValueOfMethodStubsTest.groovy
index 744c293..fd35c43 100644
--- a/src/test/org/codehaus/groovy/tools/stubgenerator/WrongCastForGenericReturnValueOfMethodStubsTest.groovy
+++ b/src/test/org/codehaus/groovy/tools/stubgenerator/WrongCastForGenericReturnValueOfMethodStubsTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.stubgenerator
 
 /**
diff --git a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
index dd80d60..565f72c 100644
--- a/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/BuilderTransformTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2014 the original author or authors.
+ * Copyright 2008-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -157,6 +157,65 @@ class BuilderTransformTest extends CompilableTestSupport {
         """
     }
 
+    void testDefaultBuilderGenerics() {
+        assertScript """
+            import groovy.transform.builder.Builder
+
+            @Builder
+            class CookBook {
+                List<String> recipes
+            }
+
+            def c = CookBook.builder().recipes(['Eggs Benedict', 'Poached Salmon']).build()
+            assert c.recipes == ['Eggs Benedict', 'Poached Salmon']
+        """
+        def message = shouldNotCompile '''
+            import groovy.transform.builder.Builder
+            import groovy.transform.CompileStatic
+
+            @Builder
+            class CookBook {
+                List<String> recipes
+            }
+
+
+            @CompileStatic
+            def methodBadParams() {
+                CookBook.builder().recipes([35, 42]).build()
+            }
+        '''
+        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.List\s?<java.lang.Integer>.*/
+    }
+
+    void testInitializerGenerics() {
+        assertScript """
+            import groovy.transform.builder.*
+
+            @Builder(builderStrategy=InitializerStrategy)
+            class CookBook {
+                List<String> recipes
+            }
+
+            def c = new CookBook(CookBook.createInitializer().recipes(['Eggs Benedict', 'Poached Salmon']))
+            assert c.recipes == ['Eggs Benedict', 'Poached Salmon']
+        """
+        def message = shouldNotCompile '''
+            import groovy.transform.builder.*
+
+            @Builder(builderStrategy=InitializerStrategy)
+            class CookBook {
+                List<String> recipes
+            }
+
+
+            @groovy.transform.CompileStatic
+            def methodBadParams() {
+                new CookBook(CookBook.createInitializer().recipes([35, 42]))
+            }
+        '''
+        assert message =~ /.*Cannot call.*recipes.*java.util.List\s?<java.lang.String>.*with arguments.*java.util.List\s?<java.lang.Integer>.*/
+    }
+
     void testDefaultBuilderCustomNames() {
         def shell = new GroovyShell()
         shell.parse """
@@ -392,10 +451,54 @@ class BuilderTransformTest extends CompilableTestSupport {
 
             @CompileStatic
             def firstLastAge() {
-                assert new Person(Person.createInitializer().firstName("John").lastName("Smith").age(21)).toString() == 'Person(John, Smith, 21)\'
+                assert new Person(Person.createInitializer().firstName("John").lastName("Smith").age(21)).toString() == 'Person(John, Smith, 21)'
             }
             firstLastAge()
         '''
     }
 
+    void testInitializerStrategyOnConstructorAndMethods() {
+        assertScript '''
+            import groovy.transform.builder.*
+            import groovy.transform.*
+
+            @ToString
+            @Builder(builderStrategy=InitializerStrategy)
+            class Person {
+                String firstName
+                String lastName
+                int age
+
+                @Builder(builderStrategy=InitializerStrategy, builderClassName='FullNameInitializer', builderMethodName='fullNameInitializer')
+                Person(String fullName, int age) {
+                    String[] splitFullName = fullName.split(' ')
+                    firstName = splitFullName?.first()
+                    lastName = splitFullName?.last()
+                    this.age = age
+                }
+
+                @Builder(builderStrategy=InitializerStrategy, builderClassName='NameListInitializer', builderMethodName='listInitializer')
+                Person(List<String> nameParts, Integer age) {
+                    firstName = nameParts[0]
+                    lastName = nameParts[-1]
+                    this.age = age
+                }
+
+                @Builder(builderStrategy=InitializerStrategy, builderClassName='StringInitializer', builderMethodName='stringInitializer')
+                static Person personStringFactory(String allBits) {
+                    String[] bits = allBits.split(',')
+                    new Person(bits[0], bits[1], bits[2].toInteger())
+                }
+            }
+
+            @CompileStatic
+            def test() {
+                assert new Person(Person.createInitializer().firstName('John').lastName('Smith').age(10)).toString() == 'Person(John, Smith, 10)'
+                assert new Person(Person.fullNameInitializer().fullName('John Smith').age(10)).toString() == 'Person(John, Smith, 10)'
+                assert new Person(Person.listInitializer().nameParts(['John', 'Smith']).age(10)).toString() == 'Person(John, Smith, 10)'
+                assert Person.personStringFactory(Person.stringInitializer().allBits("John,Smith,10")).toString() == 'Person(John, Smith, 10)'
+            }
+            test()
+        '''
+    }
 }
diff --git a/src/test/org/codehaus/groovy/transform/CanonicalComponentsTransformTest.groovy b/src/test/org/codehaus/groovy/transform/CanonicalComponentsTransformTest.groovy
index 3a7e737..b5c14e4 100644
--- a/src/test/org/codehaus/groovy/transform/CanonicalComponentsTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/CanonicalComponentsTransformTest.groovy
@@ -535,6 +535,46 @@ class CanonicalComponentsTransformTest extends GroovyShellTestCase {
     void testToStringForEnums() {
         assert Color.PURPLE.toString() == 'org.codehaus.groovy.transform.Color(r:255, g:0, b:255)'
     }
+
+    void testCustomCopyConstructor_GROOVY7016() {
+        new GroovyShell().evaluate """
+            import org.codehaus.groovy.transform.Shopper
+            def p1 = new Shopper('John', [['bread', 'milk'], ['bacon', 'eggs']])
+            def p2 = p1.clone()
+            p2.shoppingHistory[0][1] = 'jam'
+            assert p1.shoppingHistory[0] == ['bread', 'milk']
+            assert p2.shoppingHistory[0] == ['bread', 'jam']
+        """
+    }
+
+    void testNullCloneableField_GROOVY7091() {
+        new GroovyShell().evaluate """
+            import groovy.transform.AutoClone
+            @AutoClone
+            class B {
+              String name='B'
+            }
+
+            @AutoClone
+            class A {
+              B b
+              C c
+              ArrayList x
+              List y
+              String name='A'
+            }
+
+            @AutoClone
+            class C {
+              String name='C'
+            }
+
+            def b = new B().clone()
+            assert b
+            assert new A(b:b).clone()
+            assert new A().clone()
+        """
+    }
 }
 
 @TupleConstructor
@@ -722,3 +762,14 @@ enum Color {
     int r, g, b
     Color(int r, g, b) { this.r = r; this.g = g; this.b = b }
 }
+
+ at TupleConstructor(force=true) @AutoClone(style=COPY_CONSTRUCTOR)
+class Shopper {
+    final String name
+    final List<List<String>> shoppingHistory
+    Shopper(Shopper other) {
+        name = other.name
+        // requires deep clone
+        shoppingHistory = other.shoppingHistory*.clone()
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
index 798f92a..794043e 100644
--- a/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/DelegateTransformTest.groovy
@@ -487,6 +487,51 @@ class DelegateTransformTest extends CompilableTestSupport {
         """
     }
 
+    // GROOVY-7243
+    void testInclude() {
+        assertScript '''
+            class Book {
+                String title
+                String author
+
+                String getTitleAndAuthor() {
+                    "${title} : ${author}"
+                }
+
+                String getAuthorAndTitle() {
+                    "${author} : ${title}"
+                }
+            }
+
+            class OwnedBook {
+                String owner
+
+                @Delegate(includes=['author', 'getTitleAndAuthor'])
+                Book book
+            }
+            
+            Book book = new Book(title: 'Ulysses', author: 'James Joyce')
+            OwnedBook ownedBook = new OwnedBook(owner: 'John Smith', book: book)
+
+            ownedBook.author = 'John Smith'
+            assert book.author == 'John Smith'
+
+            assert ownedBook.getTitleAndAuthor() == 'Ulysses : John Smith'
+
+            try {
+                ownedBook.getAuthorAndTitle()
+                assert false, 'Non-included methods should not be delegated'
+            } catch(groovy.lang.MissingMethodException expected) {
+            }
+
+            try {
+                ownedBook.title = 'Finnegans Wake'
+                assert false, 'Non-included properties should not be delegated'
+            } catch(groovy.lang.MissingPropertyException expected) {
+            }
+        '''
+    }
+    
     // GROOVY-6329
     void testIncludeAndExcludeByType() {
         assertScript """
@@ -597,6 +642,55 @@ def foo = new Foo()
 assert foo.dm.x == '123'
 '''
     }
+
+    // GROOVY-7118
+    void testDelegateOfMethodHavingPlaceholder() {
+        assertScript """
+            interface FooInt {
+              public <T extends Throwable> T get(Class<T> clazz) throws Exception
+            }
+
+            class Foo implements FooInt {
+              public <T extends Throwable> T get(Class<T> clazz) throws Exception {
+                clazz.newInstance()
+              }
+            }
+
+            class FooMain {
+                @Delegate Foo foo = new Foo()
+            }
+
+            @groovy.transform.CompileStatic
+            class FooMain2 {
+                @Delegate Foo foo = new Foo()
+            }
+
+            assert new FooMain().get(Exception).class == Exception
+            assert new FooMain2().get(Exception).class == Exception
+
+            import org.codehaus.groovy.transform.Bar
+            class BarMain {
+                @Delegate Bar bar = new Bar()
+            }
+            assert new BarMain().get(Exception).class == Exception
+        """
+    }
+
+    // GROOVY-7261
+    void testShouldWorkWithLazyTransform() {
+        assertScript '''
+            class Foo {
+                private @Delegate @Lazy ArrayList list = ['bar', 'baz']
+                // fragile: $list is an internal implementation detail that may change
+                def getInternalDelegate() { $list }
+            }
+
+            def f = new Foo()
+            assert f.internalDelegate == null
+            assert f.size() == 2
+            assert f.internalDelegate == ['bar', 'baz']
+        '''
+    }
 }
 
 interface DelegateFoo {
@@ -652,6 +746,16 @@ class SomeClass4619 {
     SomeOtherInterface4619 delegate
 }
 
+interface BarInt {
+    public <T extends Throwable> T get(Class<T> clazz) throws Exception
+}
+
+class Bar implements BarInt {
+    public <T extends Throwable> T get(Class<T> clazz) throws Exception {
+        clazz.newInstance()
+    }
+}
+
 // DO NOT MOVE INSIDE THE TEST SCRIPT OR IT WILL NOT TEST
 // WHAT IT IS SUPPOSED TO TEST ANYMORE !
 class DelegateMap {
diff --git a/src/test/org/codehaus/groovy/transform/InheritConstructorsTransformTest.groovy b/src/test/org/codehaus/groovy/transform/InheritConstructorsTransformTest.groovy
index 7a1ed53..26fac43 100644
--- a/src/test/org/codehaus/groovy/transform/InheritConstructorsTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/InheritConstructorsTransformTest.groovy
@@ -57,6 +57,59 @@ class InheritConstructorsTransformTest extends GroovyShellTestCase {
         """
     }
 
+    void testCopyAnnotations_groovy7059() {
+        assertScript """
+            import java.lang.annotation.*
+            import groovy.transform.InheritConstructors
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @Target([ElementType.CONSTRUCTOR])
+            public @interface Foo1 {}
+
+            @Retention(RetentionPolicy.SOURCE)
+            @Target([ElementType.CONSTRUCTOR])
+            public @interface Foo2 {}
+
+            @Retention(RetentionPolicy.RUNTIME)
+            @Target([ElementType.PARAMETER])
+            public @interface Foo3 {}
+
+            class Bar {
+                @Foo1 @Foo2
+                Bar() {}
+
+                @Foo2
+                Bar(@Foo3 String name) {}
+
+                @Foo1
+                Bar(Integer num) {}
+
+                Bar(String name, @Foo3 Integer num) {}
+            }
+
+            @InheritConstructors(constructorAnnotations=true, parameterAnnotations=true)
+            class Baz extends Bar {}
+
+            new Baz().class.constructors.each { cons ->
+                def ans = cons.annotations.toString() + cons.parameterAnnotations.toString()
+                switch(cons.toString()) {
+                    case 'public Baz(java.lang.String,java.lang.Integer)':
+                        assert ans == '[][[], [@Foo3()]]'
+                        break
+                    case 'public Baz(java.lang.String)':
+                        assert ans == '[][[@Foo3()]]'
+                        break
+                    case 'public Baz(java.lang.Integer)':
+                        assert ans == '[@Foo1()][[]]'
+                        break
+                    case 'public Baz()':
+                        assert ans == '[@Foo1()][]'
+                        break
+                }
+            }
+        """
+    }
+
     void testInnerClassUsage() {
         assertScript """
             import groovy.transform.InheritConstructors
diff --git a/src/test/org/codehaus/groovy/transform/LocalASTTransformTest.groovy b/src/test/org/codehaus/groovy/transform/LocalASTTransformTest.groovy
index c9afcb3..af17e5c 100644
--- a/src/test/org/codehaus/groovy/transform/LocalASTTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/LocalASTTransformTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.transform
 
 import org.codehaus.groovy.control.CompilationFailedException
diff --git a/src/test/org/codehaus/groovy/transform/MemoizedASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/MemoizedASTTransformationTest.groovy
index 0c7b011..f4a933e 100644
--- a/src/test/org/codehaus/groovy/transform/MemoizedASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/MemoizedASTTransformationTest.groovy
@@ -144,6 +144,16 @@ class MemoizedASTTransformationTest extends GroovyTestCase {
         assertEquals(ins.methodWithoutParams(), 123)
     }
 
+    void testVarargsMemoizedMethod() {
+        def ins = new MemoizedTestClassWithVarargs()
+        assertEquals(ins.getValue(12, 'foo', 'boo'), 'foo')
+    }
+
+    void testMultiDimensionalArrayMemoizedMethod() {
+        def ins = new MemoizedTestClassWithMultiDimensionalArray()
+        assertEquals(ins.getValue(new String[2][2]), 'foo')
+    }
+
     // -- static methods -- //
 
     void testStaticMethodWithoutParams() {
@@ -274,6 +284,20 @@ class MemoizedTestClass {
     }
 }
 
+class MemoizedTestClassWithVarargs {
+    @Memoized
+    String getValue(Integer inp, ... params) {
+        'foo'
+    }
+}
+
+class MemoizedTestClassWithMultiDimensionalArray {
+    @Memoized
+    String getValue(Object[][] params) {
+        'foo'
+    }
+}
+
 @CompileStatic
 class MemoizedTestClass3 {
     int methodCallCounter
diff --git a/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy b/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy
index 6090b06..9225465 100644
--- a/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/NewifyTransformTest.groovy
@@ -144,4 +144,14 @@ class NewifyTransformTest extends GroovyShellTestCase {
             assert t.toString() == 'Branch(Leaf(1), Branch(Branch(Leaf(2), Leaf(3)), Leaf(4)))'
         """
     }
+
+    void testNewifyInnerClassNode_Groovy6438() {
+        def test = evaluate '''
+            @Newify String test() {
+              new Object() { def x() { String.new('ABC') } }.x()
+            }
+            test()
+        '''
+        assert test == 'ABC'
+    }
 }
\ No newline at end of file
diff --git a/src/test/org/codehaus/groovy/transform/PackageScopeTransformTest.groovy b/src/test/org/codehaus/groovy/transform/PackageScopeTransformTest.groovy
index 8032632..8aff762 100644
--- a/src/test/org/codehaus/groovy/transform/PackageScopeTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/PackageScopeTransformTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2008-2010 the original author or authors.
+ * Copyright 2008-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -35,6 +35,8 @@ class PackageScopeTransformTest extends GroovyShellTestCase {
                 def method() {}
             }
             class Bar {
+                Bar() {}
+                @PackageScope Bar(String x) { this.x = x }
                 @PackageScope String x
                 @PackageScope def method() {}
             }
@@ -78,6 +80,24 @@ class PackageScopeTransformTest extends GroovyShellTestCase {
             } else {
                 assert Modifier.isPublic(c.modifiers)
             }
+            def cons = c.declaredConstructors
+            if (c.name == 'Bar') {
+                assert cons.size() == 2
+                cons.each { con ->
+                    if (con.parameterTypes*.name == []) {
+                        assert Modifier.isPublic(con.modifiers)
+                    } else {
+                        assert con.parameterTypes*.name == ['java.lang.String']
+                        assert !Modifier.isPrivate(con.modifiers)
+                        assert !Modifier.isPublic(con.modifiers)
+                        assert !Modifier.isProtected(con.modifiers)
+                    }
+
+                }
+            } else {
+                assert cons.size() == 1
+                assert Modifier.isPublic(cons[0].modifiers)
+            }
         }
     }
 }
\ No newline at end of file
diff --git a/src/test/org/codehaus/groovy/transform/SynchronizedTransformTest.groovy b/src/test/org/codehaus/groovy/transform/SynchronizedTransformTest.groovy
index d7024e8..572776b 100644
--- a/src/test/org/codehaus/groovy/transform/SynchronizedTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/SynchronizedTransformTest.groovy
@@ -17,9 +17,11 @@ package org.codehaus.groovy.transform
 
 import groovy.transform.CompileStatic
 import groovy.transform.Synchronized
+import org.codehaus.groovy.control.CompilationFailedException
 
 import java.util.concurrent.CountDownLatch
-import java.util.concurrent.TimeUnit
+
+import static java.util.concurrent.TimeUnit.SECONDS
 
 /**
  * @author Paul King
@@ -27,10 +29,10 @@ import java.util.concurrent.TimeUnit
  */
 class SynchronizedTransformTest extends GroovyTestCase {
 
-    def countReadyLatch = new CountDownLatch(1);
-    def testReadyLatch = new CountDownLatch(1);
-    CountDownLatch countReadyLatchCS = new CountDownLatch(1);
-    CountDownLatch testReadyLatchCS = new CountDownLatch(1);
+    def countReadyLatch = new CountDownLatch(1)
+    def testReadyLatch = new CountDownLatch(1)
+    CountDownLatch countReadyLatchCS = new CountDownLatch(1)
+    CountDownLatch testReadyLatchCS = new CountDownLatch(1)
 
     void testSynchronized() {
         def c = new Count()
@@ -38,7 +40,17 @@ class SynchronizedTransformTest extends GroovyTestCase {
             c.incDec()
         }
         testReadyLatch.countDown()
-        countReadyLatch.await(5, TimeUnit.SECONDS)
+        countReadyLatch.await(5, SECONDS)
+        c.incDec()
+    }
+
+    void testSynchronizedCustom() {
+        def c = new CountCustom()
+        Thread.start {
+            c.incDec()
+        }
+        testReadyLatch.countDown()
+        countReadyLatch.await(5, SECONDS)
         c.incDec()
     }
 
@@ -48,10 +60,31 @@ class SynchronizedTransformTest extends GroovyTestCase {
             c.incDec()
         }
         testReadyLatchCS.countDown()
-        countReadyLatchCS.await(5, TimeUnit.SECONDS)
+        countReadyLatchCS.await(5, SECONDS)
         c.incDec()
     }
 
+    void testSynchronizedAbstractShouldNotCompile() {
+        def msg = shouldFail CompilationFailedException, '''
+            class Foo {
+                @groovy.transform.Synchronized
+                abstract void bar()
+            }
+        '''
+        assert msg.contains("annotation not allowed on abstract method 'bar'")
+    }
+
+    void testSynchronizedInstanceLockWithStaticMethodShouldNotCompile() {
+        def msg = shouldFail CompilationFailedException, '''
+            class Foo {
+                private mylock = new Object[0]
+                @groovy.transform.Synchronized('mylock')
+                static void bar() {}
+            }
+        '''
+        assert msg.contains("lock field with name 'mylock' must be static for static method 'bar'")
+    }
+
     class Count {
         private val = 0
 
@@ -59,7 +92,20 @@ class SynchronizedTransformTest extends GroovyTestCase {
         void incDec() {
             assert val == 0; val++; assert val == 1
             countReadyLatch.countDown()
-            testReadyLatch.await(5, TimeUnit.SECONDS)
+            testReadyLatch.await(5, SECONDS)
+            assert val == 1; val--; assert val == 0
+        }
+    }
+
+    class CountCustom {
+        private val = 0
+        private mylock = new Object[0]
+
+        @Synchronized('mylock')
+        void incDec() {
+            assert val == 0; val++; assert val == 1
+            countReadyLatch.countDown()
+            testReadyLatch.await(5, SECONDS)
             assert val == 1; val--; assert val == 0
         }
     }
@@ -72,7 +118,7 @@ class SynchronizedTransformTest extends GroovyTestCase {
         void incDec() {
             assert val == 0; val++; assert val == 1
             countReadyLatchCS.countDown()
-            testReadyLatchCS.await(5, TimeUnit.SECONDS)
+            testReadyLatchCS.await(5, SECONDS)
             assert val == 1; val--; assert val == 0
         }
     }
diff --git a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
index 82c1f11..e2476f1 100644
--- a/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/ToStringTransformTest.groovy
@@ -116,6 +116,27 @@ class ToStringTransformTest extends GroovyShellTestCase {
         assertEquals("Person(surName:Doe, age:50)", toString)
     }
 
+    void testIncludeSuperProperties() {
+        def toString = evaluate("""
+            import groovy.transform.ToString
+
+            class Person {
+                String name
+                private boolean flag = true
+                static final int MAX_NAME_LENGTH = 30
+            }
+
+            @ToString(includeSuperProperties = true, includeNames = true)
+            class BandMember extends Person {
+                String bandName
+            }
+
+            new BandMember(name:'Bono', bandName: 'U2').toString()
+        """)
+
+        assertEquals("BandMember(bandName:U2, name:Bono)", toString)
+    }
+
     void testSuper()  {
 
         def toString = evaluate("""
diff --git a/src/test/org/codehaus/groovy/transform/stc/SignatureCodecTest.groovy b/src/test/org/codehaus/groovy/transform/stc/SignatureCodecTest.groovy
index a0e15d0..d2d6702 100644
--- a/src/test/org/codehaus/groovy/transform/stc/SignatureCodecTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/stc/SignatureCodecTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.transform.stc
 
 import static org.codehaus.groovy.ast.ClassHelper.*
diff --git a/src/test/org/codehaus/groovy/transform/tailrec/TailRecursiveExamples.groovy b/src/test/org/codehaus/groovy/transform/tailrec/TailRecursiveExamples.groovy
index 066d30a..7f822f6 100644
--- a/src/test/org/codehaus/groovy/transform/tailrec/TailRecursiveExamples.groovy
+++ b/src/test/org/codehaus/groovy/transform/tailrec/TailRecursiveExamples.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.transform.tailrec
 
 import groovy.transform.CompileStatic
diff --git a/src/test/org/codehaus/groovy/transform/tailrec/TernaryToIfStatementConverterTest.groovy b/src/test/org/codehaus/groovy/transform/tailrec/TernaryToIfStatementConverterTest.groovy
index 189daa0..0500cfd 100644
--- a/src/test/org/codehaus/groovy/transform/tailrec/TernaryToIfStatementConverterTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/tailrec/TernaryToIfStatementConverterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.transform.tailrec
 
 import org.codehaus.groovy.ast.builder.AstAssert
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy6697Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy6697Bug.groovy
new file mode 100644
index 0000000..6b28b17
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy6697Bug.groovy
@@ -0,0 +1,149 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy6697Bug extends GroovyTestCase {
+    void testShouldAllowTraitSuperPropertyNotation() {
+        assertScript '''
+trait A {
+  String foo
+}
+
+class C implements A {
+  void setBar(String foo) {
+    // This fails with "Caught: groovy.lang.MissingPropertyException: No such property: super for class: A"
+    A.super.foo = foo
+
+    // This work
+    //A.super.setFoo(foo)
+  }
+
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.bar = 'bar'
+assert c.yell() == 'BAR!!'
+        '''
+    }
+
+    void testShouldAllowTraitSuperPropertyNotationWithAmbiguousCall() {
+        assertScript '''
+trait A {
+  String foo
+}
+
+trait B {
+    String foo
+}
+
+class C implements A,B {
+  void setBar(String foo) {
+    A.super.foo = foo+'Bar'
+  }
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.foo = 'foo'
+c.bar = 'bar'
+assert c.yell() == 'FOO!!'
+        '''
+
+    assertScript '''
+trait A {
+  String foo
+}
+
+trait B {
+    String foo
+}
+
+class C implements A,B {
+  void setBar(String foo) {
+    B.super.foo = foo+'Bar'
+  }
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.foo = 'foo'
+c.bar = 'bar'
+assert c.yell() == 'BARBAR!!'
+        '''
+    }
+
+    void testShouldAllowTraitSuperSetterNotation() {
+        assertScript '''
+trait A {
+  String foo
+}
+
+class C implements A {
+  void setBar(String foo) {
+    A.super.setFoo(foo)
+  }
+
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.bar = 'bar'
+assert c.yell() == 'BAR!!'
+        '''
+    }
+
+    void testShouldAllowTraitSuperSetterNotationWithAmbiguousCall() {
+        assertScript '''
+trait A {
+  String foo
+}
+
+trait B {
+    String foo
+}
+
+class C implements A,B {
+  void setBar(String foo) {
+    A.super.setFoo(foo+'Bar')
+  }
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.foo = 'foo'
+c.bar = 'bar'
+assert c.yell() == 'FOO!!'
+        '''
+
+    assertScript '''
+trait A {
+  String foo
+}
+
+trait B {
+    String foo
+}
+
+class C implements A,B {
+  void setBar(String foo) {
+    B.super.setFoo(foo+'Bar')
+  }
+  def yell() { foo.toUpperCase() + "!!" }
+}
+def c = new C()
+c.foo = 'foo'
+c.bar = 'bar'
+assert c.yell() == 'BARBAR!!'
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy6741Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy6741Bug.groovy
new file mode 100644
index 0000000..d1bf97b
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy6741Bug.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy6741Bug extends GroovyTestCase {
+    void testRunTimeCoercionOfTraitUsingGenerics() {
+        assertScript '''
+            trait GPredicate<T> {
+                abstract boolean test( T t )
+            }
+
+            GPredicate<Integer> p = { Integer n -> n > 1 }
+            assert p.test(0) == false
+            assert p.test(1) == false
+            assert p.test(2) == true
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7011Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7011Bug.groovy
new file mode 100644
index 0000000..3eb792b
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7011Bug.groovy
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7011Bug extends GroovyTestCase {
+    void testTraitWithDefaultArgumentMethod() {
+        assertScript '''
+            trait HiSupport {
+               def sayHi(String msg = "hi") {
+                   msg
+               }
+            }
+
+            class A implements HiSupport { }
+
+            def result = new A().sayHi()
+            assert result == 'hi'
+        '''
+    }
+
+    void testTraitWithDefaultArgumentMethod2() {
+        assertScript '''
+            trait HiSupport {
+               def sayHi(int x, String msg = "hi") {
+                   "${msg}, $x"
+               }
+            }
+
+            class A implements HiSupport { }
+
+            def result = new A().sayHi(2)
+            assert result == 'hi, 2'
+        '''
+    }
+
+    void testTraitWithDefaultArgumentMethodCompileStatic() {
+        assertScript '''import groovy.transform.CompileStatic
+
+            @CompileStatic
+            trait HiSupport {
+               def sayHi(String msg = "hi") {
+                   msg
+               }
+            }
+
+            @CompileStatic
+            class A implements HiSupport { }
+
+            @CompileStatic
+            void foo() {
+                def result = new A().sayHi()
+                assert result == 'hi'
+            }
+            foo()
+        '''
+    }
+
+    void testTraitWithDefaultArgumentMethod2CompileStatic() {
+        assertScript '''import groovy.transform.CompileStatic
+
+            @CompileStatic
+            trait HiSupport {
+               def sayHi(int x=1, String msg = "hi") {
+                   "${msg}, $x"
+               }
+            }
+
+            @CompileStatic
+            class A implements HiSupport { }
+
+            @CompileStatic
+
+            void foo() {
+                def result = new A().sayHi(2)
+                assert result == 'hi, 2'
+            }
+            foo()
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7190Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7190Bug.groovy
new file mode 100644
index 0000000..8a3bba4
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7190Bug.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7190Bug extends GroovyTestCase {
+    void testStaticPropertyBug() {
+        assertScript '''
+            trait SomeTrait {
+                private static String someString
+
+                static String getStringValue() {
+                    if(someString == null) {
+                        someString = 'Default Value'
+                    }
+                    someString
+                }
+
+                static String getStringValueUsingThis() {
+                    if(this.someString == null) {
+                        someString = 'Default Value'
+                    }
+                    this.someString
+                }
+            }
+            class SomeClass implements SomeTrait {}
+
+            assert 'Default Value' == SomeClass.stringValue
+            assert 'Default Value' == SomeClass.stringValueUsingThis
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7196Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196Bug.groovy
new file mode 100644
index 0000000..9d41ce8
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196Bug.groovy
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7196Bug extends GroovyTestCase {
+    void testShouldNotThrowDuplicateMethodWithPrecompiledTrait() {
+        assertScript '''import org.codehaus.groovy.transform.traitx.Groovy7196SupportTrait
+            class SomeTestClass implements Groovy7196SupportTrait {}
+            assert SomeTestClass.org_codehaus_groovy_transform_traitx_Groovy7196SupportTrait__someString == 'ok'
+        '''
+    }
+    void testStaticFieldShouldBeInitialized() {
+        assert Groovy7196SupportTraitImpl.org_codehaus_groovy_transform_traitx_Groovy7196SupportTrait__someString == 'ok'
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTrait.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTrait.groovy
new file mode 100644
index 0000000..64e7f5a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTrait.groovy
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+trait Groovy7196SupportTrait {
+    public static String someString = 'ok'
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTraitImpl.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTraitImpl.groovy
new file mode 100644
index 0000000..962a480
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7196SupportTraitImpl.groovy
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7196SupportTraitImpl implements Groovy7196SupportTrait {
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7206Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7206Bug.groovy
new file mode 100644
index 0000000..4013a5e
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7206Bug.groovy
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7206Bug extends GroovyTestCase {
+    void testShouldNotThrowNPEDuringCompilation() {
+        assertScript '''
+            trait SetUnknown {
+                def setup() {
+                    this.unknownProperty = 1
+                }
+            }
+            class A implements SetUnknown {
+                def unknownProperty
+            }
+            def a = new A()
+            a.setup()
+            assert a.unknownProperty == 1
+        '''
+    }
+
+    void testShouldNotThrowNPEDuringCompilation2() {
+        assertScript '''
+            trait SetUnknown {
+                int pInt = 2
+                def setup() {
+                    this.unknownProperty = 1
+                }
+            }
+            class A implements SetUnknown {
+                def unknownProperty
+            }
+            def a = new A()
+            a.setup()
+            assert a.unknownProperty == 1
+            assert a.pInt == 2
+        '''
+    }
+
+    void testShouldNotThrowNPEDuringCompilation3() {
+        assertScript '''
+            trait SetUnknown {
+                int pInt = 2
+                def setup() {
+                    this.unknownProperty = unknownProperty + pInt
+                }
+            }
+            class A implements SetUnknown {
+                def unknownProperty = 1
+            }
+            def a = new A()
+            a.setup()
+            assert a.unknownProperty == 3
+            assert a.pInt == 2
+        '''
+    }
+
+    void testShouldRecognizeStaticProperty() {
+        assertScript '''
+trait Validateable {
+    private static Map constraintsMapInternal
+    static Map getConstraintsMap() {
+        if(this.constraintsMapInternal == null) {
+            this.constraintsMapInternal = [:]
+        }
+    }
+}
+class ValidateTest implements Validateable {}
+def v = new ValidateTest()
+assert v.constraintsMap == [:]
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7213Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7213Bug.groovy
new file mode 100644
index 0000000..cf78f6c
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7213Bug.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7213Bug extends GroovyTestCase {
+    void testShouldAllowPrivateMethodInTraitEvenIfUseCompileStatic() {
+        assertScript '''
+trait Foo {
+   private int f(int x) { x }
+   int foo() { f(2) }
+}
+
+ at groovy.transform.CompileStatic
+class A implements Foo {}
+assert new A().foo() == 2
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7214Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7214Bug.groovy
new file mode 100644
index 0000000..7dbe251
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7214Bug.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7214Bug extends GroovyTestCase {
+    void testShouldAllowPrivateStaticMethodCallInTrait() {
+        assertScript '''
+            trait SomeTrait {
+                private static int magic = 0
+
+                static getSomeValue() {
+                    someHelperMethod()
+                    magic
+                }
+
+                private static someHelperMethod() {
+                    magic = 42
+                }
+            }
+            class SomeClass implements SomeTrait {}
+
+            assert SomeClass.someValue == 42'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7215Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7215Bug.groovy
new file mode 100644
index 0000000..49870d1
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7215Bug.groovy
@@ -0,0 +1,45 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+import org.codehaus.groovy.tools.stubgenerator.StringSourcesStubTestCase
+
+class Groovy7215Bug extends StringSourcesStubTestCase {
+    @Override
+    Map<String, String> provideSources() {
+        [
+                'FooJ.java': '''
+
+                public class FooJ {
+                    public static String TEXT = "FooJ";
+                }
+            ''',
+                'FilterConfig.groovy':'''
+
+                @groovy.transform.CompileStatic
+                class FilterConfig implements org.codehaus.groovy.transform.traitx.Groovy7215SupportTrait {
+                    String text
+                }
+        '''
+        ]
+    }
+
+    @Override
+    void verifyStubs() {
+
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7215SupportTrait.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7215SupportTrait.groovy
new file mode 100644
index 0000000..f1ffd2a
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7215SupportTrait.groovy
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+ at groovy.transform.CompileStatic
+trait Groovy7215SupportTrait {
+    void setText(String text) {}
+    String getText() { 'ok' }
+}
\ No newline at end of file
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7217Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7217Bug.groovy
new file mode 100644
index 0000000..3e35bac
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7217Bug.groovy
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7217Bug extends GroovyTestCase {
+    void testNumberInitializationInTrait() {
+        assertScript '''
+            trait Version {
+                Long version = 1
+            }
+
+            class HasVersion implements Version {}
+
+            def v = new HasVersion()
+            assert v.version == 1'''
+    }
+
+    void testAnyInitializerInTrait() {
+        assertScript '''
+            class SomeA {}
+            trait DummyInit {
+                SomeA a = init()
+            }
+            class Dummy implements DummyInit {
+                def init() {
+                    new SomeA()
+                }
+            }
+            def d = new Dummy()
+            assert d.a instanceof SomeA
+        '''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy
new file mode 100644
index 0000000..9bf18fb
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7255Bug.groovy
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7255Bug extends GroovyTestCase {
+    void testShouldAllowSettingStaticFieldInTraitUsingCompileStatic() {
+        assertScript '''
+ at groovy.transform.CompileStatic
+trait SomeTrait {
+    static List stuff = [1,2,3]
+
+    static void initStuff(List l) {
+        stuff = stuff + l
+    }
+}
+
+class A implements SomeTrait {}
+A.initStuff([4,5,6])
+assert A.stuff == [1,2,3,4,5,6]
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7269Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7269Bug.groovy
new file mode 100644
index 0000000..ef1ba05
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7269Bug.groovy
@@ -0,0 +1,58 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7269Bug extends GroovyTestCase {
+    void testTraitWithMetaClassMod() {
+        assertScript '''
+            trait SomeTrait {
+                String title
+            }
+
+            class Widget implements SomeTrait {}
+
+            Widget.metaClass.getTitle = {
+                'Some Default Title'
+            }
+            def w = new Widget()
+            w.title = 'Some New Title'
+            assert w.title == 'Some Default Title'
+        '''
+    }
+
+    // GROOVY-7308
+    void testMixOfStaticAndNotStaticPropertiesOfSameName() {
+        assertScript '''class Widget {
+
+    static Integer someNumber = 42
+}
+
+Widget.metaClass.getSomeNumber = {
+    2112
+}
+
+def widget = new Widget()
+
+assert widget.someNumber == 2112
+
+
+        '''
+    }
+}
+
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7275Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7275Bug.groovy
new file mode 100644
index 0000000..c8242e0
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7275Bug.groovy
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7275Bug extends GroovyTestCase {
+    void testShouldNotThrowCompileBug() {
+        assertScript '''
+
+import groovy.transform.SelfType
+import groovy.transform.CompileStatic
+
+class BitcoinClient {
+   Map<String,Object> getTransaction(String txid) {}
+}
+
+ at SelfType(BitcoinClient)
+ at CompileStatic
+trait BitcoinCLIAPI {
+
+    Map<String, Object> gettransaction(String txid) {
+       return getTransaction(txid)
+    }
+}
+
+BitcoinCLIAPI
+
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/Groovy7285Bug.groovy b/src/test/org/codehaus/groovy/transform/traitx/Groovy7285Bug.groovy
new file mode 100644
index 0000000..6e82271
--- /dev/null
+++ b/src/test/org/codehaus/groovy/transform/traitx/Groovy7285Bug.groovy
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+
+
+
+package org.codehaus.groovy.transform.traitx
+
+class Groovy7285Bug extends GroovyTestCase {
+    void testRuntimeStackableTraits() {
+        assertScript '''trait D {
+    void methodA() { ref << "D"; super.methodA() }
+}
+trait C {
+    void methodA() { ref << "C"; super.methodA() }
+}
+trait B {
+    void methodA() { ref << "B"; super.methodA() }
+}
+trait A {
+    void methodA() { ref << "A" }
+}
+
+class M implements A, D, C, B { List ref = [] }
+class Q {  List ref = []  }
+
+def direct = new M()
+
+println "Static: ${direct.methodA();direct.ref}"
+
+def runtime = new Q().withTraits(A,D,C,B)
+
+// we need another test to make sure that 2 proxies with the same set of traits are different
+// because the traits ordering is different
+def runtime2 = new Q().withTraits(A,D,C,B)
+
+println "Dynamic: ${runtime.methodA();runtime.ref}"
+println "Dynamic 2: ${runtime2.methodA();runtime2.ref}"
+
+assert direct.ref == ['B','C','D','A']
+assert direct.ref == runtime.ref
+assert runtime2.ref == ['B','C','D','A']
+
+'''
+    }
+}
diff --git a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
index 2f46026..291f544 100644
--- a/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
+++ b/src/test/org/codehaus/groovy/transform/traitx/TraitASTTransformationTest.groovy
@@ -16,9 +16,32 @@
 
 package org.codehaus.groovy.transform.traitx
 
-import groovy.transform.NotYetImplemented
+import groovy.transform.SelfType
+import org.codehaus.groovy.ast.ClassHelper
+import org.codehaus.groovy.ast.expr.ClassExpression
+import org.codehaus.groovy.ast.expr.ListExpression
 
 class TraitASTTransformationTest extends GroovyTestCase {
+    void testTraitOverrideAnnotation() {
+        assertScript '''
+        interface MyInterface {
+            String fooMethod()
+            void noMethod()
+        }
+
+        trait MyTrait implements MyInterface {
+            @Override String fooMethod() { "foo" }
+            @Override void noMethod() { }
+        }
+
+        class Foo implements MyTrait {}
+        def foo = new Foo()
+
+        foo.noMethod()
+        assert foo.fooMethod() == "foo"
+        '''
+    }
+
     void testTraitWithNoMethod() {
         assertScript '''
         trait MyTrait {}
@@ -2113,7 +2136,308 @@ d.foo()
 '''
     }
 
+    // GROOVY-7058
+    void testShouldNotThrowNPEBecauseOfIncompleteGenericsTypeInformation() {
+        assertScript '''
+    class Project { Task task(String name, Map args) {} }
+    class Task {}
+    interface Plugin<P>{}
+    trait PluginUtils {
+        abstract Project getProject()
+
+        public <T extends Task> T createTask(String name, Class<T> type, Closure<?> config) {
+          project.task(name, type: type, config)
+        }
+    }
+
+    class MyPlugin implements Plugin<Project>, PluginUtils { Project project }
+    new MyPlugin()
+'''
+    }
+
+    // GROOVY-7123
+    void testHelperSetterShouldNotReturnVoid() {
+        assertScript '''
+            trait A {
+                def foo
+                def bar() { foo = 42 }
+            }
+            class C implements A {}
+
+            assert new C().bar() == 42
+        '''
+    }
+
     static trait TestTrait {
         int a() { 123 }
     }
+
+    void testSimpleSelfType() {
+        assertScript '''import groovy.transform.SelfType
+        import groovy.transform.CompileStatic
+
+        trait A {
+            int a() { 1 }
+        }
+
+        @CompileStatic
+        @SelfType(A)
+        trait B {
+            int b() { 2*a() }
+        }
+        class C implements A,B {}
+        def c = new C()
+        assert c.b() == 2
+        '''
+    }
+
+    void testSimpleSelfTypeInSubTrait() {
+        assertScript '''import groovy.transform.SelfType
+        import groovy.transform.CompileStatic
+
+        trait A {
+            int a() { 1 }
+        }
+
+        @CompileStatic
+        @SelfType(A)
+        trait B {
+            int b() { 2*a() }
+        }
+
+        @CompileStatic
+        trait SubB extends B {
+            int c() { 3*a() }
+        }
+
+
+        class C implements A,SubB {}
+        def c = new C()
+        assert c.c() == 3
+        '''
+    }
+
+    void testDoubleSelfType() {
+        assertScript '''import groovy.transform.SelfType
+        import groovy.transform.CompileStatic
+
+        trait A {
+            int a() { 1 }
+        }
+        trait A2 {
+            int a2() { 2 }
+        }
+
+        @CompileStatic
+        @SelfType([A,A2])
+        trait B {
+            int b() { 2*a()*a2() }
+        }
+        class C implements A,A2,B {}
+        def c = new C()
+        assert c.b() == 4
+        '''
+    }
+
+    void testClassDoesNotImplementSelfType() {
+        def err = shouldFail '''
+        import groovy.transform.SelfType
+        import groovy.transform.CompileStatic
+
+        @CompileStatic
+        @SelfType([String,Serializable])
+        trait B {
+            String b() { toUpperCase() }
+        }
+        class C implements B {}
+        def c = new C()
+        '''
+        assert err.contains("class 'C' implements trait 'B' but does not extend self type class 'java.lang.String'")
+        assert err.contains("class 'C' implements trait 'B' but does not implement self type interface 'java.io.Serializable'")
+    }
+
+    void testClassDoesNotImplementSelfTypeUsingAbstractClass() {
+        def err = shouldFail '''
+        import groovy.transform.SelfType
+        import groovy.transform.CompileStatic
+
+        @CompileStatic
+        @SelfType([String,Serializable])
+        trait B {
+            String b() { toUpperCase() }
+        }
+        abstract class C implements B {}
+        class D extends C {}
+        def c = new D()
+
+        '''
+        assert err.contains("class 'C' implements trait 'B' but does not extend self type class 'java.lang.String'")
+        assert err.contains("class 'C' implements trait 'B' but does not implement self type interface 'java.io.Serializable'")
+    }
+
+    void testMethodAcceptingThisAsSelfTrait() {
+        assertScript '''
+import groovy.transform.SelfType
+import groovy.transform.CompileStatic
+
+class CommunicationService {
+    static void sendMessage(String from, String to, String message) {
+        println "$from sent [$message] to $to"
+    }
+}
+
+class Device { String id }
+
+ at SelfType(Device)
+ at CompileStatic
+trait Communicating {
+    void sendMessage(Device to, String message) {
+        SecurityService.check(this)
+        CommunicationService.sendMessage(id, to.id, message)
+    }
+}
+
+class MyDevice extends Device implements Communicating {}
+
+def bob = new MyDevice(id:'Bob')
+def alice = new MyDevice(id:'Alice')
+bob.sendMessage(alice,'secret')
+
+class SecurityService {
+    static void check(Device d) { if (d.id==null) throw new SecurityException() }
+}
+'''
+    }
+
+    void testRuntimeSelfType() {
+        assertScript '''import groovy.transform.CompileStatic
+import groovy.transform.SelfType
+
+trait A {
+    int a() { 1 }
+}
+
+ at CompileStatic
+ at SelfType(A)
+trait B {
+    int b() { 2*a() }
+}
+class C implements A {}
+def c = new C() as B
+assert c.b() == 2
+'''
+    }
+
+    void testRuntimeSelfTypeWithInheritance() {
+        assertScript '''import groovy.transform.CompileStatic
+import groovy.transform.SelfType
+
+trait A {
+    int a() { 1 }
+}
+
+ at CompileStatic
+ at SelfType(A)
+trait B {
+    int b() { 2*a() }
+}
+
+trait B2 extends B {}
+
+class C implements A {}
+def c = new C() as B2
+assert c.b() == 2
+'''
+    }
+    void testAnnotationsOfPrecompiledTrait() {
+        def cn = ClassHelper.make(DoubleSelfTypeTrait)
+        def ann = cn.getAnnotations(ClassHelper.make(SelfType))
+        assert ann.size() == 1
+        def st = ann[0]
+        def val = st.getMember('value')
+        assert val instanceof ListExpression
+        val.expressions.each {
+            assert it instanceof ClassExpression
+        }
+    }
+
+
+    @SelfType([String, Date])
+    trait DoubleSelfTypeTrait {}
+
+    //GROOVY-7287
+    void testTraitWithMethodLevelGenericsShadowing() {
+        assertScript '''
+            trait Configurable<ConfigObject> {
+                ConfigObject configObject
+
+                void configure(Closure<Void> configSpec) {
+                    configSpec.resolveStrategy = Closure.DELEGATE_FIRST
+                    configSpec.delegate = configObject
+                    configSpec()
+                }
+            }
+            public <T,U extends Configurable<T>> U configure(Class<U> clazz, @DelegatesTo(type="T") Closure configSpec) {
+                Configurable<T> obj = (Configurable<T>) clazz.newInstance()
+                obj.configure(configSpec)
+                obj
+            }
+
+
+            class Module implements Configurable<ModuleConfig> {
+                String value
+
+                Module(){
+                    configObject = new ModuleConfig()
+                }
+
+
+                @Override
+                void configure(Closure<Void> configSpec) {
+                    Configurable.super.configure(configSpec)
+                    value = "${configObject.name}-${configObject.version}"
+                }
+            }
+
+
+            class ModuleConfig {
+                String name
+                String version
+            }
+            def module = configure(Module) {
+                name = 'test\'
+                version = '1.0\'
+            }
+            assert module.value == 'test-1.0\'
+        '''
+
+        assertScript '''
+            trait SomeTrait {
+                def <T extends Number> T someOtherMethod() {}
+            }
+            class SuperClass<T> implements SomeTrait {}
+            class SubClass extends SuperClass<String> implements SomeTrait {}
+            SubClass.declaredMethods.findAll    {it.name=="someOtherMethod"}.
+                                     each {
+                                         assert it.returnType == Number
+                                         assert it.genericReturnType.name == "T"
+                                     }
+        '''
+    }
+
+    //GROOVY-7297
+    void testMethodlevelGenericsFromPrecompiledClass() {
+        //SomeTrait needs to be outside the script
+        assertScript '''
+            trait SomeTrait {
+                String title
+                public <T> List<T> someMethod(T data) {}
+            }
+            class Foo implements SomeTrait {}
+
+            def sc = new Foo(title: 'some title')
+            assert 'some title' == sc.title
+        '''
+    }
+
 }
diff --git a/src/test/org/codehaus/groovy/util/ManagedLinkedlistTest.groovy b/src/test/org/codehaus/groovy/util/ManagedLinkedlistTest.groovy
index 1dfb013..6964fae 100644
--- a/src/test/org/codehaus/groovy/util/ManagedLinkedlistTest.groovy
+++ b/src/test/org/codehaus/groovy/util/ManagedLinkedlistTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.util
 
 class ManagedLinkedListTest extends GroovyTestCase{
diff --git a/subprojects/groovy-ant/build.gradle b/subprojects/groovy-ant/build.gradle
index 4211167..015d971 100644
--- a/subprojects/groovy-ant/build.gradle
+++ b/subprojects/groovy-ant/build.gradle
@@ -10,3 +10,5 @@ dependencies {
     compile project(':groovy-groovydoc')
     testCompile project(':groovy-test')
 }
+
+apply from: "${rootProject.projectDir}/gradle/jacoco/jacocofix.gradle"
\ No newline at end of file
diff --git a/subprojects/groovy-ant/src/main/java/groovy/util/AntBuilder.java b/subprojects/groovy-ant/src/main/java/groovy/util/AntBuilder.java
index bf0ea04..6475aa2 100644
--- a/subprojects/groovy-ant/src/main/java/groovy/util/AntBuilder.java
+++ b/subprojects/groovy-ant/src/main/java/groovy/util/AntBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -62,6 +62,7 @@ public class AntBuilder extends BuilderSupport {
     private final ProjectHelper2.TargetHandler antTargetHandler = new ProjectHelper2.TargetHandler();
     private final Target collectorTarget;
     private final Target implicitTarget;
+    private Target definingTarget;
     private Object lastCompletedNode;
     // true when inside a task so special ant.target handling occurs just at top level
     boolean insideTask;
@@ -226,6 +227,10 @@ public class AntBuilder extends BuilderSupport {
             log.finest("parent is not null: no perform on nodeCompleted");
             return; // parent will care about when children perform
         }
+        if (definingTarget != null && definingTarget == parent && node instanceof Task) return; // inside defineTarget
+        if (definingTarget == node) {
+            definingTarget = null;
+        }
 
         // as in Target.execute()
         if (node instanceof Task) {
@@ -401,6 +406,8 @@ public class AntBuilder extends BuilderSupport {
             antXmlContext.setCurrentTarget(implicitTarget);
         } else if ("target".equals(name) && !insideTask) {
             return onStartTarget(attrs, tagName, ns);
+        } else if ("defineTarget".equals(name) && !insideTask) {
+            return onDefineTarget(attrs, "target", ns);
         }
 
         try {
@@ -411,17 +418,34 @@ public class AntBuilder extends BuilderSupport {
         }
 
         insideTask = true;
-        final RuntimeConfigurable wrapper = (RuntimeConfigurable) antXmlContext.getWrapperStack().lastElement();
+        final RuntimeConfigurable wrapper = antXmlContext.getWrapperStack().lastElement();
         return wrapper.getProxy();
     }
 
+    private Target onDefineTarget(final Attributes attrs, String tagName, String ns) {
+        final Target target = new Target();
+        target.setProject(project);
+        target.setLocation(new Location(antXmlContext.getLocator()));
+        try {
+            antTargetHandler.onStartElement(ns, tagName, tagName, attrs, antXmlContext);
+            final Target newTarget = getProject().getTargets().get(attrs.getValue("name"));
+            antXmlContext.setCurrentTarget(newTarget);
+            definingTarget = newTarget;
+            return newTarget;
+        }
+        catch (final SAXParseException e) {
+            log.log(Level.SEVERE, "Caught: " + e, e);
+        }
+        return null;
+    }
+
     private Target onStartTarget(final Attributes attrs, String tagName, String ns) {
         final Target target = new Target();
         target.setProject(project);
         target.setLocation(new Location(antXmlContext.getLocator()));
         try {
             antTargetHandler.onStartElement(ns, tagName, tagName, attrs, antXmlContext);
-            final Target newTarget = (Target) getProject().getTargets().get(attrs.getValue("name"));
+            final Target newTarget = getProject().getTargets().get(attrs.getValue("name"));
 
             // execute dependencies (if any)
             final Vector<Target> targets = new Vector<Target>();
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
index e161180..f45c0c0 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovy.java
@@ -59,6 +59,7 @@ import java.util.Vector;
 public class Groovy extends Java {
     private static final String PREFIX = "embedded_script_in_";
     private static final String SUFFIX = "groovy_Ant_task";
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
 
     private final LoggingHelper log = new LoggingHelper(this);
 
@@ -419,7 +420,7 @@ public class Groovy extends Java {
                 final Field contextField = propsHandler.getClass().getDeclaredField("context");
                 contextField.setAccessible(true);
                 final Object context = contextField.get(propsHandler);
-                mavenPom = InvokerHelper.invokeMethod(context, "getProject", new Object[0]);
+                mavenPom = InvokerHelper.invokeMethod(context, "getProject", EMPTY_OBJECT_ARRAY);
             }
             catch (Exception e) {
                 throw new BuildException("Impossible to retrieve Maven's Ant project: " + e.getMessage(), getLocation());
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
index d754bdc..ba66a03 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/Groovyc.java
@@ -169,6 +169,7 @@ import org.codehaus.groovy.tools.javac.JavaAwareCompilationUnit;
  * @author Paul King
  */
 public class Groovyc extends MatchingTask {
+    private static final URL[] EMPTY_URL_ARRAY = new URL[0];
     private final LoggingHelper log = new LoggingHelper(this);
 
     private Path src;
@@ -1252,7 +1253,7 @@ public class Groovyc extends MatchingTask {
         }
         ClassLoader parent = getIncludeantruntime()
                 ? getClass().getClassLoader()
-                : new AntClassLoader(new RootLoader(new URL[0], null), getProject(), getClasspath());
+                : new AntClassLoader(new RootLoader(EMPTY_URL_ARRAY, null), getProject(), getClasspath());
         if (parent instanceof AntClassLoader) {
             AntClassLoader antLoader = (AntClassLoader) parent;
             String[] pathElm = antLoader.getClasspath().split(File.pathSeparator);
diff --git a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/package.html b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/package.html
index aa78a68..0660382 100644
--- a/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/package.html
+++ b/subprojects/groovy-ant/src/main/java/org/codehaus/groovy/ant/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package org.codehaus.groovy.ant.*</title>
diff --git a/subprojects/groovy-ant/src/spec/doc/ant-builder.adoc b/subprojects/groovy-ant/src/spec/doc/ant-builder.adoc
new file mode 100644
index 0000000..bffbe97
--- /dev/null
+++ b/subprojects/groovy-ant/src/spec/doc/ant-builder.adoc
@@ -0,0 +1,71 @@
+= AntBuilder
+
+Despite being primarily a build tool, http://ant.apache.org/[Apache Ant] is
+a very practical tool for manipulating files including zip files, copy, resource processing, ...
+But if ever you’ve been working with a `build.xml` file or some _Jelly script_
+and found yourself a little restricted by all those pointy brackets, or
+found it a bit weird using XML as a scripting language and wanted
+something a little cleaner and more straight forward, then maybe Ant
+scripting with Groovy might be what you're after.
+
+Groovy has a helper class called `AntBuilder` which makes the scripting
+of Ant tasks really easy; allowing a real scripting language to be used
+for programming constructs (variables, methods, loops, logical
+branching, classes etc). It still looks like a neat concise version of
+Ant's XML without all those pointy brackets; though you can mix and
+match this markup inside your script. Ant itself is a collection of jar
+files. By adding them to your classpath, you can easily use them within
+Groovy as is. We believe using `AntBuilder` leads to more concise and
+readily understood syntax.
+
+`AntBuilder` exposes Ant tasks directly using the convenient builder notation that
+we are used to in Groovy. Here is the most basic example, which is printing a message
+on the standard output:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=example_echo,indent=0]
+----
+<1> creates an instance of `AntBuilder`
+<2> executes the `echo` task with the message in parameter
+
+Imagine that you need to create a ZIP file:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=create_zip_builder,indent=0]
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=create_zip_zip,indent=0]
+----
+
+In the next example, we demonstrate the use of `AntBuilder` to copy a list of files
+using a classical Ant pattern directly in Groovy:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=copy_files,indent=0]
+----
+
+Another example would be iterating over a list of files matching a specific pattern:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=filescanner,indent=0]
+----
+
+Or execute a JUnit test:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=run_junit,indent=0]
+----
+
+We can even go further by compiling and executing a Java file directly from Groovy:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy[tags=compile_java,indent=0]
+----
+
+It is worth mentioning that `AntBuilder` is included in http://gradle.org/[Gradle], so you can use it in Gradle
+just like you would in Groovy. Additional documentation can be found in the
+http://gradle.org/docs/current/userguide/ant.html[Gradle manual].
\ No newline at end of file
diff --git a/subprojects/groovy-ant/src/spec/test/AntBuilderTest.groovy b/subprojects/groovy-ant/src/spec/test/AntBuilderTest.groovy
new file mode 100644
index 0000000..12fefa0
--- /dev/null
+++ b/subprojects/groovy-ant/src/spec/test/AntBuilderTest.groovy
@@ -0,0 +1,105 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.ant
+import groovy.util.GroovyTestCase
+import org.junit.Test
+
+/**
+* Tests for AntBuilder. The tests directly in this file are specific
+* to AntBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class AntBuilderTest  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::antbuilder_nullobject1[]
+    AntBuilder antbuilder;
+    
+    // antbuilder should be null when not initialized
+    assert antbuilder == null;
+// end::antbuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::antbuilder_nullobject2[]
+    AntBuilder antbuilder = null;
+    
+    // antbuilder should be null when initialized to null
+    assert antbuilder == null;
+// end::antbuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::antbuilder_object_exists1[]
+    AntBuilder antbuilder = new AntBuilder();
+    
+    // antbuilder should not be null after construction
+    assert antbuilder != null;
+// end::antbuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::antbuilder_object_exists2[]
+    AntBuilder antbuilder = new AntBuilder();
+    
+    // antbuilder should be an instance of correct AntBuilder class
+    assert antbuilder instanceof AntBuilder, 'default AntBuilder constructor did not build a version of AntBuilder'
+// end::antbuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::antbuilder_object_exists3[]
+    shouldFail 
+    {
+        // antbuilder should throw an exception when null parm used in constructor
+        AntBuilder antbuilder = new AntBuilder(null);
+    }    
+// end::antbuilder_object_exists3[]
+    } // end of method
+    
+        
+    void testObjectEcho() {
+// tag::antbuilder_echo4[]        
+    def ant = new AntBuilder()
+    ant.echo(message:"message via attribute!")         
+    ant.echo("Hello World!")
+// end::antbuilder_echo4[]
+    } // end of method
+    
+    void testObjectNullEcho() {
+// tag::antbuilder_echo5[]        
+    def ant = new AntBuilder()
+    ant.echo(message:null)         
+// end::antbuilder_echo5[]
+    } // end of method
+    
+    void testObjectEmptyEcho() {
+// tag::antbuilder_echo6[]        
+    shouldFail
+    {
+        def ant = new AntBuilder()
+        ant.echo(null)
+    }
+// end::antbuilder_echo6[]
+    } // end of method
+
+} // end of AntBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy b/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy
new file mode 100644
index 0000000..7e4e87a
--- /dev/null
+++ b/subprojects/groovy-ant/src/spec/test/builder/AntBuilderSpecTest.groovy
@@ -0,0 +1,152 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package builder
+/**
+ * Test cases for the Ant builder documentation.
+ */
+class AntBuilderSpecTest extends GroovyTestCase {
+
+    void doInTmpDir(Closure cl) {
+        // tag::create_zip_builder[]
+        def ant = new AntBuilder()
+        // end::create_zip_builder[]
+        def baseDir = File.createTempDir()
+        ant.project.baseDir = baseDir
+        try {
+            cl.call(ant, new FileTreeBuilder(baseDir))
+        } finally {
+            baseDir.deleteDir()
+        }
+    }
+
+    void testEcho() {
+        // tag::example_echo[]
+        def ant = new AntBuilder()          // <1>
+        ant.echo('hello from Ant!')         // <2>
+        // end::example_echo[]
+    }
+
+    void testCreateZip() {
+        doInTmpDir { ant, baseDir ->
+            baseDir.src {
+                'test.groovy'("println 'Hello'")
+            }
+            // tag::create_zip_zip[]
+            ant.zip(destfile: 'sources.zip', basedir: 'src')
+            // end::create_zip_zip[]
+        }
+    }
+
+    void testCopyFiles() {
+        doInTmpDir {ant, baseDir ->
+            baseDir.src {
+                test {
+                    groovy {
+                        'test1.groovy'('assert 1+1==2')
+                        'test2.groovy'('assert 1+1==2')
+                        util {
+                            'AntTest.groovy'('assert 1+1==2')
+                        }
+                    }
+                }
+            }
+            // tag::copy_files[]
+            // lets just call one task
+            ant.echo("hello")
+
+            // here is an example of a block of Ant inside GroovyMarkup
+            ant.sequential {
+                echo("inside sequential")
+                def myDir = "target/AntTest/"
+                mkdir(dir: myDir)
+                copy(todir: myDir) {
+                    fileset(dir: "src/test") {
+                        include(name: "**/*.groovy")
+                    }
+                }
+                echo("done")
+            }
+
+            // now lets do some normal Groovy again
+            def file = new File(ant.project.baseDir,"target/AntTest/groovy/util/AntTest.groovy")
+            assert file.exists()
+            // end::copy_files[]
+        }
+    }
+
+    void testFileScanner() {
+        doInTmpDir {ant, baseDir ->
+            baseDir.src {
+                test {
+                    groovy {
+                        'test1.groovy'('assert 1+1==2')
+                        'test2.groovy'('assert 1+1==2')
+                        util {
+                            'AntTest.groovy'('assert 1+1==2')
+                        }
+                    }
+                }
+            }
+            // tag::filescanner[]
+            // lets create a scanner of filesets
+            def scanner = ant.fileScanner {
+                fileset(dir:"src/test") {
+                    include(name:"**/Ant*.groovy")
+                }
+            }
+
+            // now lets iterate over
+            def found = false
+            for (f in scanner) {
+                println("Found file $f")
+                found = true
+                assert f instanceof File
+                assert f.name.endsWith(".groovy")
+            }
+            assert found
+            // end::filescanner[]
+        }
+    }
+
+    void testExecuteJUnit() {
+        doInTmpDir {ant, baseDir ->
+            // tag::run_junit[]
+            // lets create a scanner of filesets
+            ant.junit {
+                test(name:'groovy.util.SomethingThatDoesNotExist')
+            }
+            // end::run_junit[]
+        }
+    }
+
+    void testCompileRunJava() {
+        doInTmpDir {ant, baseDir ->
+            // tag::compile_java[]
+            ant.echo(file:'Temp.java', '''
+                class Temp {
+                    public static void main(String[] args) {
+                        System.out.println("Hello");
+                    }
+                }
+            ''')
+            ant.javac(srcdir:'.', includes:'Temp.java', fork:'true')
+            ant.java(classpath:'.', classname:'Temp', fork:'true')
+            ant.echo('Done')
+            // end::compile_java[]
+        }
+    }
+}
diff --git a/subprojects/groovy-ant/src/test-resources/org/codehaus/groovy/ant/GroovycTest.xml b/subprojects/groovy-ant/src/test-resources/org/codehaus/groovy/ant/GroovycTest.xml
index 0d98f63..def4fef 100644
--- a/subprojects/groovy-ant/src/test-resources/org/codehaus/groovy/ant/GroovycTest.xml
+++ b/subprojects/groovy-ant/src/test-resources/org/codehaus/groovy/ant/GroovycTest.xml
@@ -20,7 +20,7 @@
     <property name="srcPath" value="."/>
     <property name="destPath" value="${user.dir}/target/classes/test"/>
 
-    <property name="javaVersion" value="5"/>
+    <property name="javaVersion" value="6"/>
 
     <path id="groovyMaterials">
         <pathelement path="${java.class.path}"/>
diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/util/AntTest.groovy b/subprojects/groovy-ant/src/test/groovy/groovy/util/AntTest.groovy
index 1dd0ad1..153d52f 100644
--- a/subprojects/groovy-ant/src/test/groovy/groovy/util/AntTest.groovy
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/util/AntTest.groovy
@@ -260,6 +260,42 @@ finished: echo[message:echo from AntBuilder's target foo]
         ant.project.executeTarget('myTestTarget')
         assertEquals expectedSpoof, customListener.spoof.toString()
     }
+
+    void testDefineTarget_groovy2900() {
+        def ant = new AntBuilder()
+        def project = ant.project
+        def customListener = new SimpleListener()
+        project.addBuildListener customListener
+        ant.defineTarget(name: 'myTestTarget') {
+            echo(message: "myTestTarget")
+        }
+        ant.defineTarget(name: 'myTestTarget2', depends: 'myTestTarget') {
+            echo(message: "myTestTarget2")
+        }
+        ant.target(name: 'myTestTarget3', depends: 'myTestTarget') {
+            ant.defineTarget(name: 'myTestTarget4') {
+                echo(message: "myTestTarget4")
+            }
+            echo(message: "myTestTarget3")
+        }
+        ant.defineTarget(name: 'myTestTarget5', depends: 'myTestTarget4') {
+            echo(message: "myTestTarget5 should not appear")
+        }
+        project.executeTarget('myTestTarget2')
+        project.executeTarget('myTestTarget4')
+        assert customListener.spoof.toString() == '''\
+started: echo[message:myTestTarget]
+finished: echo[message:myTestTarget]
+started: echo[message:myTestTarget3]
+finished: echo[message:myTestTarget3]
+started: echo[message:myTestTarget]
+finished: echo[message:myTestTarget]
+started: echo[message:myTestTarget2]
+finished: echo[message:myTestTarget2]
+started: echo[message:myTestTarget4]
+finished: echo[message:myTestTarget4]
+'''
+    }
 }
 
 class SimpleListener extends org.apache.tools.ant.DefaultLogger {
diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTask.java b/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTask.java
index fdcc8dd..2df4b18 100644
--- a/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTask.java
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTask.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 import org.apache.tools.ant.BuildException;
diff --git a/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTaskContainer.java b/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTaskContainer.java
index 9587e27..7132f47 100644
--- a/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTaskContainer.java
+++ b/subprojects/groovy-ant/src/test/groovy/groovy/util/SpoofTaskContainer.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 import org.apache.tools.ant.BuildException;
diff --git a/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovyTest2Class.groovy b/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovyTest2Class.groovy
index 30f9f25..1aff566 100644
--- a/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovyTest2Class.groovy
+++ b/subprojects/groovy-ant/src/test/groovy/org/codehaus/groovy/ant/GroovyTest2Class.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.ant
 /*
  * Copyright 2003-2012 the original author or authors.
diff --git a/subprojects/groovy-bsf/build.gradle b/subprojects/groovy-bsf/build.gradle
index 4f51dd9..3108e9f 100644
--- a/subprojects/groovy-bsf/build.gradle
+++ b/subprojects/groovy-bsf/build.gradle
@@ -2,7 +2,7 @@ dependencies {
     compile('bsf:bsf:2.4.0') {
         exclude(group: 'commons-logging', module: 'commons-logging')
     }
-    compile 'commons-logging:commons-logging:1.1.1'
+    compile 'commons-logging:commons-logging:1.2'
     compile rootProject
     testCompile project(':groovy-test')
 }
diff --git a/subprojects/groovy-bsf/src/main/java/org/codehaus/groovy/bsf/package.html b/subprojects/groovy-bsf/src/main/java/org/codehaus/groovy/bsf/package.html
index feb0a25..a02c694 100644
--- a/subprojects/groovy-bsf/src/main/java/org/codehaus/groovy/bsf/package.html
+++ b/subprojects/groovy-bsf/src/main/java/org/codehaus/groovy/bsf/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package org.codehaus.groovy.bsf.*</title>
diff --git a/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc b/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc
index c2ae62d..c79101d 100644
--- a/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc
+++ b/subprojects/groovy-bsf/src/spec/doc/integrating-bsf.adoc
@@ -1,7 +1,7 @@
 = Bean Scripting Framework
 
 WARNING: The http://commons.apache.org/proper/commons-bsf/[Bean Scripting Framework] is an attempt to create an API
-to allow calling scripting languages from Java. It hasn't been updated for long and abandonned in favor of the
+to allow calling scripting languages from Java. It hasn't been updated for long and abandoned in favor of the
 standard <<jsr223,JSR-223>> API.
 
 The BSF engine for Groovy is implemented by the `org.codehaus.groovy.bsf.GroovyEngine` class. However, that fact is
@@ -19,7 +19,7 @@ following Java code to run a sample Groovy script:
 
 [source,java]
 -------------------------------------------------------------------------------
-include::{rootDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_simple,indent=0]
+include::{rootProjectDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_simple,indent=0]
 -------------------------------------------------------------------------------
 
 == Passing in variables
@@ -33,7 +33,7 @@ approach is the normal approach used with Groovy. Here is an example:
 
 [source,java]
 -----------------------------------------------------------------------
-include::{rootDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_variable_passing,indent=0]
+include::{rootProjectDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_variable_passing,indent=0]
 -----------------------------------------------------------------------
 
 == Other calling options
@@ -48,7 +48,7 @@ closures. Here is an example:
 
 [source,java]
 --------------------------------------------------------------------------------
-include::{rootDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_apply,indent=0]
+include::{rootProjectDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_apply,indent=0]
 --------------------------------------------------------------------------------
 
 == Access to the scripting engine
@@ -60,6 +60,6 @@ is an example:
 
 [source,java]
 --------------------------------------------------------------------------
-include::{rootDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_access,indent=0]
+include::{rootProjectDir}/subprojects/groovy-bsf/src/spec/test/BSFSpecTest.java[tags=bsf_access,indent=0]
 --------------------------------------------------------------------------
 
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstNodeToScriptAdapter.groovy b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstNodeToScriptAdapter.groovy
index c771557..27ef15a 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstNodeToScriptAdapter.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/AstNodeToScriptAdapter.groovy
@@ -267,7 +267,7 @@ class AstNodeToScriptVisitor extends PrimaryClassNodeOperation implements Groovy
         print "class $node.name"
         visitGenerics node?.genericsTypes
         boolean first = true
-        node.interfaces?.each {
+        node.unresolvedInterfaces?.each {
             if (!first) {
                 print ', '
             } else {
@@ -277,7 +277,7 @@ class AstNodeToScriptVisitor extends PrimaryClassNodeOperation implements Groovy
             visitType it
         }
         print ' extends '
-        visitType node.superClass
+        visitType node.unresolvedSuperClass
         print ' { '
         printDoubleBreak()
 
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/package.html b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/package.html
index 941a96e..acc1573 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/package.html
+++ b/subprojects/groovy-console/src/main/groovy/groovy/inspect/swingui/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.inspect.swingui.*</title>
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/ui/package.html b/subprojects/groovy-console/src/main/groovy/groovy/ui/package.html
index f50b9c9..c202f0a 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/ui/package.html
+++ b/subprojects/groovy-console/src/main/groovy/groovy/ui/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.ui.*</title>
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/ui/text/package.html b/subprojects/groovy-console/src/main/groovy/groovy/ui/text/package.html
index 9a7e41f..cb4cecf 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/ui/text/package.html
+++ b/subprojects/groovy-console/src/main/groovy/groovy/ui/text/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.ui.text.*</title>
diff --git a/subprojects/groovy-console/src/main/groovy/groovy/ui/view/BasicStatusBar.groovy b/subprojects/groovy-console/src/main/groovy/groovy/ui/view/BasicStatusBar.groovy
index 1ec1da4..c5ffeca 100644
--- a/subprojects/groovy-console/src/main/groovy/groovy/ui/view/BasicStatusBar.groovy
+++ b/subprojects/groovy-console/src/main/groovy/groovy/ui/view/BasicStatusBar.groovy
@@ -22,7 +22,7 @@ import javax.swing.SwingConstants
 statusPanel = panel(constraints: BorderLayout.SOUTH) {
     gridBagLayout()
     separator(gridwidth:GridBagConstraints.REMAINDER, fill:GridBagConstraints.HORIZONTAL)
-    status = label('Welcome to Groovy.',
+    status = label("Welcome to Groovy ${GroovySystem.version}.",
         weightx:1.0,
         anchor:GridBagConstraints.WEST,
         fill:GridBagConstraints.HORIZONTAL,
diff --git a/src/spec/doc/assets/img/GroovyConsole.gif b/subprojects/groovy-console/src/spec/doc/assets/img/GroovyConsole.gif
similarity index 100%
rename from src/spec/doc/assets/img/GroovyConsole.gif
rename to subprojects/groovy-console/src/spec/doc/assets/img/GroovyConsole.gif
diff --git a/src/spec/doc/assets/img/astbrowser.png b/subprojects/groovy-console/src/spec/doc/assets/img/astbrowser.png
similarity index 100%
rename from src/spec/doc/assets/img/astbrowser.png
rename to subprojects/groovy-console/src/spec/doc/assets/img/astbrowser.png
diff --git a/src/spec/doc/assets/img/gconsole-sc-with-visu.png b/subprojects/groovy-console/src/spec/doc/assets/img/gconsole-sc-with-visu.png
similarity index 100%
rename from src/spec/doc/assets/img/gconsole-sc-with-visu.png
rename to subprojects/groovy-console/src/spec/doc/assets/img/gconsole-sc-with-visu.png
diff --git a/src/spec/doc/assets/img/gconsole-sc-without-visu.png b/subprojects/groovy-console/src/spec/doc/assets/img/gconsole-sc-without-visu.png
similarity index 100%
rename from src/spec/doc/assets/img/gconsole-sc-without-visu.png
rename to subprojects/groovy-console/src/spec/doc/assets/img/gconsole-sc-without-visu.png
diff --git a/subprojects/groovy-console/src/spec/doc/groovy-console.adoc b/subprojects/groovy-console/src/spec/doc/groovy-console.adoc
new file mode 100644
index 0000000..cab889f
--- /dev/null
+++ b/subprojects/groovy-console/src/spec/doc/groovy-console.adoc
@@ -0,0 +1,187 @@
+= groovyConsole, the Groovy swing console
+
+[[title-heading]]
+== Groovy : Groovy Console
+
+The Groovy Swing Console allows a user to enter and run Groovy scripts.
+This page documents the features of this user interface.
+
+[[GroovyConsole-Basics]]
+== Basics
+
+image:assets/img/GroovyConsole.gif[image]
+
+. Groovy Console is launched via `groovyConsole` or
+`groovyConsole.bat`, both located in `$GROOVY_HOME/bin`
+. The Console has an input area and an output area.
+. You type a Groovy script in the input area.
+. When you select `Run` from the `Actions` menu, the console
+compiles the script and runs it.
+. Anything that would normally be printed on `System.out` is printed in
+the output area.
+. If the script returns a non-null result, that result is printed.
+
+[[GroovyConsole-Features]]
+== Features
+
+[[GroovyConsole-RunningScripts]]
+=== Running Scripts
+
+There are several shortcuts that you can use to run scripts or code snippets:
+
+* `Ctrl+Enter` and `Ctrl+R` are both shortcut keys for `Run Script`.
+* If you highlight just part of the text in the input area, then Groovy
+runs just that text.
+* The result of a script is the the value of the last expression
+executed.
+* You can turn the System.out capture on and off by selecting `Capture
+System.out` from the `Actions` menu
+
+[[GroovyConsole-EditingFiles]]
+=== Editing Files
+
+You can open any text file, edit it, run it (as a Groovy Script) and
+then save it again when you are finished.
+
+* Select `File > Open` (shortcut key `ctrl+O`) to open a file
+* Select `File > Save` (shortcut key `ctrl+S`) to save a file
+* Select `File > New File` (shortcut key `ctrl+Q`) to start again with a
+blank input area
+
+[[GroovyConsole-Historyandresults]]
+=== History and results
+
+* You can pop-up a gui inspector on the last (non-null) result by
+selecting `Inspect Last` from the `Actions` menu. The inspector is a
+convenient way to view lists and maps.
+* The console remembers the last ten script runs. You can scroll back
+and forth through the history by selecting `Next` and `Previous`
+from the `Edit` menu. `Ctrl-N` and `ctrl-P` are convenient shortcut keys.
+* The last (non-null) result is bound to a variable named `_` (an
+underscore).
+* The last result (null and non-null) for every run in the history is
+bound into a list variable named `__` (two underscores). The result of
+the last run is `__[-1]`, the result of the second to last run is
+`__[-2]` and so forth.
+
+[[GroovyConsole-Interrupt]]
+=== Interrupting a script
+
+The Groovy console is a very handy tool to develop scripts. Often, you will
+find yourself running a script multiple times until it works the way you want
+it to. However, what if your code takes too long to finish or worse, creates
+an infinite loop? Interrupting script execution can be achieved by clicking
+the `interrupt` button on the small dialog box that pops up when a script
+is executing or through the `interrupt` icon in the tool bar.
+
+image:assets/img/gconsole-toolbar.png[Toolbar]
+
+However, this may not be sufficient to interrupt a script: clicking the button
+will interrupt the execution thread, but if your code doesn't handle the interrupt
+flag, the script is likely to keep running without you being able to effectively
+stop it. To avoid that, you have to make sure that the `Script > Allow interruption`
+menu item is flagged. This will automatically apply an AST transformation to your
+script which will take care of checking the interrupt flag (`@ThreadInterrupt`).
+This way, you guarantee that the script can be interrupted even if you don't explicitly
+handle interruption, at the cost of extra execution time.
+
+[[GroovyConsole-Andmore]]
+=== And more
+
+* You can change the font size by selecting `Smaller Font` or `Larger
+Font` from the `Actions menu`
+* The console can be run as an Applet thanks to `groovy.ui.ConsoleApplet`
+* Code is auto indented when you hit return
+* You can drag'n'drop a Groovy script over the text area to open a file
+* You can modify the classpath with which the script in the console is
+being run by adding a new JAR or a directory to the classpath from the
+`Script` menu
+* Error hyperlinking from the output area when a compilation error is
+expected or when an exception is thrown
+
+[[GroovyConsole-EmbeddingtheConsole]]
+== Embedding the Console
+
+To embed a Swing console in your application, simply create the Console
+object, +
+ load some variables, and then launch it. The console can be embedded in
+either Java or Groovy code. +
+ The Java code for this is:
+
+[source,java]
+--------------------------------------------------
+import groovy.ui.Console;
+
+    ...
+
+    Console console = new Console();
+    console.setVariable("var1", getValueOfVar1());
+    console.setVariable("var2", getValueOfVar2());
+    console.run();
+
+    ...
+--------------------------------------------------
+
+Once the console is launched, you can use the variable values in Groovy
+code.
+
+An example of how to embed either the GroovyConsole or GroovyShell in a
+Spring Web application can be found at
+http://groovy.codehaus.org/Embedding+a+Groovy+Console+in+a+Java+Server+Application[Embedding
+a Groovy Console in a Java Server Application]
+
+[[GroovyConsole-Visualizingscriptoutputresults]]
+== Visualizing script output results
+
+You can customize the way script output results are visualized. Let’s
+see how we can customize this. For example, viewing a map result would
+show something like this:
+
+image:assets/img/gconsole-sc-without-visu.png[image]
+
+What you see here is the usual textual representation of a Map. But,
+what if we enabled custom visualization of certain results? The Swing
+console allows you to do just that. First of all, you have to ensure
+that the visualization option is ticked: `View -> Visualize Script
+Results` — for the record, all settings of the Groovy Console are stored
+and remembered thanks to the Preference API. There are a few result
+visualizations built-in: if the script returns a `java.awt.Image`, a
+`javax.swing.Icon`, or a `java.awt.Component` with no parent, the object is
+displayed instead of its `toString()` representation. Otherwise,
+everything else is still just represented as text. Now, create the
+following Groovy script in `~/.groovy/OutputTransforms.groovy`:
+
+[source,groovy]
+---------------------------------------------------------
+import javax.swing.*
+
+transforms << { result ->
+    if (result instanceof Map) {
+        def table = new JTable(
+            result.collect{ k, v ->
+                [k, v?.inspect()] as Object[]
+            } as Object[][],
+            ['Key', 'Value'] as Object[])
+        table.preferredViewportSize = table.preferredSize
+        return new JScrollPane(table)
+    }
+}
+---------------------------------------------------------
+
+The Groovy Swing console will execute that script on startup, injecting
+a transforms list in the binding of the script, so that you can add your
+own script results representations. In our case, we transform the Map
+into a nice-looking Swing JTable. And we’re now able to visualize maps
+in a friendly and attractive fashion, as the screenshot below shows:
+
+image:assets/img/gconsole-sc-with-visu.png[image]
+
+[[GroovyConsole-ASTbrowser]]
+== AST browser
+
+Groovy Console can visualize the AST (Abstract Syntax Tree) representing
+the currently edited script, as shown by the screenshot below. This is
+particularly handy when you want to develop AST transformations.
+
+image:assets/img/astbrowser.png[AST Browser]
+
diff --git a/subprojects/groovy-console/src/test/groovy/groovy/inspect/swingui/AstNodeToScriptAdapterTest.groovy b/subprojects/groovy-console/src/test/groovy/groovy/inspect/swingui/AstNodeToScriptAdapterTest.groovy
index 751e81a..4c855f0 100644
--- a/subprojects/groovy-console/src/test/groovy/groovy/inspect/swingui/AstNodeToScriptAdapterTest.groovy
+++ b/subprojects/groovy-console/src/test/groovy/groovy/inspect/swingui/AstNodeToScriptAdapterTest.groovy
@@ -42,7 +42,7 @@ class AstNodeToScriptAdapterTest extends GroovyTestCase {
 
         assert result =~ /public class script[0-9]* extends groovy\.lang\.Script \{/
         assert result =~ /public script[0-9]*\(\) \{\s*\}/
-        assert result =~ /public script[0-9]*\(groovy.lang.Binding context\) \{\s*super.setBinding\(context\)\s*\}/
+        assert result =~ /public script[0-9]*\(groovy.lang.Binding context\) \{\s*super\(context\)\s*\}/
         assert result =~ /public java.lang.Object run\(\) \{\s*true\s*\}/
     }
 
@@ -103,7 +103,7 @@ class AstNodeToScriptAdapterTest extends GroovyTestCase {
                    int size() {}
                 }'''
         String result = compileToScript(script, CompilePhase.SEMANTIC_ANALYSIS)
-        assert result.contains('public class MyList<E> implements java.util.List<E> extends java.util.AbstractList<E extends java.lang.Object> {')
+        assert result.contains('public class MyList<E> implements java.util.List<E> extends java.util.AbstractList<E> {')
     }
 
     void testGenericBoundsOnClass() {
@@ -112,7 +112,7 @@ class AstNodeToScriptAdapterTest extends GroovyTestCase {
         String result = compileToScript(script, CompilePhase.SEMANTIC_ANALYSIS)
         assert result.contains('MyClass<T extends java.lang.String & java.util.concurrent.Callable<String>, U extends java.lang.Integer> ' +
                 'implements java.util.concurrent.Callable<? super java.lang.Number> ' +
-                'extends java.util.AbstractList<E extends java.lang.Object> {')
+                'extends java.util.AbstractList<String> {')
     }
 
     void testGenericsInVariables() {
diff --git a/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy b/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
index f14c74c..d2f7b8c 100644
--- a/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
+++ b/subprojects/groovy-console/src/test/groovy/groovy/swing/SwingBuilderConsoleTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.swing
 /*
  * Copyright 2003-2013 the original author or authors.
diff --git a/subprojects/groovy-console/src/test/groovy/groovy/ui/HistoryRecordGetTextToRunTests.groovy b/subprojects/groovy-console/src/test/groovy/groovy/ui/HistoryRecordGetTextToRunTests.groovy
index cfb81ea..edb12a9 100644
--- a/subprojects/groovy-console/src/test/groovy/groovy/ui/HistoryRecordGetTextToRunTests.groovy
+++ b/subprojects/groovy-console/src/test/groovy/groovy/ui/HistoryRecordGetTextToRunTests.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.ui
 
 import junit.framework.TestCase
diff --git a/subprojects/groovy-docgenerator/src/main/groovy/org/codehaus/groovy/tools/DocGenerator.groovy b/subprojects/groovy-docgenerator/src/main/groovy/org/codehaus/groovy/tools/DocGenerator.groovy
index 9b47c86..cbc9bfd 100644
--- a/subprojects/groovy-docgenerator/src/main/groovy/org/codehaus/groovy/tools/DocGenerator.groovy
+++ b/subprojects/groovy-docgenerator/src/main/groovy/org/codehaus/groovy/tools/DocGenerator.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2014 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -53,7 +53,7 @@ class DocGenerator {
     }
 
     /**
-     * Parse the DefaultGroovyMethods class to build a graph representing the structure of the class,
+     * Parse the *GroovyMethods (DGM) classes to build a graph representing the structure of the class,
      * with its methods, javadoc comments and tags.
      */
     private static DocSource parseSource(List<File> sourceFiles) {
@@ -78,10 +78,9 @@ class DocGenerator {
             if (!method.isPublic() || !method.isStatic()) {
                 return // skip it
             }
-            def firstParamType = method.parameters[0].type
-            if (firstParamType.javaClass.fullyQualifiedName.startsWith('groovy')) {
-                return // nothing, skip it
-            }
+
+            def firstParam = method.parameters[0]
+            def firstParamType = firstParam.resolvedValue.isEmpty() ? firstParam.type : new Type(firstParam.resolvedValue, 0, firstParam.parentClass)
             docSource.add(firstParamType, method)
         }
         docSource.populateInheritedMethods()
@@ -444,10 +443,10 @@ class DocGenerator {
 
     private static class DocUtil {
         static String resolveJdkClassName(String className) {
-            if (className in ['T', 'E', 'U', 'K', 'V', 'G']) {
+            if (className in ['A', 'B', 'E', 'G', 'K', 'S', 'T', 'U', 'V', 'W']) {
                 return 'java.lang.Object'
             }
-            if (className in ['T[]', 'E[]']) {
+            if (className in ['T[]', 'E[]', 'K[]']) {
                 return 'java.lang.Object[]'
             }
             return className
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/index.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/index.html
index ab9c51c..7d3b346 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/index.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/index.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/overview-summary.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/overview-summary.html
index 8361e0a..f3f92cd 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/overview-summary.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/overview-summary.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN""http://www.w3.org/TR/REC-html40/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/stylesheet.css b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/stylesheet.css
index 3aba844..80bca8f 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/stylesheet.css
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/stylesheet.css
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 @charset "${props.charset}";
 
 /*! normalize.css v2.1.0 | MIT License | git.io/normalize */
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.allclasses-frame.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.allclasses-frame.html
index 183f66e..f3b2f8e 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.allclasses-frame.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.allclasses-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.class.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.class.html
index 0a8b792..6858504 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.class.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.class.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.index-all.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.index-all.html
index f1d33a7..dce5921 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.index-all.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.index-all.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//Dtd HTML 4.0 transitional//EN""http://www.w3.org/tr/REC-html40/loose.dtd">
 <html>
     <head>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.overview-frame.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.overview-frame.html
index dc4420b..e7e82d6 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.overview-frame.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.overview-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
 <html>
diff --git a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.package-frame.html b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.package-frame.html
index 5eb7618..7ea97ef 100644
--- a/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.package-frame.html
+++ b/subprojects/groovy-docgenerator/src/main/resources/org/codehaus/groovy/tools/template.package-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/groovydoc/package.html b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/groovydoc/package.html
index 64a504b..6bc2b47 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/groovydoc/package.html
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/groovydoc/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package org.codehaus.groovy.groovydoc.*</title>
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
index 6576a94..f30dbcd 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/GroovyRootDocBuilder.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2012 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -189,7 +189,8 @@ public class GroovyRootDocBuilder {
 
     private void processFile(String filename, File srcFile, boolean isAbsolute) throws IOException {
         String src = ResourceGroovyMethods.getText(srcFile);
-        String packagePath = isAbsolute ? "DefaultPackage" : tool.getPath(filename).replace('\\', FS);
+        String relPackage = tool.getPath(filename).replace('\\', FS);
+        String packagePath = isAbsolute ? "DefaultPackage" : relPackage;
         String file = tool.getFile(filename);
         SimpleGroovyPackageDoc packageDoc = null;
         if (!isAbsolute) {
@@ -198,7 +199,8 @@ public class GroovyRootDocBuilder {
         // todo: this might not work correctly for absolute paths
         if (filename.endsWith("package.html") || filename.endsWith("package-info.java") || filename.endsWith("package-info.groovy")) {
             if (packageDoc == null) {
-                packageDoc = new SimpleGroovyPackageDoc(packagePath);
+                packageDoc = new SimpleGroovyPackageDoc(relPackage);
+                packagePath = relPackage;
             }
             processPackageInfo(src, filename, packageDoc);
             rootDoc.put(packagePath, packageDoc);
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDoc.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDoc.java
index 6e06e32..eeb7a6a 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDoc.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDoc.java
@@ -282,7 +282,7 @@ public class SimpleGroovyClassDoc extends SimpleGroovyAbstractableElementDoc imp
 
     private Class getClassOf(String next) {
         try {
-            return Class.forName(next.replace("/", "."));
+            return Class.forName(next.replace("/", "."), false, getClass().getClassLoader());
         } catch (Throwable t) {
             return null;
         }
@@ -606,7 +606,7 @@ public class SimpleGroovyClassDoc extends SimpleGroovyAbstractableElementDoc imp
 
     private Class resolveFromJavaLang(String name) {
         try {
-            return Class.forName("java.lang." + name);
+            return Class.forName("java.lang." + name, false, getClass().getClassLoader());
         } catch (NoClassDefFoundError e) {
             // ignore
         } catch (ClassNotFoundException e) {
@@ -647,7 +647,7 @@ public class SimpleGroovyClassDoc extends SimpleGroovyAbstractableElementDoc imp
             if (candidate != null) {
                 try {
                     // TODO cache these??
-                    return Class.forName(candidate);
+                    return Class.forName(candidate, false, getClass().getClassLoader());
                 } catch (NoClassDefFoundError e) {
                     // ignore
                 } catch (ClassNotFoundException e) {
@@ -662,7 +662,7 @@ public class SimpleGroovyClassDoc extends SimpleGroovyAbstractableElementDoc imp
         String candidate = name.replace('/', '.');
         try {
             // TODO cache these??
-            return Class.forName(candidate);
+            return Class.forName(candidate, false, getClass().getClassLoader());
         } catch (NoClassDefFoundError e) {
             // ignore
         } catch (ClassNotFoundException e) {
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDocAssembler.java b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDocAssembler.java
index 4e4e519..58ca6ea 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDocAssembler.java
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/SimpleGroovyClassDocAssembler.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2014 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -549,8 +549,13 @@ public class SimpleGroovyClassDocAssembler extends VisitorAdapter implements Gro
                 currentModifier = currentModifier.getNextSibling();
             }
             if (!hasNonPublicVisibility && isGroovy && !(memberOrClass instanceof GroovyFieldDoc)) {
-                // in groovy methods and classes are assumed public, unless informed otherwise
-                memberOrClass.setPublic(true);
+                // in groovy, methods and classes are assumed public, unless informed otherwise
+                if (isPackageScope(modifiers)) {
+                    memberOrClass.setPackagePrivate(true);
+                    hasNonPublicVisibility = true;
+                } else {
+                    memberOrClass.setPublic(true);
+                }
             } else if (!hasNonPublicVisibility && !hasPublicVisibility && !isGroovy) {
                 if (insideInterface(memberOrClass) || insideAnnotationDef(memberOrClass)) {
                     memberOrClass.setPublic(true);
@@ -558,9 +563,15 @@ public class SimpleGroovyClassDocAssembler extends VisitorAdapter implements Gro
                     memberOrClass.setPackagePrivate(true);
                 }
             }
+            if (memberOrClass instanceof GroovyFieldDoc && isGroovy && !hasNonPublicVisibility & !hasPublicVisibility) {
+                if (isPackageScope(modifiers)) {
+                    memberOrClass.setPackagePrivate(true);
+                    hasNonPublicVisibility = true;
+                }
+            }
             if (memberOrClass instanceof GroovyFieldDoc && !hasNonPublicVisibility && !hasPublicVisibility && isGroovy) return true;
         } else if (isGroovy && !(memberOrClass instanceof GroovyFieldDoc)) {
-            // in groovy methods and classes are assumed public, unless informed otherwise
+            // in groovy, methods and classes are assumed public, unless informed otherwise
             memberOrClass.setPublic(true);
         } else if (!isGroovy) {
             if (insideInterface(memberOrClass) || insideAnnotationDef(memberOrClass)) {
@@ -572,6 +583,20 @@ public class SimpleGroovyClassDocAssembler extends VisitorAdapter implements Gro
         return memberOrClass instanceof GroovyFieldDoc && isGroovy && !hasNonPublicVisibility & !hasPublicVisibility;
     }
 
+    private boolean isPackageScope(GroovySourceAST modifiers) {
+        List<String> names = getAnnotationNames(modifiers);
+        return names.contains("groovy/transform/PackageScope") || names.contains("PackageScope");
+    }
+
+    private List<String> getAnnotationNames(GroovySourceAST modifiers) {
+        List<String> annotationNames = new ArrayList<String>();
+        List<GroovySourceAST> annotations = modifiers.childrenOfType(ANNOTATION);
+        for (GroovySourceAST annotation : annotations) {
+            annotationNames.add(buildName((GroovySourceAST) annotation.getFirstChild()));
+        }
+        return annotationNames;
+    }
+
     private boolean insideInterface(SimpleGroovyAbstractableElementDoc memberOrClass) {
         SimpleGroovyClassDoc current = getCurrentClassDoc();
         if (current == null || current == memberOrClass) return false;
diff --git a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/package.html b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/package.html
index ec53050..9f48fee 100644
--- a/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/package.html
+++ b/subprojects/groovy-groovydoc/src/main/java/org/codehaus/groovy/tools/groovydoc/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package org.codehaus.groovy.tools.groovydoc.*</title>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
index c6d1ebd..56e12b8 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/classLevel/classDocName.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <!-- **************************************************************** -->
 <!-- *  PLEASE KEEP COMPLICATED EXPRESSIONS OUT OF THESE TEMPLATES, * -->
@@ -371,7 +388,7 @@ if (classDoc.isInterface()) {
                         <% visibleProperties.eachWithIndex { prop, i -> %>
                         <tr class="${i%2==0?'altColor':'rowColor'}">
                             <td class="colFirst"><code><strong>${modifiersBrief(prop) + linkable(prop.type())}</strong></code> </td>
-                            <td class="colLast"><code><a href="#${prop.name()}"></a>${prop.name()}</code><br>${prop.firstSentenceCommentText()}</td>
+                            <td class="colLast"><code><a href="#${prop.name()}">${prop.name()}</a></code><br>${prop.firstSentenceCommentText()}</td>
                         </tr>
                         <% } %>
                     </table>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-frame.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-frame.html
index 4d29655..ab16293 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-frame.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-summary.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-summary.html
index f4a006a..c92fc0e 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-summary.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/packageLevel/package-summary.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
@@ -65,9 +82,10 @@ function windowTitle()
     <h1 class="title">Package ${packageDoc.nameWithDots()}</h1>
 </div>
 
-<div class="header">
-    <h2 title="${packageDoc.description()}" class="title">${packageDoc.description()}</h2>
-</div>
+<% if (!packageDoc.description().trim().isEmpty()) { %>
+<h2 title="Package ${packageDoc.nameWithDots()} Description" class="title">Package ${packageDoc.nameWithDots()} Description</h2>
+<div class="header">${packageDoc.description()}</div>
+<% } %>
 
 <div class="contentContainer">
 <%
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/allclasses-frame.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/allclasses-frame.html
index b1df321..4cee293 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/allclasses-frame.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/allclasses-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/deprecated-list.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/deprecated-list.html
index 03676cf..0a7ec68 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/deprecated-list.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/deprecated-list.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <%
 def subtitle = 'Deprecated API'
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/help-doc.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/help-doc.html
index 5ede833..ac692a0 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/help-doc.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/help-doc.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <% def subtitle = 'API Help' %>
 <% def title = subtitle + (props.windowTitle ? " (${props.windowTitle})" : "") %>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index-all.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index-all.html
index 5e24c24..36bc885 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index-all.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index-all.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <%
 def subtitle = 'Index'
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index.html
index 4c48fe8..07ff4c6 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/index.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN" "http://www.w3.org/TR/html4/frameset.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-frame.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-frame.html
index 22f0273..57192ca 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-frame.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-frame.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-summary.html b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-summary.html
index ba8d794..9441234 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-summary.html
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/overview-summary.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <% def title = "Overview" + (props.windowTitle ? " (${props.windowTitle})" : "") %>
 <html>
diff --git a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/stylesheet.css b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/stylesheet.css
index 59e73c7..8d8c43b 100644
--- a/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/stylesheet.css
+++ b/subprojects/groovy-groovydoc/src/main/resources/org/codehaus/groovy/tools/groovydoc/gstringTemplates/topLevel/stylesheet.css
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 @charset "${props.charset}";
 
 /*! normalize.css v2.1.0 | MIT License | git.io/normalize */
diff --git a/subprojects/groovy-groovydoc/src/spec/doc/groovydoc.adoc b/subprojects/groovy-groovydoc/src/spec/doc/groovydoc.adoc
new file mode 100644
index 0000000..639fd3d
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/spec/doc/groovydoc.adoc
@@ -0,0 +1,218 @@
+= groovydoc, the Groovy & Java documentation generator
+
+GroovyDoc is a tool responsible for generating documentation from your code. It acts like the Javadoc tool in the
+Java world but is capable of handling both `groovy` and `java` files. The distribution comes with two ways of generating
+documentation: from <<Groovydoc-CommandLine,command line>> or from <<Groovydoc-Ant,Apache Ant>>. Other build tools
+like Maven or Gradle also offer wrappers for Groovydoc.
+
+[[Groovydoc-CommandLine]]
+== The groovydoc command line tool
+
+The `groovydoc` command line can be invoked to generate groovydocs:
+
+----
+groovydoc [options] [packagenames] [sourcefiles]
+----
+
+where options must be picked from the following table:
+
+[cols="2,2,5",options="header,footer"]
+|=======================================================================
+|Short version |Long version |Description
+|-author | |Include @author paragraphs (currently not used)
+|-charset <charset>| |Charset for cross-platform viewing of generated documentation
+|-classpath, -cp | --classpath |Specify where to find the class files - must be
+first argument
+|-d |--destdir <dir> |Destination directory for output files
+| |--debug|Enable debug output
+|-doctitle <html> | |Include title for the overview page
+|-exclude <pkglist>| | Specify a list of packages to exclude
+(separated by colons for all operating systems)
+|-fileEncoding <charset>| |Charset for generated documentation files
+|-footer <html> | |Include footer text for each page
+|-header <html> | |Include header text for each page
+|-help|--help|Display help message
+|-nomainforscripts| |Don't include the implicit 'public static void
+main' method for scripts
+|-noscripts| |Don't process Groovy Scripts
+|-overview <file>| |Read overview documentation from HTML file
+|-package| |Show package/protected/public classes and members
+|-private| |Show all classes and members
+|-protected| |Show protected/public classes and members (default)
+|-public| |Show only public classes and members
+|-quiet| |Suppress superfluous output
+|-sourcepath <pathlist>| |Specify where to find source files (dirs
+separated by platform path separator)
+|-stylesheetfile <path>| |File to change style of the generated documentation
+|-verbose| |Enable verbose output
+| |--version|Display the version
+|-windowtitle <text>| |Browser window title for the documentation
+|=======================================================================
+
+[[Groovydoc-Ant]]
+== The groovydoc Ant task
+
+The `groovydoc` Ant task allows generating groovydocs from an Ant build.
+
+[[ThegroovydocAnttask-Requiredtaskdef]]
+=== Required taskdef
+
+Assuming `groovy-all-{groovyversion}.jar` is in _my.classpath_ you will need to
+declare this task at some point in the build.xml prior to the groovydoc
+task being invoked.
+
+[source,xml]
+-----------------------------------------------------------
+<taskdef name         = "groovydoc"
+         classname    = "org.codehaus.groovy.ant.Groovydoc"
+         classpathref = "my.classpath"/>
+-----------------------------------------------------------
+
+[[ThegroovydocAnttask-groovydocAttributes]]
+=== <groovydoc> Attributes
+
+[cols="1,2,1",options="header,footer"]
+|=======================================================================
+|Attribute |Description |Required
+|destdir |Location to store the class files. |Yes
+|sourcepath |The sourcepath to use. |No
+|packagenames |Comma separated list of package files (with terminating
+wildcard). |No
+|use |Create class and package usage pages. |No
+|windowtitle |Browser window title for the documentation (text). |No
+|doctitle |Include title for the package index(first) page (html-code).
+|No
+|header |Include header text for each page (html-code). |No
+|footer |Include footer text for each page (html-code). |No
+|overview |Read overview documentation from HTML file. |No
+|private |Show all classes and members (i.e. including private ones) if
+set to ``true''. |No
+|=======================================================================
+
+[[ThegroovydocAnttask-groovydocNestedElements]]
+=== <groovydoc> Nested Elements
+
+[[ThegroovydocAnttask-link]]
+==== link
+
+Create link to groovydoc/javadoc output at the given URL.
+
+[cols="<,<,<",options="header,footer"]
+|=======================================================
+|Attribute |Description |Required
+|packages |Comma separated list of package prefixes |Yes
+|href |Base URL of external site |Yes
+|=======================================================
+
+[[ThegroovydocAnttask-Example1-groovydocAnttask]]
+==== Example #1 - <groovydoc> Ant task
+
+[source,xml]
+----------------------------------------------------------------------------------------------------------------
+<taskdef name           = "groovydoc"
+         classname      = "org.codehaus.groovy.ant.Groovydoc"
+         classpathref   = "path_to_groovy_all"/>
+
+<groovydoc destdir      = "${docsDirectory}/gapi"
+           sourcepath   = "${mainSourceDirectory}"
+           packagenames = "**.*"
+           use          = "true"
+           windowtitle  = "${title}"
+           doctitle     = "${title}"
+           header       = "${title}"
+           footer       = "${docFooter}"
+           overview     = "src/main/overview.html"
+           private      = "false">
+        <link packages="java.,org.xml.,javax.,org.xml." href="http://docs.oracle.com/javase/8/docs/api/"/>
+        <link packages="org.apache.tools.ant."          href="http://docs.groovy-lang.org/docs/ant/api/"/>
+        <link packages="org.junit.,junit.framework."    href="http://junit.org/apidocs/"/>
+        <link packages="groovy.,org.codehaus.groovy."   href="http://docs.groovy-lang.org/latest/html/api/"/>
+        <link packages="org.codehaus.gmaven."           href="http://groovy.github.io/gmaven/apidocs/"/>
+</groovydoc>
+----------------------------------------------------------------------------------------------------------------
+
+[[ThegroovydocAnttask-Example2-ExecutinggroovydocfromGroovy]]
+==== Example #2 - Executing <groovydoc> from Groovy
+
+[source,groovy]
+--------------------------------------------------------------------------------------------------------------
+def ant = new AntBuilder()
+ant.taskdef(name: "groovydoc", classname: "org.codehaus.groovy.ant.Groovydoc")
+ant.groovydoc(
+    destdir      : "${docsDirectory}/gapi",
+    sourcepath   : "${mainSourceDirectory}",
+    packagenames : "**.*",
+    use          : "true",
+    windowtitle  : "${title}",
+    doctitle     : "${title}",
+    header       : "${title}",
+    footer       : "${docFooter}",
+    overview     : "src/main/overview.html",
+    private      : "false") {
+        link(packages:"java.,org.xml.,javax.,org.xml.",href:"http://docs.oracle.com/javase/8/docs/api/")
+        link(packages:"groovy.,org.codehaus.groovy.",  href:"http://docs.groovy-lang.org/latest/html/api/")
+        link(packages:"org.apache.tools.ant.",         href:"http://docs.groovy-lang.org/docs/ant/api/")
+        link(packages:"org.junit.,junit.framework.",   href:"http://junit.org/apidocs/")
+        link(packages:"org.codehaus.gmaven.",          href:"http://groovy.github.io/gmaven/apidocs/")
+}
+--------------------------------------------------------------------------------------------------------------
+
+=== Custom templates
+
+The `groovydoc` Ant task supports custom templates, but it requires two steps:
+
+. A custom groovydoc class
+. A new groovydoc task definition
+
+==== Custom Groovydoc class
+
+The first step requires you to extend the `Groovydoc` class, like in the following example:
+
+[source,java]
+----
+package org.codehaus.groovy.tools.groovydoc;
+
+import org.codehaus.groovy.ant.Groovydoc;
+
+/**
+ * Overrides GroovyDoc's default class template - for testing purpose only.
+ *
+ * @author Andre Steingress
+ */
+public class CustomGroovyDoc extends Groovydoc {
+
+    @Override
+    protected String[] getClassTemplates() {
+        return new String[]{"org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html"};
+    }
+}
+----
+
+You can override the following methods:
+
+* `getClassTemplates` for class-level templates
+* `getPackageTemplates` for package-level templates
+* `getDocTemplates` for top-level templates
+
+You can find the list of default templates in the `org.codehaus.groovy.tools.groovydoc.gstringTemplates.GroovyDocTemplateInfo`
+class.
+
+==== Using the custom groovydoc task
+
+Once you've written the class, using it is just a matter of redefining the `groovydoc` task:
+
+[source,xml]
+----
+<taskdef name           = "groovydoc"
+         classname      = "org.codehaus.groovy.ant.CustomGroovyDoc"
+         classpathref   = "path_to_groovy_all"/>
+----
+
+Please note that template customization is provided as is. APIs are subject to change, so you must consider this as a
+fragile feature.
+
+[[Groovydoc-GMavenPlus]]
+== GMavenPlus Maven Plugin
+https://github.com/groovy/GMavenPlus[GMavenPlus] is a Maven plugin with goals that
+support GroovyDoc generation.
+
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
index 406cfd3..dea9189 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTest.java
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2013 the original author or authors.
+ * Copyright 2007-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -73,14 +73,18 @@ public class GroovyDocToolTest extends GroovyTestCase {
         link.setPackages("java.,org.xml.,javax.,org.xml.");
         links.add(link);
 
-        htmlTool = new GroovyDocTool(
+        htmlTool = makeHtmltool(links, new Properties());
+    }
+
+    private GroovyDocTool makeHtmltool(ArrayList<LinkArgument> links, Properties props) {
+        return new GroovyDocTool(
                 new FileSystemResourceManager("src/main/resources"), // template storage
                 new String[] {"src/test/groovy", "../../src/test"}, // source file dirs
                 GroovyDocTemplateInfo.DEFAULT_DOC_TEMPLATES,
                 GroovyDocTemplateInfo.DEFAULT_PACKAGE_TEMPLATES,
                 GroovyDocTemplateInfo.DEFAULT_CLASS_TEMPLATES,
                 links,
-                new Properties()
+                props
         );
     }
 
@@ -308,6 +312,66 @@ public class GroovyDocToolTest extends GroovyTestCase {
         assertTrue("innerClassMethod found in: \"" + classWithAnonymousInnerClassDoc + "\"", !classWithAnonymousInnerClassDoc.contains("innerClassMethod"));
     }
 
+    public void testVisibilityPublic() throws Exception {
+        Properties props = new Properties();
+        props.put("publicScope", "true");
+        testVisibility(props, true, false, false, false);
+    }
+
+    public void testVisibilityProtected() throws Exception {
+        Properties props = new Properties();
+        props.put("protectedScope", "true");
+        testVisibility(props, true, true, false, false);
+    }
+
+    public void testVisibilityPackage() throws Exception {
+        Properties props = new Properties();
+        props.put("packageScope", "true");
+        testVisibility(props, true, true, true, false);
+    }
+
+    public void testVisibilityPrivate() throws Exception {
+        Properties props = new Properties();
+        props.put("privateScope", "true");
+        testVisibility(props, true, true, true, true);
+    }
+
+    private void testVisibility(Properties props, boolean a, boolean b, boolean c, boolean d) throws Exception {
+        htmlTool = makeHtmltool(new ArrayList<LinkArgument>(), props);
+        List<String> srcList = new ArrayList<String>();
+        String base = "org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibility";
+        srcList.add(base + "G.groovy");
+        srcList.add(base + "J.java");
+        htmlTool.add(srcList);
+        MockOutputTool output = new MockOutputTool();
+        htmlTool.renderToOutput(output, MOCK_DIR);
+        String javaExampleClass = output.getText(MOCK_DIR + "/" + base + "J.html");
+        assertMethodVisibility(base, output, javaExampleClass, a, b, c, d);
+        String groovyExampleClass = output.getText(MOCK_DIR + "/" + base + "G.html");
+        assertMethodVisibility(base, output, groovyExampleClass, a, b, c, d);
+    }
+
+    private void assertMethodVisibility(String base, MockOutputTool output, String text, boolean a, boolean b, boolean c, boolean d) {
+        assertNotNull("No GroovyDoc found for " + base + "\nFound: " + output, text);
+        assertTrue("method a1" + (a ? " not" : "") + " found in: \"" + text + "\"", a ^ !text.contains("<a href=\"#a1()\">a1</a>"));
+        assertTrue("method a2" + (a ? " not" : "") + " found in: \"" + text + "\"", a ^ !text.contains("<a href=\"#a2()\">a2</a>"));
+        assertTrue("method b" + (b ? " not" : "") + " found in: \"" + text + "\"", b ^ !text.contains("<a href=\"#b()\">b</a>"));
+        assertTrue("method c1" + (c ? " not" : "") + " found in: \"" + text + "\"", c ^ !text.contains("<a href=\"#c1()\">c1</a>"));
+        assertTrue("method c2" + (c ? " not" : "") + " found in: \"" + text + "\"", c ^ !text.contains("<a href=\"#c2()\">c2</a>"));
+        assertTrue("method d" + (d ? " not" : "") + " found in: \"" + text + "\"", d ^ !text.contains("<a href=\"#d()\">d</a>"));
+
+        assertTrue("field _a" + (a ? " not" : "") + " found in: \"" + text + "\"", a ^ !text.contains("<a href=\"#_a\">_a</a>"));
+        assertTrue("field _b" + (b ? " not" : "") + " found in: \"" + text + "\"", b ^ !text.contains("<a href=\"#_b\">_b</a>"));
+        assertTrue("field _c" + (c ? " not" : "") + " found in: \"" + text + "\"", c ^ !text.contains("<a href=\"#_c\">_c</a>"));
+        assertTrue("field _d" + (d ? " not" : "") + " found in: \"" + text + "\"", d ^ !text.contains("<a href=\"#_d\">_d</a>"));
+
+        assertTrue("class A1" + (a ? " not" : "") + " found in: \"" + text + "\"", a ^ !text.contains(".A1</a></code>"));
+        assertTrue("class A2" + (a ? " not" : "") + " found in: \"" + text + "\"", a ^ !text.contains(".A2</a></code>"));
+        assertTrue("class B" + (b ? " not" : "") + " found in: \"" + text + "\"", b ^ !text.contains(".B</a></code>"));
+        assertTrue("class C" + (c ? " not" : "") + " found in: \"" + text + "\"", c ^ !text.contains(".C</a></code>"));
+        assertTrue("class D" + (d ? " not" : "") + " found in: \"" + text + "\"", d ^ !text.contains(".D</a></code>"));
+    }
+
     public void testMultipleConstructorErrorBug() throws Exception {
         List<String> srcList = new ArrayList<String>();
         srcList.add("org/codehaus/groovy/tools/groovydoc/testfiles/MultipleConstructorErrorBug.java");
@@ -455,6 +519,18 @@ public class GroovyDocToolTest extends GroovyTestCase {
         assertEquals("There has to be at least a single reference to the ArrayPropertyLink[]", "ArrayPropertyLink", m.group(2));
     }
 
+    public void testClassesAreNotInitialized() throws Exception {
+        List<String> srcList = new ArrayList<String>();
+        srcList.add("org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/UsesClassesWithFailingStaticInit.groovy");
+        htmlTool.add(srcList);
+
+        MockOutputTool output = new MockOutputTool();
+        htmlTool.renderToOutput(output, MOCK_DIR);
+        String doc = output.getText(MOCK_DIR + "/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/UsesClassesWithFailingStaticInit.html");
+
+        assertTrue(doc.contains("org.codehaus.groovy.tools.groovydoc.testfiles.staticInit.JavaWithFailingStaticInit"));
+    }
+
     public void testArrayPropertyLinkWithExternalReference() throws Exception {
         List<String> srcList = new ArrayList<String>();
         srcList.add("org/codehaus/groovy/tools/groovydoc/testfiles/PropertyLink.groovy");
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTestSampleGroovy.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTestSampleGroovy.groovy
index 9dbe01b..ff6b1cd 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTestSampleGroovy.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/GroovyDocToolTestSampleGroovy.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc;
 
 public class GroovyDocToolTestSampleGroovy {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityG.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityG.groovy
new file mode 100644
index 0000000..e876635
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityG.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.tools.groovydoc.testfiles
+
+import groovy.transform.PackageScope
+
+class ExampleVisibilityG {
+    public void a1() {}
+    void a2() {}
+    protected void b() {}
+    @groovy.transform.PackageScope void c1() {}
+    @PackageScope void c2() {}
+    private void d() {}
+
+    public _a
+    protected _b
+    @PackageScope _c
+    private _d
+
+    public class A1 {}
+    class A2 {}
+    protected class B {}
+    @PackageScope class C {}
+    private class D {}
+}
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityJ.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityJ.java
new file mode 100644
index 0000000..abd8f4b
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/ExampleVisibilityJ.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.codehaus.groovy.tools.groovydoc.testfiles;
+
+public class ExampleVisibilityJ {
+    public void a1() { }
+    public void a2() { }
+    protected void b() { }
+    void c1() { }
+    void c2() { }
+    private void d() { }
+
+    public Object _a;
+    protected Object _b;
+    Object _c;
+    private Object _d;
+
+    public class A1 {}
+    public class A2 {}
+    protected class B {}
+    class C {}
+    private class D {}
+}
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyClassWithMultipleInterfaces.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyClassWithMultipleInterfaces.groovy
index 3e484a5..8bd591c 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyClassWithMultipleInterfaces.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyClassWithMultipleInterfaces.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles
 
 abstract class GroovyClassWithMultipleInterfaces implements GroovyInterface1, JavaInterface1, Runnable {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterface1.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterface1.groovy
index b018729..20d3d33 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterface1.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterface1.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles
 
 public interface GroovyInterface1 {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterfaceWithMultipleInterfaces.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterfaceWithMultipleInterfaces.groovy
index 656785b..ffb3b74 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterfaceWithMultipleInterfaces.groovy
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/GroovyInterfaceWithMultipleInterfaces.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles
 
 public interface GroovyInterfaceWithMultipleInterfaces extends GroovyInterface1, JavaInterface1, Runnable {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaClassWithMultipleInterfaces.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaClassWithMultipleInterfaces.java
index 5363313..7a4dd5d 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaClassWithMultipleInterfaces.java
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaClassWithMultipleInterfaces.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles;
 
 public abstract class JavaClassWithMultipleInterfaces implements GroovyInterface1, JavaInterface1, Runnable {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterface1.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterface1.java
index 1657c2f..75c615f 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterface1.java
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterface1.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles;
 
 public interface JavaInterface1 {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterfaceWithMultipleInterfaces.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterfaceWithMultipleInterfaces.java
index ac4d33a..0ce79bd 100644
--- a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterfaceWithMultipleInterfaces.java
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/JavaInterfaceWithMultipleInterfaces.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.groovydoc.testfiles;
 
 public interface JavaInterfaceWithMultipleInterfaces extends GroovyInterface1, JavaInterface1, Runnable {
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/GroovyWithFailingStaticInit.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/GroovyWithFailingStaticInit.groovy
new file mode 100644
index 0000000..1393afb
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/GroovyWithFailingStaticInit.groovy
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.groovydoc.testfiles.staticInit
+
+class GroovyWithFailingStaticInit {
+
+    static {
+        throw new Exception("!");
+    }
+
+}
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/JavaWithFailingStaticInit.java b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/JavaWithFailingStaticInit.java
new file mode 100644
index 0000000..a74efbd
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/JavaWithFailingStaticInit.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.groovydoc.testfiles.staticInit;
+
+public class JavaWithFailingStaticInit {
+
+    static {
+        doError();
+    }
+
+    private static void doError() {
+        throw new RuntimeException("!");
+    }
+}
diff --git a/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/UsesClassesWithFailingStaticInit.groovy b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/UsesClassesWithFailingStaticInit.groovy
new file mode 100644
index 0000000..1fdd3a8
--- /dev/null
+++ b/subprojects/groovy-groovydoc/src/test/groovy/org/codehaus/groovy/tools/groovydoc/testfiles/staticInit/UsesClassesWithFailingStaticInit.groovy
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.groovydoc.testfiles.staticInit
+
+class UsesClassesWithFailingStaticInit {
+
+    GroovyWithFailingStaticInit getGroovy() { null }
+    JavaWithFailingStaticInit getJava() { null }
+
+}
diff --git a/subprojects/groovy-groovydoc/src/test/resources/groovydoc/groovyDocTests.xml b/subprojects/groovy-groovydoc/src/test/resources/groovydoc/groovyDocTests.xml
index e8ef2e5..6ff8bd8 100644
--- a/subprojects/groovy-groovydoc/src/test/resources/groovydoc/groovyDocTests.xml
+++ b/subprojects/groovy-groovydoc/src/test/resources/groovydoc/groovyDocTests.xml
@@ -16,10 +16,10 @@
                    packagenames="org/codehaus/groovy/tools/groovydoc/testfiles/**.*"
                    use="true" windowtitle="GroovyDoc" private="false">
             <link packages="java.,org.groovy.xml.,javax.,org.groovy.w3c." href="http://docs.oracle.com/javase/7/docs/api/"/>
-            <link packages="org.apache.tools.ant." href="http://evgeny-goldin.org/javadoc/ant/api"/>
-            <link packages="org.junit.,junit.framework." href="http://junit.org/javadoc/latest"/>
+            <link packages="org.apache.tools.ant." href="http://docs.groovy-lang.org/docs/ant/api/"/>
+            <link packages="org.junit.,junit.framework." href="http://junit.org/apidocs/"/>
             <link packages="groovy.,org.codehaus.groovy." href="http://groovy.codehaus.org/api/"/>
-            <link packages="org.codehaus.gmaven." href="http://evgeny-goldin.org/javadoc/gmaven"/>
+            <link packages="org.codehaus.gmaven." href="http://groovy.github.io/gmaven/apidocs/"/>
         </groovydoc>
     </target>
 
@@ -34,10 +34,10 @@
                 fileEncoding="UTF-16LE">
 
             <link packages="java.,org.groovy.xml.,javax.,org.groovy.w3c." href="http://docs.oracle.com/javase/7/docs/api/"/>
-            <link packages="org.apache.tools.ant." href="http://evgeny-goldin.org/javadoc/ant/api"/>
-            <link packages="org.junit.,junit.framework." href="http://junit.org/javadoc/latest"/>
+            <link packages="org.apache.tools.ant." href="http://docs.groovy-lang.org/docs/ant/api/"/>
+            <link packages="org.junit.,junit.framework." href="http://junit.org/apidocs/"/>
             <link packages="groovy.,org.codehaus.groovy." href="http://groovy.codehaus.org/api/"/>
-            <link packages="org.codehaus.gmaven." href="http://evgeny-goldin.org/javadoc/gmaven"/>
+            <link packages="org.codehaus.gmaven." href="http://groovy.github.io/gmaven/apidocs/"/>
         </groovydoc>
     </target>
 </project>
diff --git a/subprojects/groovy-groovydoc/src/test/resources/org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html b/subprojects/groovy-groovydoc/src/test/resources/org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html
index 45e606b..935edad 100644
--- a/subprojects/groovy-groovydoc/src/test/resources/org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html
+++ b/subprojects/groovy-groovydoc/src/test/resources/org/codehaus/groovy/tools/groovydoc/testfiles/classDocName.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <!-- **************************************************************** -->
 <!-- *  PLEASE KEEP COMPLICATED EXPRESSIONS OUT OF THESE TEMPLATES, * -->
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/AnsiDetector.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/AnsiDetector.groovy
index f0108b2..55a0765 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/AnsiDetector.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/AnsiDetector.groovy
@@ -16,13 +16,16 @@
 
 package org.codehaus.groovy.tools.shell
 
+import groovy.transform.CompileStatic
 import jline.TerminalFactory
 
 import java.util.concurrent.Callable
 
+ at CompileStatic
 class AnsiDetector implements Callable<Boolean>
 {
-    public Boolean call() throws Exception {
+    @Override
+    Boolean call() throws Exception {
         return TerminalFactory.create().isAnsiSupported()
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Command.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Command.groovy
index 3c0206e..ec298b4 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Command.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Command.groovy
@@ -16,9 +16,8 @@
 
 package org.codehaus.groovy.tools.shell
 
-import groovy.transform.CompileStatic;
-import jline.console.completer.Completer;
-import java.util.List;
+import groovy.transform.CompileStatic
+import jline.console.completer.Completer
 
 /**
  * Provides the interface required for command extensions.
@@ -27,23 +26,23 @@ import java.util.List;
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
 @CompileStatic
-public interface Command
+interface Command
 {
-    public String getName();
+    String getName()
 
-    public String getShortcut();
+    String getShortcut()
 
-    public Completer getCompleter();
+    Completer getCompleter()
 
-    public String getDescription();
+    String getDescription()
 
-    public String getUsage();
+    String getUsage()
 
-    public String getHelp();
+    String getHelp()
 
-    public List/*<CommandAlias>*/ getAliases();
+    List/*<CommandAlias>*/ getAliases()
 
-    public Object execute(List<String> args);
+    Object execute(final List<String> args)
 
-    public boolean getHidden();
+    boolean getHidden()
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandAlias.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandAlias.groovy
index 358d91e..0b6fca5 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandAlias.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandAlias.groovy
@@ -29,52 +29,58 @@ class CommandAlias
     extends CommandSupport
 {
     final String targetName
-    
+
     CommandAlias(final Groovysh shell, final String name, final String shortcut, final String target) {
         super(shell, name, shortcut)
-        
+
         assert target
 
         this.targetName = target
     }
-    
+
     Command getTarget() {
         Command command = registry.find(targetName)
-        
+
         assert command != null
-        
+
         return command
     }
-    
+
+    @Override
     protected List<Completer> createCompleters() {
         try {
             // TODO: Use interface with createCompleters()
             if (target instanceof CommandSupport) {
-                CommandSupport support = (CommandSupport) target;
+                CommandSupport support = (CommandSupport) target
                 return support.createCompleters()
             }
 
         } catch (MissingMethodException) {
-            log.warn("Aliased Command without createCompleters Method")
+            log.warn('Aliased Command without createCompleters Method')
         }
     }
-    
+
+    @Override
     String getDescription() {
         return messages.format('info.alias_to', targetName)
     }
 
+    @Override
     String getUsage() {
         return target.usage
     }
-    
+
+    @Override
     String getHelp() {
         return target.help
     }
-    
+
+    @Override
     boolean getHidden() {
         return target.hidden
     }
-    
+
+    @Override
     Object execute(final List<String> args) {
         target.execute(args)
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandException.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandException.groovy
index 8fb8f3b..1adfc33 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandException.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandException.groovy
@@ -16,7 +16,7 @@
 
 package org.codehaus.groovy.tools.shell
 
-import groovy.transform.CompileStatic;
+import groovy.transform.CompileStatic
 
 /**
  * Thrown to indicate a problem with command execution.
@@ -25,23 +25,23 @@ import groovy.transform.CompileStatic;
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
 @CompileStatic
-public class CommandException
+class CommandException
     extends Exception
 {
 
-    private final Command command;
+    private final Command command
 
-    public CommandException(final Command command, String msg) {
-        super(msg);
-        this.command = command;
+    CommandException(final Command command, final String msg) {
+        super(msg)
+        this.command = command
     }
 
-    public CommandException(final Command command, String msg, Throwable cause) {
-        super(msg, cause);
-        this.command = command;
+    CommandException(final Command command, final String msg, final Throwable cause) {
+        super(msg, cause)
+        this.command = command
     }
 
-    public Command getCommand() {
-        return command;
+    Command getCommand() {
+        return command
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandRegistry.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandRegistry.groovy
index bfa4c00..d83f8a2 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandRegistry.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandRegistry.groovy
@@ -27,30 +27,30 @@ import org.codehaus.groovy.tools.shell.util.Logger
 class CommandRegistry
 {
     protected final Logger log = Logger.create(CommandRegistry)
-    
+
     //
     // TODO: Hook up support so one can for (command in registry) { }
     //
-    
+
     /** A list of all of the registered commands. */
-    final List<Command> commands = []
+    final List<Command> commandList = []
 
     /** A set of all of the command names and shortcuts to ensure they are unique. */
     private final Set<String> names = new TreeSet<String>()
-    
+
     Command register(final Command command) {
         assert command
 
         // Make sure that the command name and shortcut are unique
-        assert !names.contains(command.name) : "Duplicate comamnd name: $command.name"
+        assert !names.contains(command.name) : "Duplicate command name: $command.name"
         names << command.name
-        
+
         assert !names.contains(command.shortcut) : "Duplicate command shortcut: $command.shortcut"
         names << command.shortcut
 
         // Hold on to the command in order
-        commands << command
-        
+        commandList << command
+
         // Hookup context for alias commands
         if (command instanceof CommandSupport) {
             ((CommandSupport) command).registry = this
@@ -58,18 +58,18 @@ class CommandRegistry
 
         // Add any standard aliases for the command if any
         command.aliases?.each {Command it -> this.register(it) }
-        
+
         if (log.debugEnabled) {
             log.debug("Registered command: $command.name")
         }
-        
+
         return command
     }
-    
+
     Command find(final String name) {
         assert name
-        
-        for (c in commands) {
+
+        for (c in commandList) {
             if (name in [ c.name, c.shortcut ]) {
                 return c
             }
@@ -78,32 +78,32 @@ class CommandRegistry
                 return c
             }
         }
-        
+
         return null
     }
-    
+
     void remove(final Command command) {
         assert command
-        
-        commands.remove(command)
-        
+
+        commandList.remove(command)
+
         names.remove(command.name)
         names.remove(command.shortcut)
-        
+
         if (log.debugEnabled) {
             log.debug("Removed command: $command.name")
         }
     }
-    
+
     List<Command> commands() {
-        return commands
+        return commandList
     }
 
     Command getProperty(final String name) {
         return find(name)
     }
-    
-    Iterator<Command> iterator() {
+
+    Iterator iterator() {
         return commands().iterator()
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandSupport.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandSupport.groovy
index 2029b0e..bcc4413 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandSupport.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/CommandSupport.groovy
@@ -34,7 +34,7 @@ abstract class CommandSupport
     implements Command
 {
     protected static final String NEWLINE = System.properties['line.separator']
-    
+
     /** Instance logger for the command, initialized late to include the command name. */
     protected final Logger log
 
@@ -46,7 +46,7 @@ abstract class CommandSupport
 
     /** The shortcut switch */
     final String shortcut
-    
+
     /** The owning shell. */
     protected final Groovysh shell
 
@@ -55,51 +55,74 @@ abstract class CommandSupport
 
     /** Provides the command instance with the registry, for aliasing support. */
     protected CommandRegistry registry
-    
+
     /** Standard aliases for the command. */
     final List/*<CommandAlias>*/ aliases = []
-    
+
     /** Flag to indicate if the command should be hidden or not. */
     boolean hidden = false
-    
+
     protected CommandSupport(final Groovysh shell, final String name, final String shortcut) {
         assert shell != null
         assert name
         assert shortcut
-        
+
         this.log = Logger.create(this.class, name)
         this.shell = shell
         this.io = shell.io
         this.name = name
         this.shortcut = shortcut
-        
+
         //
         // NOTE: Registry will be added once registered.
         //
     }
 
+    @Override
     String getDescription() {
         return messages['command.description']
     }
 
+    @Override
     String getUsage() {
         return messages['command.usage']
     }
 
+    @Override
     String getHelp() {
         return messages['command.help']
     }
 
-    /**
+    @Override
+    boolean getHidden() {
+        return hidden
+    }
+
+    @Override
+    List getAliases() {
+        return aliases
+    }
+
+    @Override
+    String getShortcut() {
+        return shortcut
+    }
+
+    @Override
+    String getName() {
+        return name
+    }
+/**
      * Override to provide custom completion semantics for the command.
      */
     protected List<Completer> createCompleters() {
-        return null
+        return []
     }
 
     /**
      * Setup the Completer for the command.
      */
+    @Override
     Completer getCompleter() {
         if (hidden) {
             return null
@@ -109,7 +132,7 @@ abstract class CommandSupport
         list << new StringsCompleter(name, shortcut)
 
         List<Completer> completers = createCompleters()
-        
+
         if (completers) {
             completers.each {Completer it ->
                 if (it) {
@@ -126,7 +149,7 @@ abstract class CommandSupport
 
         return new StricterArgumentCompleter(list)
     }
-    
+
     //
     // Helpers
     //
@@ -138,19 +161,19 @@ abstract class CommandSupport
     protected void fail(final String msg) {
         throw new CommandException(this, msg)
     }
-    
+
     protected void fail(final String msg, final Throwable cause) {
         throw new CommandException(this, msg, cause)
     }
-    
-    protected void assertNoArguments(final List args) {
+
+    protected void assertNoArguments(final List<String> args) {
         assert args != null
-        
+
         if (args.size() > 0) {
             fail(messages.format('error.unexpected_args', args.join(' ')))
         }
     }
-    
+
     //
     // Shell access helpers
     //
@@ -166,19 +189,19 @@ abstract class CommandSupport
     protected List<String> getImports() {
         return shell.imports
     }
-    
+
     protected Binding getBinding() {
         return shell.interp.context
     }
-    
+
     protected Map getVariables() {
         return binding.variables
     }
-    
+
     protected FileHistory getHistory() {
         return shell.history
     }
-    
+
     protected GroovyClassLoader getClassLoader() {
         return shell.interp.classLoader
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ComplexCommandSupport.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ComplexCommandSupport.groovy
index ae02ccf..9a641fc 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ComplexCommandSupport.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ComplexCommandSupport.groovy
@@ -16,6 +16,7 @@
 
 package org.codehaus.groovy.tools.shell
 
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.util.SimpleCompletor
 
 /**
@@ -26,76 +27,74 @@ import org.codehaus.groovy.tools.shell.util.SimpleCompletor
 abstract class ComplexCommandSupport
     extends CommandSupport
 {
-    protected List<String> functions
-    
-    protected String defaultFunction
-    
-    ComplexCommandSupport(final Groovysh shell, final String name, final String shortcut, List<String> comFunctions) {
+
+    protected final List<String> functions
+
+    protected final String defaultFunction
+
+    protected ComplexCommandSupport(final Groovysh shell, final String name, final String shortcut, final List<String> comFunctions) {
         this(shell, name, shortcut, comFunctions, null)
     }
 
-    ComplexCommandSupport(final Groovysh shell, final String name, final String shortcut, List<String> comFunctions,
-                          String defaultFunction) {
+    protected ComplexCommandSupport(final Groovysh shell, final String name, final String shortcut,
+                                    final List<String> comFunctions, final String defaultFunction) {
         super(shell, name, shortcut)
         this.functions = comFunctions
         this.defaultFunction = defaultFunction
         assert(defaultFunction  == null || defaultFunction in functions)
     }
 
-    protected List createCompleters() {
+    @Override
+    protected List<Completer> createCompleters() {
         def c = new SimpleCompletor()
-        
-        getFunctions().each { String it -> c.add(it) }
-        
+
+        functions.each { String it -> c.add(it) }
+
         return [ c, null ]
     }
 
-    List<String> getFunctions() {
-        return functions
-    }
-    
+    @Override
     Object execute(List<String> args) {
         assert args != null
-        
+
         if (args.size() == 0) {
             if (defaultFunction) {
                 args = [ defaultFunction ]
             } else {
-                fail("Command '$name' requires at least one argument of ${getFunctions()}")
+                fail("Command '$name' requires at least one argument of ${functions}")
             }
         }
-        
+
         return executeFunction(args[0], args.tail())
     }
-    
-    protected executeFunction(String fname, List<String> args) {
+
+    protected executeFunction(final String fname, final List<String> args) {
         assert args != null
 
-        List<String> myFunctions = getFunctions()
-        assert myFunctions
+        List<String> myFunctions = functions
 
         if (fname in myFunctions) {
-            def func = loadFunction(fname)
-            
+            Closure func = loadFunction(fname)
+
             log.debug("Invoking function '$fname' w/args: $args")
-            
+
             return func.call(args)
         }
         fail("Unknown function name: '$fname'. Valid arguments: $myFunctions")
     }
-    
+
     protected Closure loadFunction(final String name) {
         assert name
-        
+
         try {
             return this."do_${name}"
         } catch (MissingPropertyException e) {
             fail("Failed to load delegate function: $e")
         }
     }
-    
+
     def do_all = {
-        getFunctions().findAll {it != 'all'}.collect {executeFunction(it, [])}
+        functions.findAll {it != 'all'}.collect {executeFunction(it, [])}
     }
 }
 
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Groovysh.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Groovysh.groovy
index 987d93a..cf9d35c 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Groovysh.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Groovysh.groovy
@@ -17,19 +17,33 @@
 package org.codehaus.groovy.tools.shell
 
 import antlr.TokenStreamException
+import groovy.transform.CompileStatic
 import jline.Terminal
-import jline.TerminalFactory
+import jline.WindowsTerminal
 import jline.console.history.FileHistory
+import org.codehaus.groovy.control.CompilationFailedException
+import org.codehaus.groovy.control.ErrorCollector
+import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.codehaus.groovy.control.messages.Message
 import org.codehaus.groovy.runtime.InvokerHelper
 import org.codehaus.groovy.runtime.StackTraceUtils
 import org.codehaus.groovy.tools.shell.commands.LoadCommand
 import org.codehaus.groovy.tools.shell.commands.RecordCommand
 import org.codehaus.groovy.tools.shell.util.*
+import org.codehaus.groovy.tools.shell.util.PackageHelper
+import org.codehaus.groovy.tools.shell.util.ScriptVariableAnalyzer
 import org.fusesource.jansi.AnsiRenderer
 
+import java.util.regex.Pattern
+
 /**
  * An interactive shell for evaluating Groovy code from the command-line (aka. groovysh).
  *
+ * The set of available commands can be modified by placing a file in the classpath named
+ * <code>org/codehaus/groovy/tools/shell/commands.xml</code>
+ *
+ * See {@link XmlCommandRegistrar}
+ *
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
 class Groovysh extends Shell {
@@ -37,25 +51,36 @@ class Groovysh extends Shell {
 
     private static final MessageSource messages = new MessageSource(Groovysh)
 
+    private static final Pattern TYPEDEF_PATTERN = ~'^\\s*((?:public|protected|private|static|abstract|final)\\s+)*(?:class|enum|interface).*'
+    private static final Pattern METHODDEF_PATTERN = ~'^\\s*((?:public|protected|private|static|abstract|final|synchronized)\\s+)*[a-zA-Z_.]+[a-zA-Z_.<>]+\\s+[a-zA-Z_]+\\(.*'
+
+    public static final String COLLECTED_BOUND_VARS_MAP_VARNAME = 'groovysh_collected_boundvars'
+
+    public static final String INTERPRETER_MODE_PREFERENCE_KEY = 'interpreterMode'
+    public static final String AUTOINDENT_PREFERENCE_KEY = 'autoindent'
+    public static final String COLORS_PREFERENCE_KEY = 'colors'
+    // after how many prefix characters we start displaying all metaclass methods
+    public static final String METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY = 'meta-completion-prefix-length'
+
+
     final BufferManager buffers = new BufferManager()
 
     final Parser parser
 
     final Interpreter interp
-    
+
     final List<String> imports = []
 
-    public static final String AUTOINDENT_PREFERENCE_KEY = "autoindent"
-    // after how many prefix characters we start displaying all metaclass methods
-    public static final String METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY = "meta-completion-prefix-length"
     int indentSize = 2
-    
+
     InteractiveShellRunner runner
 
     FileHistory history
 
     boolean historyFull  // used as a workaround for GROOVY-2177
+
     String evictedLine  // remembers the command which will get evicted if history is full
+
     PackageHelper packageHelper
 
     Groovysh(final ClassLoader classLoader, final Binding binding, final IO io, final Closure registrar) {
@@ -71,7 +96,7 @@ class Groovysh extends Shell {
 
         registrar.call(this)
 
-        this.packageHelper = new PackageHelper(classLoader)
+        this.packageHelper = new PackageHelperImpl(classLoader)
     }
 
     private static Closure createDefaultRegistrar(final ClassLoader classLoader) {
@@ -98,7 +123,7 @@ class Groovysh extends Shell {
     Groovysh(final IO io) {
         this(new Binding(), io)
     }
-    
+
     Groovysh() {
         this(new IO())
     }
@@ -110,9 +135,10 @@ class Groovysh extends Shell {
     /**
      * Execute a single line, where the line may be a command or Groovy code (complete or incomplete).
      */
+    @Override
     Object execute(final String line) {
         assert line != null
-        
+
         // Ignore empty lines
         if (line.trim().size() == 0) {
             return null
@@ -120,20 +146,20 @@ class Groovysh extends Shell {
 
         maybeRecordInput(line)
 
-        def result
-        
+        Object result
+
         // First try normal command execution
         if (isExecutable(line)) {
             result = executeCommand(line)
-            
-            // For commands, only set the last result when its non-null/true
-            if (result) {
+
+            // For commands, only set the last result when its non-null
+            if (result != null) {
                 setLastResult(result)
             }
-            
+
             return result
         }
-        
+
         // Otherwise treat the line as Groovy
         List<String> current = new ArrayList<String>(buffers.current())
 
@@ -147,16 +173,21 @@ class Groovysh extends Shell {
 
         switch (status.code) {
             case ParseCode.COMPLETE:
-                log.debug("Evaluating buffer...")
+                log.debug('Evaluating buffer...')
 
                 if (io.verbose) {
                     displayBuffer(current)
                 }
 
-                // Evaluate the current buffer w/imports and dummy statement
-                List buff = [importsSpec] + [ 'true' ] + current
+                if (!Boolean.valueOf(Preferences.get(INTERPRETER_MODE_PREFERENCE_KEY, 'false')) || isTypeOrMethodDeclaration(current)) {
+                    // Evaluate the current buffer w/imports and dummy statement
+                    List buff = [importsSpec] + [ 'true' ] + current
+                    setLastResult(result = interp.evaluate(buff))
+                } else {
+                    // Evaluate Buffer wrapped with code storing bounded vars
+                    result = evaluateWithStoredBoundVars(current)
+                }
 
-                setLastResult(result = interp.evaluate(buff))
                 buffers.clearSelected()
                 break
 
@@ -176,6 +207,49 @@ class Groovysh extends Shell {
         return result
     }
 
+    /**
+     * return true if the buffer can be recognized as a type declaration statement
+     * @param strings
+     * @return
+     */
+    @CompileStatic
+    static boolean isTypeOrMethodDeclaration(final List<String> buffer) {
+        final String joined = buffer.join('')
+        return joined.matches(TYPEDEF_PATTERN) || joined.matches(METHODDEF_PATTERN)
+    }
+/*
+     * to simulate an interpreter mode, this method wraps the statements into a try/finally block that
+     * stores bound variables like unbound variables
+     */
+    private Object evaluateWithStoredBoundVars(final List<String> current) {
+        Object result
+        String variableBlocks = ''
+        // To make groovysh behave more like an interpreter, we need to retrive all bound
+        // vars at the end of script execution, and then update them into the groovysh Binding context.
+        Set<String> boundVars = ScriptVariableAnalyzer.getBoundVars(current.join(Parser.NEWLINE))
+        variableBlocks += "$COLLECTED_BOUND_VARS_MAP_VARNAME = new HashMap();"
+        if (boundVars) {
+            boundVars.each({ String varname ->
+                // bound vars can be in global or some local scope.
+                // We discard locally scoped vars by ignoring MissingPropertyException
+                variableBlocks += """
+try {$COLLECTED_BOUND_VARS_MAP_VARNAME[\"$varname\"] = $varname;
+} catch (MissingPropertyException e){}"""
+            })
+        }
+
+        // Evaluate the current buffer w/imports and dummy statement
+        List<String> buff = imports + ['try {', 'true'] + current + ['} finally {' + variableBlocks + '}']
+
+        setLastResult(result = interp.evaluate(buff))
+
+        Map<String, Object> boundVarValues = interp.context.getVariable(COLLECTED_BOUND_VARS_MAP_VARNAME)
+        boundVarValues.each({ String name, Object value -> interp.context.setVariable(name, value) })
+        return result
+    }
+
+
+
     protected Object executeCommand(final String line) {
         return super.execute(line)
     }
@@ -188,7 +262,7 @@ class Groovysh extends Shell {
 
         buffer.eachWithIndex { line, index ->
             def lineNum = formatLineNumber(index)
-            
+
             io.out.println(" ${lineNum}@|bold >|@ $line")
         }
     }
@@ -215,11 +289,11 @@ class Groovysh extends Shell {
     private String buildPrompt() {
         def lineNum = formatLineNumber(buffers.current().size())
 
-        def groovyshellProperty = System.getProperty("groovysh.prompt")
+        def groovyshellProperty = System.getProperty('groovysh.prompt')
         if (groovyshellProperty) {
-            return  "@|bold ${groovyshellProperty}:|@${lineNum}@|bold >|@ "
+            return "@|bold ${groovyshellProperty}:|@${lineNum}@|bold >|@ "
         }
-        def groovyshellEnv = System.getenv("GROOVYSH_PROMPT")
+        def groovyshellEnv = System.getenv('GROOVYSH_PROMPT')
         if (groovyshellEnv) {
             return  "@|bold ${groovyshellEnv}:|@${lineNum}@|bold >|@ "
         }
@@ -235,7 +309,7 @@ class Groovysh extends Shell {
     String getIndentPrefix() {
         List<String> buffer = this.buffers.current()
         if (buffer.size() < 1) {
-            return ""
+            return ''
         }
         StringBuilder src = new StringBuilder()
         for (String line: buffer) {
@@ -243,7 +317,7 @@ class Groovysh extends Shell {
         }
 
         // not sure whether the same Lexer instance could be reused.
-        def lexer = CurlyCountingGroovyLexer.createGroovyLexer(src.toString());
+        def lexer = CurlyCountingGroovyLexer.createGroovyLexer(src.toString())
 
         // read all tokens
         try {
@@ -254,7 +328,7 @@ class Groovysh extends Shell {
         int parenIndent = (lexer.getParenLevel()) * indentSize
 
         // dedent after closing brackets
-        return " " * Math.max(parenIndent, 0)
+        return ' ' * Math.max(parenIndent, 0)
     }
 
     public String renderPrompt() {
@@ -287,9 +361,9 @@ class Groovysh extends Shell {
      */
     protected void loadUserScript(final String filename) {
         assert filename
-        
+
         File file = new File(getUserStateDirectory(), filename)
-        
+
         if (file.exists()) {
             Command command = registry[LoadCommand.COMMAND_NAME] as Command
 
@@ -318,7 +392,7 @@ class Groovysh extends Shell {
     //
 
     private void maybeRecordInput(final String line) {
-        def record = registry[RecordCommand.COMMAND_NAME]
+        RecordCommand record = registry[RecordCommand.COMMAND_NAME]
 
         if (record != null) {
             record.recordInput(line)
@@ -326,7 +400,7 @@ class Groovysh extends Shell {
     }
 
     private void maybeRecordResult(final Object result) {
-        def record = registry[RecordCommand.COMMAND_NAME]
+        RecordCommand record = registry[RecordCommand.COMMAND_NAME]
 
         if (record != null) {
             record.recordResult(result)
@@ -334,19 +408,16 @@ class Groovysh extends Shell {
     }
 
     private void maybeRecordError(Throwable cause) {
-        def record = registry[RecordCommand.COMMAND_NAME]
+        RecordCommand record = registry[RecordCommand.COMMAND_NAME]
 
         if (record != null) {
-            boolean sanitize = Preferences.sanitizeStackTrace
-
-            if (sanitize) {
-                cause = StackTraceUtils.deepSanitize(cause);
+            if (Preferences.sanitizeStackTrace) {
+                cause = StackTraceUtils.deepSanitize(cause)
             }
-
             record.recordError(cause)
         }
     }
-    
+
     //
     // Hooks
     //
@@ -364,7 +435,7 @@ class Groovysh extends Shell {
 
     private void setLastResult(final Object result) {
         if (resultHook == null) {
-            throw new IllegalStateException("Result hook is not set")
+            throw new IllegalStateException('Result hook is not set')
         }
 
         resultHook.call((Object)result)
@@ -377,52 +448,72 @@ class Groovysh extends Shell {
     final Closure defaultErrorHook = { Throwable cause ->
         assert cause != null
 
-        io.err.println("@|bold,red ERROR|@ ${cause.getClass().name}:")
-        io.err.println("@|bold,red ${cause.message}|@")
+        if (log.debug || ! cause instanceof CompilationFailedException) {
+            // For CompilationErrors, the Exception Class is usually not useful to the user
+            io.err.println("@|bold,red ERROR|@ ${cause.getClass().name}:")
+        }
 
-        maybeRecordError(cause)
+        if (cause instanceof MultipleCompilationErrorsException) {
+            StringWriter data = new StringWriter();
+            PrintWriter writer = new PrintWriter(data);
+            ErrorCollector collector = ((MultipleCompilationErrorsException) cause).getErrorCollector()
+            Iterator<Message> msgIterator = collector.getErrors().iterator()
+            while (msgIterator.hasNext()) {
+                Message errorMsg = msgIterator.next()
+                errorMsg.write(writer)
+                if (msgIterator.hasNext()) {
+                    writer.println()
+                }
+            }
+            io.err.println("@|bold,red ${data.toString()}|@")
+        } else {
+            io.err.println("@|bold,red ${cause.message}|@")
 
-        if (log.debug) {
-            // If we have debug enabled then skip the fancy bits below
-            log.debug(cause)
-        }
-        else {
-            boolean sanitize = Preferences.sanitizeStackTrace
 
-            // Sanitize the stack trace unless we are in verbose mode, or the user has request otherwise
-            if (!io.verbose && sanitize) {
-                cause = StackTraceUtils.deepSanitize(cause);
+            maybeRecordError(cause)
+
+            if (log.debug) {
+                // If we have debug enabled then skip the fancy bits below
+                log.debug(cause)
             }
+            else {
+                boolean sanitize = Preferences.sanitizeStackTrace
 
-            def trace = cause.stackTrace
+                // Sanitize the stack trace unless we are in verbose mode, or the user has request otherwise
+                if (!io.verbose && sanitize) {
+                    cause = StackTraceUtils.deepSanitize(cause)
+                }
 
-            def buff = new StringBuffer()
+                def trace = cause.stackTrace
 
-            boolean doBreak = false;
+                def buff = new StringBuffer()
 
-            for (e in trace) {
-                // Stop the trace once we find the root of the evaluated script
-                if (e.className == Interpreter.SCRIPT_FILENAME && e.methodName == 'run') {
-                    if (io.verbosity != IO.Verbosity.DEBUG && io.verbosity != IO.Verbosity.VERBOSE) {
-                        break
+                boolean doBreak = false
+
+                for (e in trace) {
+                    // Stop the trace once we find the root of the evaluated script
+                    if (e.className == Interpreter.SCRIPT_FILENAME && e.methodName == 'run') {
+                        if (io.verbosity != IO.Verbosity.DEBUG && io.verbosity != IO.Verbosity.VERBOSE) {
+                            break
+                        }
+                        doBreak = true
                     }
-                    doBreak = true
-                }
 
-                buff << "        @|bold at|@ ${e.className}.${e.methodName} (@|bold "
+                    buff << "        @|bold at|@ ${e.className}.${e.methodName} (@|bold "
 
-                buff << (e.nativeMethod ? 'Native Method' :
+                    buff << (e.nativeMethod ? 'Native Method' :
                             (e.fileName != null && e.lineNumber != -1 ? "${e.fileName}:${e.lineNumber}" :
-                                (e.fileName != null ? e.fileName : 'Unknown Source')))
+                                    (e.fileName != null ? e.fileName : 'Unknown Source')))
 
-                buff << '|@)'
+                    buff << '|@)'
 
-                io.err.println(buff)
+                    io.err.println(buff)
 
-                buff.setLength(0) // Reset the buffer
-                if (doBreak) {
-                    io.err.println('        @|bold ...|@')
-                    break
+                    buff.setLength(0) // Reset the buffer
+                    if (doBreak) {
+                        io.err.println('        @|bold ...|@')
+                        break
+                    }
                 }
             }
         }
@@ -432,7 +523,7 @@ class Groovysh extends Shell {
 
     private void displayError(final Throwable cause) {
         if (errorHook == null) {
-            throw new IllegalStateException("Error hook is not set")
+            throw new IllegalStateException('Error hook is not set')
         }
         if (cause instanceof MissingPropertyException) {
             if (cause.type && cause.type.canonicalName == Interpreter.SCRIPT_FILENAME) {
@@ -444,88 +535,58 @@ class Groovysh extends Shell {
         errorHook.call(cause)
     }
 
-    //
-    // Interactive Shell
-    //
-
-    int run(final String[] args) {
-        String commandLine = null
+    /**
+    * Run Interactive Shell with optional initial script and files to load
+    */
+    int run(final String evalString, final List<String> filenames) {
+        List<String> startCommands = []
 
-        if (args != null && args.length > 0) {
-            commandLine = args.join(' ')
+        if (evalString != null && evalString.trim().size() > 0) {
+            startCommands.add(evalString)
         }
-
-        return run(commandLine as String)
+        if (filenames != null && filenames.size() > 0) {
+            startCommands.addAll(filenames.collect({String it -> "${LoadCommand.COMMAND_NAME} $it"}))
+        }
+        return run(startCommands.join('\n'))
     }
 
+    /**
+     * Run Interactive Shell with initial command
+     */
     int run(final String commandLine) {
-        Terminal term = TerminalFactory.create()
-
-        if (log.debug) {
-            log.debug("Terminal ($term)")
-            log.debug("    Supported:  $term.supported")
-            log.debug("    ECHO:       (enabled: $term.echoEnabled)")
-            log.debug("    H x W:      ${term.getHeight()} x ${term.getWidth()}")
-            log.debug("    ANSI:       ${term.isAnsiSupported()}")
-
-            if (term instanceof jline.WindowsTerminal) {
-                jline.WindowsTerminal winterm = (jline.WindowsTerminal) term
-                log.debug("    Direct:     ${winterm.directConsole}")
-            }
-        }
-
         def code
 
         try {
             loadUserScript('groovysh.profile')
+            loadUserScript('groovysh.rc')
+
+            // Setup the interactive runner
+            runner = new InteractiveShellRunner(
+                    this,
+                    this.&renderPrompt as Closure)
 
             // if args were passed in, just execute as a command
             // (but cygwin gives an empty string, so ignore that)
             if (commandLine != null && commandLine.trim().size() > 0) {
-                // Run the given commands
-                execute(commandLine)
-            } else {
-                loadUserScript('groovysh.rc')
-
-                // Setup the interactive runner
-                runner = new InteractiveShellRunner(
-                        this,
-                        this.&renderPrompt as Closure,
-                        Integer.valueOf(Preferences.get(METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
+                runner.wrappedInputStream.insert(commandLine + '\n')
+            }
 
-                // Setup the history
-                File histFile = new File(userStateDirectory, 'groovysh.history')
-                history = new FileHistory(histFile)
-                runner.setHistory(history)
+            // Setup the history
+            File histFile = new File(userStateDirectory, 'groovysh.history')
+            history = new FileHistory(histFile)
+            runner.setHistory(history)
 
-                // Setup the error handler
-                runner.errorHandler = this.&displayError
+            // Setup the error handler
+            runner.errorHandler = this.&displayError
 
-                //
-                // TODO: See if we want to add any more language specific completions, like for println for example?
-                //
+            displayWelcomeBanner(runner)
 
-                // Display the welcome banner
-                if (!io.quiet) {
-                    int width = term.getWidth()
+            // And let 'er rip... :-)
+            runner.run()
 
-                    // If we can't tell, or have something bogus then use a reasonable default
-                    if (width < 1) {
-                        width = 80
-                    }
-
-                    io.out.println(messages.format('startup_banner.0', GroovySystem.version, System.properties['java.version']))
-                    io.out.println(messages['startup_banner.1'])
-                    io.out.println('-' * (width - 1))
-                }
-
-                // And let 'er rip... :-)
-                runner.run()
-            }
 
             code = 0
-        }
-        catch (ExitNotification n) {
+        } catch (ExitNotification n) {
             log.debug("Exiting w/code: ${n.code}")
 
             code = n.code
@@ -541,4 +602,43 @@ class Groovysh extends Shell {
 
         return code
     }
+
+
+    /**
+     * maybe displays log information and a welcome message
+     * @param term
+     */
+    public void displayWelcomeBanner(InteractiveShellRunner runner) {
+        if (!log.debug && io.quiet) {
+            // nothing to do here
+            return
+        }
+        Terminal term = runner.reader.terminal
+        if (log.debug) {
+            log.debug("Terminal ($term)")
+            log.debug("    Supported:  $term.supported")
+            log.debug("    ECHO:       (enabled: $term.echoEnabled)")
+            log.debug("    H x W:      ${term.getHeight()} x ${term.getWidth()}")
+            log.debug("    ANSI:       ${term.isAnsiSupported()}")
+
+            if (term instanceof WindowsTerminal) {
+                WindowsTerminal winterm = (WindowsTerminal) term
+                log.debug("    Direct:     ${winterm.directConsole}")
+            }
+        }
+
+        // Display the welcome banner
+        if (!io.quiet) {
+            int width = term.getWidth()
+
+            // If we can't tell, or have something bogus then use a reasonable default
+            if (width < 1) {
+                width = 80
+            }
+
+            io.out.println(messages.format('startup_banner.0', GroovySystem.version, System.properties['java.version']))
+            io.out.println(messages['startup_banner.1'])
+            io.out.println('-' * (width - 1))
+        }
+    }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
index 06e02b5..4e58170 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/InteractiveShellRunner.groovy
@@ -18,7 +18,6 @@ package org.codehaus.groovy.tools.shell
 
 import jline.console.ConsoleReader
 import jline.console.completer.AggregateCompleter
-
 import jline.console.history.FileHistory
 import org.codehaus.groovy.tools.shell.completion.*
 import org.codehaus.groovy.tools.shell.util.Logger
@@ -36,22 +35,19 @@ class InteractiveShellRunner
     implements Runnable
 {
     ConsoleReader reader
-    
+
     final Closure prompt
-    
+
     final CommandsMultiCompleter completer
     WrappedInputStream wrappedInputStream
 
     InteractiveShellRunner(final Groovysh shell, final Closure prompt) {
-        this(shell, prompt, 0)
-    }
-
-    InteractiveShellRunner(final Groovysh shell, final Closure prompt, int metaclass_completion_prefix_length) {
         super(shell)
-        
+
         this.prompt = prompt
         this.wrappedInputStream = new WrappedInputStream(shell.io.inputStream)
-        this.reader = new ConsoleReader(wrappedInputStream, shell.io.outputStream)
+        this.reader = new PatchedConsoleReader(wrappedInputStream, shell.io.outputStream)
+        this.reader.setCompletionHandler(new PatchedCandidateListCompletionHandler())
         // expand events ia an advanced feature of JLine that clashes with Groovy syntax (e.g. invoke "2!=3")
         this.reader.expandEvents = false
 
@@ -60,16 +56,19 @@ class InteractiveShellRunner
         this.completer = new CommandsMultiCompleter()
         reader.addCompleter(this.completer)
 
+        CustomClassSyntaxCompletor classnameCompletor = new CustomClassSyntaxCompletor(shell)
+
         reader.addCompleter(new GroovySyntaxCompletor(shell,
-                new ReflectionCompletor(shell,
-                        metaclass_completion_prefix_length),
+                new ReflectionCompletor(shell),
+                classnameCompletor,
                 [new KeywordSyntaxCompletor(),
                         new VariableSyntaxCompletor(shell),
-                        new CustomClassSyntaxCompletor(shell),
+                        classnameCompletor,
                         new ImportsSyntaxCompletor(shell)],
                 new FileNameCompleter(false)))
     }
-    
+
+    @Override
     void run() {
         for (Command command in shell.registry.commands()) {
             completer.add(command)
@@ -82,39 +81,40 @@ class InteractiveShellRunner
         adjustHistory()
         super.run()
     }
-    
+
     void setHistory(final FileHistory history) {
         reader.history = history
         def dir = history.file.parentFile
-        
+
         if (!dir.exists()) {
             dir.mkdirs()
-            
+
             log.debug("Created base directory for history file: $dir")
         }
-        
+
         log.debug("Using history file: $history.file")
     }
-    
+
+    @Override
     protected String readLine() {
         try {
             if (Boolean.valueOf(Preferences.get(Groovysh.AUTOINDENT_PREFERENCE_KEY))) {
                 // prevent auto-indent when pasting code blocks
                 if (shell.io.inputStream.available() == 0) {
-                    wrappedInputStream.insert(((Groovysh) shell).getIndentPrefix())
+                    wrappedInputStream.insert(((Groovysh) shell).indentPrefix)
                 }
             }
             return reader.readLine(prompt.call() as String)
         } catch (StringIndexOutOfBoundsException e) {
-            log.debug("HACK: Try and work around GROOVY-2152 for now", e)
+            log.debug('HACK: Try and work around GROOVY-2152 for now', e)
             reader.println()
-            return "";
+            return ''
         } catch (Throwable t) {
             if (shell.io.verbosity == IO.Verbosity.DEBUG) {
                 throw t
             }
             reader.println()
-            return ""
+            return ''
         }
     }
 
@@ -130,7 +130,7 @@ class InteractiveShellRunner
         // we save the evicted line in casesomeone wants to use it with history recall
         if (shell instanceof Groovysh) {
             def history = shell.history
-            shell.historyFull = (history != null) && (history.size() >= history.getMaxSize())
+            shell.historyFull = (history != null) && (history.size() >= history.maxSize)
             if (shell.historyFull) {
                 def first = history.first()
                 if (first) {
@@ -152,40 +152,41 @@ class CommandsMultiCompleter
     extends AggregateCompleter
 {
     protected final Logger log = Logger.create(this.class)
-    
+
     List/*<Completer>*/ list = []
-    
+
     private boolean dirty = false
-    
+
     def add(final Command command) {
         assert command
-        
+
         //
         // FIXME: Need to handle completer removal when things like aliases are rebound
         //
-        
+
         def c = command.completer
-        
+
         if (c) {
             list << c
-            
+
             log.debug("Added completer[${list.size()}] for command: $command.name")
-            
+
             dirty = true
         }
     }
 
     void refresh() {
-        log.debug("Refreshing the completer list")
+        log.debug('Refreshing the completer list')
 
-        getCompleters().clear()
-        getCompleters().addAll(list)
+        completers.clear()
+        completers.addAll(list)
         dirty = false
     }
 
+    @Override
     int complete(final String buffer, final int pos, final List cand) {
         assert buffer != null
-        
+
         //
         // FIXME: This is a bit of a hack, I'm too lazy to rewrite a more efficient
         //        completer impl that is more dynamic than the jline.MultiCompleter version
@@ -195,7 +196,7 @@ class CommandsMultiCompleter
         if (dirty) {
             refresh()
         }
-        
+
         return super.complete(buffer, pos, cand)
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Interpreter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Interpreter.groovy
index 1ee6506..e8fce38 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Interpreter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Interpreter.groovy
@@ -27,10 +27,10 @@ import java.lang.reflect.Method
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
-class Interpreter
+class Interpreter implements Evaluator
 {
     static final String SCRIPT_FILENAME = 'groovysh_evaluate'
-    
+
     private final Logger log = Logger.create(this.class)
 
     private final GroovyShell shell
@@ -43,13 +43,14 @@ class Interpreter
     }
 
     Binding getContext() {
-        return shell.getContext()
+        return shell.context
     }
 
     GroovyClassLoader getClassLoader() {
-        return shell.getClassLoader()
+        return shell.classLoader
     }
 
+    @Override
     def evaluate(final Collection<String> buffer) {
         assert buffer
 
@@ -90,4 +91,8 @@ class Interpreter
 
         return result
     }
-}
\ No newline at end of file
+}
+
+interface Evaluator {
+    def evaluate(final Collection<String> buffer)
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Main.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Main.groovy
index 65626c1..868ec00 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Main.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Main.groovy
@@ -16,6 +16,10 @@
 
 package org.codehaus.groovy.tools.shell
 
+import jline.TerminalFactory
+import jline.UnixTerminal
+import jline.UnsupportedTerminal
+import jline.WindowsTerminal
 import org.codehaus.groovy.tools.shell.util.HelpFormatter
 import org.codehaus.groovy.tools.shell.util.Logger
 import org.codehaus.groovy.tools.shell.util.MessageSource
@@ -24,6 +28,17 @@ import org.fusesource.jansi.Ansi
 import org.fusesource.jansi.AnsiConsole
 
 /**
+ * A Main instance has a Groovysh member representing the shell,
+ * and a startGroovysh() method to run an interactive shell.
+ * Subclasses should preferably extend createIO() or configure the shell
+ * via getShell prior to invoking startGroovysh.
+ * Clients may use configureAndStartGroovysh to provide the same CLI params
+ * but a different Groovysh implementation (implementing getIO() and run()).
+ *
+ *
+ * The class also has static utility methods to manipulate the
+ * static ansi state using the jAnsi library.
+ *
  * Main CLI entry-point for <tt>groovysh</tt>.
  *
  * @version $Id$
@@ -31,50 +46,81 @@ import org.fusesource.jansi.AnsiConsole
  */
 class Main
 {
-    static {
-        // Install the system adapters
-        AnsiConsole.systemInstall()
+    final Groovysh groovysh
 
-        // Register jline ansi detector
-        Ansi.setDetector(new AnsiDetector())
+    /**
+     * @param io: may just be new IO(), which is the default
+     */
+    Main(IO io) {
+        Logger.io = io
+        groovysh = new Groovysh(io)
     }
 
-    private static final MessageSource messages = new MessageSource(Main)
+    Groovysh getGroovysh() {
+        return groovysh
+    }
 
+    /**
+     * create a Main instance, configures it according to CLI arguments, and starts the shell.
+     * @param main must have a Groovysh member that has an IO member.
+     */
     static void main(final String[] args) {
-        IO io = new IO()
-        Logger.io = io
-
-        CliBuilder cli = new CliBuilder(usage : 'groovysh [options] [...]', formatter: new HelpFormatter(), writer: io.out)
-
-        cli.classpath(messages['cli.option.classpath.description'])
-        cli.cp(longOpt: 'classpath', messages['cli.option.cp.description'])
-        cli.h(longOpt: 'help', messages['cli.option.help.description'])
-        cli.V(longOpt: 'version', messages['cli.option.version.description'])
-        cli.v(longOpt: 'verbose', messages['cli.option.verbose.description'])
-        cli.q(longOpt: 'quiet', messages['cli.option.quiet.description'])
-        cli.d(longOpt: 'debug', messages['cli.option.debug.description'])
-        cli.C(longOpt: 'color', args: 1, argName: 'FLAG', optionalArg: true, messages['cli.option.color.description'])
-        cli.D(longOpt: 'define', args: 1, argName: 'NAME=VALUE', messages['cli.option.define.description'])
-        cli.T(longOpt: 'terminal', args: 1, argName: 'TYPE', messages['cli.option.terminal.description'])
-
+        CliBuilder cli = new CliBuilder(usage: 'groovysh [options] [...]', formatter: new HelpFormatter(), stopAtNonOption: false)
+        MessageSource messages = new MessageSource(Main)
+        cli.with {
+            classpath(messages['cli.option.classpath.description'])
+            cp(longOpt: 'classpath', messages['cli.option.cp.description'])
+            h(longOpt: 'help', messages['cli.option.help.description'])
+            V(longOpt: 'version', messages['cli.option.version.description'])
+            v(longOpt: 'verbose', messages['cli.option.verbose.description'])
+            q(longOpt: 'quiet', messages['cli.option.quiet.description'])
+            d(longOpt: 'debug', messages['cli.option.debug.description'])
+            e(longOpt: 'evaluate', args: 1, optionalArg: false, messages['cli.option.evaluate.description'])
+            C(longOpt: 'color', args: 1, argName: 'FLAG', optionalArg: true, messages['cli.option.color.description'])
+            D(longOpt: 'define', args: 1, argName: 'NAME=VALUE', messages['cli.option.define.description'])
+            T(longOpt: 'terminal', args: 1, argName: 'TYPE', messages['cli.option.terminal.description'])
+        }
         OptionAccessor options = cli.parse(args)
 
+        if (options == null) {
+            // CliBuilder prints error, but does not exit
+            System.exit(22) // Invalid Args
+        }
+
         if (options.h) {
             cli.usage()
             System.exit(0)
         }
 
         if (options.V) {
-            io.out.println(messages.format('cli.info.version', GroovySystem.version))
+            System.out.println(messages.format('cli.info.version', GroovySystem.version))
             System.exit(0)
         }
 
+        boolean suppressColor = false
+        if (options.hasOption('C')) {
+            def value = options.getOptionValue('C')
+            if (value != null) {
+                suppressColor = !Boolean.valueOf(value).booleanValue() // For JDK 1.4 compat
+            }
+        }
+
+        String type = TerminalFactory.AUTO
         if (options.hasOption('T')) {
-            def type = options.getOptionValue('T')
-            setTerminalType(type)
+            type = options.getOptionValue('T')
+        }
+        try {
+            setTerminalType(type, suppressColor)
+        } catch (IllegalArgumentException e) {
+            System.err.println(e.getMessage())
+            cli.usage()
+            System.exit(22) // Invalid Args
         }
 
+        // IO must be constructed AFTER calling setTerminalType()/AnsiConsole.systemInstall(),
+        // else wrapped System.out does not work on Windows.
+        IO io = new IO()
+
         if (options.hasOption('D')) {
             def values = options.getOptionValues('D')
 
@@ -95,15 +141,23 @@ class Main
             io.verbosity = IO.Verbosity.QUIET
         }
 
-        if (options.hasOption('C')) {
-            def value = options.getOptionValue('C')
-            setColor(value)
+        String evalString = null
+        if (options.e) {
+            evalString = options.getOptionValue('e')
         }
 
-        int code
+        List<String> filenames = options.arguments()
+        Main main = new Main(io)
+        main.startGroovysh(evalString, filenames)
+    }
 
-        // Boot up the shell... :-)
-        final Groovysh shell = new Groovysh(io)
+    /**
+     * @param evalString commands that will be executed at startup after loading files given with filenames param
+     * @param filenames files that will be loaded at startup
+     */
+    protected void startGroovysh(String evalString, List<String> filenames) {
+        int code
+        Groovysh shell = getGroovysh()
 
         // Add a hook to display some status when shutting down...
         addShutdownHook {
@@ -115,7 +169,6 @@ class Main
                 // Give the user a warning when the JVM shutdown abnormally, normal shutdown
                 // will set an exit code through the proper channels
 
-
                 println('WARNING: Abnormal JVM shutdown detected')
             }
 
@@ -129,7 +182,7 @@ class Main
         System.setSecurityManager(new NoExitSecurityManager())
 
         try {
-            code = shell.run(options.arguments() as String[])
+            code = shell.run(evalString, filenames)
         }
         finally {
             System.setSecurityManager(psm)
@@ -142,52 +195,59 @@ class Main
         System.exit(code)
     }
 
-    static void setTerminalType(String type) {
+    /**
+     * @param type: one of 'auto', 'unix', ('win', 'windows'), ('false', 'off', 'none')
+     * @param suppressColor only has effect when ansi is enabled
+     */
+    static void setTerminalType(String type, boolean suppressColor) {
         assert type != null
-        
-        type = type.toLowerCase();
 
+        type = type.toLowerCase()
+        boolean enableAnsi = true
         switch (type) {
-            case 'auto':
-                type = null;
-                break;
-
-            case 'unix':
-                type = 'jline.UnixTerminal'
+            case TerminalFactory.AUTO:
+                type = null
                 break
-
-            case 'win':
-            case 'windows':
-                type = 'jline.WindowsTerminal'
+            case TerminalFactory.UNIX:
+                type = UnixTerminal.canonicalName
                 break
-
-            case 'false':
-            case 'off':
-            case 'none':
-                type = 'jline.UnsupportedTerminal'
+            case TerminalFactory.WIN:
+            case TerminalFactory.WINDOWS:
+                type = WindowsTerminal.canonicalName
+                break
+            case TerminalFactory.FALSE:
+            case TerminalFactory.OFF:
+            case TerminalFactory.NONE:
+                type = UnsupportedTerminal.canonicalName
                 // Disable ANSI, for some reason UnsupportedTerminal reports ANSI as enabled, when it shouldn't
-                Ansi.enabled = false
-                break;
+                enableAnsi = false
+                break
+            default:
+                // Should never happen
+                throw new IllegalArgumentException("Invalid Terminal type: $type")
+        }
+        if (enableAnsi) {
+            installAnsi() // must be called before IO(), since it modifies System.in
+            Ansi.enabled = !suppressColor
+        } else {
+            Ansi.enabled = false
         }
 
         if (type != null) {
-            System.setProperty('jline.terminal', type)
+            System.setProperty(TerminalFactory.JLINE_TERMINAL, type)
         }
     }
 
-    static void setColor(String value) {
-        boolean ansiEnabled
-
-        if (value == null) {
-            ansiEnabled = true // --color is the same as --color=true
-        }
-        else {
-            ansiEnabled = Boolean.valueOf(value).booleanValue(); // For JDK 1.4 compat
-        }
+    static void installAnsi() {
+        // Install the system adapters, replaces System.out and System.err
+        // Must be called before using IO(), because IO stores refs to System.out and System.err
+        AnsiConsole.systemInstall()
 
-        Ansi.enabled = ansiEnabled
+        // Register jline ansi detector
+        Ansi.setDetector(new AnsiDetector())
     }
 
+
     static void setSystemProperty(final String nameValue) {
         String name
         String value
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Parser.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Parser.groovy
index abb7e7f..43a89ea 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Parser.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Parser.groovy
@@ -28,9 +28,11 @@ import antlr.collections.AST
 import antlr.RecognitionException
 import antlr.TokenStreamException
 
+import java.util.regex.Pattern
+
 
 interface Parsing {
-    ParseStatus parse(final Collection<String> buffer);
+    ParseStatus parse(final Collection<String> buffer)
 }
 
 /**
@@ -50,7 +52,7 @@ class Parser
         String flavor = Preferences.getParserFlavor()
 
         log.debug("Using parser flavor: $flavor")
-        
+
         switch (flavor) {
             case Preferences.PARSER_RELAXED:
                 delegate = new RelaxedParser()
@@ -66,7 +68,7 @@ class Parser
                 break
         }
     }
-    
+
     ParseStatus parse(final Collection<String> buffer) {
         return delegate.parse(buffer)
     }
@@ -83,6 +85,7 @@ final class RelaxedParser implements Parsing
 
     private String[] tokenNames
 
+    @Override
     ParseStatus parse(final Collection<String> buffer) {
         assert buffer
 
@@ -103,12 +106,12 @@ final class RelaxedParser implements Parsing
             switch (e.getClass()) {
                 case TokenStreamException:
                 case RecognitionException:
-                    log.debug("Parse incomplete: $e (${e.getClass().getName()})")
-    
+                    log.debug("Parse incomplete: $e (${e.getClass().name})")
+
                     return new ParseStatus(ParseCode.INCOMPLETE)
 
                 default:
-                    log.debug("Parse error: $e (${e.getClass().getName()})")
+                    log.debug("Parse error: $e (${e.getClass().name})")
 
                     return new ParseStatus(e)
             }
@@ -121,10 +124,10 @@ final class RelaxedParser implements Parsing
 
         def parser = GroovyRecognizer.make(lexer)
         parser.setSourceBuffer(sourceBuffer)
-        tokenNames = parser.getTokenNames()
+        tokenNames = parser.tokenNames
 
         parser.compilationUnit()
-        return parser.getAST()
+        return parser.AST
     }
 }
 
@@ -133,10 +136,12 @@ final class RelaxedParser implements Parsing
  */
 final class RigidParser implements Parsing
 {
+    private static final Pattern ANNOTATION_PATTERN = Pattern.compile('^@[a-zA-Z_][a-zA-Z_0-9]*(.*)$')
     static final String SCRIPT_FILENAME = 'groovysh_parse'
 
     private final Logger log = Logger.create(this.class)
 
+    @Override
     ParseStatus parse(final Collection<String> buffer) {
         assert buffer
 
@@ -156,7 +161,13 @@ final class RigidParser implements Parsing
             return new ParseStatus(ParseCode.COMPLETE)
         }
         catch (CompilationFailedException e) {
-            //
+            // During a shell session often a user will hit enter without having completed a class definition
+            // for the parser this means it will raise some kind of compilation exception.
+            // The following code has to attempt to hide away all such exceptions that are due to the code being
+            // incomplete, but show all exceptions due to the code being incorrect.
+            // Unexpected EOF is most common for incomplete code, however there are several other situations
+            // where the code is incomplete, but the Exception is raised without failedWithUnexpectedEOF().
+
             // FIXME: Seems like failedWithUnexpectedEOF() is not always set as expected, as in:
             //
             // class a {               <--- is true here
@@ -164,13 +175,13 @@ final class RigidParser implements Parsing
             //
 
             if (parser.errorCollector.errorCount > 1 || !parser.failedWithUnexpectedEOF()) {
- 
+
                 // HACK: Super insane hack... we detect a syntax error, but might still ignore
                 // it depending on the line ending
-                if (ignoreSyntaxErrorForLineEnding(buffer[-1].trim())) {
+                if (ignoreSyntaxErrorForLineEnding(buffer[-1].trim()) ||
+                    isAnnotationExpression(e, buffer[-1].trim())) {
                     log.debug("Ignoring parse failure; might be valid: $e")
-                }
-                else {
+                } else {
                     error = e
                 }
             }
@@ -187,14 +198,20 @@ final class RigidParser implements Parsing
         log.debug('Parse incomplete')
         return new ParseStatus(ParseCode.INCOMPLETE)
     }
-    
-    private boolean ignoreSyntaxErrorForLineEnding(String line) {
-        def lineEndings = ['{', '[', '(', ',', '.', '-', '+', '/', '*', '%', '&', '|', '?', '<', '>', '=', ':', "'''", '"""', '\\']
-        for(String lineEnding in lineEndings) {
-            if(line.endsWith(lineEnding)) return true
+
+    static boolean ignoreSyntaxErrorForLineEnding(String line) {
+        def final lineEndings = ['{', '[', '(', ',', '.', '-', '+', '/', '*', '%', '&', '|', '?', '<', '>', '=', ':', "'''", '"""', '\\']
+        for (String lineEnding in lineEndings) {
+            if (line.endsWith(lineEnding)) {
+                return true
+            }
         }
         return false
     }
+
+    static boolean isAnnotationExpression(CompilationFailedException e, String line) {
+        return e.getMessage().contains('unexpected token: @') && ANNOTATION_PATTERN.matcher(line).find()
+    }
 }
 
 /**
@@ -214,6 +231,7 @@ final class ParseCode
         this.code = code
     }
 
+    @Override
     String toString() {
         return code
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedCandidateListCompletionHandler.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedCandidateListCompletionHandler.groovy
new file mode 100644
index 0000000..69750bd
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedCandidateListCompletionHandler.groovy
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell
+
+import groovy.transform.CompileStatic
+import jline.console.ConsoleReader
+import jline.console.CursorBuffer
+import jline.console.completer.CandidateListCompletionHandler
+import org.codehaus.groovy.tools.shell.util.JAnsiHelper
+
+/**
+ * jline completion handler displays ANSIfied candidates nicely,
+ * but does not de-ANSIfy when adding to the prompt :-(
+ *
+ * So this class just adds this functionality.
+ *
+ * See https://github.com/jline/jline2/issues/132
+ */
+ at CompileStatic
+class PatchedCandidateListCompletionHandler extends CandidateListCompletionHandler {
+
+    public boolean complete(final ConsoleReader reader, final List<CharSequence> candidates, final int pos) throws
+            IOException
+    {
+        CursorBuffer buf = reader.getCursorBuffer();
+        final List<CharSequence> deAnsifiedcandidates = candidates.collect({CharSequence candidate -> JAnsiHelper.stripAnsi(candidate) })
+
+        // if there is only one completion, then fill in the buffer
+        if (candidates.size() == 1) {
+            CharSequence value = deAnsifiedcandidates.get(0);
+
+            // fail if the only candidate is the same as the current buffer
+            if (value.equals(buf.toString())) {
+                return false;
+            }
+
+            setBuffer(reader, value, pos);
+
+            return true;
+        }
+        else if (candidates.size() > 1) {
+            String value = this.getUnambiguousCompletions(deAnsifiedcandidates);
+            setBuffer(reader, value, pos);
+        }
+
+        printCandidates(reader, candidates);
+
+        // redraw the current console buffer
+        reader.drawLine();
+
+        return true;
+    }
+
+    /**
+     * copied from CandidateListCompletionHandler because it was private :-(
+     * Returns a root that matches all the {@link String} elements of the specified {@link List},
+     * or null if there are no commonalities. For example, if the list contains
+     * <i>foobar</i>, <i>foobaz</i>, <i>foobuz</i>, the method will return <i>foob</i>.
+     */
+    private String getUnambiguousCompletions(final List<CharSequence> candidates) {
+        if (candidates == null || candidates.isEmpty()) {
+            return null;
+        }
+
+        // convert to an array for speed
+        String[] strings = candidates.toArray(new String[candidates.size()]);
+
+        String first = strings[0];
+        StringBuilder candidate = new StringBuilder();
+
+        for (int i = 0; i < first.length(); i++) {
+            if (startsWith(first.substring(0, i + 1), strings)) {
+                candidate.append(first.charAt(i));
+            }
+            else {
+                break;
+            }
+        }
+
+        return candidate.toString();
+    }
+
+    /**
+     * copied from CandidateListCompletionHandler because it was private :-(
+     * @return true is all the elements of <i>candidates</i> start with <i>starts</i>
+     */
+    private boolean startsWith(final String starts, final String[] candidates) {
+        for (String candidate : candidates) {
+            if (!candidate.startsWith(starts)) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedConsoleReader.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedConsoleReader.groovy
new file mode 100644
index 0000000..1c270f1
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/PatchedConsoleReader.groovy
@@ -0,0 +1,106 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell
+
+import groovy.transform.CompileStatic
+import jline.console.ConsoleReader
+import jline.internal.Log
+import org.codehaus.groovy.tools.shell.util.JAnsiHelper
+import org.fusesource.jansi.AnsiOutputStream
+
+ at CompileStatic
+class PatchedConsoleReader extends ConsoleReader {
+
+
+    public PatchedConsoleReader(final InputStream inStream, final OutputStream out) throws IOException {
+        super(inStream, out);
+    }
+
+    /**
+     * copied from jline2.0 and modified to invoke stripAnsi() for length calculations
+     * Output the specified {@link Collection} in proper columns.
+     * See https://github.com/jline/jline2/issues/132
+     */
+    public void printColumns(final Collection<? extends CharSequence> items) throws IOException {
+        if (items == null || items.isEmpty()) {
+            return;
+        }
+
+        int width = getTerminal().getWidth();
+        int height = getTerminal().getHeight();
+
+        int maxWidth = 0;
+        for (CharSequence item : items) {
+            maxWidth = Math.max(maxWidth, JAnsiHelper.stripAnsi(item).length());
+        }
+        maxWidth = maxWidth + 3;
+        Log.debug("Max width: ", maxWidth);
+
+        int showLines;
+        if (isPaginationEnabled()) {
+            showLines = height - 1; // page limit
+        }
+        else {
+            showLines = Integer.MAX_VALUE;
+        }
+
+        StringBuilder buff = new StringBuilder();
+        int realLength = 0;
+        for (CharSequence item : items) {
+            if ((realLength + maxWidth) > width) {
+                println(buff);
+                buff.setLength(0);
+                realLength = 0;
+
+                if (--showLines == 0) {
+                    // Overflow
+                    print(resources.getString("DISPLAY_MORE"));
+                    flush();
+                    int c = readCharacter();
+                    if (c == '\r' || c == '\n') {
+                        // one step forward
+                        showLines = 1;
+                    }
+                    else if (c != 'q') {
+                        // page forward
+                        showLines = height - 1;
+                    }
+
+                    back(resources.getString("DISPLAY_MORE").length());
+                    if (c == 'q') {
+                        // cancel
+                        break;
+                    }
+                }
+            }
+
+            // NOTE: toString() is important here due to AnsiString being retarded
+            buff.append(item.toString());
+            int strippedItemLength = JAnsiHelper.stripAnsi(item).length()
+            realLength += strippedItemLength
+            for (int i = 0; i < (maxWidth - strippedItemLength); i++) {
+                buff.append(' ');
+            }
+            realLength += maxWidth - strippedItemLength;
+        }
+
+        if (buff.length() > 0) {
+            println(buff);
+        }
+    }
+
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Shell.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Shell.groovy
index 45a882c..87619a7 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Shell.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/Shell.groovy
@@ -17,6 +17,7 @@
 package org.codehaus.groovy.tools.shell
 
 import org.codehaus.groovy.runtime.InvokerHelper
+import org.codehaus.groovy.tools.shell.util.CommandArgumentParser
 import org.codehaus.groovy.tools.shell.util.Logger
 import org.fusesource.jansi.Ansi
 
@@ -38,23 +39,23 @@ class Shell
 
     Shell(final IO io) {
         assert(io != null)
-        
+
         this.io = io
     }
-    
+
     Shell() {
         this(new IO())
     }
-    
-    protected List parseLine(final String line) {
-        assert line != null
-        
-        return line.trim().tokenize()
-    }
-    
-    Command findCommand(final String line) {
+
+
+
+    /**
+     * @param line the line to parse
+     * @param parsedArgs accumulate the rest of the line after the command
+     */
+    Command findCommand(final String line, List<String> parsedArgs = null) {
         assert line
-        
+
         //
         // TODO: Introduce something like 'boolean Command.accepts(String)' to ask
         //       commands if they can take the line?
@@ -67,49 +68,48 @@ class Shell
         //       Or maybe allow commands to register specific syntax hacks into the registry?
         //       then ask the registry for the command for a given line?
         //
-        
-        List<String> args = parseLine(line)
-        
-        assert args.size() > 0
 
-        Command command = registry.find(args[0])
-        
+        // command id is first word, unless empty
+        Command command = null;
+        List<String> linetokens = line.trim().tokenize()
+        assert linetokens.size() > 0
+
+        if (linetokens[0].length() > 0) {
+            command = registry.find(linetokens[0])
+            if (command != null && linetokens.size() > 1 && parsedArgs != null) {
+                List<String> args = CommandArgumentParser.parseLine(line, parsedArgs == null ? 1 : -1)
+                parsedArgs.addAll(args[1..-1])
+            }
+        }
         return command
     }
-    
+
     boolean isExecutable(final String line) {
         return findCommand(line) != null
     }
-    
+
     Object execute(final String line) {
         assert line
-        
-        def command = findCommand(line)
-        
+
+        List<String> args = []
+        Command command = findCommand(line, args)
+
         def result = null
-        
+
         if (command) {
-            List<String> args = parseLine(line)
-            
-            if (args.size() == 1) {
-                args = []
-            }
-            else {
-                args = args[1..-1]
-            }
-            
+
             log.debug("Executing command($command.name): $command; w/args: $args")
             try {
                 result = command.execute(args)
             } catch (CommandException e) {
-                io.err.println(ansi().a(Ansi.Attribute.INTENSITY_BOLD).fg(Ansi.Color.RED).a(e.getMessage()).reset());
+                io.err.println(ansi().a(Ansi.Attribute.INTENSITY_BOLD).fg(Ansi.Color.RED).a(e.message).reset())
             }
             log.debug("Result: ${InvokerHelper.toString(result)}")
         }
-        
+
         return result
     }
-    
+
     Command register(final Command command) {
         return registry.register(command)
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ShellRunner.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ShellRunner.groovy
index bba21e2..75a25ab 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ShellRunner.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/ShellRunner.groovy
@@ -28,30 +28,31 @@ abstract class ShellRunner
     implements Runnable
 {
     protected final Logger log = Logger.create(this.class)
-    
+
     final Shell shell
-    
+
     boolean running = false
-    
+
     boolean breakOnNull = true
-    
+
     Closure errorHandler = { e ->
         log.debug(e)
-        
+
         running = false
     }
-    
+
     protected ShellRunner(final Shell shell) {
         assert(shell != null)
-        
+
         this.shell = shell
     }
-    
+
+    @Override
     void run() {
         log.debug('Running')
-        
+
         running = true
-        
+
         while (running) {
             try {
                 running = work()
@@ -61,41 +62,41 @@ abstract class ShellRunner
             }
             catch (Throwable t) {
                 log.debug("Work failed: $t", t)
-                
+
                 if (errorHandler) {
                     try {
                         errorHandler.call(t)
                     } catch (Throwable t2) {
-                        errorHandler(new IllegalArgumentException("Error when handling error: " + t.message))
+                        errorHandler(new IllegalArgumentException("Error when handling error: $t.message"))
                         errorHandler.call(t2)
                     }
                 }
             }
         }
-        
+
         log.debug('Finished')
     }
-    
+
     protected boolean work() {
         def line = readLine()
-        
+
         if (log.debugEnabled) {
             log.debug("Read line: $line")
         }
-        
+
         // Stop on null (maybe)
         if (line == null && breakOnNull) {
             return false // stop the loop
         }
-        
+
         // Ignore empty lines
         if (line.trim().size() > 0) {
             shell << line
         }
-        
+
         return true
     }
-    
+
     protected abstract String readLine()
 }
 
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/AliasCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/AliasCommand.groovy
index 5dac689..b2e89c5 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/AliasCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/AliasCommand.groovy
@@ -16,12 +16,11 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.Command
-import org.codehaus.groovy.tools.shell.CommandRegistry
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
 import org.codehaus.groovy.tools.shell.completion.CommandNameCompleter
-import org.codehaus.groovy.tools.shell.util.SimpleCompletor
 
 /**
  * The 'alias' command.
@@ -38,23 +37,25 @@ class AliasCommand
         super(shell, COMMAND_NAME, ':a', )
     }
 
-    protected List createCompleters() {
+    @Override
+    protected List<Completer> createCompleters() {
         return [
                 new CommandNameCompleter(registry),
                 null
         ]
     }
 
-    Object execute(final List args) {
+    @Override
+    Object execute(final List<String> args) {
         assert args != null
-        
+
         if (args.size() < 2) {
             fail("Command 'alias' requires at least 2 arguments") // TODO: i18n
         }
-        
+
         String name = args[0]
         List target = args[1..-1]
-        
+
         Command command = registry.find(name)
 
         if (command == null) {
@@ -63,23 +64,23 @@ class AliasCommand
         if (command != null) {
             if (command instanceof AliasTargetProxyCommand) {
                 log.debug("Rebinding alias: $name")
-                
+
                 registry.remove(command)
             }
             else {
                 fail("Can not rebind non-user aliased command: ${command.name}") // TODO: i18n
             }
         }
-        
+
         log.debug("Creating alias '$name' to: $target")
-        
+
         // Register the command
         command = shell << new AliasTargetProxyCommand(shell, name, target)
-        
+
         //
         // TODO: Should this be here... or should this be in the Shell's impl?
         //
-        
+
         // Try to install the completor
         if (shell.runner) {
             shell.runner.completer.add(command)
@@ -91,38 +92,42 @@ class AliasTargetProxyCommand
     extends CommandSupport implements Command
 {
     private static int counter = 0
-    
-    final List args
-    
+
+    final List<String> args
+
     AliasTargetProxyCommand(final Groovysh shell, final String name, final List args) {
         super(shell, name, ':a' + counter++)
-        
+
         assert args
-        
+
         this.args = args
     }
-    
+
+    @Override
     String getDescription() {
         return "User defined alias to: @|bold ${args.join(' ')}|@"
     }
 
+    @Override
     String getUsage() {
         return ''
     }
-    
+
+    @Override
     String getHelp() {
         return description
     }
-    
-    Object execute(List args) {
-        args = this.args + args
-        
-        log.debug("Executing with args: $args")
-        
+
+    @Override
+    Object execute(final List<String> args) {
+        List<String> allArgs = this.args + args
+
+        log.debug("Executing with args: $allArgs")
+
         //
         // FIXME: Should go back through shell.execute() to allow aliases to groovy snips too
         //
-        
-        return shell.executeCommand(args.join(' '))
+
+        return shell.executeCommand(allArgs.join(' '))
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ClearCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ClearCommand.groovy
index ab1f620..3463cb1 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ClearCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ClearCommand.groovy
@@ -33,10 +33,11 @@ class ClearCommand
     ClearCommand(final Groovysh shell) {
         super(shell, COMMAND_NAME, ':c')
     }
-    
+
+    @Override
     Object execute(final List<String> args) {
         assertNoArguments(args)
-        
+
         buffer.clear()
 
         if (io.verbose) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DisplayCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DisplayCommand.groovy
index 6f4db5e..f2761bf 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DisplayCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DisplayCommand.groovy
@@ -20,7 +20,7 @@ import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
 
 /**
- * The 'display' command.
+ * The 'display' command. Displays the current buffer (e.g. while method declaration was not finished).
  *
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
@@ -34,9 +34,10 @@ class DisplayCommand
         super(shell, COMMAND_NAME, ':d')
     }
 
+    @Override
     Object execute(final List<String> args) {
         assertNoArguments(args)
-        
+
         if (buffer.isEmpty()) {
             io.out.println('Buffer is empty') // TODO: i18n
         }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DocCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DocCommand.groovy
index 73e97f3..f880d8f 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DocCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/DocCommand.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,8 +23,6 @@ import jline.console.completer.StringsCompleter
 
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
-import org.codehaus.groovy.tools.shell.Shell
-import org.codehaus.groovy.tools.shell.commands.ImportCompleter
 
 /**
  * The 'doc' command.
@@ -38,8 +36,8 @@ class DocCommand extends CommandSupport {
 
     public static final String COMMAND_NAME = ':doc'
 
-    private static final String ENV_BROWSER = "BROWSER"
-    private static final String ENV_BROWSER_GROOVYSH = "GROOVYSH_BROWSER"
+    private static final String ENV_BROWSER = 'BROWSER'
+    private static final String ENV_BROWSER_GROOVYSH = 'GROOVYSH_BROWSER'
 
     private static final int TIMEOUT_CONN = 5 * 1000 // ms
     private static final int TIMEOUT_READ = 5 * 1000 // ms
@@ -53,12 +51,12 @@ class DocCommand extends CommandSupport {
      */
     static {
         try {
-            def desktopClass = Class.forName("java.awt.Desktop")
+            def desktopClass = Class.forName('java.awt.Desktop')
             desktop = desktopClass.desktopSupported ? desktopClass.desktop : null
 
             hasAWTDesktopPlatformSupport =
                 desktop != null &&
-                        desktop.isSupported(desktopClass.declaredClasses.find { it.simpleName == "Action" }.BROWSE)
+                        desktop.isSupported(desktopClass.declaredClasses.find { it.simpleName == 'Action' }.BROWSE)
 
         } catch (Exception e) {
             hasAWTDesktopPlatformSupport = false
@@ -78,6 +76,7 @@ class DocCommand extends CommandSupport {
                 new ImportCompleter(shell.packageHelper, shell.interp, false)])])
     }
 
+    @Override
     Object execute(final List<String> args) {
         if (args?.size() == 1) {
             doc(args[0])
@@ -95,7 +94,7 @@ class DocCommand extends CommandSupport {
 
         // Print the URLs.
         // It is useful especially when the browsing fails.
-        urls.each { url -> println url }
+        urls.each { url -> io.out.println url }
 
         browse(urls)
     }
@@ -135,32 +134,31 @@ class DocCommand extends CommandSupport {
     protected void browseWithNativeBrowser(String browser, List urls) {
         try {
             "$browser ${urls.join(' ')}".execute()
-
         } catch (Exception e) {
             // we could be here caused by a IOException, SecurityException or NP Exception
-
             fail "Browser could not be opened (${e}). Please check the $ENV_BROWSER_GROOVYSH or $ENV_BROWSER " +
                  "environment variable."
         }
     }
 
     protected List urlsFor(String className) {
-        def path = className.replaceAll(/\./, '/') + ".html"
+        String groovyVersion = GroovySystem.version
+        def path = className.replaceAll(/\./, '/') + '.html'
 
         def urls = []
         if (className.matches(/^(groovy|org\.codehaus\.groovy|)\..+/)) {
-            def url = new URL("http://groovy.codehaus.org/gapi/$path")
+            def url = new URL("http://docs.groovy-lang.org/$groovyVersion/html/gapi/$path")
             if (sendHEADRequest(url)) {
                 urls << url
             }
         } else {
-            // Don't specify package names not to depend on a version of Java SE.
-            // Java SE includes none-java(x) packages such as org.w3m.*, org.omg.*. org.xml.* for now
-            // and new packages might be added in a future.
+            // Don't specify package names to not depend on a specific version of Java SE.
+            // Java SE includes non-java(x) packages such as org.w3m.*, org.omg.*. org.xml.* for now
+            // and new packages might be added in the future.
             def url = new URL("http://docs.oracle.com/javase/${simpleVersion()}/docs/api/$path")
             if (sendHEADRequest(url)) {
                 urls << url
-                url = new URL("http://groovy.codehaus.org/groovy-jdk/$path")
+                url = new URL("http://docs.groovy-lang.org/$groovyVersion/html/groovy-jdk/$path")
                 if (sendHEADRequest(url)) {
                     urls << url
                 }
@@ -171,13 +169,13 @@ class DocCommand extends CommandSupport {
     }
 
     private static simpleVersion() {
-        System.getProperty("java.version").tokenize('_')[0]
+        System.getProperty('java.version').split(/\./)[1]
     }
 
     protected boolean sendHEADRequest(URL url) {
         try {
             HttpURLConnection conn = url.openConnection() as HttpURLConnection
-            conn.requestMethod = "HEAD"
+            conn.requestMethod = 'HEAD'
             conn.connectTimeout = TIMEOUT_CONN
             conn.readTimeout = TIMEOUT_READ
             conn.instanceFollowRedirects = true
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/EditCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/EditCommand.groovy
index 2f6346a..175eab9 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/EditCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/EditCommand.groovy
@@ -21,7 +21,7 @@ import org.codehaus.groovy.tools.shell.Groovysh
 import org.codehaus.groovy.tools.shell.util.Preferences
 
 /**
- * The 'edit' command.
+ * The 'edit' command. Opens Editor to write into the current Buffer.
  *
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
@@ -35,13 +35,13 @@ class EditCommand
         super(shell, COMMAND_NAME, ':e')
     }
 
-    ProcessBuilder getEditorProcessBuilder(String editCommand, String tempFilename) {
+    ProcessBuilder getEditorProcessBuilder(final String editCommand, final String tempFilename) {
         def pb = new ProcessBuilder(editCommand, tempFilename)
 
         // GROOVY-6201: Editor should inherit I/O from the current process.
         //    Fixed only for java >= 1.7 using new ProcessBuilder api
-        pb.redirectErrorStream(true);
-        def javaVer = Double.valueOf(System.getProperty("java.specification.version"));
+        pb.redirectErrorStream(true)
+        def javaVer = Double.valueOf(System.getProperty('java.specification.version'))
         if (javaVer >= 1.7) {
             pb.redirectInput(ProcessBuilder.Redirect.INHERIT)
             pb.redirectOutput(ProcessBuilder.Redirect.INHERIT)
@@ -51,27 +51,28 @@ class EditCommand
     }
 
     private String getEditorCommand() {
-        def editor = Preferences.editor;
+        def editor = Preferences.editor
 
         log.debug("Using editor: $editor")
 
         if (!editor) {
             fail("Unable to determine which editor to use; check \$EDITOR") // TODO: i18n
         }
-        
+
         return editor
     }
-    
+
+    @Override
     Object execute(final List<String> args) {
         assertNoArguments(args)
-        
+
         File file = File.createTempFile('groovysh-buffer', '.groovy')
         file.deleteOnExit()
-        
+
         try {
             // Write the current buffer to a tmp file
             file.write(buffer.join(NEWLINE))
-            
+
             //Try to launch the editor.
             log.debug("Executing: $editorCommand $file")
             def pb = getEditorProcessBuilder("$editorCommand", "$file")
@@ -82,22 +83,22 @@ class EditCommand
             p.waitFor()
 
             log.debug("Editor contents: ${file.text}")
-            
+
             replaceCurrentBuffer(file.readLines())
         }
         finally {
             file.delete()
         }
     }
-    
-    void replaceCurrentBuffer(List contents) {
+
+    void replaceCurrentBuffer(List<String> contents) {
         // clear current buffer contents
-        shell.buffers.clearSelected()       
-        
+        shell.buffers.clearSelected()
+
         // load editor contents into current buffer
-        for (line in contents) {
-            shell.execute(line as String)
+        for (String line : contents) {
+            shell.execute(line)
         }
     }
-    
+
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommand.groovy
index 97b6c57..f87f91a 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommand.groovy
@@ -37,17 +37,18 @@ class ExitCommand
         alias(':quit', ':q')
     }
 
+    @Override
     Object execute(final List<String> args) {
         assertNoArguments(args)
-        
+
         //
         // TODO: Maybe support a single arg for the code?
         //
-        
+
         if (io.verbose) {
             io.out.println(messages['info.bye'])
         }
-        
+
         throw new ExitNotification(0)
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HelpCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HelpCommand.groovy
index e87a96d..f97a721 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HelpCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HelpCommand.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2007 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -16,17 +16,15 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Command
 import org.codehaus.groovy.tools.shell.Groovysh
-import org.codehaus.groovy.tools.shell.CommandRegistry
 import org.codehaus.groovy.tools.shell.completion.CommandNameCompleter
-import org.codehaus.groovy.tools.shell.util.SimpleCompletor
 
 /**
  * The 'help' command.
  *
- * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
 class HelpCommand
@@ -41,20 +39,21 @@ class HelpCommand
         alias('?', ':?')
     }
 
-    protected List createCompleters() {
+    protected List<Completer> createCompleters() {
         return [
             new CommandNameCompleter(registry),
             null
         ]
     }
 
+    @Override
     Object execute(final List<String> args) {
         assert args != null
 
         if (args.size() > 1) {
             fail(messages.format('error.unexpected_args', args.join(' ')))
         }
-        
+
         if (args.size() == 1) {
             help(args[0])
         }
@@ -65,12 +64,12 @@ class HelpCommand
 
     private void help(final String name) {
         assert name
-        
+
         Command command = registry.find(name)
         if (!command) {
             fail("No such command: $name") // TODO: i18n
         }
-        
+
         io.out.println()
         io.out.println("usage: @|bold ${command.name}|@ $command.usage") // TODO: i18n
         io.out.println()
@@ -82,24 +81,24 @@ class HelpCommand
         // Figure out the max command name and shortcut length dynamically
         int maxName = 0
         int maxShortcut
-        
+
         for (Command command in registry.commands()) {
             if (command.hidden) {
                 continue
             }
-            
+
             if (command.name.size() > maxName) {
                 maxName = command.name.size()
             }
-            
+
             if (command.shortcut.size() > maxShortcut) {
                 maxShortcut = command.shortcut.size()
             }
         }
-        
+
         io.out.println()
         io.out.println('For information about @|green Groovy|@, visit:') // TODO: i18n
-        io.out.println('    @|cyan http://groovy.codehaus.org|@ ') // FIXME: parsing freaks out if end tok is at the last char...
+        io.out.println('    @|cyan http://groovy-lang.org|@ ') // FIXME: parsing freaks out if end tok is at the last char...
         io.out.println()
 
         // List the commands we know about
@@ -109,19 +108,19 @@ class HelpCommand
             if (command.hidden) {
                 continue
             }
-            
+
             def n = command.name.padRight(maxName, ' ')
             def s = command.shortcut.padRight(maxShortcut, ' ')
-            
+
             //
             // TODO: Wrap description if needed
             //
-            
+
             def d = command.description
-            
+
             io.out.println("  @|bold ${n}|@  (@|bold ${s}|@) $d")
         }
-        
+
         io.out.println()
         io.out.println('For help on a specific command type:') // TODO: i18n
         io.out.println('    :help @|bold command|@ ')
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommand.groovy
index 60e6ca9..87f79d6 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommand.groovy
@@ -37,11 +37,11 @@ class HistoryCommand
         super(shell, COMMAND_NAME, ':H', [ 'show', 'clear', 'flush', 'recall' ], 'show')
     }
 
+    @Override
     protected List createCompleters() {
         def loader = {
             def list = []
-
-            getFunctions().each { String fun -> list << fun }
+            list.addAll(functions)
 
             return list
         }
@@ -52,9 +52,10 @@ class HistoryCommand
         ]
     }
 
+    @Override
     Object execute(List<String> args) {
         if (!history) {
-            fail("Shell does not appear to be interactive; Can not query history")
+            fail('Shell does not appear to be interactive; Can not query history')
         }
 
         super.execute(args)
@@ -66,7 +67,7 @@ class HistoryCommand
     def do_show = {
         Iterator<History.Entry> histIt = history.iterator()
         while (histIt.hasNext()) {
-            History.Entry next = histIt.next();
+            History.Entry next = histIt.next()
             if (next) {
                 io.out.println(" @|bold ${next.index().toString().padLeft(3, ' ')}|@  ${next.value()}")
             }
@@ -97,7 +98,7 @@ class HistoryCommand
         String line
 
         if (!args || ((List)args).size() != 1) {
-            fail("History recall requires a single history identifer")
+            fail('History recall requires a single history identifer')
         }
 
         String ids = ((List<String>)args)[0]
@@ -113,14 +114,14 @@ class HistoryCommand
                 // has been added to history before it actually gets executed
                 // so we need to shift by one
                 id--
-            };
+            }
 
             Iterator<History.Entry> listEntryIt = history.iterator()
             if (listEntryIt.hasNext()) {
                 History.Entry next = listEntryIt.next()
                 if (id < next.index() -1) {
                     // not using id on purpose, as might be decremented
-                    fail("Unknown index:" + ids)
+                    fail("Unknown index: $ids")
                 } else if (id == next.index() -1) {
                     line = shell.evictedLine
                 } else if (next.index() == id) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommand.groovy
index 91d4571..9b7a253 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommand.groovy
@@ -16,19 +16,24 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
+import groovy.transform.CompileStatic
 import jline.console.completer.AggregateCompleter
 import jline.console.completer.ArgumentCompleter
 import jline.console.completer.Completer
 import jline.console.completer.StringsCompleter
 import org.codehaus.groovy.control.CompilationFailedException
-
+import org.codehaus.groovy.control.ResolveVisitor
 import org.codehaus.groovy.tools.shell.CommandSupport
+import org.codehaus.groovy.tools.shell.Evaluator
 import org.codehaus.groovy.tools.shell.Groovysh
 import org.codehaus.groovy.tools.shell.Interpreter
+import org.codehaus.groovy.tools.shell.completion.ReflectionCompletionCandidate
 import org.codehaus.groovy.tools.shell.completion.ReflectionCompletor
 import org.codehaus.groovy.tools.shell.util.Logger
 import org.codehaus.groovy.tools.shell.util.PackageHelper
 
+import java.util.regex.Pattern
+
 /**
  * The 'import' command.
  *
@@ -37,6 +42,14 @@ import org.codehaus.groovy.tools.shell.util.PackageHelper
 class ImportCommand
     extends CommandSupport
 {
+
+    /**
+     * pattern used to validate the arguments to the import command,
+     * which proxies the Groovy import statement
+     * chars, digits, underscore, dot, star
+     */
+    private static final Pattern IMPORTED_ITEM_PATTERN = ~'[a-zA-Z0-9_. *]+;?$'
+
     ImportCommand(final Groovysh shell) {
         super(shell, 'import', ':i')
     }
@@ -68,7 +81,7 @@ class ImportCommand
         assert args != null
 
         if (args.isEmpty()) {
-            fail("Command 'import' requires one or more arguments") // TODO: i18n
+            fail('Command \'import\' requires one or more arguments') // TODO: i18n
         }
 
         def importSpec = args.join(' ')
@@ -80,7 +93,7 @@ class ImportCommand
         // "java.awt.TextField" so it is not implemented as such here.  Perhaps this could be made to be more
         // intelligent if someone could figure out why that is happening or could write a nicer batch of regex to
         // solve the problem
-        if (! (importSpec ==~ '[\\da-zA-Z_. *]+;?$')) {
+        if (! (importSpec.matches(IMPORTED_ITEM_PATTERN))) {
             def msg = "Invalid import definition: '${importSpec}'" // TODO: i18n
             log.debug(msg)
             fail(msg)
@@ -90,20 +103,20 @@ class ImportCommand
 
         def buff = [ 'import ' + args.join(' ') ]
         buff << 'def dummp = false'
-        
+
         def type
         try {
             type = classLoader.parseClass(buff.join(NEWLINE))
-            
+
             // No need to keep duplicates, but order may be important so remove the previous def, since
             // the last defined import will win anyways
-            
+
             if (imports.remove(importSpec)) {
-                log.debug("Removed duplicate import from list")
+                log.debug('Removed duplicate import from list')
             }
-            
+
             log.debug("Adding import: $importSpec")
-            
+
             imports.add(importSpec)
             return imports.join(', ')
         }
@@ -121,29 +134,31 @@ class ImportCommand
 
 class ImportCompleter implements Completer {
 
+    protected final Logger log = Logger.create(ImportCompleter)
+
     PackageHelper packageHelper
     Groovysh shell
-    protected final Logger log = Logger.create(ImportCompleter)
+
     /*
      * The following rules do not need to work for all thinkable situations,just for all reasonable situations.
      * In particular the underscore and dollar signs in Class or method names usually indicate something internal,
      * which we intentionally want to hide in tab completion
      */
     // matches fully qualified Classnames with dot at the end
-    public static final String QUALIFIED_CLASS_DOT_PATTERN = /^[a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*\.[A-Z][^.]*\.$/
+    private static final Pattern QUALIFIED_CLASS_DOT_PATTERN = ~/^[a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*\.[A-Z][^.]*\.$/
     // matches empty, packagenames or fully qualified classNames
-    public static final String PACK_OR_CLASSNAME_PATTERN = /^([a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*(\.[A-Z][^.]*)?)?$/
+    private static final Pattern PACK_OR_CLASSNAME_PATTERN = ~/^([a-z_]{1}[a-z0-9_]*(\.[a-z0-9_]*)*(\.[A-Z][^.]*)?)?$/
     // matches empty, packagenames or fully qualified classNames without special symbols
-    public static final String PACK_OR_SIMPLE_CLASSNAME_PATTERN = '^([a-z_]{1}[a-z0-9_]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*)?)?\$'
+    private static final Pattern PACK_OR_SIMPLE_CLASSNAME_PATTERN = ~'^([a-z_]{1}[a-z0-9_]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*)?)?\$'
     // matches empty, packagenames or fully qualified classNames or fully qualified method names
-    public static final String PACK_OR_CLASS_OR_METHODNAME_PATTERN = '^([a-z_]{1}[a-z0-9.]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*(\\.[a-zA-Z0-9_]*)?)?)?\$'
-
+    private static final Pattern PACK_OR_CLASS_OR_METHODNAME_PATTERN = ~'^([a-z_]{1}[a-z0-9.]*(\\.[a-z0-9_]*)*(\\.[A-Z][^.\$_]*(\\.[a-zA-Z0-9_]*)?)?)?\$'
+    private static final Pattern LOWERCASE_IMPORT_ITEM_PATTERN = ~/^[a-z0-9.]+$/
 
-    boolean staticImport
-    def interpreter
+    final boolean staticImport
+    final Evaluator interpreter
 
 
-    public ImportCompleter(PackageHelper packageHelper, interp, boolean staticImport) {
+    ImportCompleter(final PackageHelper packageHelper, final Evaluator interp, final boolean staticImport) {
         this.packageHelper = packageHelper
         this.staticImport = staticImport
         this.interpreter = interp
@@ -151,41 +166,42 @@ class ImportCompleter implements Completer {
     }
 
     @Override
-    int complete(String buffer, int cursor, List result) {
-        String currentImportExpression = buffer ? buffer.substring(0, cursor) : ""
+    @CompileStatic
+    int complete(final String buffer, final int cursor, final List<CharSequence> result) {
+        String currentImportExpression = buffer ? buffer.substring(0, cursor) : ''
         if (staticImport) {
-            if (! (currentImportExpression ==~ PACK_OR_CLASS_OR_METHODNAME_PATTERN)) {
+            if (! (currentImportExpression.matches(PACK_OR_CLASS_OR_METHODNAME_PATTERN))) {
                 return -1
             }
         } else {
-            if (! (currentImportExpression ==~ PACK_OR_SIMPLE_CLASSNAME_PATTERN)) {
+            if (! (currentImportExpression.matches(PACK_OR_SIMPLE_CLASSNAME_PATTERN))) {
                 return -1
             }
         }
-        if (currentImportExpression.contains("..")) {
+        if (currentImportExpression.contains('..')) {
             return -1
         }
 
         if (currentImportExpression.endsWith('.')) {
             // no upper case?
-            if (currentImportExpression ==~ /^[a-z0-9.]+$/) {
+            if (currentImportExpression.matches(LOWERCASE_IMPORT_ITEM_PATTERN)) {
                 Set<String> classnames = packageHelper.getContents(currentImportExpression[0..-2])
                 if (classnames) {
                     if (staticImport) {
-                        result.addAll(classnames.collect { String it -> it + "."})
+                        result.addAll(classnames.collect({ String it -> it + '.'}))
                     } else {
-                        result.addAll(classnames.collect { String it -> filterMatches(it) })
+                        result.addAll(classnames.collect({ String it -> addDotOrBlank(it) }))
                     }
                 }
                 if (! staticImport) {
                     result.add('* ')
                 }
                 return currentImportExpression.length()
-            } else if (staticImport && currentImportExpression ==~ QUALIFIED_CLASS_DOT_PATTERN) {
+            } else if (staticImport && currentImportExpression.matches(QUALIFIED_CLASS_DOT_PATTERN)) {
                 Class clazz = interpreter.evaluate([currentImportExpression[0..-2]]) as Class
                 if (clazz != null) {
-                    Collection<String> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, "")
-                    result.addAll(members.collect({ String it -> it.replace('(', '').replace(')', '') + " " }))
+                    Collection<ReflectionCompletionCandidate> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, '')
+                    result.addAll(members.collect({ ReflectionCompletionCandidate it -> it.value.replace('(', '').replace(')', '') + ' ' }))
                 }
                 result.add('* ')
                 return currentImportExpression.length()
@@ -203,11 +219,11 @@ class ImportCompleter implements Completer {
         String baseString = currentImportExpression.substring(0, Math.max(lastDot, 0))
 
         // expression could be for Classname, or for static methodname
-        if (currentImportExpression ==~ PACK_OR_CLASSNAME_PATTERN) {
+        if (currentImportExpression.matches(PACK_OR_CLASSNAME_PATTERN)) {
             Set<String> candidates = packageHelper.getContents(baseString)
             if (candidates == null || candidates.size() == 0) {
                 // At least give standard package completion, else static keyword is highly annoying
-                Collection<String> standards = org.codehaus.groovy.control.ResolveVisitor.DEFAULT_IMPORTS.findAll {String it -> it.startsWith(currentImportExpression)}
+                Collection<String> standards = ResolveVisitor.DEFAULT_IMPORTS.findAll({ String it -> it.startsWith(currentImportExpression)})
                 if (standards) {
                     result.addAll(standards)
                     return 0
@@ -216,17 +232,17 @@ class ImportCompleter implements Completer {
             }
 
             log.debug(prefix)
-            Collection<String> matches = candidates.findAll { String it -> it.startsWith(prefix) }
+            Collection<String> matches = candidates.findAll({ String it -> it.startsWith(prefix) })
             if (matches) {
-                result.addAll(matches.collect { String it -> filterMatches(it) })
+                result.addAll(matches.collect({ String it -> addDotOrBlank(it) }))
                 return lastDot <= 0 ? 0 : lastDot + 1
             }
         } else if (staticImport) {
             Class clazz = interpreter.evaluate([baseString]) as Class
             if (clazz != null) {
-                Collection<String> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, prefix)
+                Collection<ReflectionCompletionCandidate> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, prefix)
                 if (members) {
-                    result.addAll(members.collect({ String it -> it.replace('(', '').replace(')', '') + " " }))
+                    result.addAll(members.collect({ ReflectionCompletionCandidate it -> it.value.replace('(', '').replace(')', '') + ' ' }))
                     return lastDot <= 0 ? 0 : lastDot + 1
                 }
             }
@@ -234,7 +250,7 @@ class ImportCompleter implements Completer {
         return -1
     }
 
-    def filterMatches(String it) {
+    private static String addDotOrBlank(final String it) {
         if (it[0] in 'A' .. 'Z') {
            return it + ' '
         }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/InspectCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/InspectCommand.groovy
index d8833bf..3a2456b 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/InspectCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/InspectCommand.groovy
@@ -17,6 +17,7 @@
 package org.codehaus.groovy.tools.shell.commands
 
 import groovy.inspect.swingui.ObjectBrowser
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.Groovysh
 
 import java.awt.HeadlessException
@@ -39,28 +40,30 @@ class InspectCommand
     InspectCommand(final Groovysh shell) {
         super(shell, COMMAND_NAME, ':n')
     }
-    
+
     def lafInitialized = false
     def headless
-    
-    protected List createCompleters() {
+
+    @Override
+    protected List<Completer> createCompleters() {
         return [
             new InspectCommandCompletor(binding),
             null
         ]
     }
 
+    @Override
     Object execute(final List<String> args) {
         assert args != null
-        
+
         log.debug("Inspecting w/args: $args")
-        
+
         if (args.size() > 1) {
             fail(messages.format('error.unexpected_args', args.join(' ')))
         }
-        
+
         def subject
-        
+
         if (args.size() == 1) {
             subject = binding.variables[args[0]]
         } else {
@@ -74,23 +77,23 @@ class InspectCommand
             if (!lafInitialized) {
                 lafInitialized = true
                 try {
-                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName())
-                    
+                    UIManager.setLookAndFeel(UIManager.systemLookAndFeelClassName)
+
                     // The setLAF doesn't throw a HeadlessException on Mac.
                     // So try really creating a frame.
                     new java.awt.Frame().dispose()
-                    
+
                     headless = false
                 } catch (HeadlessException he) {
                     headless = true
                 }
             }
-            
+
             if (headless) {
                 io.err.println("@|red ERROR:|@ Running in AWT Headless mode, 'inspect' is not available.")
                 return
             }
-            
+
             if (io.verbose) {
                 io.out.println("Launching object browser to inspect: $subject") // TODO: i18n
             }
@@ -110,15 +113,16 @@ class InspectCommandCompletor
     extends SimpleCompletor
 {
     private final Binding binding
-    
+
     InspectCommandCompletor(final Binding binding) {
         assert binding
 
         this.binding = binding
     }
 
-    SortedSet getCandidates() {
-        def set = new TreeSet()
+    @Override
+    SortedSet<String> getCandidates() {
+        SortedSet<String> set = new TreeSet<String>()
 
         binding.variables.keySet().each {
             set << it
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/LoadCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/LoadCommand.groovy
index ee78925..a39b9aa 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/LoadCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/LoadCommand.groovy
@@ -16,9 +16,10 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
-import jline.console.completer.FileNameCompleter
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
+import org.codehaus.groovy.tools.shell.completion.FileNameCompleter
 
 /**
  * The 'load' command.
@@ -37,32 +38,34 @@ class LoadCommand
         alias('.', ':.')
     }
 
-    protected List createCompleters() {
-        return [ new FileNameCompleter() ]
+    @Override
+    protected List<Completer> createCompleters() {
+        return [ new FileNameCompleter(true, true) ]
     }
 
+    @Override
     Object execute(final List<String> args) {
         assert args != null
-        
+
         if (args.size() == 0) {
             fail("Command '$COMMAND_NAME' requires at least one argument") // TODO: i18n
         }
 
         for (source in args) {
             URL url
-            
-            log.debug("Attempting to load: $url")
-            
+
+            log.debug("Attempting to load: \"$url\"")
+
             try {
                 url = new URL("$source")
             }
             catch (MalformedURLException e) {
                 def file = new File("$source")
-                
+
                 if (!file.exists()) {
-                    fail("File not found: $file") // TODO: i18n
+                    fail("File not found: \"$file\"") // TODO: i18n
                 }
-                
+
                 url = file.toURI().toURL()
             }
 
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/PurgeCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/PurgeCommand.groovy
index ace0e72..1a5e947 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/PurgeCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/PurgeCommand.groovy
@@ -34,51 +34,51 @@ class PurgeCommand
     PurgeCommand(final Groovysh shell) {
         super(shell, COMMAND_NAME, ':p', [ 'variables', 'classes', 'imports', 'preferences', 'all' ])
     }
-    
+
     def do_variables = {
         if (variables.isEmpty()) {
             io.out.println('No variables defined') // TODO: i18n
         }
         else {
             variables.clear()
-            
+
             if (io.verbose) {
-                io.out.println("Custom variables purged") // TODO: i18n
+                io.out.println('Custom variables purged') // TODO: i18n
             }
         }
     }
-    
+
     def do_classes = {
         if (classLoader.loadedClasses.size() == 0) {
-            io.out.println("No classes have been loaded") // TODO: i18n
+            io.out.println('No classes have been loaded') // TODO: i18n
         }
         else {
             classLoader.clearCache()
-            
+
             if (io.verbose) {
                 io.out.println('Loaded classes purged') // TODO: i18n
             }
         }
     }
-    
+
     def do_imports = {
         if (imports.isEmpty()) {
-            io.out.println("No custom imports have been defined") // TODO: i18n
+            io.out.println('No custom imports have been defined') // TODO: i18n
         }
         else {
             imports.clear()
-            
+
             if (io.verbose) {
-                io.out.println("Custom imports purged") // TODO: i18n
+                io.out.println('Custom imports purged') // TODO: i18n
             }
         }
     }
 
     def do_preferences = {
         Preferences.clear()
-        
+
         if (io.verbose) {
-            io.out.println("Preferences purged") // TODO: i18n
+            io.out.println('Preferences purged') // TODO: i18n
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommand.groovy
index 3939fb1..4b48870 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommand.groovy
@@ -83,7 +83,7 @@ class RecordCommand
 
     def do_start = {List<String> args ->
         if (isRecording()) {
-            fail("Already recording to: $file")
+            fail("Already recording to: \"$file\"")
         }
 
         if (args.size() == 0) {
@@ -91,32 +91,32 @@ class RecordCommand
         } else if (args.size() == 1) {
             file = new File(args[0] as String)
         } else {
-            fail("Too many arguments. Usage: record start [filename]")
+            fail('Too many arguments. Usage: record start [filename]')
         }
 
         if (file.parentFile) file.parentFile.mkdirs()
 
         writer = file.newPrintWriter()
-        writer.println("// OPENED: " + new Date())
+        writer.println('// OPENED: ' + new Date())
         writer.flush()
-        
-        io.out.println("Recording session to: $file")
+
+        io.out.println("Recording session to: \"$file\"")
 
         return file
     }
 
     def do_stop = {
         if (!isRecording()) {
-            fail("Not recording")
+            fail('Not recording')
         }
 
-        writer.println("// CLOSED: " + new Date())
+        writer.println('// CLOSED: ' + new Date())
         writer.flush()
 
         writer.close()
         writer = null
 
-        io.out.println("Recording stopped; session saved as: $file (${file.length()} bytes)")
+        io.out.println("Recording stopped; session saved as: \"$file\" (${file.length()} bytes)")
 
         def tmp = file
         file = null
@@ -126,12 +126,12 @@ class RecordCommand
 
     def do_status = {
         if (!isRecording()) {
-            io.out.println("Not recording")
+            io.out.println('Not recording')
 
             return null
         }
 
-        io.out.println("Recording to file: $file (${file.length()} bytes)")
+        io.out.println("Recording to file: \"$file\" (${file.length()} bytes)")
 
         return file
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RegisterCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RegisterCommand.groovy
index db92c2d..46843e3 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RegisterCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/RegisterCommand.groovy
@@ -31,13 +31,14 @@ import org.codehaus.groovy.tools.shell.Command
 class RegisterCommand
     extends CommandSupport
 {
-    public static final String COMMAND_NAME = ':register'
+    static final String COMMAND_NAME = ':register'
 
     RegisterCommand(final Groovysh shell) {
-        super(shell, COMMAND_NAME, ":rc")
+        super(shell, COMMAND_NAME, ':rc')
     }
 
-    public Object execute(List<String> args) {
+    @Override
+    Object execute(final List<String> args) {
         assert args != null
 
         if (args.size() < 1) {
@@ -46,9 +47,9 @@ class RegisterCommand
 
         String classname = args.get(0)
 
-        Class type = getClassLoader().loadClass(classname)
+        Class type = classLoader.loadClass(classname)
 
-        Command command = null;
+        Command command = null
 
         if (args.size() == 1) {                   // use default name
             command = type.newInstance(shell) as Command
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SaveCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SaveCommand.groovy
index e756a90..c776127 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SaveCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SaveCommand.groovy
@@ -16,6 +16,7 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
+import jline.console.completer.Completer
 import jline.console.completer.FileNameCompleter
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
@@ -35,16 +36,18 @@ class SaveCommand
         super(shell, COMMAND_NAME, ':s')
     }
 
-    protected List createCompleters() {
+    @Override
+    protected List<Completer> createCompleters() {
         return [
             new FileNameCompleter(),
             null
         ]
     }
 
+    @Override
     Object execute(final List<String> args) {
         assert args != null
-        
+
         if (args.size() != 1) {
             fail("Command '$COMMAND_NAME' requires a single file argument") // TODO: i18n
         }
@@ -57,20 +60,20 @@ class SaveCommand
         //
         // TODO: Support special '-' file to simply dump text to io.out
         //
-        
+
         def file = new File("${args[0]}")
 
         if (io.verbose) {
-            io.out.println("Saving current buffer to file: $file") // TODO: i18n
+            io.out.println("Saving current buffer to file: \"$file\"") // TODO: i18n
         }
 
         def dir = file.parentFile
         if (dir && !dir.exists()) {
-            log.debug("Creating parent directory path: $dir")
-            
+            log.debug("Creating parent directory path: \"$dir\"")
+
             dir.mkdirs()
         }
-        
+
         file.write(buffer.join(NEWLINE))
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SetCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SetCommand.groovy
index 678a00f..f206725 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SetCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/SetCommand.groovy
@@ -16,6 +16,7 @@
 
 package org.codehaus.groovy.tools.shell.commands
 
+import jline.console.completer.Completer
 import org.codehaus.groovy.tools.shell.CommandSupport
 import org.codehaus.groovy.tools.shell.Groovysh
 import org.codehaus.groovy.tools.shell.util.PackageHelper
@@ -37,7 +38,8 @@ class SetCommand
         super(shell, COMMAND_NAME, ':=')
     }
 
-    protected List createCompleters() {
+    @Override
+    protected List<Completer> createCompleters() {
         def loader = {
             Set<String> set = [] as Set<String>
 
@@ -50,7 +52,9 @@ class SetCommand
             set << Preferences.PARSER_FLAVOR_KEY
             set << Preferences.SANITIZE_STACK_TRACE_KEY
             set << Preferences.SHOW_LAST_RESULT_KEY
+            set << Groovysh.INTERPRETER_MODE_PREFERENCE_KEY
             set << Groovysh.AUTOINDENT_PREFERENCE_KEY
+            set << Groovysh.COLORS_PREFERENCE_KEY
             set << Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY
             set << PackageHelper.IMPORT_COMPLETION_PREFERENCE_KEY
 
@@ -63,12 +67,13 @@ class SetCommand
         ]
     }
 
+    @Override
     Object execute(final List<String> args) {
         assert args != null
-        
+
         if (args.size() == 0) {
             def keys = Preferences.keys()
-            
+
             if (keys.size() == 0) {
                 io.out.println('No preferences are set')
                 return
@@ -77,27 +82,27 @@ class SetCommand
             io.out.println('Preferences:')
             keys.each { String key ->
                 def keyvalue = Preferences.get(key, null)
-                println("    $key=$keyvalue")
+                io.out.println("    $key=$keyvalue")
             }
             return
         }
-        
+
         if (args.size() > 2) {
             fail("Command '$name' requires arguments: <name> [<value>]")
         }
-        
+
         String name = args[0]
         def value
-        
+
         if (args.size() == 1) {
             value = true
         }
         else {
             value = args[1]
         }
-        
+
         log.debug("Setting preference: $name=$value")
-        
+
         Preferences.put(name, String.valueOf(value))
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ShowCommand.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ShowCommand.groovy
index ba3e209..86b75e7 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ShowCommand.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/commands/ShowCommand.groovy
@@ -37,14 +37,14 @@ class ShowCommand
     ShowCommand(final Groovysh shell) {
         super(shell, COMMAND_NAME, ':S', [ 'variables', 'classes', 'imports', 'preferences', 'all' ])
     }
-    
+
     def do_variables = {
         if (variables.isEmpty()) {
             io.out.println('No variables defined') // TODO: i18n
         }
         else {
             io.out.println('Variables:') // TODO: i18n
-            
+
             variables.each { key, value ->
                 // Special handling for defined methods, just show the sig
                 if (value instanceof MethodClosure) {
@@ -58,29 +58,29 @@ class ShowCommand
             }
         }
     }
-    
+
     def do_classes = {
         Class[] classes = classLoader.loadedClasses
-        
+
         if (classes.size() == 0) {
-            io.out.println("No classes have been loaded") // TODO: i18n
+            io.out.println('No classes have been loaded') // TODO: i18n
         }
         else {
             io.out.println('Classes:') // TODO: i18n
-            
+
             classes.each { Class classIt ->
                 io.out.println("  $classIt")
             }
         }
     }
-    
+
     def do_imports = {
         if (imports.isEmpty()) {
-            io.out.println("No custom imports have been defined") // TODO: i18n
+            io.out.println('No custom imports have been defined') // TODO: i18n
         }
         else {
-            io.out.println("Custom imports:") // TODO: i18n
-            
+            io.out.println('Custom imports:') // TODO: i18n
+
             imports.each {String importIt ->
                 io.out.println("  $importIt")
             }
@@ -98,7 +98,7 @@ class ShowCommand
         io.out.println('Preferences:')
         keys.each { String key ->
             def value = Preferences.get(key, null)
-            println("    $key=$value")
+            io.out.println("    $key=$value")
         }
         return
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CommandNameCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CommandNameCompleter.groovy
index 3c87295..ff3ec55 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CommandNameCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CommandNameCompleter.groovy
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.codehaus.groovy.tools.shell.completion
 
 import org.codehaus.groovy.tools.shell.Command
@@ -19,8 +35,9 @@ class CommandNameCompleter extends SimpleCompletor {
         this.registry = registry
     }
 
-    SortedSet getCandidates() {
-        def set = new TreeSet()
+    @Override
+    SortedSet<String> getCandidates() {
+        SortedSet<String> set = new TreeSet<String>()
 
         for (Command command in registry.commands()) {
             if (command.hidden) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassSyntaxCompletor.groovy
index 8c7ca55..d857818 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassSyntaxCompletor.groovy
@@ -22,21 +22,21 @@ import org.codehaus.groovy.tools.shell.Groovysh
 /**
  * Completor completingclasses defined in the shell
  */
-public class CustomClassSyntaxCompletor implements IdentifierCompletor {
+class CustomClassSyntaxCompletor implements IdentifierCompletor {
 
-    Groovysh shell
+    private final Groovysh shell
 
-    CustomClassSyntaxCompletor(Groovysh shell) {
+    CustomClassSyntaxCompletor(final Groovysh shell) {
         this.shell = shell
     }
 
     @Override
-    public boolean complete(final List<GroovySourceToken> tokens, List candidates) {
-        String prefix = tokens.last().getText()
+    boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+        String prefix = tokens.last().text
         boolean foundMatch = false
         Class[] classes = shell.interp.classLoader.loadedClasses
         if (classes.size() > 0) {
-            List<String> classnames = classes.collect {Class it -> it.getName()}
+            List<String> classnames = classes*.name
             for (String varName in classnames) {
                 if (varName.startsWith(prefix)) {
                     candidates << varName
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleter.groovy
index 7537a1f..cd4959f 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleter.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.shell.completion
 
 import jline.console.completer.Completer
@@ -48,6 +63,8 @@ implements Completer
 
     private final boolean blankSuffix = true;
 
+    private final handleLeadingHyphen = false;
+
     static {
         String os = Configuration.getOsName();
         OS_IS_WINDOWS = os.contains("windows");
@@ -60,9 +77,16 @@ implements Completer
         this.blankSuffix = blankSuffix;
     }
 
+
+    public FileNameCompleter(boolean blankSuffix, boolean handleLeadingHyphen) {
+        this(blankSuffix)
+        this.handleLeadingHyphen = handleLeadingHyphen
+    }
+
     public int complete(String buffer, final int cursor, final List<CharSequence> candidates) {
         // buffer can be null
         checkNotNull(candidates);
+        String hyphenChar = null;
 
         if (buffer == null) {
             buffer = "";
@@ -73,6 +97,10 @@ implements Completer
         }
 
         String translated = buffer;
+        if (handleLeadingHyphen && (translated.startsWith('\'') || translated.startsWith('"'))) {
+            hyphenChar = translated[0];
+            translated = translated.substring(1);
+        }
 
         File homeDir = getUserHome();
 
@@ -98,9 +126,9 @@ implements Completer
             dir = file.getParentFile();
         }
 
-        File[] entries = dir == null ? new File[0] : dir.listFiles();
+        File[] entries = (dir == null) ? new File[0] : dir.listFiles();
 
-        return matchFiles(buffer, translated, entries, candidates);
+        return matchFiles(buffer, translated, entries, candidates, hyphenChar);
     }
 
     protected String separator() {
@@ -115,7 +143,7 @@ implements Completer
         return new File(".");
     }
 
-    protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates) {
+    protected int matchFiles(final String buffer, final String translated, final File[] files, final List<CharSequence> candidates, hyphenChar) {
         if (files == null) {
             return -1;
         }
@@ -135,12 +163,12 @@ implements Completer
                     if (file.isDirectory()) {
                         name += separator();
                     } else {
-                        if (blankSuffix) {
+                        if (blankSuffix && !hyphenChar) {
                             name += ' ';
                         }
                     }
                 }
-                candidates.add(render(file, name).toString());
+                candidates.add(render(name, hyphenChar).toString());
             }
         }
 
@@ -149,7 +177,18 @@ implements Completer
         return index + separator().length();
     }
 
-    protected CharSequence render(final File file, final CharSequence name) {
+    protected CharSequence render(final CharSequence name, final String hyphenChar) {
+        if (hyphenChar != null) {
+            return escapedNameInHyphens(name, hyphenChar);
+        }
+        if (name.contains(' ')) {
+            return escapedNameInHyphens(name, '\'');
+        }
         return name;
     }
+
+    private String escapedNameInHyphens(String name, String hyphen) {
+        // need to escape every instance of chartoEscape, and every instance of the escape char backslash
+        return hyphen + name.replace('\\', '\\\\').replace(hyphen, '\\' + hyphen) + hyphen
+    }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletor.groovy
index 5cf1cd5..5cad5a9 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletor.groovy
@@ -36,34 +36,41 @@ import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.*
  */
 class GroovySyntaxCompletor implements Completer {
 
+    protected final static Logger LOG = Logger.create(GroovySyntaxCompletor)
+
     private final Groovysh shell
     private final List<IdentifierCompletor> identifierCompletors
+    private final IdentifierCompletor classnameCompletor
     private final ReflectionCompletor reflectionCompletor
     private final InfixKeywordSyntaxCompletor infixCompletor
     private final Completer filenameCompletor
-    protected String[] classes
-    protected static final Logger log = Logger.create(GroovySyntaxCompletor)
 
     static final enum CompletionCase {
         SECOND_IDENT,
         NO_COMPLETION,
         DOT_LAST,
+        SPREAD_DOT_LAST,
         PREFIX_AFTER_DOT,
-        NO_DOT_PREFIX
+        PREFIX_AFTER_SPREAD_DOT,
+        NO_DOT_PREFIX,
+        INSTANCEOF
     }
 
-    GroovySyntaxCompletor(Groovysh shell,
-                          ReflectionCompletor reflectionCompletor,
-                          List<IdentifierCompletor> identifierCompletors,
-                          Completer filenameCompletor) {
+    GroovySyntaxCompletor(final Groovysh shell,
+                          final ReflectionCompletor reflectionCompletor,
+                          IdentifierCompletor classnameCompletor,
+                          final List<IdentifierCompletor> identifierCompletors,
+                          final Completer filenameCompletor) {
         this.shell = shell
+        this.classnameCompletor = classnameCompletor
         this.identifierCompletors = identifierCompletors
         infixCompletor = new InfixKeywordSyntaxCompletor()
         this.reflectionCompletor = reflectionCompletor
         this.filenameCompletor = filenameCompletor
     }
 
-    int complete(final String bufferLine, final int cursor, List candidates) {
+    @Override
+    int complete(final String bufferLine, final int cursor, final List<CharSequence> candidates) {
         if (! bufferLine) {
             return -1
         }
@@ -79,7 +86,8 @@ class GroovySyntaxCompletor implements Completer {
             }
         } catch (InStringException ise) {
             int completionStart = ise.column + 1
-            int fileResult = + filenameCompletor.complete(bufferLine.substring(completionStart), cursor - completionStart, candidates)
+            int fileResult = + filenameCompletor.complete(bufferLine.substring(completionStart),
+                    cursor - completionStart, candidates)
             if (fileResult >= 0) {
                 return completionStart + fileResult
             }
@@ -92,7 +100,13 @@ class GroovySyntaxCompletor implements Completer {
         }
         if (completionCase == CompletionCase.SECOND_IDENT) {
             if (infixCompletor.complete(tokens, candidates)) {
-                return tokens.last().getColumn() - 1
+                return tokens.last().column - 1
+            }
+            return -1
+        }
+        if (completionCase == CompletionCase.INSTANCEOF) {
+            if (classnameCompletor.complete(tokens, candidates)) {
+                return tokens.last().column - 1
             }
             return -1
         }
@@ -105,6 +119,8 @@ class GroovySyntaxCompletor implements Completer {
                 break
             case CompletionCase.DOT_LAST:
             case CompletionCase.PREFIX_AFTER_DOT:
+            case CompletionCase.SPREAD_DOT_LAST:
+            case CompletionCase.PREFIX_AFTER_SPREAD_DOT:
                 result = reflectionCompletor.complete(tokens, candidates)
                 break
             default:
@@ -119,22 +135,28 @@ class GroovySyntaxCompletor implements Completer {
         GroovySourceToken currentToken = tokens[-1]
 
         // now look at last 2 tokens to decide whether we are in a completion situation at all
-        if (currentToken.getType() == IDENT) {
+        if (currentToken.type == IDENT) {
             // cursor is on identifier, use it as prefix and check whether it follows a dot
 
             if (tokens.size() == 1) {
                 return CompletionCase.NO_DOT_PREFIX
             }
             GroovySourceToken previousToken = tokens[-2]
-            if (previousToken.getType() == DOT) {
+            if (previousToken.type == DOT || previousToken.type == OPTIONAL_DOT) {
                 // we have a dot, so need to evaluate the statement up to the dot for completion
                 if (tokens.size() < 3) {
                     return CompletionCase.NO_COMPLETION
                 }
                 return CompletionCase.PREFIX_AFTER_DOT
+            } else if (previousToken.type == SPREAD_DOT) {
+                    // we have a dot, so need to evaluate the statement up to the dot for completion
+                    if (tokens.size() < 3) {
+                        return CompletionCase.NO_COMPLETION
+                    }
+                    return CompletionCase.PREFIX_AFTER_SPREAD_DOT
             } else {
                 // no dot, so we complete a varname, classname, or similar
-                switch (previousToken.getType()) {
+                switch (previousToken.type) {
                 // if any of these is before, no useful completion possible in this completor
                     case LITERAL_import:
                     case LITERAL_class:
@@ -168,23 +190,33 @@ class GroovySyntaxCompletor implements Completer {
                 }
             }
 
-        } else if (currentToken.getType() == DOT) {
+        } else if (currentToken.type == DOT || currentToken.type == OPTIONAL_DOT) {
             // cursor is on dot, so need to evaluate the statement up to the dot for completion
             if (tokens.size() == 1) {
                 return CompletionCase.NO_COMPLETION
             }
             return CompletionCase.DOT_LAST
+        } else if (currentToken.type == SPREAD_DOT) {
+            // cursor is on spread-dot, so need to evaluate the statement up to the dot for completion
+            if (tokens.size() == 1) {
+                return CompletionCase.NO_COMPLETION
+            }
+            return CompletionCase.SPREAD_DOT_LAST
+        } else if (currentToken.type == LITERAL_instanceof) {
+            return CompletionCase.INSTANCEOF
+        } else {
+            LOG.debug('Untreated toke type: ' + currentToken.type)
         }
         return CompletionCase.NO_COMPLETION
     }
 
-    int completeIdentifier(final  List<GroovySourceToken> tokens, List candidates) {
+    int completeIdentifier(final  List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
         boolean foundMatches = false
         for (IdentifierCompletor completor: identifierCompletors) {
             foundMatches |= completor.complete(tokens, candidates)
         }
         if (foundMatches) {
-            return tokens.last().getColumn() - 1
+            return tokens.last().column - 1
         }
         return -1
     }
@@ -193,7 +225,7 @@ class GroovySyntaxCompletor implements Completer {
         // for shell commands, don't complete
         int commandEnd = bufferLine.indexOf(' ')
         if (commandEnd != -1) {
-            String commandTokenText = bufferLine.substring(0, commandEnd);
+            String commandTokenText = bufferLine.substring(0, commandEnd)
             for (command in registry.commands()) {
                 if (commandTokenText == command.name || commandTokenText in command.aliases) {
                     return true
@@ -203,10 +235,10 @@ class GroovySyntaxCompletor implements Completer {
         return false
     }
 
-    static GroovyLexer createGroovyLexer(String src) {
+    static GroovyLexer createGroovyLexer(final String src) {
         Reader unicodeReader = new UnicodeEscapingReader(new StringReader(src), new SourceBuffer())
         GroovyLexer lexer = new GroovyLexer(unicodeReader)
-        unicodeReader.setLexer(lexer);
+        unicodeReader.setLexer(lexer)
         return lexer
     }
 
@@ -224,9 +256,9 @@ class GroovySyntaxCompletor implements Completer {
      * @param result
      * @return true if lexing was successfull
      */
-    static boolean tokenizeBuffer(String bufferLine,
+    static boolean tokenizeBuffer(final String bufferLine,
                                   final List<String> previousLines,
-                                  List<GroovySourceToken> result) {
+                                  final List<GroovySourceToken> result) {
         GroovyLexer groovyLexer
         if (previousLines.size() > 0) {
             StringBuilder src = new StringBuilder()
@@ -245,14 +277,14 @@ class GroovySyntaxCompletor implements Completer {
         while (true) {
             try {
                 nextToken = groovyLexer.nextToken() as GroovySourceToken
-                if (nextToken.getType() == EOF) {
-                    if (! result.isEmpty() && nextToken.getLine() > result.last().getLine()) {
+                if (nextToken.type == EOF) {
+                    if (! result.isEmpty() && nextToken.line > result.last().line) {
                         // no completion if EOF line has no tokens
                         return false
                     }
                     break
                 }
-                if (nextToken.getType() == STRING_CTOR_START) {
+                if (nextToken.type == STRING_CTOR_START) {
                     isGString = true
                 }
                 result << nextToken
@@ -266,21 +298,17 @@ class GroovySyntaxCompletor implements Completer {
                         char firstChar = restline.charAt(leadingBlanks)
                         // Exception with following hyphen either means we're in String or at end of GString.
                         if (firstChar.toString() in ['"', "'"]
-                                && previousLines.size() + 1 == lastToken.getLine()) {
+                                && previousLines.size() + 1 == lastToken.line) {
                             throw new InStringException(lastToken.columnLast + leadingBlanks - 1)
                         }
                     }
                 }
                 return false
-            } catch (java.lang.NullPointerException e) {
+            } catch (NullPointerException e) {
                 // this can happen when e.g. a string as not closed
                 return false
             }
         }
-        if (result.isEmpty()) {
-            return false
-        }
-
-        return true
+        return !result.empty
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/IdentifierCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/IdentifierCompletor.groovy
index 9e439d2..5a93ad5 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/IdentifierCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/IdentifierCompletor.groovy
@@ -23,7 +23,7 @@ import org.codehaus.groovy.antlr.GroovySourceToken
  * (Class, variable, keyword, method, ...)
  * Similar to JLine Completor, but adapted for usage in GroovySyntaxCompletor
  */
-public interface IdentifierCompletor {
+interface IdentifierCompletor {
 
     /**
      *
@@ -31,6 +31,6 @@ public interface IdentifierCompletor {
      * @param candidates
      * @return
      */
-    boolean complete(List<GroovySourceToken> tokens, List candidates);
+    boolean complete(List<GroovySourceToken> tokens, List<CharSequence> candidates)
 
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
index 7c02bad..f865059 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletor.groovy
@@ -17,25 +17,26 @@
 package org.codehaus.groovy.tools.shell.completion
 
 import org.codehaus.groovy.antlr.GroovySourceToken
+import org.codehaus.groovy.control.ResolveVisitor
 import org.codehaus.groovy.tools.shell.Groovysh
 
 /**
  * Completor completing imported classnames
  */
-public class ImportsSyntaxCompletor implements IdentifierCompletor {
+class ImportsSyntaxCompletor implements IdentifierCompletor {
 
-    Groovysh shell
+    final Groovysh shell
     // cache for all preimported classes
     List<String> preimportedClassNames
     // cache for all manually imported classes
-    Map<String, Collection<String>> cachedImports = new HashMap<String, Collection<String>>()
+    final Map<String, Collection<String>> cachedImports = new HashMap<String, Collection<String>>()
 
-    ImportsSyntaxCompletor(Groovysh shell) {
+    ImportsSyntaxCompletor(final Groovysh shell) {
         this.shell = shell
     }
 
     @Override
-    public boolean complete(final List<GroovySourceToken> tokens, List candidates) {
+    boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
         String prefix = tokens.last().getText()
         boolean foundMatch = findMatchingPreImportedClasses(prefix, candidates)
         for (String importName in shell.imports) {
@@ -44,16 +45,16 @@ public class ImportsSyntaxCompletor implements IdentifierCompletor {
         return foundMatch
     }
 
-    boolean findMatchingImportedClassesCached(final String prefix, final String importSpec, List candidates) {
+    boolean findMatchingImportedClassesCached(final String prefix, final String importSpec, final List<String> candidates) {
         Collection<String> cached
         if (! cachedImports.containsKey(importSpec)) {
             cached = new HashSet<String>()
             collectImportedSymbols(importSpec, cached)
-            cachedImports.put(importSpec, cached);
+            cachedImports.put(importSpec, cached)
         } else {
             cached = cachedImports.get(importSpec)
         }
-        Collection<String> matches = cached.findAll {String it -> it.startsWith(prefix)}
+        Collection<String> matches = cached.findAll({String it -> it.startsWith(prefix)})
         if (matches) {
             candidates.addAll(matches)
             return true
@@ -61,30 +62,30 @@ public class ImportsSyntaxCompletor implements IdentifierCompletor {
         return false
     }
 
-    boolean findMatchingPreImportedClasses(final String prefix, Collection matches) {
+    boolean findMatchingPreImportedClasses(final String prefix, final Collection<String> matches) {
         boolean foundMatch = false
         if (preimportedClassNames == null) {
             preimportedClassNames = []
-            for (packname in org.codehaus.groovy.control.ResolveVisitor.DEFAULT_IMPORTS) {
+            for (packname in ResolveVisitor.DEFAULT_IMPORTS) {
                 Set<String> packnames = shell.packageHelper.getContents(packname[0..-2])
                 if (packnames) {
-                    preimportedClassNames.addAll(packnames.findAll{String it -> it[0] in "A".."Z"})
+                    preimportedClassNames.addAll(packnames.findAll({String it -> it[0] in 'A'..'Z'}))
                 }
             }
-            preimportedClassNames.add("BigInteger")
-            preimportedClassNames.add("BigDecimal")
+            preimportedClassNames.add('BigInteger')
+            preimportedClassNames.add('BigDecimal')
         }
         // preimported names
         for (String preImpClassname in preimportedClassNames) {
             if (preImpClassname.startsWith(prefix)) {
-                matches << preImpClassname
+                matches.add(preImpClassname)
                 foundMatch = true
             }
         }
         return foundMatch
     }
 
-    static final String STATIC_IMPORT_PATTERN = /^import static ([a-z0-9]+\.)+[A-Z][a-zA-Z0-9]*(\.(\*|[^.]+))?$/
+    private static final String STATIC_IMPORT_PATTERN = ~/^import static ([a-z0-9]+\.)+[A-Z][a-zA-Z0-9]*(\.(\*|[^.]+))?$/
 
     /**
      * finds matching imported classes or static methods
@@ -93,8 +94,8 @@ public class ImportsSyntaxCompletor implements IdentifierCompletor {
      * @param matches
      * @return
      */
-    void collectImportedSymbols(String importSpec, Collection matches) {
-        String asKeyword = " as "
+    void collectImportedSymbols(final String importSpec, final Collection<String> matches) {
+        String asKeyword = ' as '
         int asIndex = importSpec.indexOf(asKeyword)
         if (asIndex > -1) {
             String alias = importSpec.substring(asIndex + asKeyword.length())
@@ -104,17 +105,18 @@ public class ImportsSyntaxCompletor implements IdentifierCompletor {
         String staticPrefix = 'import static '
         if (importSpec.startsWith(staticPrefix)) {
             // make sure pattern is safe, though shell should have done anyway
-            if (importSpec  ==~ STATIC_IMPORT_PATTERN) {
-                if (importSpec.endsWith(".*")) {
-                    importSpec = importSpec[staticPrefix.length()..-3]
+            if (importSpec.matches(STATIC_IMPORT_PATTERN)) {
+                String evalImportSpec
+                if (importSpec.endsWith('.*')) {
+                    evalImportSpec = importSpec[staticPrefix.length()..-3]
                 } else {
-                    importSpec = importSpec[staticPrefix.length()..(importSpec.lastIndexOf('.') - 1)]
+                    evalImportSpec = importSpec[staticPrefix.length()..(importSpec.lastIndexOf('.') - 1)]
                 }
-                Class clazz = shell.interp.evaluate([importSpec]) as Class
+                Class clazz = shell.interp.evaluate([evalImportSpec]) as Class
                 if (clazz != null) {
-                    Collection<String> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, '')
+                    Collection<String> members = ReflectionCompletor.getPublicFieldsAndMethods(clazz, '')*.value
                     for (member in members) {
-                        matches << member
+                        matches.add(member)
                     }
                 }
             }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/InfixKeywordSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/InfixKeywordSyntaxCompletor.groovy
index 9833680..09faf19 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/InfixKeywordSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/InfixKeywordSyntaxCompletor.groovy
@@ -21,19 +21,19 @@ import org.codehaus.groovy.antlr.GroovySourceToken
 /**
  * Completor completing groovy keywords that appear after identifiers
  */
-public class InfixKeywordSyntaxCompletor implements IdentifierCompletor {
+class InfixKeywordSyntaxCompletor implements IdentifierCompletor {
 
     // INFIX keywords can only occur after identifiers
     private static final String[] INFIX_KEYWORDS = [
-            "in",
-            "instanceof",
-            "extends",
-            "implements",
+            'in',
+            'instanceof',
+            'extends',
+            'implements',
             ]
 
     @Override
-    public boolean complete(final List<GroovySourceToken> tokens, List candidates) {
-        String prefix = tokens.last().getText()
+    boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+        String prefix = tokens.last().text
         boolean foundMatch = false
         for (String varName in INFIX_KEYWORDS) {
             if (varName.startsWith(prefix)) {
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/KeywordSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/KeywordSyntaxCompletor.groovy
index d825e04..e3a4b74 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/KeywordSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/KeywordSyntaxCompletor.groovy
@@ -21,82 +21,82 @@ import org.codehaus.groovy.antlr.GroovySourceToken
 /**
  * Completor completing Groovy keywords and special functions
  */
-public class KeywordSyntaxCompletor implements IdentifierCompletor {
+class KeywordSyntaxCompletor implements IdentifierCompletor {
 
     private static final String[] KEYWORDS = [
-            "abstract",
-            "assert", "boolean", "break", "byte",
-            "case",
-            // "catch (", // special
-            "char", "class", "continue",
-            "def", // short, but keep, else "default" completes, annoyingly
-            "default",
-            "do",
-            "double",
-            "else", "enum",
+            'abstract',
+            'assert', 'boolean', 'break', 'byte',
+            'case',
+            // 'catch (', // special
+            'char', 'class', 'continue',
+            'def', // short, but keep, else 'default' completes, annoyingly
+            'default',
+            'do',
+            'double',
+            'else', 'enum',
 
-            //"false",// value
-            "final",
-            //"finally {", // special
-            "float",
-            //"for (", // special
-            //"if (", // special
-            //"import", // command anyway
+            //'false',// value
+            'final',
+            //'finally {', // special
+            'float',
+            //'for (', // special
+            //'if (', // special
+            //'import', // command anyway
 
-            "int", // short, but keeping for consistency, all primitives
-            "interface",
-            "long",
-            //"native",
-            "new",
-            //"null", // value
-            "private", "protected", "public",
-            "return", "short",
-            "static",
-            //"super",// value
-            //"switch (", // special
-            "synchronized",
-            //"this", // value
+            'int', // short, but keeping for consistency, all primitives
+            'interface',
+            'long',
+            //'native',
+            'new',
+            //'null', // value
+            'private', 'protected', 'public',
+            'return', 'short',
+            'static',
+            //'super',// value
+            //'switch (', // special
+            'synchronized',
+            //'this', // value
             //threadsafe,
-            "throw", "throws",
-            "transient",
-            //"true", // value
-            //"try {", //special
-            "void", "volatile"
-            //"while (" // special
+            'throw', 'throws',
+            'transient',
+            //'true', // value
+            //'try {', //special
+            'void', 'volatile'
+            //'while (' // special
     ]
 
     // VALUE_KEYWORDS and SPECIAL_FUNCTIONS completed without added blank
     private static final String[] VALUE_KEYWORDS = [
-            "true",
-            "false",
-            "this",
-            "super",
-            "null"]
+            'true',
+            'false',
+            'this',
+            'super',
+            'null']
 
     private static final String[] SPECIAL_FUNCTIONS = [
-            "catch (",
-            "finally {",
-            "for (",
-            "if (",
-            "switch (",
-            "try {",
-            "while ("]
+            'catch (',
+            'finally {',
+            'for (',
+            'if (',
+            'switch (',
+            'try {',
+            'while (']
 
     private static final String[] DEFAULT_METHODS = [
-            "use (",
-            "print ",
-            "println ",
-            "printf ",
-            "sprintf ",
+            'use (',
+            'print ',
+            'println ',
+            'printf ',
+            'sprintf ',
     ]
 
     @Override
-    public boolean complete(final List<GroovySourceToken> tokens, List candidates) {
-        String prefix = tokens.last().getText()
+    boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+        String prefix = tokens.last().text
         boolean foundMatch = false
         for (String varName in KEYWORDS) {
             if (varName.startsWith(prefix)) {
-                candidates << varName + " "
+                candidates << varName + ' '
                 foundMatch = true
             }
         }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleter.groovy
index 3e35c17..2ee2c78 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleter.groovy
@@ -1,40 +1,62 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.shell.completion
 
-public class NavigablePropertiesCompleter {
+import java.util.regex.Pattern
+
+class NavigablePropertiesCompleter {
+
+    private static final Pattern NO_CONTROL_CHARS_PATTERN = ~'^[^\\p{Cntrl}]+$'
+
+    // pattern describing particle that must not occur within a string for the string to be a possible identifier
+    private static final Pattern INVALID_CHAR_FOR_IDENTIFIER_PATTERN = ~'[ @#%^&§()+\\-={}\\[\\]~`´<>,."\'/!?:;|\\\\]'
 
     /**
      * Adds navigable properties to the list of candidates if they match the prefix
      */
-    public void addCompletions(Object instance, final String prefix, final Set<CharSequence> candidates) {
+    void addCompletions(final Object instance, final String prefix, final Set<CharSequence> candidates) {
         if (instance == null) {
-            return;
+            return
         }
         this.addIndirectObjectMembers(instance, prefix, candidates)
     }
 
 
-    void addIndirectObjectMembers(Object instance, String prefix, final Set<CharSequence> candidates) {
+    void addIndirectObjectMembers(final Object instance, final String prefix, final Set<CharSequence> candidates) {
         if (instance instanceof Map) {
-            Map map = (Map) instance;
+            Map map = (Map) instance
             addMapProperties(map, prefix, candidates)
         }
         if (instance instanceof Node) {
-            Node node = (Node) instance;
+            Node node = (Node) instance
             addNodeChildren(node, prefix, candidates)
         }
         if (instance instanceof NodeList) {
-            NodeList nodeList = (NodeList) instance;
+            NodeList nodeList = (NodeList) instance
             addNodeListEntries(nodeList, prefix, candidates)
         }
     }
 
-    void addMapProperties(Map instance, String prefix, final Set<CharSequence> candidates) {
+    static void addMapProperties(final Map instance, final String prefix, final Set<CharSequence> candidates) {
         // key can be any Object but only Strings will be completed
         for (String key in instance.keySet().findAll {it instanceof String}) {
             // if key has no Control characters
-            if (key =~ '^[^\\p{Cntrl}]+$' && key.startsWith(prefix)) {
-                // if key cannot be parsed used as property name, does no start with valid char, or contains invalid char
-                if (key =~ '^[^a-zA-Z_$]|[ @#%^&§()+\\-={}\\[\\]~`´<>,."\'/!?:;|\\\\]') {
+            if (key.matches(NO_CONTROL_CHARS_PATTERN) && key.startsWith(prefix)) {
+                // if key cannot be parsed used as identifier name, (contains invalid char or ends with $)
+                if (key.find(INVALID_CHAR_FOR_IDENTIFIER_PATTERN) || key.endsWith('$')) {
                     key = key.replace('\\', '\\\\').replace('\'', '\\\'')
                     key = '\'' + key + '\''
                 }
@@ -43,28 +65,28 @@ public class NavigablePropertiesCompleter {
         }
     }
 
-    void addNodeListEntries(NodeList instance, String prefix, final Set<CharSequence> candidates) {
-        for (Object member in instance) {
+    void addNodeListEntries(final NodeList instance, final String prefix, final Set<CharSequence> candidates) {
+        for (Object member : instance) {
             addIndirectObjectMembers(member, prefix, candidates)
         }
     }
 
-    void addNodeChildren(Node instance, String prefix, final Set<CharSequence> candidates) {
+    void addNodeChildren(final Node instance, final String prefix, final Set<CharSequence> candidates) {
         for (Object child in instance.children()) {
             String member = ''
             if (child instanceof String) {
-                member = (String) child;
+                member = (String) child
             } else if (child instanceof Node) {
-                member = ((Node) child).name();
+                member = ((Node) child).name()
             } else if (child instanceof NodeList) {
-                for (node in ((NodeList)child)) {
-                    addNodeChildren(node, prefix, candidates)
+                for (Object node : ((NodeList) child)) {
+                    addNodeChildren((Node) node, prefix, candidates)
                 }
             } else {
-                continue;
+                continue
             }
             if (member.startsWith(prefix)) {
-                candidates.add(member);
+                candidates.add(member)
             }
         }
     }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletionCandidate.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletionCandidate.groovy
new file mode 100644
index 0000000..917dd6a
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletionCandidate.groovy
@@ -0,0 +1,76 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.completion
+
+import groovy.transform.CompileStatic
+
+/**
+ * A candidate as String with additional jansi formatting codes
+ */
+ at CompileStatic
+class ReflectionCompletionCandidate implements Comparable<ReflectionCompletionCandidate> {
+
+    private final String value
+    private final List<String> jAnsiCodes
+
+    ReflectionCompletionCandidate(final String value, final String... jAnsiCodes) {
+        this.value = value
+        this.jAnsiCodes = new ArrayList<>(Arrays.asList(jAnsiCodes))
+    }
+
+    String getValue() {
+        return value
+    }
+
+    List<String> getjAnsiCodes() {
+        return jAnsiCodes
+    }
+
+    @Override
+    int compareTo(ReflectionCompletionCandidate o) {
+        boolean hasBracket = this.value.contains('(')
+        boolean otherBracket = o.value.contains('(')
+        if (hasBracket == otherBracket) {
+            this.value.compareTo(o.value)
+        } else if (hasBracket && ! otherBracket) {
+            return -1
+        } else {
+            return 1
+        }
+
+    }
+
+    @Override
+    String toString() {
+        return value
+    }
+
+    @Override
+    int hashCode() {
+        return value.hashCode()
+    }
+
+    @Override
+    boolean equals(o) {
+        if (this.is(o)) return true
+        if (getClass() != o.class) return false
+
+        ReflectionCompletionCandidate that = (ReflectionCompletionCandidate) o
+
+        return value == that.value
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletor.groovy
index b332a0c..94fdff5 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletor.groovy
@@ -20,10 +20,14 @@ import org.codehaus.groovy.antlr.GroovySourceToken
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
 import org.codehaus.groovy.runtime.InvokerHelper
 import org.codehaus.groovy.tools.shell.Groovysh
+import org.codehaus.groovy.tools.shell.util.Preferences
+import org.fusesource.jansi.Ansi
+import org.fusesource.jansi.AnsiRenderer
 
 import java.lang.reflect.Field
 import java.lang.reflect.Method
 import java.lang.reflect.Modifier
+import java.util.regex.Pattern
 
 import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.*
 
@@ -34,78 +38,111 @@ import static org.codehaus.groovy.antlr.parser.GroovyTokenTypes.*
  */
 class ReflectionCompletor {
 
-    Groovysh shell
-    static NavigablePropertiesCompleter propertiesCompleter = new NavigablePropertiesCompleter()
-    int metaclass_completion_prefix_length
+    private static final NavigablePropertiesCompleter PROPERTIES_COMPLETER = new NavigablePropertiesCompleter()
+    private static final Pattern BEAN_ACCESSOR_PATTERN = ~'^(get|set|is)[A-Z].*'
 
-    ReflectionCompletor(Groovysh shell) {
-        this(shell, 0)
-    }
+    final Groovysh shell
 
     /**
      *
      * @param shell
      * @param metaclass_completion_prefix_length how long the prefix must be to disaply candidates from metaclass
      */
-    ReflectionCompletor(Groovysh shell, int metaclass_completion_prefix_length) {
+    ReflectionCompletor(final Groovysh shell) {
         this.shell = shell
-        this.metaclass_completion_prefix_length = metaclass_completion_prefix_length
     }
 
-    public int complete(final List<GroovySourceToken> tokens, List candidates) {
+    int complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
         GroovySourceToken currentElementToken = null
         GroovySourceToken dotToken
         List<GroovySourceToken> previousTokens
         if (tokens.size() < 2) {
-            throw new IllegalArgumentException("must be invoked with at least 2 tokens, one of which is dot")
+            throw new IllegalArgumentException('must be invoked with at least 2 tokens, one of which is dot' + tokens*.text)
         }
-        if (tokens.last().getType() == DOT) {
+        if (tokens.last().type == DOT || tokens.last().type == OPTIONAL_DOT || tokens.last().type == SPREAD_DOT) {
             dotToken = tokens.last()
             previousTokens = tokens[0..-2]
         } else {
-            if (!tokens[-2] == DOT) {
-                throw new IllegalArgumentException("must be invoked with token list with dot at last position or one position before")
+            if (tokens[-2].type != DOT && tokens[-2].type != OPTIONAL_DOT && tokens[-2].type != SPREAD_DOT) {
+                throw new IllegalArgumentException('must be invoked with token list with dot at last position or one position before' + tokens*.text)
             }
             currentElementToken = tokens.last()
             dotToken = tokens[-2]
             previousTokens = tokens[0..-3]
         }
-        Object instance = getInvokerClassOrInstance(previousTokens)
-        if (instance == null) {
+
+        Object instanceOrClass = getInvokerClassOrInstance(previousTokens)
+        if (instanceOrClass == null) {
             return -1
         }
+        if (dotToken.type == SPREAD_DOT) {
+            /**
+             * for aggregate types, find an arbitrary collection-member
+             * element within the instance. This may cause invalid completion candidates when the collection is not
+             * homogenous, but still better than no completion at all. Alternatively the union or intersection of
+             * candidate completions could be built. For non-aggregate types, we assume that whatever find()
+             * returns is useful for *. completion as well.
+             */
+            instanceOrClass = instanceOrClass.find()
+            if (instanceOrClass == null) {
+                return -1
+            }
+        }
 
         String identifierPrefix
         if (currentElementToken) {
-            identifierPrefix = currentElementToken.getText()
+            identifierPrefix = currentElementToken.text
         } else {
-            identifierPrefix = ""
+            identifierPrefix = ''
         }
 
+        return completeInstanceMembers(instanceOrClass, identifierPrefix, candidates, currentElementToken, dotToken)
+    }
+
+    private int completeInstanceMembers(final Object instanceOrClass,
+                                final String identifierPrefix,
+                                final List<CharSequence> candidates,
+                                final GroovySourceToken currentElementToken,
+                                final GroovySourceToken dotToken) {
         // look for public methods/fields that match the prefix
-        Collection<String> myCandidates = getPublicFieldsAndMethods(instance, identifierPrefix)
-        boolean showAllMethods = identifierPrefix.length() >= this.metaclass_completion_prefix_length
+        Collection<ReflectionCompletionCandidate> myCandidates = getPublicFieldsAndMethods(instanceOrClass, identifierPrefix)
+
+        boolean showAllMethods = (identifierPrefix.length() >= Integer.valueOf(Preferences.get(Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
         // Also add metaclass methods if prefix is long enough (user would usually not care about those)
         myCandidates.addAll(getMetaclassMethods(
-                instance,
+                instanceOrClass,
                 identifierPrefix,
-                showAllMethods))
+                showAllMethods).collect({ String it -> new ReflectionCompletionCandidate(it) }))
+
         if (!showAllMethods) {
             // user probably does not care to see default Object / GroovyObject Methods,
             // they obfuscate the business logic
             removeStandardMethods(myCandidates)
         }
+
         // specific DefaultGroovyMethods only suggested for suitable instances
-        addDefaultMethods(instance, identifierPrefix, myCandidates)
+        myCandidates.addAll(getDefaultMethods(instanceOrClass,
+                identifierPrefix).collect({ String it -> new ReflectionCompletionCandidate(it, AnsiRenderer.Code.BLUE.name()) }))
 
         if (myCandidates.size() > 0) {
-            candidates.addAll(myCandidates.sort())
+            myCandidates = myCandidates.sort()
+            if (Boolean.valueOf(Preferences.get(Groovysh.COLORS_PREFERENCE_KEY, 'true'))) {
+                candidates.addAll(myCandidates.collect(
+                        { ReflectionCompletionCandidate it ->
+                            AnsiRenderer.render(it.value,
+                                    it.jAnsiCodes.toArray(new String[it.jAnsiCodes.size()]))
+                        }))
+            } else {
+                candidates.addAll(myCandidates*.value)
+            }
+
             int lastDot
             // dot could be on previous line
-            if (currentElementToken && dotToken.getLine() != currentElementToken.getLine()) {
-                lastDot = currentElementToken.getColumn() - 1
+            if (currentElementToken && dotToken.line != currentElementToken.line) {
+                lastDot = currentElementToken.column - 1
             } else {
-                lastDot = dotToken.getColumn()
+                // Spread-dot has length 2!
+                lastDot = dotToken.column +(dotToken.getText().length() - 1)
             }
             return lastDot
         }
@@ -119,8 +156,10 @@ class ReflectionCompletor {
      * evaluates it and returns a result. "Simple" means evaluation is known to be
      * side-effect free.
      */
-    Object getInvokerClassOrInstance(List<GroovySourceToken> groovySourceTokens) {
-        if (!groovySourceTokens || groovySourceTokens.last().getType() == DOT) {
+    Object getInvokerClassOrInstance(final List<GroovySourceToken> groovySourceTokens) {
+        if (!groovySourceTokens
+                || groovySourceTokens.last().type == DOT
+                || groovySourceTokens.last().type == OPTIONAL_DOT) {
             // we expect the list of tokens before a dot.
             return null
         }
@@ -150,32 +189,32 @@ class ReflectionCompletor {
      * @param groovySourceTokens
      * @return
      */
-    static List<GroovySourceToken> getInvokerTokens(List<GroovySourceToken> groovySourceTokens) {
-       // implementation goes backwards on token list, adding strings
-        // to be evaluated later
-        // need to collect using Strings, to support evaluation of string literals
-        Stack<Integer> expectedOpeners = new Stack<Integer>()
+    static List<GroovySourceToken> getInvokerTokens(final List<GroovySourceToken> groovySourceTokens) {
         int validIndex = groovySourceTokens.size()
         if (validIndex == 0) {
-            return null
+            return []
         }
+        // implementation goes backwards on token list, adding strings
+        // to be evaluated later
+        // need to collect using Strings, to support evaluation of string literals
+        Stack<Integer> expectedOpeners = new Stack<Integer>()
         GroovySourceToken lastToken = null
         outerloop:
         for (GroovySourceToken loopToken in groovySourceTokens.reverse()) {
-            switch (loopToken.getType()) {
+            switch (loopToken.type) {
             // a combination of any of these can be evaluated without side effects
             // this just avoids any parentheses,
             // could maybe be extended further if harmless parentheses can be detected .
-            // This allows already a lot of powerful simple completions, like [foo: Baz.bar]["foo"].
+            // This allows already a lot of powerful simple completions, like [foo: Baz.bar]['foo'].
                 case STRING_LITERAL:
                     // must escape String for evaluation, need the original string e.g. for mapping key
-                    break;
+                    break
                 case LPAREN:
                     if (expectedOpeners.empty()) {
                         break outerloop
                     }
                     if (expectedOpeners.pop() != LPAREN) {
-                        return null
+                        return []
                     }
                     break
                 case LBRACK:
@@ -183,7 +222,7 @@ class ReflectionCompletor {
                         break outerloop
                     }
                     if (expectedOpeners.pop() != LBRACK) {
-                        return null
+                        return []
                     }
                     break
                 case RBRACK:
@@ -234,13 +273,13 @@ class ReflectionCompletor {
                 // tokens we accept
                 case IDENT:
                    if (lastToken) {
-                       if (lastToken.getType() == LPAREN) {
+                       if (lastToken.type == LPAREN) {
                            //Method invocation,must be avoided
-                           return null
+                           return []
                        }
-                       if (lastToken.getType() == IDENT) {
-                           // could be attempt to invoke closure like "foo.each bar.baz"
-                           return null
+                       if (lastToken.type == IDENT) {
+                           // could be attempt to invoke closure like 'foo.each bar.baz'
+                           return []
                        }
                    }
                     break
@@ -263,6 +302,7 @@ class ReflectionCompletor {
                 case NUM_BIG_DECIMAL:
                 case MEMBER_POINTER:
                 case DOT:
+                case OPTIONAL_DOT:
                     break
                 default:
                     return null
@@ -273,30 +313,30 @@ class ReflectionCompletor {
         return groovySourceTokens[(validIndex)..-1]
     }
 
-    static String tokenListToEvalString(List<GroovySourceToken> groovySourceTokens) {
+    static String tokenListToEvalString(final List<GroovySourceToken> groovySourceTokens) {
         StringBuilder builder = new StringBuilder()
         for (GroovySourceToken token: groovySourceTokens) {
-            if (token.getType() == STRING_LITERAL) {
-                builder.append("\"").append(token.getText()).append("\"")
+            if (token.type == STRING_LITERAL) {
+                builder.append('\'').append(token.text).append('\'')
             } else {
-                builder.append(token.getText())
+                builder.append(token.text)
             }
         }
         return builder.toString()
     }
 
-    static boolean acceptName(String name, String prefix) {
+    static boolean acceptName(final String name, final String prefix) {
         return (!prefix || name.startsWith(prefix)) &&
-                (!(name.contains('$')) && !name.startsWith("_"));
+                (!(name.contains('$')) && !(name.startsWith('_')))
     }
 
-    static Collection<String> getMetaclassMethods(Object instance, String prefix, boolean includeMetaClassImplMethods) {
+    static Collection<String> getMetaclassMethods(final Object instance, final String prefix, final boolean includeMetaClassImplMethods) {
         Set<String> rv = new HashSet<String>()
         MetaClass metaclass = InvokerHelper.getMetaClass(instance)
-        if (includeMetaClassImplMethods || ! metaclass instanceof MetaClassImpl) {
+        if (includeMetaClassImplMethods || !(metaclass instanceof MetaClassImpl)) {
             metaclass.metaMethods.each { MetaMethod mmit ->
                 if (acceptName(mmit.name, prefix)) {
-                    rv << mmit.getName() + (mmit.parameterTypes.length == 0 ? "()" : "(")
+                    rv << mmit.getName() + (mmit.parameterTypes.length == 0 ? '()' : '(')
                 }
             }
         }
@@ -310,11 +350,11 @@ class ReflectionCompletor {
      * @param prefix the prefix that must be matched
      * @return the list of public methods and fields that begin with the prefix
      */
-    static Collection<String> getPublicFieldsAndMethods(Object instance, String prefix) {
-        Set<String> rv = new HashSet<String>()
+    static Collection<ReflectionCompletionCandidate> getPublicFieldsAndMethods(final Object instance, final String prefix) {
+        Set<ReflectionCompletionCandidate> rv = new HashSet<ReflectionCompletionCandidate>()
         Class clazz = instance.getClass()
         if (clazz == null) {
-            return rv;
+            return rv
         }
 
         boolean isClass = (clazz == Class)
@@ -323,22 +363,29 @@ class ReflectionCompletor {
         }
 
         Class loopclazz = clazz
+        // render immediate class members bold when completing an instance
+        boolean renderBold = ! isClass
+        // hide static members for instances unless user typed a prefix
+        boolean showStatic = isClass || (prefix.length() >= Integer.valueOf(Preferences.get(Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY, '3')))
         while (loopclazz != null && loopclazz != Object && loopclazz != GroovyObject) {
-            addClassFieldsAndMethods(loopclazz, isClass, prefix, rv)
+            addClassFieldsAndMethods(loopclazz, showStatic, !isClass, prefix, rv, renderBold)
+            renderBold = false
             loopclazz = loopclazz.superclass
         }
         if (clazz.isArray() && !isClass) {
             // Arrays are special, these public members cannot be found via Reflection
-            for (String member in ['length', 'clone()']) {
+            for (String member : ['length', 'clone()']) {
                 if (member.startsWith(prefix)) {
-                    rv.add(member)
+                    rv.add(new ReflectionCompletionCandidate(member, Ansi.Attribute.INTENSITY_BOLD.name()))
                 }
             }
         }
 
         // other completions that are commonly possible with properties
         if (!isClass) {
-            propertiesCompleter.addCompletions(instance, prefix, rv)
+            Set<String> candidates = new HashSet<String>()
+            PROPERTIES_COMPLETER.addCompletions(instance, prefix, candidates)
+            rv.addAll(candidates.collect({String it -> new ReflectionCompletionCandidate(it, AnsiRenderer.Code.MAGENTA.name())}))
         }
 
         return rv.sort()
@@ -348,13 +395,18 @@ class ReflectionCompletor {
      * removes candidates that, most of the times, a programmer does not want to see in completion
      * @param candidates
      */
-    static removeStandardMethods(Collection<String> candidates) {
-        for (String defaultMethod in [
+    static removeStandardMethods(final Collection<ReflectionCompletionCandidate> candidates) {
+        for (String defaultMethod : [
                 'clone()', 'finalize()', 'getClass()',
                 'getMetaClass()', 'getProperty(',  'invokeMethod(', 'setMetaClass(', 'setProperty(',
                 'equals(', 'hashCode()', 'toString()',
                 'notify()', 'notifyAll()', 'wait(', 'wait()']) {
-            candidates.remove(defaultMethod)
+            for (ReflectionCompletionCandidate candidate : candidates) {
+                if (defaultMethod.equals(candidate.value)) {
+                    candidates.remove(candidate)
+                    break
+                }
+            }
         }
     }
 
@@ -364,7 +416,8 @@ class ReflectionCompletor {
      * if the instance is of a suitable type.
      * This does not need to be strictly complete, only the most useful functions may appear.
      */
-    static addDefaultMethods(Object instance, String prefix, Collection<String> candidates) {
+    static List<String> getDefaultMethods(final Object instance, final String prefix) {
+        List<String> candidates = []
         if (instance instanceof Iterable) {
             [
                     'any()', 'any(',
@@ -372,13 +425,13 @@ class ReflectionCompletor {
                     'combinations()',
                     'count(',
                     'countBy(',
-                    'drop(',
-                    'dropWhile(',
+                    'drop(', 'dropRight(', 'dropWhile(',
                     'each()', 'each(',
                     'eachPermutation(',
                     'every()', 'every(',
                     'find(', 'findResult(', 'findResults(',
                     'flatten()',
+                    'init()',
                     'inject(',
                     'intersect(',
                     'join(',
@@ -387,7 +440,7 @@ class ReflectionCompletor {
                     'size()',
                     'sort()',
                     'split(',
-                    'take(', 'takeWhile(',
+                    'take(', 'takeRight(', 'takeWhile(',
                     'toSet()',
                     'retainAll(', 'removeAll(',
                     'unique()', 'unique('
@@ -403,11 +456,18 @@ class ReflectionCompletor {
         if (instance instanceof Map) {
             [
                     'any(',
+                    'collect(',
+                    'collectEntries(',
+                    'collectMany(',
+                    'count(',
                     'drop(',
                     'each(',
+                    'every(',
                     'find(', 'findAll(', 'findResult(', 'findResults(',
                     'groupEntriesBy(', 'groupBy(',
                     'inject(', 'intersect(',
+                    'max(', 'min(',
+                    'sort(',
                     'spread()',
                     'subMap(',
                     'take(', 'takeWhile('
@@ -429,12 +489,12 @@ class ReflectionCompletor {
                     'collect()', 'collect(',
                     'count(',
                     'countBy(',
-                    'drop(',
-                    'dropWhile(',
+                    'drop(', 'dropRight(', 'dropWhile(',
                     'each()', 'each(',
                     'every()', 'every(',
                     'find(', 'findResult(',
                     'flatten()',
+                    'init()',
                     'inject(',
                     'join(',
                     'max()', 'min()',
@@ -442,43 +502,103 @@ class ReflectionCompletor {
                     'size()',
                     'sort()',
                     'split(',
-                    'take(', 'takeWhile('
+                    'take(', 'takeRight(', 'takeWhile('
             ].findAll({it.startsWith(prefix)}).each({candidates.add(it)})
         }
+        return candidates
     }
 
 
 
 
 
-    private static Collection<String> addClassFieldsAndMethods(final Class clazz, final boolean staticOnly, final String prefix, Collection rv) {
-        Field[] fields = staticOnly ? clazz.fields : clazz.getDeclaredFields()
+    private static Collection<ReflectionCompletionCandidate> addClassFieldsAndMethods(final Class clazz,
+                                                                            final boolean includeStatic,
+                                                                            final boolean includeNonStatic,
+                                                                            final String prefix,
+                                                                            final Collection<ReflectionCompletionCandidate> rv,
+                                                                            final boolean renderBold) {
+
+        Field[] fields = (includeStatic && ! includeNonStatic) ? clazz.fields : clazz.getDeclaredFields()
         fields.each { Field fit ->
             if (acceptName(fit.name, prefix)) {
                 int modifiers = fit.getModifiers()
-                if (Modifier.isPublic(modifiers) && (!staticOnly || Modifier.isStatic(modifiers))) {
-                    if (!clazz.isEnum() || !(!staticOnly && Modifier.isPublic(modifiers) && Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers) && fit.getType() == clazz)) {
-                        rv << fit.name
+                if (Modifier.isPublic(modifiers) && (Modifier.isStatic(modifiers) ? includeStatic : includeNonStatic)) {
+                    if (!clazz.isEnum()
+                            || !(!includeStatic && Modifier.isPublic(modifiers) && Modifier.isFinal(modifiers) && Modifier.isStatic(modifiers) && fit.type == clazz)) {
+                        ReflectionCompletionCandidate candidate = new ReflectionCompletionCandidate(fit.name)
+                        if (!Modifier.isStatic(modifiers)) {
+                            if (renderBold) {
+                                candidate.jAnsiCodes.add(Ansi.Attribute.INTENSITY_BOLD.name())
+                            }
+                        }
+                        rv << candidate
                     }
                 }
             }
         }
-        Method[] methods = staticOnly ? clazz.methods : clazz.getDeclaredMethods()
-        methods.each { Method methIt ->
+        Method[] methods = (includeStatic && ! includeNonStatic) ? clazz.methods : clazz.getDeclaredMethods()
+        for (Method methIt : methods) {
             String name = methIt.getName()
             if (name.startsWith("super\$")) {
                 name = name.substring(name.find("^super\\\$.*\\\$").length())
             }
-            if (acceptName(name, prefix)) {
-                int modifiers = methIt.getModifiers()
-                if (Modifier.isPublic(modifiers) && (!staticOnly || Modifier.isStatic(modifiers))) {
-                    rv << name + (methIt.parameterTypes.length == 0 ? "()" : "(")
+            int modifiers = methIt.getModifiers()
+            if (Modifier.isPublic(modifiers) && (Modifier.isStatic(modifiers) ? includeStatic : includeNonStatic)) {
+                boolean fieldnameSuggested = false
+                // bean fieldname can be used instead of accessor, tidies up completion candidates
+                // the same goes for static fields // accessors
+                if (name.matches(BEAN_ACCESSOR_PATTERN)) {
+                    String fieldname = getFieldnameForAccessor(name, methIt.parameterTypes.length)
+                    if (fieldname != null && fieldname != 'metaClass' && fieldname != 'property') {
+                        if (acceptName(fieldname, prefix)) {
+                            fieldnameSuggested = true
+                            ReflectionCompletionCandidate fieldCandidate = new ReflectionCompletionCandidate(fieldname)
+                            if (!rv.contains(fieldCandidate)) {
+                                if (!Modifier.isStatic(modifiers) && renderBold) {
+                                    fieldCandidate.jAnsiCodes.add(Ansi.Attribute.INTENSITY_BOLD.name())
+                                }
+
+                                rv.add(fieldCandidate)
+                            }
+                        }
+                    }
+                }
+                if (! fieldnameSuggested && acceptName(name, prefix)) {
+                    ReflectionCompletionCandidate candidate = new ReflectionCompletionCandidate(name + (methIt.parameterTypes.length == 0 ? '()' : '('))
+                    if (!Modifier.isStatic(modifiers) && renderBold) {
+                        candidate.jAnsiCodes.add(Ansi.Attribute.INTENSITY_BOLD.name())
+                    }
+                    rv.add(candidate)
                 }
             }
         }
-        for (interface_ in clazz.getInterfaces()) {
-            addClassFieldsAndMethods(interface_, staticOnly, prefix, rv)
+
+        for (Class interface_ : clazz.getInterfaces()) {
+            addClassFieldsAndMethods(interface_, includeStatic, includeNonStatic, prefix, rv, false)
         }
     }
 
+    static CharSequence getFieldnameForAccessor(String accessor, int parameterLength) {
+        String fieldname = null
+        if (accessor.startsWith('get')) {
+            if (parameterLength == 0) {
+                fieldname = accessor.substring(3)
+            }
+        } else if (accessor.startsWith('set')) {
+            if (parameterLength == 1) {
+                fieldname = accessor.substring(3)
+            }
+        } else if (accessor.startsWith('is')) {
+            if (parameterLength == 0) {
+                fieldname = accessor.substring(2)
+            }
+        } else {
+            throw new IllegalStateException('getFieldnameForAccessor called with invalid accessor : ' + accessor)
+        }
+        if (fieldname == null) {
+            return null
+        }
+        return fieldname[0].toLowerCase() + fieldname.substring(1)
+    }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/StricterArgumentCompleter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/StricterArgumentCompleter.groovy
index 888397c..198c879 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/StricterArgumentCompleter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/StricterArgumentCompleter.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.shell.completion
 
 import groovy.transform.CompileStatic
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/VariableSyntaxCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/VariableSyntaxCompletor.groovy
index ceed9e8..ad0065a 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/VariableSyntaxCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/completion/VariableSyntaxCompletor.groovy
@@ -23,26 +23,26 @@ import org.codehaus.groovy.tools.shell.Groovysh
 /**
  * Completor completing variable and method names from known variables in the shell
  */
-public class VariableSyntaxCompletor implements IdentifierCompletor {
+class VariableSyntaxCompletor implements IdentifierCompletor {
 
-    Groovysh shell
+    final Groovysh shell
 
-    VariableSyntaxCompletor(Groovysh shell) {
+    VariableSyntaxCompletor(final Groovysh shell) {
         this.shell = shell
     }
 
     @Override
-    public boolean complete(final List<GroovySourceToken> tokens, List candidates) {
-        String prefix = tokens.last().getText()
+    boolean complete(final List<GroovySourceToken> tokens, final List<CharSequence> candidates) {
+        String prefix = tokens.last().text
         Map vars = shell.interp.context.variables
         boolean foundMatch = false
         for (String varName in vars.keySet()) {
             if (acceptName(varName, prefix)) {
                 if (vars.get(varName) instanceof MethodClosure) {
-                    if (((MethodClosure)vars.get(varName)).getMaximumNumberOfParameters() > 0) {
-                        varName += "("
+                    if (((MethodClosure) vars.get(varName)).getMaximumNumberOfParameters() > 0) {
+                        varName += '('
                     } else {
-                        varName += "()"
+                        varName += '()'
                     }
                 }
                 foundMatch = true
@@ -55,6 +55,6 @@ public class VariableSyntaxCompletor implements IdentifierCompletor {
 
     private static boolean acceptName(String name, String prefix) {
         return (!prefix || name.startsWith(prefix)) &&
-               (!(name.contains('$')) && !name.startsWith("_"));
+               (!(name.contains('$')) && !(name.startsWith('_')))
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParser.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParser.groovy
new file mode 100644
index 0000000..95b4166
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParser.groovy
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+import groovy.transform.CompileStatic
+
+ at CompileStatic
+class CommandArgumentParser {
+
+    /**
+     * takes a String and tokenizes it according to posix-shell-like rules, meaning
+     * arguments are separated by blanks or hyphens, and hyphens wrap tokens regardless
+     * of blanks, other hyphens or escaped hyphens within the wrapping hyphens.
+     *
+     * Example: "foo bar 123'456' 'abc\'def\\' ''"  has 6 tokens:
+     * ["foo", "bar", "123", "456", "abc'def\", ""]
+     *
+     * @param untrimmedLine
+     * @param numTokensToCollect stop processing after so many tokens, negative means unlimited
+     * @return
+     */
+    static List<String> parseLine(final String untrimmedLine, final int numTokensToCollect = -1) {
+        assert untrimmedLine != null
+
+        final String line = untrimmedLine.trim()
+        List<String> tokens = []
+        String currentToken = ''
+        // state machine being either in neutral state, in singleHyphenOpen state, or in doubleHyphenOpen State.
+        boolean singleHyphenOpen = false
+        boolean doubleHyphenOpen = false
+        int index = 0
+        for (; index < line.length(); index++) {
+            if (tokens.size() == numTokensToCollect) {
+                break
+            }
+            String ch = line.charAt(index)
+            // escaped char?
+            if (ch == '\\' && (singleHyphenOpen || doubleHyphenOpen)) {
+                ch = (index == line.length() - 1) ? '\\' : line.charAt(index + 1)
+                index++
+                currentToken += ch
+                continue
+            }
+
+            if (ch == '"' && !singleHyphenOpen) {
+                if (doubleHyphenOpen) {
+                    tokens.add(currentToken)
+                    currentToken = ''
+                    doubleHyphenOpen = false
+                } else {
+                    if (currentToken.size() > 0) {
+                        tokens.add(currentToken)
+                        currentToken = ''
+                    }
+                    doubleHyphenOpen = true
+                }
+                continue
+            }
+            if (ch == '\'' && !doubleHyphenOpen) {
+                if (singleHyphenOpen) {
+                    tokens.add(currentToken)
+                    currentToken = ''
+                    singleHyphenOpen = false
+                } else {
+                    if (currentToken.size() > 0) {
+                        tokens.add(currentToken)
+                        currentToken = ''
+                    }
+                    singleHyphenOpen = true
+                }
+                continue
+            }
+            if (ch == ' ' && !doubleHyphenOpen && !singleHyphenOpen) {
+                if (currentToken.size() > 0) {
+                    tokens.add(currentToken)
+                    currentToken = ''
+                }
+                continue
+            }
+            currentToken += ch
+        } // end for char in line
+        if (index == line.length() && doubleHyphenOpen) {
+            throw new IllegalArgumentException('Missing closing " in ' + line + ' -- ' + tokens)
+        }
+        if (index == line.length() && singleHyphenOpen) {
+            throw new IllegalArgumentException('Missing closing \' in ' + line  + ' -- ' + tokens)
+        }
+        if (currentToken.size() > 0) {
+            tokens.add(currentToken)
+        }
+        return tokens
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexer.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexer.groovy
index 82a5a1a..a867d82 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexer.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexer.groovy
@@ -20,45 +20,44 @@ import org.codehaus.groovy.antlr.GroovySourceToken
 import org.codehaus.groovy.antlr.SourceBuffer
 import org.codehaus.groovy.antlr.UnicodeEscapingReader
 import org.codehaus.groovy.antlr.parser.GroovyLexer
-import org.codehaus.groovy.antlr.parser.GroovyTokenTypes;
+import org.codehaus.groovy.antlr.parser.GroovyTokenTypes
 
 /**
  * patching GroovyLexer to get access to Paren level
- * Author: kruset
  */
-public class CurlyCountingGroovyLexer extends GroovyLexer {
+class CurlyCountingGroovyLexer extends GroovyLexer {
 
     private endReached = false
 
     protected CurlyCountingGroovyLexer(Reader reader) {
-        super(reader);
+        super(reader)
     }
 
-    public static CurlyCountingGroovyLexer createGroovyLexer(String src) {
+    static CurlyCountingGroovyLexer createGroovyLexer(String src) {
         Reader unicodeReader = new UnicodeEscapingReader(new StringReader(src.toString()), new SourceBuffer())
         CurlyCountingGroovyLexer lexer = new CurlyCountingGroovyLexer(unicodeReader)
-        unicodeReader.setLexer(lexer);
+        unicodeReader.setLexer(lexer)
         return lexer
     }
 
-    public int getParenLevel() {
+    int getParenLevel() {
         return parenLevelStack.size()
     }
 
     // called by nextToken()
     @Override
-    public void uponEOF() {
+    void uponEOF() {
         super.uponEOF()
         endReached = true
     }
 
-    public List<GroovySourceToken> toList() {
+    List<GroovySourceToken> toList() {
         List<GroovySourceToken> tokens = []
         GroovySourceToken token
         while (! endReached) {
             token = nextToken() as GroovySourceToken
             tokens.add(token)
-            if (token.getType() == GroovyTokenTypes.EOF) {
+            if (token.type == GroovyTokenTypes.EOF) {
                 break
             }
         }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/HelpFormatter.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/HelpFormatter.groovy
index 6bd0a98..41ad985 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/HelpFormatter.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/HelpFormatter.groovy
@@ -36,41 +36,42 @@ class HelpFormatter
     extends org.apache.commons.cli.HelpFormatter
 {
     HelpFormatter() {
-        defaultLeftPad = 2
-        defaultDescPad = 4
+        leftPadding = 2
+        descPadding = 4
     }
 
     // Detect the terminal width late
-    public int getDefaultWidth() {
+    int getDefaultWidth() {
         return Terminal.terminal.terminalWidth - 1
     }
 
+    @Override
     protected StringBuffer renderOptions(final StringBuffer sb, final int width, final Options options, final int leftPad, final int descPad) {
         assert sb != null
         assert options
-        
+
         List<StringBuffer> prefixes = []
         String lpad = ' ' * leftPad
-        
+
         List<Option> opts = options.shortOpts.values().sort {Option a, Option b ->
             return (a.opt == ' ' ? a.longOpt : a.opt) <=> (b.opt == ' ' ? b.longOpt : b.opt)
         }
-        
+
         // Render the prefixes (-X,--xxxx muck)
         opts.each {Option option ->
             StringBuffer buff = new StringBuffer(8)
-            
+
             if (option.opt == ' ') {
-                buff << "${lpad}    ${defaultLongOptPrefix}${option.longOpt}"
+                buff << "${lpad}    ${longOptPrefix}${option.longOpt}"
             }
             else {
-                buff << "${lpad}${defaultOptPrefix}${option.opt}"
-                
+                buff << "${lpad}${optPrefix}${option.opt}"
+
                 if (option.hasLongOpt()) {
-                    buff << ", ${defaultLongOptPrefix}${option.longOpt}"
+                    buff << ", ${longOptPrefix}${option.longOpt}"
                 }
             }
-            
+
             if (option.hasArg()) {
                 if (option.hasArgName()) {
                     if (option.hasOptionalArg()) {
@@ -84,34 +85,34 @@ class HelpFormatter
                     buff << ' '
                 }
             }
-            
+
             prefixes << buff
         }
-        
+
         // Figure out how long the biggest prefix is
         int maxPrefix = prefixes.max {StringBuffer a, StringBuffer b -> a.size() <=> b.size() }.size()
-        
+
         String dpad = ' ' * descPad
-        
+
         // And then render each option's prefix with its description
         opts.eachWithIndex {Option option, int i ->
             def buff = new StringBuffer(prefixes[i].toString())
-            
+
             if (buff.size() < maxPrefix) {
                 buff << ' ' * (maxPrefix - buff.size())
             }
             buff << dpad
-            
+
             int nextLineTabStop = maxPrefix + descPad
             String text = buff << option.description
-            
+
             renderWrappedText(sb, width, nextLineTabStop, text)
-            
+
             if (i < opts.size() - 1) {
-                sb << defaultNewLine
+                sb << newLine
             }
         }
-        
+
         return sb
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/JAnsiHelper.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/JAnsiHelper.groovy
new file mode 100644
index 0000000..19ac645
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/JAnsiHelper.groovy
@@ -0,0 +1,40 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+import groovy.transform.CompileStatic
+import org.fusesource.jansi.AnsiOutputStream
+
+ at CompileStatic
+class JAnsiHelper {
+
+    /**
+     * copied from jline2 ConsoleReader
+     */
+    static CharSequence stripAnsi(final CharSequence str) {
+        if (str == null) return ''
+        try {
+            ByteArrayOutputStream baos = new ByteArrayOutputStream()
+            AnsiOutputStream aos = new AnsiOutputStream(baos)
+            aos.write(str.toString().bytes)
+            aos.flush()
+            return baos.toString()
+        } catch (IOException e) {
+            return str
+        }
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/NoExitSecurityManager.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/NoExitSecurityManager.groovy
index 8bc51a0..a2a359f 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/NoExitSecurityManager.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/NoExitSecurityManager.groovy
@@ -14,9 +14,9 @@
  * limitations under the License.
  */
 
-package org.codehaus.groovy.tools.shell.util;
+package org.codehaus.groovy.tools.shell.util
 
-import java.security.Permission;
+import java.security.Permission
 
 /**
  * Custom security manager to {@link System#exit} (and related) from being used.
@@ -26,35 +26,37 @@ import java.security.Permission;
 public class NoExitSecurityManager
     extends SecurityManager
 {
-    private final SecurityManager parent;
+    private final SecurityManager parent
 
     public NoExitSecurityManager(final SecurityManager parent) {
-        this.parent = parent;
+        this.parent = parent
     }
 
     public NoExitSecurityManager() {
-        this(System.getSecurityManager());
+        this(System.getSecurityManager())
     }
 
+    @Override
     public void checkPermission(final Permission perm) {
         if (parent != null) {
-            parent.checkPermission(perm);
+            parent.checkPermission(perm)
         }
     }
 
     /**
      * Always throws {@link SecurityException}.
      */
+    @Override
     public void checkExit(final int code) {
-        throw new SecurityException("Use of System.exit() is forbidden!");
+        throw new SecurityException('Use of System.exit() is forbidden!')
     }
 
     /*
     public void checkPermission(final Permission perm) {
-        assert perm != null;
+        assert perm != null
 
         if (perm.getName().equals("exitVM")) {
-            System.out.println("exitVM");
+            System.out.println("exitVM")
         }
     }
     */
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelper.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelper.groovy
index 9695e4b..95581aa 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelper.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelper.groovy
@@ -1,370 +1,24 @@
-package org.codehaus.groovy.tools.shell.util
-
-import java.util.jar.JarEntry
-import java.util.jar.JarFile
-import java.util.prefs.PreferenceChangeEvent
-import java.util.prefs.PreferenceChangeListener
-import java.util.regex.Matcher
-import java.util.regex.Pattern
-import java.util.zip.ZipException
-
-/**
- * Helper class that crawls all items of the classpath for packages.
- * Retrieves from those sources the list of subpackages and classes on demand.
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
-class PackageHelper implements PreferenceChangeListener {
-
-    public static final String IMPORT_COMPLETION_PREFERENCE_KEY = "disable-import-completion"
-    // Pattern for regular Classnames
-    public static final Pattern NAME_PATTERN = java.util.regex.Pattern.compile("^[A-Z][^.\$_]+\$")
-
-    private static final String CLASS_SUFFIX = ".class"
-
-    Map<String, CachedPackage> rootPackages = null
-    ClassLoader groovyClassLoader
-    protected static final Logger log = Logger.create(PackageHelper)
-
-    PackageHelper(ClassLoader groovyClassLoader) {
-        this.groovyClassLoader = groovyClassLoader
-        if (! Boolean.valueOf(Preferences.get(IMPORT_COMPLETION_PREFERENCE_KEY))) {
-            rootPackages = initializePackages(groovyClassLoader)
-        }
-        Preferences.addChangeListener(this)
-    }
-
-    @Override
-    void preferenceChange(PreferenceChangeEvent evt) {
-        if (evt.getKey() == IMPORT_COMPLETION_PREFERENCE_KEY) {
-            if (Boolean.valueOf(evt.getNewValue())) {
-                rootPackages = null
-            } else if (rootPackages == null) {
-                rootPackages = initializePackages(groovyClassLoader)
-            }
-        }
-    }
-
-    static Map<String, CachedPackage> initializePackages(ClassLoader groovyClassLoader) throws IOException {
-        Map<String, CachedPackage> rootPackages = new HashMap()
-        Set<URL> urls = new HashSet<URL>()
-
-        // classes in CLASSPATH
-        for (ClassLoader loader = groovyClassLoader; loader != null; loader = loader.parent) {
-            if (!(loader instanceof URLClassLoader)) {
-                log.debug('Ignoring classloader for completion: ' + loader)
-                continue
-            }
-
-            urls.addAll(((URLClassLoader)loader).URLs)
-        }
-
-        // System classes
-        Class[] systemClasses = [String, javax.swing.JFrame, GroovyObject] as Class[]
-        systemClasses.each { Class systemClass ->
-            // normal slash even in Windows
-            String classfileName = systemClass.name.replace('.', '/') + ".class"
-            URL classURL = systemClass.getResource(classfileName)
-            if (classURL == null) {
-                // this seems to work on Windows better than the earlier approach
-                classURL = Thread.currentThread().getContextClassLoader().getResource(classfileName);
-            }
-            if (classURL != null) {
-                URLConnection uc = classURL.openConnection()
-                if (uc instanceof JarURLConnection) {
-                    urls.add(((JarURLConnection) uc).getJarFileURL())
-                } else {
-                    String filepath = classURL.toExternalForm()
-                    String rootFolder = filepath.substring(0, filepath.length() - classfileName.length() - 1)
-                    urls.add(new URL(rootFolder))
-                }
-            }
-        }
-
-        for (url in urls) {
-            Collection<String> packageNames = getPackageNames(url)
-            if (packageNames) {
-                mergeNewPackages(packageNames, url, rootPackages)
-            }
-        }
-        return rootPackages
-    }
-
-    static mergeNewPackages(Collection<String> packageNames, URL url, Map<String, CachedPackage> rootPackages) {
-        StringTokenizer tokenizer
-        packageNames.each { String packname ->
-            tokenizer = new StringTokenizer(packname, '.')
-            if (!tokenizer.hasMoreTokens()) {
-                return
-            }
-            String rootname = tokenizer.nextToken()
-            CachedPackage cp
-            CachedPackage childp
-            cp = rootPackages.get(rootname, null) as CachedPackage
-            if (cp == null) {
-                cp = new CachedPackage(rootname, [url] as Set)
-                rootPackages.put(rootname, cp)
-            }
-
-            while(tokenizer.hasMoreTokens()) {
-                String packbasename = tokenizer.nextToken()
-                if (cp.childPackages == null) {
-                    // small initial size, to save memory
-                    cp.childPackages = new HashMap<String, CachedPackage>(1)
-                }
-                childp = cp.childPackages.get(packbasename, null) as CachedPackage
-                if (childp == null) {
-                    // start with small arraylist, to save memory
-                    Set<URL> urllist = new HashSet<URL>(1)
-                    urllist.add(url)
-                    childp = new CachedPackage(packbasename, urllist)
-                    cp.childPackages.put(packbasename, childp)
-                } else {
-                    childp.sources.add(url)
-                }
-                cp = childp
-            }
-        }
-    }
-
-    /**
-     * Returns all packagenames found at URL, accepts jar files and folders
-     * @param url
-     * @return
-     */
-    static Collection<String> getPackageNames(URL url) {
-        //log.debug(url)
-        String path = URLDecoder.decode(url.getFile(), "UTF-8")
-        File urlfile = new File(path)
-        if (urlfile.isDirectory()) {
-            Set<String> packnames = new HashSet<String>()
-            collectPackageNamesFromFolderRecursive(urlfile, "", packnames)
-            return packnames
-        } else {
-            if(urlfile.path.endsWith('.jar')) {
-                try {
-                    JarFile jf = new JarFile(urlfile)
-                    return getPackageNamesFromJar(jf)
-                } catch(ZipException ze) {
-                    if (log.debugEnabled) {
-                        ze.printStackTrace();
-                    }
-                    log.debug("Error opening zipfile : '${url.getFile()}',  ${ze.toString()}");
-                } catch (FileNotFoundException fnfe) {
-                    log.debug("Error opening file : '${url.getFile()}',  ${fnfe.toString()}");
-                }
-            }
-            return null;
-        }
-    }
-
-    /**
-     * Crawls a folder, iterates over subfolders, looking for class files.
-     * @param directory
-     * @param prefix
-     * @param packnames
-     * @return
-     */
-    static Collection<String> collectPackageNamesFromFolderRecursive(File directory, String prefix, Set<String> packnames) {
-        //log.debug(directory)
-        File[] files = directory.listFiles();
-        boolean packageAdded = false;
-
-        for (int i = 0; (files != null) && (i < files.length); i++) {
-            if (files[i].isDirectory()) {
-                if (files[i].name.startsWith('.')) {
-                    return
-                }
-                String optionalDot = prefix ? '.' : ''
-                collectPackageNamesFromFolderRecursive(files[i], prefix + optionalDot + files[i].getName(), packnames);
-            } else if (! packageAdded) {
-                if (files[i].getName().endsWith(CLASS_SUFFIX)) {
-                    packageAdded = true
-                    if (prefix) {
-                        packnames.add(prefix);
-                    }
-                }
-            }
-        }
-    }
-
-
-    static Collection<String> getPackageNamesFromJar(JarFile jf) {
-        Set<String> packnames = new HashSet<String>()
-        for (Enumeration e = jf.entries(); e.hasMoreElements();) {
-            JarEntry entry = (JarEntry) e.nextElement()
 
-            if (entry == null) {
-                continue;
-            }
-
-            String name = entry.getName()
-
-            if (!name.endsWith(CLASS_SUFFIX)) {
-                // only use class files
-                continue;
-            }
-            // normal slashes also on Windows
-            String fullname = name.replace('/', '.').substring(0, name.length() - CLASS_SUFFIX.length())
-            // Discard classes in the default package
-            if (fullname.lastIndexOf('.') > -1) {
-                packnames.add(fullname.substring(0, fullname.lastIndexOf('.')))
-            }
-        }
-        return packnames
-    }
-
-    // following block does not work, because URLClassLoader.packages only ever returns SystemPackages
-    /*static Collection<String> getPackageNames(URL url) {
-        URLClassLoader urlLoader = new URLClassLoader([url] as URL[])
-        //log.debug(urlLoader.packages.getClass())
-
-        urlLoader.getPackages().collect {Package pack ->
-            pack.name
-        }
-    }*/
-
-    /**
-     * returns the names of Classes and direct subpackages contained in a package
-     * @param packagename
-     * @return
-     */
-    Set<String> getContents(String packagename) {
-        if (! rootPackages) {
-            return null
-        }
-        if (! packagename) {
-            return rootPackages.collect { String key, CachedPackage v -> key } as Set
-        }
-        if (packagename.endsWith(".*")) {
-            packagename = packagename[0..-3]
-        }
-
-        StringTokenizer tokenizer = new StringTokenizer(packagename, '.')
-        CachedPackage cp = rootPackages.get(tokenizer.nextToken())
-        while (cp != null && tokenizer.hasMoreTokens()) {
-            String token = tokenizer.nextToken()
-            if (cp.childPackages == null) {
-                // no match for taken,no subpackages known
-                return null
-            }
-            cp = cp.childPackages.get(token) as CachedPackage
-        }
-        if (cp == null) {
-            return null
-        }
-        // TreeSet for ordering
-        Set<String> children = new TreeSet()
-        if (cp.childPackages) {
-            children.addAll(cp.childPackages.collect { String key, CachedPackage v -> key })
-        }
-        if (cp.checked && !cp.containsClasses) {
-            return children
-        }
-
-        Set<String> classnames = getClassnames(cp.sources, packagename)
-
-        cp.checked = true
-        if (classnames) {
-            cp.containsClasses = true
-            children.addAll(classnames)
-        }
-        return children
-    }
-
-    /**
-     * Copied from JLine 1.0 ClassNameCompletor
-     * @param urls
-     * @param packagename
-     * @return
-     */
-    static Set<String> getClassnames(Set<URL> urls, String packagename) {
-        List<String> classes = new LinkedList<String>()
-        // normal slash even in Windows
-        String pathname = packagename.replace('.', '/')
-        for (Iterator it = urls.iterator(); it.hasNext();) {
-            URL url = (URL) it.next();
-            File file = new File(URLDecoder.decode(url.getFile(), "UTF-8"));
-            if (file == null) {
-                continue
-            }
-            if (file.isDirectory()) {
-                File packFolder = new File(file, pathname)
-                if (! packFolder.isDirectory()) {
-                    continue
-                }
-                File[] files = packFolder.listFiles();
-                for (int i = 0; (files != null) && (i < files.length); i++) {
-                    if (files[i].isFile()) {
-                        String filename = files[i].getName()
-                        if (filename.endsWith(CLASS_SUFFIX)) {
-                            String name = filename.substring(0, filename.length() - CLASS_SUFFIX.length())
-                            Matcher matcher = NAME_PATTERN.matcher(name)
-                            if (!matcher.find()) {
-                                continue
-                            }
-                            classes.add(name);
-                        }
-                    }
-                }
-                continue
-            }
-
-            if (!file.toString().endsWith (".jar")) {
-                continue
-            }
-
-            JarFile jf = new JarFile(file);
-
-            for (Enumeration e = jf.entries(); e.hasMoreElements();) {
-                JarEntry entry = (JarEntry) e.nextElement();
-
-                if (entry == null) {
-                    continue
-                }
-
-                String name = entry.getName();
-
-                // only use class files
-                if (!name.endsWith(CLASS_SUFFIX))
-                {
-                    continue
-                }
-                // normal slash inside jars even on windows
-                int lastslash = name.lastIndexOf('/')
-                if (lastslash  == -1 || name.substring(0, lastslash) != pathname) {
-                    continue
-                }
-                name = name.substring(lastslash + 1, name.length() - CLASS_SUFFIX.length())
-                Matcher matcher = NAME_PATTERN.matcher(name)
-                if (!matcher.find()) {
-                    continue
-                }
-                classes.add(name)
-            }
-        }
-
-        // now filter classes by changing "/" to "." and trimming the
-        // trailing ".class"
-        Set classNames = new TreeSet();
-
-        for (Iterator i = classes.iterator(); i.hasNext();) {
-            String name = (String) i.next()
-            classNames.add(name)
-        }
-
-        return classNames
-    }
-}
+package org.codehaus.groovy.tools.shell.util
 
+interface PackageHelper {
 
-class CachedPackage {
-    String name
-    boolean containsClasses
-    boolean checked
-    Map<String, CachedPackage> childPackages
-    Set<URL> sources
+    public static final String IMPORT_COMPLETION_PREFERENCE_KEY = 'disable-import-completion'
 
-    CachedPackage(String name, Set<URL> sources) {
-        this.sources = sources
-        this.name = name
-    }
+    Set<String> getContents(final String packagename)
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImpl.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImpl.groovy
new file mode 100644
index 0000000..616c3b0
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImpl.groovy
@@ -0,0 +1,454 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+import groovy.transform.CompileStatic
+
+import java.util.jar.JarEntry
+import java.util.jar.JarFile
+import java.util.prefs.PreferenceChangeEvent
+import java.util.prefs.PreferenceChangeListener
+import java.util.regex.Pattern
+import java.util.zip.ZipException
+
+/**
+ * Helper class that crawls all items of the classpath for packages.
+ * Retrieves from those sources the list of subpackages and classes on demand.
+ */
+class PackageHelperImpl implements PreferenceChangeListener, PackageHelper {
+
+    // Pattern for regular Classnames
+    public static final Pattern NAME_PATTERN = ~('^[A-Z][^.\$_]+\$')
+
+    private static final String CLASS_SUFFIX = '.class'
+    protected static final Logger LOG = Logger.create(PackageHelperImpl)
+
+    Map<String, CachedPackage> rootPackages = null
+    final ClassLoader groovyClassLoader
+
+    PackageHelperImpl(final ClassLoader groovyClassLoader=null) {
+        this.groovyClassLoader = groovyClassLoader
+        if (! Boolean.valueOf(Preferences.get(IMPORT_COMPLETION_PREFERENCE_KEY))) {
+            rootPackages = initializePackages(groovyClassLoader)
+        }
+        Preferences.addChangeListener(this)
+    }
+
+    @Override
+    void preferenceChange(final PreferenceChangeEvent evt) {
+        if (evt.key == IMPORT_COMPLETION_PREFERENCE_KEY) {
+            if (Boolean.valueOf(evt.getNewValue())) {
+                rootPackages = null
+            } else if (rootPackages == null) {
+                rootPackages = initializePackages(groovyClassLoader)
+            }
+        }
+    }
+
+    static Map<String, CachedPackage> initializePackages(final ClassLoader groovyClassLoader) throws IOException {
+        Map<String, CachedPackage> rootPackages = new HashMap()
+        Set<URL> urls = new HashSet<URL>()
+
+        // classes in CLASSPATH
+        for (ClassLoader loader = groovyClassLoader; loader != null; loader = loader.parent) {
+            if (!(loader instanceof URLClassLoader)) {
+                LOG.debug('Ignoring classloader for completion: ' + loader)
+                continue
+            }
+
+            urls.addAll(((URLClassLoader)loader).URLs)
+        }
+
+        // System classes
+        Class[] systemClasses = [String, javax.swing.JFrame, GroovyObject] as Class[]
+        boolean jigsaw = false
+        systemClasses.each { Class systemClass ->
+            // normal slash even in Windows
+            String classfileName = systemClass.name.replace('.', '/') + '.class'
+            URL classURL = systemClass.getResource(classfileName)
+            if (classURL == null) {
+                // this seems to work on Windows better than the earlier approach
+                classURL = Thread.currentThread().contextClassLoader.getResource(classfileName)
+            }
+            if (classURL != null) {
+                URLConnection uc = classURL.openConnection()
+                if (uc instanceof JarURLConnection) {
+                    urls.add(((JarURLConnection) uc).getJarFileURL())
+                } else if (uc.getClass().getSimpleName().equals("JavaRuntimeURLConnection")) {
+                    // Java 9 Jigsaw detected
+                    jigsaw = true
+                } else {
+                    String filepath = classURL.toExternalForm()
+                    String rootFolder = filepath.substring(0, filepath.length() - classfileName.length() - 1)
+                    urls.add(new URL(rootFolder))
+                }
+            }
+        }
+
+        for (URL url : urls) {
+            Collection<String> packageNames = getPackageNames(url)
+            if (packageNames) {
+                mergeNewPackages(packageNames, url, rootPackages)
+            }
+        }
+        if (jigsaw) {
+            Set<String> jigsawPackages = getPackagesAndClassesFromJigsaw()
+            mergeNewPackages(jigsawPackages,URI.create("jrt:/").toURL(), rootPackages)
+        }
+        return rootPackages
+    }
+
+    /**
+     * This method returns packages or classes listed from Jigsaw modules.
+     * It makes use of a GroovyShell in order to avoid a hard dependency
+     * to JDK 7+ when building the Groovysh module (uses nio2)
+     * @return
+     */
+    private static Set<String> getPackagesAndClassesFromJigsaw(Closure<Boolean> predicate = { isPackage, name -> isPackage && name }) {
+        def shell = new GroovyShell()
+        shell.setProperty('predicate', predicate)
+        shell.evaluate '''import java.nio.file.*
+
+def fs = FileSystems.newFileSystem(URI.create("jrt:/"), [:])
+
+result = [] as Set
+
+def filterPackageName(Path path) {
+    def elems = "$path".split('/')
+
+    if (elems) {
+        elems = elems[2..<elems.length]
+
+        def name = elems.join('.')
+        if (predicate(true,name)) {
+            result << name
+        }
+    }
+}
+
+def filterClassName(Path path) {
+    def elems = "$path".split('/')
+
+    if (elems) {
+        elems = elems[2..<elems.length]
+
+        def name = elems.join('.')
+        if (name.endsWith('.class')) {
+            name = name.substring(0,name.lastIndexOf('.'))
+            if (predicate(false,name)) {
+                result << name
+            }
+        }
+    }
+}
+
+fs.rootDirectories.each {
+    Files.walkFileTree(it,
+            [preVisitDirectory: { dir, attrs -> filterPackageName(dir); FileVisitResult.CONTINUE },
+             visitFile: { file, attrs -> filterClassName(file); FileVisitResult.CONTINUE}
+            ]
+                    as SimpleFileVisitor)
+}
+'''
+
+        Set<String> jigsawPackages = (Set<String>) shell.getProperty('result')
+
+        jigsawPackages
+    }
+
+    static mergeNewPackages(final Collection<String> packageNames, final URL url,
+                            final Map<String, CachedPackage> rootPackages) {
+        StringTokenizer tokenizer
+        packageNames.each { String packname ->
+            tokenizer = new StringTokenizer(packname, '.')
+            if (!tokenizer.hasMoreTokens()) {
+                return
+            }
+            String rootname = tokenizer.nextToken()
+            CachedPackage cp
+            CachedPackage childp
+            cp = rootPackages.get(rootname, null) as CachedPackage
+            if (cp == null) {
+                cp = new CachedPackage(rootname, [url] as Set)
+                rootPackages.put(rootname, cp)
+            }
+
+            while(tokenizer.hasMoreTokens()) {
+                String packbasename = tokenizer.nextToken()
+                if (cp.childPackages == null) {
+                    // small initial size, to save memory
+                    cp.childPackages = new HashMap<String, CachedPackage>(1)
+                }
+                childp = cp.childPackages.get(packbasename, null) as CachedPackage
+                if (childp == null) {
+                    // start with small arraylist, to save memory
+                    Set<URL> urllist = new HashSet<URL>(1)
+                    urllist.add(url)
+                    childp = new CachedPackage(packbasename, urllist)
+                    cp.childPackages.put(packbasename, childp)
+                } else {
+                    childp.sources.add(url)
+                }
+                cp = childp
+            }
+        }
+    }
+
+    /**
+     * Returns all packagenames found at URL, accepts jar files and folders
+     * @param url
+     * @return
+     */
+    static Collection<String> getPackageNames(final URL url) {
+        //log.debug(url)
+        String path = URLDecoder.decode(url.getFile(), 'UTF-8')
+        File urlfile = new File(path)
+        if (urlfile.isDirectory()) {
+            Set<String> packnames = new HashSet<String>()
+            collectPackageNamesFromFolderRecursive(urlfile, '', packnames)
+            return packnames
+        }
+
+        if (urlfile.path.endsWith('.jar')) {
+            try {
+                JarFile jf = new JarFile(urlfile)
+                return getPackageNamesFromJar(jf)
+            } catch(ZipException ze) {
+                if (LOG.debugEnabled) {
+                    ze.printStackTrace()
+                }
+                LOG.debug("Error opening zipfile : '${url.getFile()}',  ${ze.toString()}")
+            } catch (FileNotFoundException fnfe) {
+                LOG.debug("Error opening file : '${url.getFile()}',  ${fnfe.toString()}")
+            }
+        }
+        return []
+    }
+
+    /**
+     * Crawls a folder, iterates over subfolders, looking for class files.
+     * @param directory
+     * @param prefix
+     * @param packnames
+     * @return
+     */
+    static Collection<String> collectPackageNamesFromFolderRecursive(final File directory, final String prefix,
+                                                                     final Set<String> packnames) {
+        //log.debug(directory)
+        File[] files = directory.listFiles()
+        boolean packageAdded = false
+
+        for (int i = 0; (files != null) && (i < files.length); i++) {
+            if (files[i].isDirectory()) {
+                if (files[i].name.startsWith('.')) {
+                    return
+                }
+                String optionalDot = prefix ? '.' : ''
+                collectPackageNamesFromFolderRecursive(files[i], prefix + optionalDot + files[i].name, packnames)
+            } else if (! packageAdded) {
+                if (files[i].name.endsWith(CLASS_SUFFIX)) {
+                    packageAdded = true
+                    if (prefix) {
+                        packnames.add(prefix)
+                    }
+                }
+            }
+        }
+    }
+
+
+    static Collection<String> getPackageNamesFromJar(final JarFile jf) {
+        Set<String> packnames = new HashSet<String>()
+        for (Enumeration e = jf.entries(); e.hasMoreElements();) {
+            JarEntry entry = (JarEntry) e.nextElement()
+
+            if (entry == null) {
+                continue
+            }
+
+            String name = entry.name
+
+            if (!name.endsWith(CLASS_SUFFIX)) {
+                // only use class files
+                continue
+            }
+            // normal slashes also on Windows
+            String fullname = name.replace('/', '.').substring(0, name.length() - CLASS_SUFFIX.length())
+            // Discard classes in the default package
+            if (fullname.lastIndexOf('.') > -1) {
+                packnames.add(fullname.substring(0, fullname.lastIndexOf('.')))
+            }
+        }
+        return packnames
+    }
+
+    // following block does not work, because URLClassLoader.packages only ever returns SystemPackages
+    /*static Collection<String> getPackageNames(URL url) {
+        URLClassLoader urlLoader = new URLClassLoader([url] as URL[])
+        //log.debug(urlLoader.packages.getClass())
+
+        urlLoader.getPackages().collect {Package pack ->
+            pack.name
+        }
+    }*/
+
+    /**
+     * returns the names of Classes and direct subpackages contained in a package
+     * @param packagename
+     * @return
+     */
+    @CompileStatic
+    Set<String> getContents(final String packagename) {
+        if (! rootPackages) {
+            return [] as Set
+        }
+        if (! packagename) {
+            return rootPackages.collect { String key, CachedPackage v -> key } as Set
+        }
+        String sanitizedPackageName
+        if (packagename.endsWith('.*')) {
+            sanitizedPackageName = packagename[0..-3]
+        } else {
+            sanitizedPackageName = packagename
+        }
+
+        StringTokenizer tokenizer = new StringTokenizer(sanitizedPackageName, '.')
+        CachedPackage cp = rootPackages.get(tokenizer.nextToken())
+        while (cp != null && tokenizer.hasMoreTokens()) {
+            String token = tokenizer.nextToken()
+            if (cp.childPackages == null) {
+                // no match for taken,no subpackages known
+                return [] as Set
+            }
+            cp = cp.childPackages.get(token) as CachedPackage
+        }
+        if (cp == null) {
+            return [] as Set
+        }
+        // TreeSet for ordering
+        Set<String> children = new TreeSet()
+        if (cp.childPackages) {
+            children.addAll(cp.childPackages.collect { String key, CachedPackage v -> key })
+        }
+        if (cp.checked && !cp.containsClasses) {
+            return children
+        }
+
+        Set<String> classnames = getClassnames(cp.sources, sanitizedPackageName)
+
+        cp.checked = true
+        if (classnames) {
+            cp.containsClasses = true
+            children.addAll(classnames)
+        }
+        return children
+    }
+
+    /**
+     * Copied from JLine 1.0 ClassNameCompletor
+     * @param urls
+     * @param packagename
+     * @return
+     */
+    @CompileStatic
+    static Set<String> getClassnames(final Set<URL> urls, final String packagename) {
+        Set<String> classes = new TreeSet<String>()
+        // normal slash even in Windows
+        String pathname = packagename.replace('.', '/')
+        for (Iterator it = urls.iterator(); it.hasNext();) {
+            URL url = (URL) it.next()
+            if (url.protocol=='jrt') {
+                getPackagesAndClassesFromJigsaw { boolean isPackage, String name ->
+                    !isPackage && name.startsWith(packagename)
+                }.collect(classes) { it - "${packagename}." }
+            } else {
+                File file = new File(URLDecoder.decode(url.getFile(), 'UTF-8'))
+                if (file == null) {
+                    continue
+                }
+                if (file.isDirectory()) {
+                    File packFolder = new File(file, pathname)
+                    if (!packFolder.isDirectory()) {
+                        continue
+                    }
+                    File[] files = packFolder.listFiles()
+                    for (int i = 0; (files != null) && (i < files.length); i++) {
+                        if (files[i].isFile()) {
+                            String filename = files[i].name
+                            if (filename.endsWith(CLASS_SUFFIX)) {
+                                String name = filename.substring(0, filename.length() - CLASS_SUFFIX.length())
+                                if (!name.matches(NAME_PATTERN)) {
+                                    continue
+                                }
+                                classes.add(name)
+                            }
+                        }
+                    }
+                    continue
+                }
+
+                if (!file.toString().endsWith('.jar')) {
+                    continue
+                }
+
+                JarFile jf = new JarFile(file)
+
+                for (Enumeration e = jf.entries(); e.hasMoreElements();) {
+                    JarEntry entry = (JarEntry) e.nextElement()
+
+                    if (entry == null) {
+                        continue
+                    }
+
+                    String name = entry.name
+
+                    // only use class files
+                    if (!name.endsWith(CLASS_SUFFIX)) {
+                        continue
+                    }
+                    // normal slash inside jars even on windows
+                    int lastslash = name.lastIndexOf('/')
+                    if (lastslash == -1 || name.substring(0, lastslash) != pathname) {
+                        continue
+                    }
+                    name = name.substring(lastslash + 1, name.length() - CLASS_SUFFIX.length())
+                    if (!name.matches(NAME_PATTERN)) {
+                        continue
+                    }
+                    classes.add(name)
+                }
+            }
+        }
+
+
+        return classes
+    }
+}
+
+
+class CachedPackage {
+    String name
+    boolean containsClasses
+    boolean checked
+    Map<String, CachedPackage> childPackages
+    Set<URL> sources
+
+    CachedPackage(String name, Set<URL> sources) {
+        this.sources = sources
+        this.name = name
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzer.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzer.groovy
new file mode 100644
index 0000000..d2cbd68
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzer.groovy
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+import groovy.transform.TypeChecked
+import org.codehaus.groovy.ast.ClassCodeVisitorSupport
+import org.codehaus.groovy.ast.ClassNode
+import org.codehaus.groovy.ast.DynamicVariable
+import org.codehaus.groovy.ast.GroovyClassVisitor
+import org.codehaus.groovy.ast.expr.VariableExpression
+import org.codehaus.groovy.classgen.GeneratorContext
+import org.codehaus.groovy.control.*
+
+import java.security.CodeSource
+
+/**
+ * Class to Class parsing a script to detect all bound and unbound variables.
+ * Based on http://glaforge.appspot.com/article/knowing-which-variables-are-bound-or-not-in-a-groovy-script
+ */
+ at TypeChecked
+class ScriptVariableAnalyzer {
+
+    /**
+     * define a visitor that visits all variable expressions
+     */
+    static class VariableVisitor extends ClassCodeVisitorSupport implements GroovyClassVisitor {
+        Set<String> bound = new HashSet<String>()
+        Set<String> unbound = new HashSet<String>()
+
+        @Override
+        void visitVariableExpression(VariableExpression expression) {
+            // we're not interested in some special implicit variables
+            if (!(expression.variable in ['args', 'context', 'this', 'super'])) {
+                // thanks to this instanceof
+                // we know if the variable is bound or not
+                if (expression.accessedVariable instanceof DynamicVariable) {
+                    unbound << expression.variable
+                } else {
+                    bound << expression.variable
+                }
+            }
+            super.visitVariableExpression(expression)
+        }
+
+        @Override
+        protected SourceUnit getSourceUnit() {
+            return null
+        }
+    }
+
+    /**
+     * custom PrimaryClassNodeOperation
+     * to be able to hook our code visitor
+     */
+    static class VisitorSourceOperation extends CompilationUnit.PrimaryClassNodeOperation {
+
+        final GroovyClassVisitor visitor
+
+        VisitorSourceOperation(final GroovyClassVisitor visitor) {
+            this.visitor = visitor
+        }
+
+        @Override
+        void call(final SourceUnit source, final GeneratorContext context, final ClassNode classNode)
+                throws CompilationFailedException {
+            classNode.visitContents(visitor)
+        }
+    }
+
+    /**
+     * class loader to add our phase operation
+     */
+    static class VisitorClassLoader extends GroovyClassLoader {
+        final GroovyClassVisitor visitor
+
+        VisitorClassLoader(final GroovyClassVisitor visitor) {
+            this.visitor = visitor
+        }
+
+        @Override
+        protected CompilationUnit createCompilationUnit(final CompilerConfiguration config, final CodeSource source) {
+            CompilationUnit cu = super.createCompilationUnit(config, source)
+            cu.addPhaseOperation(new VisitorSourceOperation(visitor), Phases.CLASS_GENERATION)
+            return cu
+        }
+    }
+
+    static Set<String> getBoundVars(final String scriptText) {
+        assert scriptText != null
+        GroovyClassVisitor visitor = new VariableVisitor()
+        VisitorClassLoader myCL = new VisitorClassLoader(visitor)
+        // simply by parsing the script with our classloader
+        // our visitor will be called and will visit all the variables
+        myCL.parseClass(scriptText)
+        return visitor.bound
+    }
+
+}
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/SimpleCompletor.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/SimpleCompletor.groovy
index 7cf4f28..74a1e37 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/SimpleCompletor.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/SimpleCompletor.groovy
@@ -25,114 +25,114 @@ import org.codehaus.groovy.runtime.InvokerHelper
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  */
-public class SimpleCompletor implements Completer {
+class SimpleCompletor implements Completer {
 
-    SortedSet candidates;
+    SortedSet<String> candidates
 
     /**
     * A delimiter to use to qualify completions.
     */
-    String delimiter;
+    String delimiter
 
 
-    public SimpleCompletor(final String[] candidates) {
-        setCandidateStrings(candidates);
+    SimpleCompletor(final String[] candidates) {
+        setCandidateStrings(candidates)
     }
-    
-    public SimpleCompletor() {
-        this(new String[0]);
+
+    SimpleCompletor() {
+        this(new String[0])
     }
-    
-    public SimpleCompletor(final Closure loader) {
-        this();
-        
-        assert loader != null;
-        
-        Object obj = loader.call();
-        
-        List list = null;
-        
+
+    SimpleCompletor(final Closure loader) {
+        this()
+
+        assert loader != null
+
+        Object obj = loader.call()
+
+        List list = null
+
         if (obj instanceof List) {
-            list = (List)obj;
+            list = (List) obj
         }
-        
+
         //
         // TODO: Maybe handle arrays too?
         //
-        
+
         if (list == null) {
-            throw new IllegalStateException("The loader closure did not return a list of candidates; found: " + obj);
+            throw new IllegalStateException('The loader closure did not return a list of candidates; found: ' + obj)
         }
 
-        Iterator iter = list.iterator();
+        Iterator iter = list.iterator()
 
         while (iter.hasNext()) {
-            add(InvokerHelper.toString(iter.next()));
+            add(InvokerHelper.toString(iter.next()))
         }
     }
 
-    public void add(final String candidate) {
-        addCandidateString(candidate);
+    void add(final String candidate) {
+        addCandidateString(candidate)
     }
 
-    public Object leftShift(final String s) {
-        add(s);
+    Object leftShift(final String s) {
+        add(s)
 
-        return null;
+        return null
     }
 
     //
     // NOTE: Duplicated (and augmented) from JLine sources to make it call getCandidates() to make the list more dynamic
     //
+    @Override
+    int complete(final String buffer, final int cursor, final List<CharSequence> clist) {
+        String start = (buffer == null) ? '' : buffer
 
-    public int complete(final String buffer, final int cursor, final List clist) {
-        String start = (buffer == null) ? "" : buffer;
-
-        SortedSet matches = getCandidates().tailSet(start);
+        SortedSet<String> matches = getCandidates().tailSet(start)
 
         for (Iterator i = matches.iterator(); i.hasNext();) {
-            String can = (String) i.next();
+            String can = (String) i.next()
 
             if (!(can.startsWith(start))) {
-                break;
+                break
             }
-            
-            String delim = getDelimiter();
-            
+
+            String delim = delimiter
+
             if (delim != null) {
-                int index = can.indexOf(delim, cursor);
+                int index = can.indexOf(delim, cursor)
 
                 if (index != -1) {
-                    can = can.substring(0, index + 1);
+                    can = can.substring(0, index + 1)
                 }
             }
 
-            clist.add(can);
+            clist.add(can)
         }
 
         if (clist.size() == 1) {
-            clist.set(0, ((String) clist.get(0)) + " ");
+            clist.set(0, ((String) clist.get(0)) + ' ')
         }
 
         // the index of the completion is always from the beginning of the buffer.
-        return (clist.size() == 0) ? (-1) : 0;
+        return (clist.size() == 0) ? (-1) : 0
     }
 
-    public void setCandidates(final SortedSet candidates) {
+    void setCandidates(final SortedSet<String> candidates) {
         this.candidates = candidates
     }
 
-    public SortedSet getCandidates() {
+    SortedSet<String> getCandidates() {
         return Collections.unmodifiableSortedSet(this.candidates)
     }
 
-    public void setCandidateStrings(final String[] strings) {
+    void setCandidateStrings(final String[] strings) {
         setCandidates(new TreeSet(Arrays.asList(strings)))
     }
 
-    public void addCandidateString(final String string) {
+    void addCandidateString(final String string) {
         if (string != null) {
-            candidates.add(string);
+            candidates.add(string)
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStream.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStream.groovy
index 429ab1e..962b3e0 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStream.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStream.groovy
@@ -20,36 +20,36 @@ package org.codehaus.groovy.tools.shell.util
  * In order to modify JLine Behavior, we need to wrap the IO streams so we can hack into them
  * This allows autoindent and redisplaying the chars typed so far after exceptions during completion
  */
-class WrappedInputStream extends InputStream {
+class WrappedInputStream extends InputStream implements Closeable {
 
-    InputStream wrapped;
+    final InputStream wrapped
     // observed sometimes ClassNotFoundException when not qualifying with java.io
-    java.io.ByteArrayInputStream inserted = new java.io.ByteArrayInputStream();
-    protected final Logger log = Logger.create(WrappedInputStream)
+    java.io.ByteArrayInputStream inserted = new java.io.ByteArrayInputStream()
+
 
     /**
      * Construct a new IO container using system streams.
      */
-    public WrappedInputStream(InputStream wrapped) {
+    WrappedInputStream(final InputStream wrapped) {
         super()
         this.wrapped = wrapped
     }
 
     @Override
-    int read() throws IOException {
+    int read() throws java.io.IOException {
         if (inserted != null && inserted.available() > 0) {
             return inserted.read()
         }
         return wrapped.read()
     }
 
-    public void insert(String chars) {
+    void insert(String chars) {
         inserted.close()
-        inserted = new ByteArrayInputStream(chars.getBytes("UTF-8"))
+        inserted = new java.io.ByteArrayInputStream(chars.getBytes('UTF-8'))
     }
 
     @Override
-    public int read(byte[] b) throws java.io.IOException {
+    int read(byte[] b) throws java.io.IOException {
         def insertb = inserted.read(b)
         if (insertb > 0) {
             return insertb
@@ -58,7 +58,7 @@ class WrappedInputStream extends InputStream {
     }
 
     @Override
-    public int read(byte[] b, int off, int len) throws java.io.IOException {
+    int read(byte[] b, int off, int len) throws java.io.IOException {
         def insertb = inserted.read(b, off, len)
         if (insertb > 0) {
             return insertb
@@ -67,7 +67,7 @@ class WrappedInputStream extends InputStream {
     }
 
     @Override
-    public long skip(long n) throws java.io.IOException {
+    long skip(long n) throws java.io.IOException {
         def skipb = inserted.skip(n)
         if (skipb > 0) {
             return skipb
@@ -76,7 +76,7 @@ class WrappedInputStream extends InputStream {
     }
 
     @Override
-    public int available() throws java.io.IOException {
+    int available() throws java.io.IOException {
         int x = inserted.available()
         if (x > 0) {
             return x
@@ -85,23 +85,23 @@ class WrappedInputStream extends InputStream {
     }
 
     @Override
-    public void close() throws java.io.IOException {
+    void close() throws java.io.IOException {
         wrapped.close()
         inserted.close()
     }
 
     @Override
-    public synchronized void mark(int readlimit) {
+    synchronized void mark(int readlimit) {
         throw new UnsupportedOperationException()
     }
 
     @Override
-    public synchronized void reset() throws java.io.IOException {
+    synchronized void reset() throws java.io.IOException {
         throw new UnsupportedOperationException()
     }
 
     @Override
-    public boolean markSupported() {
+    boolean markSupported() {
         return false
     }
 }
diff --git a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/XmlCommandRegistrar.groovy b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/XmlCommandRegistrar.groovy
index 55c425c..e8358bb 100644
--- a/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/XmlCommandRegistrar.groovy
+++ b/subprojects/groovy-groovysh/src/main/groovy/org/codehaus/groovy/tools/shell/util/XmlCommandRegistrar.groovy
@@ -21,10 +21,33 @@ import org.codehaus.groovy.tools.shell.Command
 
 /**
  * Registers {@link Command} classes from an XML file like:
- * <commands>
- *  <command>org.codehaus.groovy.tools.shell.commands.HelpCommand</command>
- * ...
- * </commands>
+ *
+ * <pre>
+  {@literal
+ <commands>
+   <!-- default commands -->
+   <command>org.codehaus.groovy.tools.shell.commands.HelpCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.ExitCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.ImportCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.DisplayCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.ClearCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.ShowCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.InspectCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.PurgeCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.EditCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.LoadCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.SaveCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.RecordCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.HistoryCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.AliasCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.SetCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.ShadowCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.RegisterCommand</command>
+   <command>org.codehaus.groovy.tools.shell.commands.DocCommand</command>
+   <!-- custom commands -->
+ </commands>
+ * }
+ * <pre>
  *
  * @version $Id$
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
@@ -32,40 +55,40 @@ import org.codehaus.groovy.tools.shell.Command
 class XmlCommandRegistrar
 {
     private final Logger log = Logger.create(this.class)
-    
+
     private final Shell shell
-    
+
     private final ClassLoader classLoader
-    
+
     XmlCommandRegistrar(final Shell shell, final ClassLoader classLoader) {
         assert shell != null
         assert classLoader != null
-        
+
         this.shell = shell
         this.classLoader = classLoader
     }
-    
+
     void register(final URL url) {
         assert url
-        
+
         if (log.debugEnabled) {
             log.debug("Registering commands from: $url")
         }
-        
+
         url.withReader {Reader reader ->
             groovy.util.Node doc = new groovy.util.XmlParser().parse(reader)
 
             doc.children().each {groovy.util.Node element ->
                 String classname = element.text()
-                
+
                 Class type = classLoader.loadClass(classname)
-                
+
                 Command command = type.newInstance(shell) as Command
-                
+
                 if (log.debugEnabled) {
                     log.debug("Created command '${command.name}': $command")
                 }
-                
+
                 shell << command
             }
         }
diff --git a/subprojects/groovy-groovysh/src/main/resources/org/codehaus/groovy/tools/shell/Main.properties b/subprojects/groovy-groovysh/src/main/resources/org/codehaus/groovy/tools/shell/Main.properties
index 8cfc4b7..cf2bde1 100644
--- a/subprojects/groovy-groovysh/src/main/resources/org/codehaus/groovy/tools/shell/Main.properties
+++ b/subprojects/groovy-groovysh/src/main/resources/org/codehaus/groovy/tools/shell/Main.properties
@@ -32,6 +32,8 @@ cli.option.quiet.description=Suppress superfluous output
 
 cli.option.debug.description=Enable debug output
 
+cli.option.evaluate.description=Evaluate option fist when starting interactive session
+
 cli.option.cp.description=Aliases for '-classpath'
 
 cli.option.classpath.description=Specify where to find the class files - must be first argument
@@ -42,4 +44,4 @@ cli.option.define.description=Define a system property
 
 cli.option.terminal.description=Specify the terminal TYPE to use
 
-cli.info.version=@|green Groovy Shell|@ {0}
\ No newline at end of file
+cli.info.version=@|green Groovy Shell|@ {0}
diff --git a/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
new file mode 100644
index 0000000..1fcd310
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/spec/doc/groovysh.adoc
@@ -0,0 +1,586 @@
+= Groovysh, the Groovy shell
+
+== Groovy : Groovy Shell
+
+The Groovy Shell, aka. `groovysh` is a command-line application which
+allows easy access to evaluate Groovy expressions, define classes and
+run simple experiments.
+
+[[GroovyShell-Features]]
+=== Features
+
+* No need for `go` command to execute buffer.
+* Rich cross-platform edit-line editing, history and completion thanks
+to https://github.com/jline/jline2[JLine2].
+* ANSI colors (prompt, exception traces, etc).
+* Simple, yet robust, command system with online help, user alias
+support and more.
+* User profile support
+
+[[GroovyShell-Command-lineOptionsandArguments]]
+=== Command-line Options and Arguments
+
+The shell supports several options to control verbosity, ANSI coloring
+and other features.
+
+[source,groovy]
+-----------------------------------------------------------------
+./bin/groovysh --help
+usage: groovysh [options] [...]
+  -C, --color[=FLAG]         Enable or disable use of ANSI colors
+  -D, --define=NAME=VALUE    Define a system property
+  -T, --terminal=TYPE        Specify the terminal TYPE to use
+  -V, --version              Display the version
+  -classpath                 Specify where to find the class files - must
+                             be first argument
+  -cp, --classpath           Aliases for '-classpath'
+  -d, --debug                Enable debug output
+  -e, --evaluate=arg         Evaluate option fist when starting
+                             interactive session
+  -h, --help                 Display this help message
+  -q, --quiet                Suppress superfluous output
+  -v, --verbose              Enable verbose output
+-----------------------------------------------------------------
+
+[[GroovyShell-EvaluatingExpressions]]
+=== Evaluating Expressions
+
+[[GroovyShell-SimpleExpressions]]
+==== Simple Expressions
+
+[source,groovy]
+---------------
+println "Hello"
+---------------
+
+[[GroovyShell-EvaluationResult]]
+==== Evaluation Result
+
+When a complete expression is found, it is compiled and evaluated. The
+result of the evaluation is stored into the _ variable.
+
+[[GroovyShell-Multi-lineExpressions]]
+==== Multi-line Expressions
+
+Multi-line/complex expressions (like closure or class definitions) may
+be defined over several lines. When the shell detects that it has a
+complete expression it will compile and evaluate it.
+
+[[GroovyShell-DefineaClass]]
+===== Define a Class
+
+[source,groovy]
+---------------------
+class Foo {
+    def bar() {
+        println "baz"
+    }
+}
+---------------------
+
+[[GroovyShell-UsetheClass]]
+===== Use the Class
+
+[source,groovy]
+---------------
+foo = new Foo()
+foo.bar()
+---------------
+
+[[GroovyShell-Variables]]
+==== Variables
+
+Shell variables are *all* untyped (i.e. no `def` or other type information).
+
+This *will* set a shell variable:
+
+[source,groovy]
+-----------
+foo = "bar"
+-----------
+
+But, this will evaluate a local variable and will *not* be saved to the shell’s environment:
+
+[source,groovy]
+---------------
+def foo = "bar"
+---------------
+
+This behavior can be changed by activating <<GroovyShell-InterpreterMode,interpreter mode>>.
+
+[[GroovyShell-Functions]]
+==== Functions
+
+Functions can be defined in the shell, and will be saved for later use.
+
+Defining a function is easy:
+
+[source,groovy]
+----------------------------------
+groovy:000> def hello(name) {
+groovy:001> println("Hello $name")
+groovy:002> }
+----------------------------------
+
+And then using it is as one might expect:
+
+[source,groovy]
+--------------
+hello("Jason")
+--------------
+
+Internally the shell creates a closure to encapsulate the function and
+then binds the closure to a variable. So variables and functions share
+the same namespace.
+
+[[GroovyShell-Commands]]
+=== Commands
+
+The shell has a number of different commands, which provide rich access
+to the shell’s environment.
+
+Commands all have a _name_ and a _shortcut_ (which is something like
+`\h`). Commands may also have some predefined system _aliases_. Users
+may also create their own aliases.
+
+[[GroovyShell-RecognizedCommands]]
+==== Recognized Commands
+
+[[GroovyShell-help]]
+===== `help`
+
+Display the list of commands (and aliases) or the help text for specific command.
+
+[[GroovyShell-TheCommandList]]
+The Command List
+
+----------------------------------------------------------------------------------
+groovy:000> :help
+
+For information about Groovy, visit:
+    http://groovy-lang.org
+
+Available commands:
+  :help      (:h ) Display this help message
+  ?          (:? ) Alias to: :help
+  :exit      (:x ) Exit the shell
+  :quit      (:q ) Alias to: :exit
+  import     (:i ) Import a class into the namespace
+  :display   (:d ) Display the current buffer
+  :clear     (:c ) Clear the buffer and reset the prompt counter.
+  :show      (:S ) Show variables, classes or imports
+  :inspect   (:n ) Inspect a variable or the last result with the GUI object browser
+  :purge     (:p ) Purge variables, classes, imports or preferences
+  :edit      (:e ) Edit the current buffer
+  :load      (:l ) Load a file or URL into the buffer
+  .          (:. ) Alias to: :load
+  :save      (:s ) Save the current buffer to a file
+  :record    (:r ) Record the current session to a file
+  :history   (:H ) Display, manage and recall edit-line history
+  :alias     (:a ) Create an alias
+  :set       (:= ) Set (or list) preferences
+  :register  (:rc) Registers a new command with the shell
+  :doc       (:D ) Opens a browser window displaying the doc for the argument
+
+For help on a specific command type:
+    :help <command>
+----------------------------------------------------------------------------------
+
+[[GroovyShell-HelpforaCommand]]
+Help for a Command
+
+While in the interactive shell, you can ask for help for any command to
+get more details about its syntax or function. Here is an example of
+what happens when you ask for help for the `help` command:
+
+------------------------------------------------------------
+groovy:000> :help :help
+
+usage: :help [<command>]
+
+Display the list of commands or the help text for <command>.
+------------------------------------------------------------
+
+[[GroovyShell-exit]]
+===== `exit`
+
+Exit the shell.
+
+This is the *only* way to exit the shell. Well, you can still `CTRL-C`,
+but the shell will complain about an abnormal shutdown of the JVM.
+
+[[GroovyShell-import]]
+===== `import`
+
+Add a custom import which will be included for all shell evaluations.
+
+This command can be given at any time to add new imports.
+
+[[GroovyShell-display]]
+===== `display`
+
+Display the contents of the current buffer.
+
+This only displays the buffer of an incomplete expression. Once the
+expression is complete, the buffer is rest. The prompt will update to
+show the size of the current buffer as well.
+
+[[GroovyShell-Example]]
+Example
+
+-----------------------
+groovy:000> class Foo {
+groovy:001> def bar
+groovy:002> def baz() {
+groovy:003> display
+ 001> class Foo {
+ 002> def bar
+ 003> def baz() {
+-----------------------
+
+[[GroovyShell-clear]]
+===== `clear`
+
+Clears the current buffer, resetting the prompt counter to 000. Can be used to recover from compilation errors.
+
+[[GroovyShell-show]]
+===== `show`
+
+Show variables, classes or preferences or imports.
+
+[[GroovyShell-showvariables]]
+`show variables`
+
+--------------------------
+groovy:000> :show variables
+Variables:
+  _ = true
+--------------------------
+
+[[GroovyShell-showclasses]]
+`show classes`
+
+[[GroovyShell-showimports]]
+`show imports`
+
+[[GroovyShell-showpreferences]]
+`show preferences`
+
+[[GroovyShell-showall]]
+`show all`
+
+[[GroovyShell-inspect]]
+===== `inspect`
+
+Opens the GUI object browser to inspect a variable or the result of the
+last evaluation.
+
+[[GroovyShell-purge]]
+===== `purge`
+
+Purges objects from the shell.
+
+[[GroovyShell-purgevariables]]
+`purge variables`
+
+[[GroovyShell-purgeclasses]]
+`purge classes`
+
+[[GroovyShell-purgeimports]]
+`purge imports`
+
+[[GroovyShell-purgepreferences]]
+`purge preferences`
+
+[[GroovyShell-purgeall]]
+`purge all`
+
+[[GroovyShell-edit]]
+===== `edit`
+
+Edit the current buffer in an external editor.
+
+Currently only works on UNIX systems which have the `EDITOR` environment
+variable set, or have configured the `editor` preference.
+
+[[GroovyShell-load]]
+===== `load`
+
+Load one or more files (or urls) into the buffer.
+
+[[GroovyShell-save]]
+===== `save`
+
+Saves the buffer’s contents to a file.
+
+[[GroovyShell-record]]
+===== `record`
+
+Record the current session to a file.
+
+[[GroovyShell-recordstart]]
+`record start`
+
+[[GroovyShell-recordstop]]
+`record stop`
+
+[[GroovyShell-recordstatus]]
+`record status`
+
+[[GroovyShell-history]]
+===== `history`
+
+Display, manage and recall edit-line history.
+
+[[GroovyShell-historyshow]]
+`history show`
+
+[[GroovyShell-historyrecall]]
+`history recall`
+
+[[GroovyShell-historyflush]]
+`history flush`
+
+[[GroovyShell-historyclear]]
+`history clear`
+
+[[GroovyShell-alias]]
+===== `alias`
+
+Create an alias.
+
+[[GroovyShell-doc]]
+===== `doc`
+
+Opens a browser with documentation for the provided class. For example:
+
+----
+groovy:000> :doc java.util.List
+http://docs.oracle.com/javase/7/docs/api/java/util/List.html
+http://docs.groovy-lang.org/2.4.2-SNAPSHOT/html/groovy-jdk/java/util/List.html
+----
+
+will open two windows (or tabs, depending on your browser):
+
+* one for the JDK documentation
+* one for the GDK documentation
+
+[[GroovyShell-set]]
+===== `set`
+
+Set or list preferences.
+
+[[GroovyShell-Preferences]]
+=== Preferences
+
+Some of aspects of `groovysh` behaviors can be customized by setting
+preferences. Preferences are set using the `set` command or the `\=`
+shortcut.
+
+[[GroovyShell-RecognizedPreferences]]
+==== Recognized Preferences
+
+[[GroovyShell-InterpreterMode]]
+===== `interpreterMode`
+
+Allows the use of typed variables (i.e. `def` or other type information):
+
+----
+groovy:000> def x = 3
+===> 3
+groovy:000> x
+===> 3
+----
+
+It's especially useful for copy&pasting code from tutorials etc. into the running session.
+
+[[GroovyShell-verbosity]]
+===== `verbosity`
+
+Set the shell’s verbosity level. Expected to be one of:
+
+* `DEBUG`
+* `VERBOSE`
+* `INFO`
+* `QUIET`
+
+Default is `INFO`.
+
+If this preference is set to an invalid value, then the previous setting
+will be used, or if there is none, then the preference is removed and
+the default is used.
+
+===== `colors`
+
+Set the shell’s use of colors.
+
+Default is `true`.
+
+[[GroovyShell-show-last-result]]
+===== `show-last-result`
+
+Show the last result after an execution.
+
+Default is `true`.
+
+[[GroovyShell-sanitize-stack-trace]]
+===== `sanitize-stack-trace`
+
+Sanitize (trim-down/filter) stack traces.
+
+Default is `true`.
+
+[[GroovyShell-editor]]
+===== `editor`
+
+Configures the editor used by the `edit` command.
+
+Default is the value of the system environment variable `EDITOR`.
+
+Mac OS XTo use TextEdit, the default text editor on Mac OS X, configure:
+set editor /Applications/TextEdit.app/Contents/MacOS/TextEdit
+
+[[GroovyShell-SettingaPreference]]
+==== Setting a Preference
+
+-------------------
+groovy:000> :set verbosity DEBUG
+-------------------
+
+[[GroovyShell-ListingPreferences]]
+==== Listing Preferences
+
+To list the current _set_ preferences (and their values):
+
+----------------
+groovy:000> :show preferences
+----------------
+
+Limitation: At the moment, there is no way to list all of the
+known/available preferences to be set.
+
+[[GroovyShell-ClearingPreferencesieResettingtoDefaults]]
+==== Clearing Preferences (i.e. Resetting to Defaults)
+
+-----------------
+groovy:000> :purge preferences
+-----------------
+
+[[GroovyShell-UserProfileScriptsandState]]
+=== User Profile Scripts and State
+
+[[GroovyShell-ProfileScripts]]
+==== Profile Scripts
+
+[[GroovyShell-HOMEgroovygroovyshprofile]]
+===== `$HOME/.groovy/groovysh.profile`
+
+This script, if it exists, is loaded when the shell starts up.
+
+[[GroovyShell-HOMEgroovygroovyshrc]]
+===== `$HOME/.groovy/groovysh.rc`
+
+This script, if it exists, is loaded when the shell enters interactive
+mode.
+
+[[GroovyShell-State]]
+==== State
+
+[[GroovyShell-HOMEgroovygroovyshhistory]]
+===== `$HOME/.groovy/groovysh.history`
+
+Edit-line history is stored in this file.
+
+[[GroovyShell-register]]
+=== Custom commands
+
+The `register` command allows you to register custom commands in the shell. For example, writing the following
+will register the `Stats` command:
+
+----
+groovy:000> :register Stats
+----
+
+where the `Stats` class is a class extending the `org.codehaus.groovy.tools.shell.CommandSupport` class. For example:
+
+[source,groovy]
+----
+import org.codehaus.groovy.tools.shell.CommandSupport
+import org.codehaus.groovy.tools.shell.Groovysh
+
+class Stats extends CommandSupport {
+    protected Stats(final Groovysh shell) {
+        super(shell, 'stats', 'T')
+    }
+
+    public Object execute(List args) {
+        println "Free memory: ${Runtime.runtime.freeMemory()}"
+    }
+
+}
+----
+
+Then the command can be called using:
+
+----
+groovy:000> :stats
+stats
+Free memory: 139474880
+groovy:000>
+----
+
+Note that the command class must be found on classpath: you cannot define a new command from within the shell.
+
+[[GroovyShell-Troubleshooting]]
+=== Troubleshooting
+
+Please http://jira.codehaus.org/browse/GROOVY[report] any problems you
+run into. Please be sure to mark the JIRA issue with the `Groovysh`
+component.
+
+[[GroovyShell-PlatformProblems]]
+==== Platform Problems
+
+[[GroovyShell-ProblemsloadingtheJLineDLL]]
+===== Problems loading the JLine DLL
+
+On Windows, https://github.com/jline/jline2[JLine2] (which is used for the fancy
+shell input/history/completion fluff), uses a *tiny* DLL file to trick
+the *evil* Windows faux-shell (`CMD.EXE` or `COMMAND.COM`) into
+providing Java with unbuffered input. In some rare cases, this might
+fail to load or initialize.
+
+One solution is to disable the frills and use the unsupported terminal
+instance. You can do that on the command-line using the `--terminal`
+flag and set it to one of:
+
+* `none`
+* `false`
+* `off`
+* `jline.UnsupportedTerminal`
+
+------------------------
+groovysh --terminal=none
+------------------------
+
+[[GroovyShell-ProblemswithCygwinonWindows]]
+===== Problems with Cygwin on Windows
+
+Some people have issues when running groovysh with cygwin. If you have
+troubles, the following may help:
+
+------------------------
+stty -icanon min 1 -echo
+groovysh --terminal=unix
+stty icanon echo
+------------------------
+
+[[GroovyShell-GMavenPlus]]
+== GMavenPlus Maven Plugin
+https://github.com/groovy/GMavenPlus[GMavenPlus] is a Maven plugin with goals
+that support launching a Groovy Shell or Groovy Console bound to a Maven
+project.
+
+[[GroovyShell-GradleGroovyshPlugin]]
+== Gradle Groovysh Plugin
+https://github.com/tkruse/gradle-groovysh-plugin[Gradle Groovysh Plugin] is a Gradle plugin that provides gradle tasks to start a Groovy Shell bound to a Gradle project.
\ No newline at end of file
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/AllCompletorsTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/AllCompletorsTest.groovy
index 03fbc1b..af38460 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/AllCompletorsTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/AllCompletorsTest.groovy
@@ -33,10 +33,10 @@ import org.codehaus.groovy.tools.shell.commands.ShowCommand
  */
 class AllCompletorsTest extends GroovyTestCase {
 
-    IO testio
-    BufferedOutputStream mockOut
-    BufferedOutputStream mockErr
-    List<Completer> completers
+    private IO testio
+    private BufferedOutputStream mockOut
+    private BufferedOutputStream mockErr
+    private List<Completer> completers
 
     /**
      * code copied from Jline console Handler,
@@ -47,32 +47,33 @@ class AllCompletorsTest extends GroovyTestCase {
      *
      */
     private List complete(String buffer, cursor) throws IOException {
-        // debug ("tab for (" + buf + ")");
+        // debug ("tab for (" + buf + ")")
         if (completers.size() == 0) {
-            return null;
+            return []
         }
-        List candidates = new LinkedList();
-        String bufstr = buffer;
-        int position = -1;
+        List candidates = new LinkedList()
+        String bufstr = buffer
+        int position = -1
         for (Completer comp : completers) {
             if ((position = comp.complete(bufstr, cursor, candidates)) != -1) {
-                break;
+                break
             }
         }
         // no candidates? Fail.
         if (candidates.size() == 0) {
-            return null;
+            return []
         }
         return [candidates, position]
     }
 
+    @Override
     void setUp() {
         super.setUp()
         mockOut = new BufferedOutputStream(
-                new ByteArrayOutputStream());
+                new ByteArrayOutputStream())
 
         mockErr = new BufferedOutputStream(
-                new ByteArrayOutputStream());
+                new ByteArrayOutputStream())
 
         testio = new IO(
                 new ByteArrayInputStream(),
@@ -82,7 +83,7 @@ class AllCompletorsTest extends GroovyTestCase {
 
         Groovysh groovysh = new Groovysh(testio)
 
-        def filemock = new File("aaaa") {
+        def filemock = new File('aaaa') {
             @Override
             boolean delete() {
                 return true
@@ -94,76 +95,76 @@ class AllCompletorsTest extends GroovyTestCase {
             }
         }
         groovysh.history = new FileHistory(filemock)
-        InteractiveShellRunner shellRun = new InteractiveShellRunner(groovysh, { ">"})
+        InteractiveShellRunner shellRun = new InteractiveShellRunner(groovysh, { '>'})
         // setup completers in run()
         shellRun.run()
-        completers = shellRun.reader.getCompleters()
+        completers = shellRun.reader.completers
     }
 
     void testEmpty() {
-        def result = complete("", 0)
-        assertTrue(HelpCommand.COMMAND_NAME in result[0])
-        assertTrue(ExitCommand.COMMAND_NAME in result[0])
-        assertTrue('import' in result[0])
-        assertTrue(ShowCommand.COMMAND_NAME in result[0])
-        assertTrue(SetCommand.COMMAND_NAME in result[0])
-        assertTrue(InspectCommand.COMMAND_NAME in result[0])
-        assertTrue(DocCommand.COMMAND_NAME in result[0])
+        def result = complete('', 0)
+        assert HelpCommand.COMMAND_NAME in result[0]
+        assert ExitCommand.COMMAND_NAME in result[0]
+        assert 'import' in result[0]
+        assert ShowCommand.COMMAND_NAME in result[0]
+        assert SetCommand.COMMAND_NAME in result[0]
+        assert InspectCommand.COMMAND_NAME in result[0]
+        assert DocCommand.COMMAND_NAME in result[0]
         assert 0 == result[1]
     }
 
     void testExitEdit() {
-        assert [["${ExitCommand.COMMAND_NAME} ", ":e", EditCommand.COMMAND_NAME], 0] == complete(":e", 0)
+        assert [["${ExitCommand.COMMAND_NAME} ", ':e', EditCommand.COMMAND_NAME], 0] == complete(':e', 0)
     }
 
     void testShow() {
-        String prompt = ":show "
-        assert [["all", "classes", "imports", "preferences", "variables"], prompt.length()] == complete(prompt, prompt.length())
+        String prompt = ':show '
+        assert [['all', 'classes', 'imports', 'preferences', 'variables'], prompt.length()] == complete(prompt, prompt.length())
     }
 
     void testShowV() {
-        String prompt = ShowCommand.COMMAND_NAME + " v"
-        assert [["variables "], prompt.length() - 1] == complete(prompt, prompt.length())
+        String prompt = ShowCommand.COMMAND_NAME + ' v'
+        assert [['variables '], prompt.length() - 1] == complete(prompt, prompt.length())
     }
 
     void testShowVariables() {
-        String prompt = ShowCommand.COMMAND_NAME + " variables "
-        assertNull(complete(prompt, prompt.length()))
+        String prompt = ShowCommand.COMMAND_NAME + ' variables '
+        assert [] == complete(prompt, prompt.length())
     }
 
     void testImportJava() {
         // tests interaction with ReflectionCompleter
-        String prompt = "import j"
+        String prompt = 'import j'
         def result = complete(prompt, prompt.length())
         assert result
         assert prompt.length() - 1 == result[1]
-        assertTrue(result.toString() ,"java." in result[0])
+        assert 'java.' in result[0]
     }
 
     void testShowVariablesJava() {
         // tests against interaction with ReflectionCompleter
-        String prompt = ShowCommand.COMMAND_NAME + " variables java"
-        assertNull(complete(prompt, prompt.length()))
+        String prompt = ShowCommand.COMMAND_NAME + ' variables java'
+        assert [] == complete(prompt, prompt.length())
     }
 
     void testKeyword() {
         // tests against interaction with ReflectionCompleter
-        String prompt = "pub"
-        assert [["public "], 0] == complete(prompt, prompt.length())
+        String prompt = 'pub'
+        assert [['public '], 0] == complete(prompt, prompt.length())
     }
 
     void testCommandAndKeyword() {
         // tests against interaction with ReflectionCompleter
-        String prompt = ":pu" // purge, public
+        String prompt = ':pu' // purge, public
         assert [["${PurgeCommand.COMMAND_NAME} "], 0] == complete(prompt, prompt.length())
     }
 
     void testDoc() {
-        String prompt = DocCommand.COMMAND_NAME + " j"
+        String prompt = DocCommand.COMMAND_NAME + ' j'
         def result = complete(prompt, prompt.length())
         assert result
         assert prompt.length() - 1 == result[1]
-        assertTrue(result.toString() ,"java." in result[0])
+        assert 'java.' in result[0]
     }
 
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CommandCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CommandCompletorTest.groovy
index c346bd4..c2bf46e 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CommandCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CommandCompletorTest.groovy
@@ -24,9 +24,9 @@ extends CompletorTestSupport {
 
     void testEmpty() {
         CommandsMultiCompleter completor = new CommandsMultiCompleter()
-        assert -1 == completor.complete("", 0, [])
-        assert -1 == completor.complete("i", 2, [])
-        assert -1 == completor.complete("imp", 4, [])
+        assert -1 == completor.complete('', 0, [])
+        assert -1 == completor.complete('i', 2, [])
+        assert -1 == completor.complete('imp', 4, [])
     }
 
     void testAlias() {
@@ -42,10 +42,10 @@ extends CompletorTestSupport {
             completor.add(aliasCommand)
             completor.refresh()
 
-            assert 0 == completor.complete(":a", ":a".length(), candidates)
+            assert 0 == completor.complete(':a', ':a'.length(), candidates)
             assert [':a', AliasCommand.COMMAND_NAME] == candidates
             candidates = []
-            assert 3 == completor.complete(":a ", ":a ".length(), candidates)
+            assert 3 == completor.complete(':a ', ':a '.length(), candidates)
             assert [':=', ':S', SetCommand.COMMAND_NAME, ShowCommand.COMMAND_NAME] == candidates
         }
     }
@@ -53,20 +53,23 @@ extends CompletorTestSupport {
     void testSet() {
         CommandsMultiCompleter completor = new CommandsMultiCompleter()
         def candidates = []
-        groovyshMocker.demand.getAUTOINDENT_PREFERENCE_KEY(1){"autoindent"}
-        groovyshMocker.demand.getMETACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY(1){"meta-completion-prefix-length"}
+        groovyshMocker.demand.getINTERPRETER_MODE_PREFERENCE_KEY(1){'interpreterMode'}
+        groovyshMocker.demand.getAUTOINDENT_PREFERENCE_KEY(1){'autoindent'}
+        groovyshMocker.demand.getCOLORS_PREFERENCE_KEY(1){'colors'}
+        groovyshMocker.demand.getMETACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY(1){'meta-completion-prefix-length'}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             completor.add(new SetCommand(groovyshMock))
             completor.refresh()
 
-            assert 0 == completor.complete(":s", ":s".length(), candidates)
+            assert 0 == completor.complete(':s', ':s'.length(), candidates)
             String buffer = SetCommand.COMMAND_NAME + ' '
             assert [buffer] == candidates
             candidates = []
             assert 5 == completor.complete(buffer, buffer.length(), candidates)
         }
         assert Groovysh.AUTOINDENT_PREFERENCE_KEY in candidates
+        assert Groovysh.COLORS_PREFERENCE_KEY in candidates
         assert Groovysh.METACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY in candidates
         assert Preferences.EDITOR_KEY in candidates
         assert Preferences.PARSER_FLAVOR_KEY in candidates
@@ -84,7 +87,7 @@ extends CompletorTestSupport {
             completor.add(new SaveCommand(groovyshMock))
             completor.refresh()
 
-            assert 0 == completor.complete(":s", ":s".length(), candidates)
+            assert 0 == completor.complete(':s', ':s'.length(), candidates)
             assert [':s', SaveCommand.COMMAND_NAME] == candidates
             candidates = []
             String buffer = SaveCommand.COMMAND_NAME + ' '
@@ -101,10 +104,10 @@ extends CompletorTestSupport {
             completor.add(new ClearCommand(groovyshMock))
             completor.refresh()
 
-            assert 0 == completor.complete(":c", ":c".length(), candidates)
+            assert 0 == completor.complete(':c', ':c'.length(), candidates)
             assert [':c', ClearCommand.COMMAND_NAME] == candidates
             candidates = []
-            assert -1 == completor.complete(":c ", ":c ".length(), candidates)
+            assert -1 == completor.complete(':c ', ':c '.length(), candidates)
             assert [] == candidates
 
         }
@@ -114,8 +117,10 @@ extends CompletorTestSupport {
     void testSaveSetShow() {
         CommandsMultiCompleter completor = new CommandsMultiCompleter()
         def candidates = []
-        groovyshMocker.demand.getAUTOINDENT_PREFERENCE_KEY(1){"autoindent"}
-        groovyshMocker.demand.getMETACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY(1){"meta-completion-prefix-length"}
+        groovyshMocker.demand.getINTERPRETER_MODE_PREFERENCE_KEY(1){'interpreterMode'}
+        groovyshMocker.demand.getAUTOINDENT_PREFERENCE_KEY(1){'autoindent'}
+        groovyshMocker.demand.getCOLORS_PREFERENCE_KEY(1){'colors'}
+        groovyshMocker.demand.getMETACLASS_COMPLETION_PREFIX_LENGTH_PREFERENCE_KEY(1){'meta-completion-prefix-length'}
         groovyshMocker.demand.getIo(1){testio}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
@@ -124,14 +129,14 @@ extends CompletorTestSupport {
             completor.add(new ShowCommand(groovyshMock))
             completor.refresh()
 
-            assert 0 == completor.complete(":s", ":s".length(), candidates)
+            assert 0 == completor.complete(':s', ':s'.length(), candidates)
             assert [':s', SaveCommand.COMMAND_NAME, SetCommand.COMMAND_NAME + ' ', ShowCommand.COMMAND_NAME + ' '] == candidates
             candidates = []
             String buffer = SaveCommand.COMMAND_NAME + ' '
             assert 6 == completor.complete(buffer, buffer.length(), candidates)
             assert ! candidates.contains('all')
             candidates = []
-            assert 3 == completor.complete(":s ", ":s ".length(), candidates)
+            assert 3 == completor.complete(':s ', ':s '.length(), candidates)
             assert ! candidates.contains('all')
 
         }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CompletorTestSupport.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CompletorTestSupport.groovy
index 9b633e5..3145062 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CompletorTestSupport.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/CompletorTestSupport.groovy
@@ -17,13 +17,11 @@
 package org.codehaus.groovy.tools.shell
 
 import groovy.mock.interceptor.MockFor
-import org.codehaus.groovy.tools.shell.util.PackageHelper
 import org.codehaus.groovy.tools.shell.completion.IdentifierCompletor
 import org.codehaus.groovy.tools.shell.completion.ReflectionCompletor
+import org.codehaus.groovy.tools.shell.util.PackageHelper
+import org.codehaus.groovy.tools.shell.util.PackageHelperImpl
 
-/**
- * @author kruset
- */
 abstract class CompletorTestSupport extends GroovyTestCase {
 
     BufferManager bufferManager = new BufferManager()
@@ -38,11 +36,12 @@ abstract class CompletorTestSupport extends GroovyTestCase {
 
     MockFor idCompletorMocker
 
+    @Override
     void setUp() {
         super.setUp()
-        mockOut = new ByteArrayOutputStream();
+        mockOut = new ByteArrayOutputStream()
 
-        mockErr = new ByteArrayOutputStream();
+        mockErr = new ByteArrayOutputStream()
 
         testio = new IO(
                 new ByteArrayInputStream(),
@@ -55,11 +54,11 @@ abstract class CompletorTestSupport extends GroovyTestCase {
         groovyshMocker = new MockFor(Groovysh)
         groovyshMocker.demand.createDefaultRegistrar { { shell -> null } }
         groovyshMocker.demand.getIo(0..2) { testio }
-        packageHelperMocker = new MockFor(PackageHelper)
+        packageHelperMocker = new MockFor(PackageHelperImpl)
         def registry = new CommandRegistry()
         groovyshMocker.demand.getRegistry(0..1) { registry }
         groovyshMocker.demand.getClass(0..1) { Groovysh }
-        packageHelperMocker.demand.getContents(6) { ["java", "test"] }
+        packageHelperMocker.demand.getContents(6) { ['java', 'test'] }
         groovyshMocker.demand.getIo(0..2) { testio }
         for (i in 1..19) {
             groovyshMocker.demand.getIo(0..1) { testio }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ErrorDisplayTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ErrorDisplayTest.groovy
index e4c5cfa..3aa5de4 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ErrorDisplayTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ErrorDisplayTest.groovy
@@ -19,19 +19,16 @@ package org.codehaus.groovy.tools.shell
 import jline.console.ConsoleReader
 
 
-/**
- * @author kruset
- */
-public class ErrorDisplayTest extends ShellRunnerTestSupport {
+class ErrorDisplayTest extends ShellRunnerTestSupport {
 
     void testInput() {
-        readerStubber.demand.readLine { "foo" }
+        readerStubber.demand.readLine { 'foo' }
         shellMocker.use {
             readerStubber.use {
                 Groovysh shellMock = new Groovysh()
                 ConsoleReader readerStub = new ConsoleReader()
 
-                InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, { ">" })
+                InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, { '>' })
                 shellRunner.reader = readerStub
                 // assert no exception
                 shellRunner.run()
@@ -46,7 +43,7 @@ public class ErrorDisplayTest extends ShellRunnerTestSupport {
                 Groovysh shellMock = new Groovysh()
                 ConsoleReader readerStub = new ConsoleReader()
 
-                InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, { ">" })
+                InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, { '>' })
                 shellRunner.reader = readerStub
                 // assert no exception
                 shellRunner.run()
@@ -55,12 +52,12 @@ public class ErrorDisplayTest extends ShellRunnerTestSupport {
     }
 
     void testError2() {
-        readerStubber.demand.readLine { throw new Throwable("MockException") }
+        readerStubber.demand.readLine { throw new Throwable('MockException') }
         shellMocker.use { readerStubber.use {
             Groovysh shellMock = new Groovysh()
             ConsoleReader readerStub = new ConsoleReader()
 
-            InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, {">"})
+            InteractiveShellRunner shellRunner = new InteractiveShellRunner(shellMock, {'>'})
             shellRunner.reader = readerStub
             // assert no exception
             shellRunner.run()
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshParsersTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshParsersTest.groovy
new file mode 100644
index 0000000..82b189e
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshParsersTest.groovy
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell
+
+import groovy.mock.interceptor.MockFor
+import org.codehaus.groovy.control.CompilationFailedException
+
+class GroovyshParsersTest extends GroovyTestCase {
+
+    void testIgnoreSyntaxErrorForLineEnding() {
+        assert !RigidParser.ignoreSyntaxErrorForLineEnding('foo')
+        assert RigidParser.ignoreSyntaxErrorForLineEnding('foo {')
+    }
+
+    void testIsAnnotationExpression() {
+        def mock = new MockFor(CompilationFailedException)
+        mock.demand.getMessage(1) { 'unexpected token: @' }
+        mock.use {
+            CompilationFailedException mcee = new CompilationFailedException(0, null)
+            assert RigidParser.isAnnotationExpression(mcee, '@Override')
+        }
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshTest.groovy
index 4cd4195..ff4eded 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/GroovyshTest.groovy
@@ -17,43 +17,63 @@ package org.codehaus.groovy.tools.shell
 
 import org.codehaus.groovy.GroovyException
 import org.codehaus.groovy.control.MultipleCompilationErrorsException
+import org.codehaus.groovy.tools.shell.completion.ReflectionCompletionCandidate
 import org.codehaus.groovy.tools.shell.completion.ReflectionCompletor
 import org.codehaus.groovy.tools.shell.completion.TokenUtilTest
+import org.codehaus.groovy.tools.shell.util.JAnsiHelper
+import org.codehaus.groovy.tools.shell.util.Preferences
 
 class GroovyshTest extends GroovyTestCase {
 
-    IO testio
-    ByteArrayOutputStream mockOut
-    ByteArrayOutputStream mockErr
+    protected IO testio
+    protected ByteArrayOutputStream mockOut
+    protected ByteArrayOutputStream mockErr
 
+    @Override
     void setUp() {
         super.setUp()
-        mockOut = new ByteArrayOutputStream();
-        mockErr = new ByteArrayOutputStream();
+        mockOut = new ByteArrayOutputStream()
+        mockErr = new ByteArrayOutputStream()
         testio = new IO(new ByteArrayInputStream(), mockOut, mockErr)
         testio.setVerbosity(IO.Verbosity.INFO)
     }
 
     void testCompleteExpr() {
         Groovysh groovysh = new Groovysh(testio)
-        groovysh.execute("x = 3")
+        groovysh.execute('x = 3')
         assert mockOut.toString().length() > 0
-        assert " 3\n" == mockOut.toString().normalize()[-3..-1]
+        assert ' 3\n' == mockOut.toString().normalize()[-3..-1]
     }
 
+    void testClassDef() {
+        Groovysh groovysh = new Groovysh(testio)
+        groovysh.execute('class Foo {}')
+        assert mockOut.toString().length() > 0
+        assert ' true\n' == mockOut.toString().normalize()[-6..-1]
+    }
+
+    void testmethodDef() {
+        Groovysh groovysh = new Groovysh(testio)
+        groovysh.execute('int foo() {42}')
+        assert mockOut.toString().length() > 0
+        assert ' true\n' == mockOut.toString().normalize()[-6..-1]
+    }
+
+
+
     void testIncompleteExpr() {
         Groovysh groovysh = new Groovysh(testio)
-        groovysh.execute("def x() {")
-        assert "" == mockOut.toString()
+        groovysh.execute('def x() {')
+        assert '' == mockOut.toString()
     }
 
     void testBadExpr() {
         Groovysh groovysh = new Groovysh(testio)
         try {
-            groovysh.execute("x}")
-            fail()
+            groovysh.execute('x}')
+            fail('expected MultipleCompilationErrorsException ')
         } catch (MultipleCompilationErrorsException e) {
-            assert "" == mockOut.toString()
+            assert '' == mockOut.toString()
         }
     }
 
@@ -61,109 +81,109 @@ class GroovyshTest extends GroovyTestCase {
         Groovysh groovysh = new Groovysh(testio)
         // this is a special case, e.g. happens for Gradle DefaultExtraPropertiesExtension
         // assert no fail
-        groovysh.execute("x = new Object() {public Object getProperty(String name) {throw new MissingPropertyException('From test', name, null)}}")
+        groovysh.execute(/x = new Object() {public Object getProperty(String name) {throw new MissingPropertyException('From test', name, null)}}/)
     }
 
     void testDisplayBuffer() {
         Groovysh groovysh = new Groovysh(testio)
-        groovysh.displayBuffer(["foo", "bar"])
+        groovysh.displayBuffer(['foo', 'bar'])
         def out = mockOut.toString().normalize()
         // was 20 on my windows box after normalize()
         // is it relying on other preference settings?
 //        assertEquals(34, out.length())
-        assert out.contains("foo\n")
-        assert out.contains("bar\n")
+        assert out.contains('foo\n')
+        assert out.contains('bar\n')
     }
 
     void testDefaultErrorHook() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultErrorHook(new Throwable() {
             StackTraceElement[] stackTrace = [
-                    new StackTraceElement("fooClass", "fooMethod", "fooFile", 42),
-                    new StackTraceElement(Interpreter.SCRIPT_FILENAME, "run", "scriptFile", 42)]
+                    new StackTraceElement('fooClass', 'fooMethod', 'fooFile', 42),
+                    new StackTraceElement(Interpreter.SCRIPT_FILENAME, 'run', 'scriptFile', 42)]
         })
-        assert "" == mockOut.toString()
-        assert mockErr.toString().contains("foo")
+        assert '' == mockOut.toString()
+        assert mockErr.toString().contains('foo')
         assert ! mockErr.toString().contains(Interpreter.SCRIPT_FILENAME)
-        assert ! mockErr.toString().contains("...")
+        assert ! mockErr.toString().contains('...')
     }
 
     void testDefaultResultHookStringArray() {
         Groovysh groovysh = new Groovysh(testio)
-        groovysh.defaultResultHook("foo bar".split())
-        assert mockOut.toString().trim().endsWith("[foo, bar]")
-        assert "" == mockErr.toString()
+        groovysh.defaultResultHook('foo bar'.split())
+        assert mockOut.toString().trim().endsWith('[foo, bar]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultHookObjectArray() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook(Object.fields)
-        assert mockOut.toString().trim().endsWith("[]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultPrimitive() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook(3)
-        assert mockOut.toString().trim().endsWith("3")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('3')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultNull() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook(null)
-        assert mockOut.toString().trim().endsWith("null")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('null')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultList() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook([])
-        assert mockOut.toString().trim().endsWith("[]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultSet() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook([42] as Set)
-        assert mockOut.toString().trim().endsWith("[42]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[42]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultArray() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook([42] as int[])
-        assert mockOut.toString().trim().endsWith("[42]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[42]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultMapEmpty() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook([:])
-        assert mockOut.toString().trim().endsWith("[:]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[:]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultMap() {
         Groovysh groovysh = new Groovysh(testio)
         groovysh.defaultResultHook(['class': 'foo'])
-        assert mockOut.toString().trim().endsWith("[class:foo]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[class:foo]')
+        assert '' == mockErr.toString()
     }
 
     void testDefaultResultConfigObject() {
         // ConfigObject are like maps
         Groovysh groovysh = new Groovysh(testio)
         ConfigObject co = new ConfigObject()
-        co.put("class", "foo")
+        co.put('class', 'foo')
         groovysh.defaultResultHook(co)
-        assert mockOut.toString().trim().endsWith("[class:foo]")
-        assert "" == mockErr.toString()
+        assert mockOut.toString().trim().endsWith('[class:foo]')
+        assert '' == mockErr.toString()
     }
 
     void testFindCommandDuplicate() {
         Groovysh groovysh = new Groovysh(testio)
-        CommandSupport command = new CommandSupport(groovysh, "import", "imp") {
+        CommandSupport command = new CommandSupport(groovysh, 'import', 'imp') {
             @Override
             Object execute(List args) {
                 return null
@@ -179,48 +199,55 @@ class GroovyshTest extends GroovyTestCase {
 
     void testFindCommandFoo() {
         Groovysh groovysh = new Groovysh(testio)
-        assertNull(groovysh.findCommand(" foo import "))
-        assert !groovysh.isExecutable(" foo import ")
-        CommandSupport command2 = new CommandSupport(groovysh, "foo", "/foo") {
+        assertNull(groovysh.findCommand(' foo import '))
+        assert !groovysh.isExecutable(' foo import ')
+        CommandSupport command2 = new CommandSupport(groovysh, 'foo', '/foo') {
             @Override
             Object execute(List args) {
                 return null
             }
         }
         groovysh.register(command2)
-        assert command2 == groovysh.findCommand(" foo bar ")
-        assert groovysh.isExecutable(" foo import ")
-        assert command2 == groovysh.findCommand(" /foo bar ")
-        assertNull(groovysh.findCommand(" bar foo "))
+        assert command2 == groovysh.findCommand(' foo bar ')
+        assert groovysh.isExecutable(' foo import ')
+        List accumulateArgs = []
+        assert command2 == groovysh.findCommand(' foo bar ', accumulateArgs)
+        assert accumulateArgs == ['bar']
+        accumulateArgs = []
+        assert command2 == groovysh.findCommand(' foo bar baz', accumulateArgs)
+        assert accumulateArgs == ['bar', 'baz']
+        assert groovysh.isExecutable(' foo import ')
+        assert command2 == groovysh.findCommand(' /foo bar ')
+        assertNull(groovysh.findCommand(' bar foo '))
     }
 
     void testExecuteCommandFoo() {
         Groovysh groovysh = new Groovysh(testio)
-        assertNull(groovysh.findCommand(" foo import "))
-        assert ! groovysh.isExecutable(" foo import ")
-        CommandSupport command2 = new CommandSupport(groovysh, "foo", "/foo") {
+        assertNull(groovysh.findCommand(' foo import '))
+        assert ! groovysh.isExecutable(' foo import ')
+        CommandSupport command2 = new CommandSupport(groovysh, 'foo', '/foo') {
             @Override
             Object execute(List args) {
-                throw new CommandException(this, "Test Command failure")
+                throw new CommandException(this, 'Test Command failure')
             }
         }
         groovysh.register(command2)
         // also assert CommandException caught
-        assertNull(groovysh.execute(" foo import "))
-        assert mockErr.toString().contains("Test Command failure")
-        assert 1 == mockErr.toString().count("\n")
-        assert "" == mockOut.toString()
+        assertNull(groovysh.execute(' foo import '))
+        assert mockErr.toString().contains('Test Command failure')
+        assert 1 == mockErr.toString().count('\n')
+        assert '' == mockOut.toString()
     }
 
     void testGetIndentLevel() {
         Groovysh groovysh = new Groovysh(testio)
-        assert "" == groovysh.getIndentPrefix()
-        groovysh.buffers.buffers.add(["Foo {"])
+        assert '' == groovysh.indentPrefix
+        groovysh.buffers.buffers.add(['Foo {'])
         groovysh.buffers.select(1)
-        assert " " * groovysh.indentSize == groovysh.getIndentPrefix()
-        groovysh.buffers.buffers.add(["Foo {{"])
+        assert ' ' * groovysh.indentSize == groovysh.indentPrefix
+        groovysh.buffers.buffers.add(['Foo {{'])
         groovysh.buffers.select(2)
-        assert " " * groovysh.indentSize * 2 == groovysh.getIndentPrefix()
+        assert ' ' * groovysh.indentSize * 2 == groovysh.indentPrefix
     }
 
     void testLoadUserScript() {
@@ -228,24 +255,67 @@ class GroovyshTest extends GroovyTestCase {
         Groovysh groovysh = new Groovysh(testio) {
             @Override
             File getUserStateDirectory() {
-                return file.getParentFile()
+                return file.parentFile
             }
         }
         try {
-            groovysh.loadUserScript(file.getName())
+            groovysh.loadUserScript(file.name)
             fail('Expected ArithmeticException')
         } catch (ArithmeticException e) {}
     }
 
-    File createTemporaryGroovyScriptFile(content) {
-        String testName = "GroovyshTest" + System.currentTimeMillis()
-        File groovyCode = new File(System.getProperty("java.io.tmpdir"), testName)
+    static File createTemporaryGroovyScriptFile(content) {
+        String testName = 'GroovyshTest' + System.currentTimeMillis()
+        File groovyCode = new File(System.getProperty('java.io.tmpdir'), testName)
         groovyCode.write(content)
         groovyCode.deleteOnExit()
         return groovyCode
     }
 }
 
+/**
+ * Runs all tests of groovyshTests with interpreter mode enabled
+ */
+class GroovyshInterpreterModeTest extends GroovyshTest {
+
+    @Override
+    void setUp() {
+        super.setUp()
+        Preferences.put(Groovysh.INTERPRETER_MODE_PREFERENCE_KEY, 'true')
+    }
+
+    @Override
+    void tearDown() {
+        super.tearDown()
+        Preferences.put(Groovysh.INTERPRETER_MODE_PREFERENCE_KEY, 'false')
+    }
+
+    void testBoundVar() {
+        Groovysh groovysh = new Groovysh(testio)
+        // default is false
+
+        groovysh.execute('int x = 3')
+        assert mockOut.toString().length() > 0
+        assert ' 3\n' == mockOut.toString().normalize()[-3..-1]
+        groovysh.execute('x')
+        assert mockOut.toString().length() > 0
+        assert ' 3\n' == mockOut.toString().normalize()[-3..-1]
+    }
+
+    void testBoundVarmultiple() {
+        Groovysh groovysh = new Groovysh(testio)
+        // default is false
+        Preferences.put(Groovysh.INTERPRETER_MODE_PREFERENCE_KEY, 'true')
+        groovysh.execute('int x, y, z')
+        assert mockOut.toString().length() > 0
+        assert ' 0\n' == mockOut.toString().normalize()[-3..-1]
+        groovysh.execute('y')
+        assert mockOut.toString().length() > 0
+        assert ' 0\n' == mockOut.toString().normalize()[-3..-1]
+    }
+
+}
+
 
 class GroovyshCompletorTest extends GroovyTestCase {
 
@@ -253,16 +323,16 @@ class GroovyshCompletorTest extends GroovyTestCase {
         IO testio
         ByteArrayOutputStream mockOut
         ByteArrayOutputStream mockErr
-        mockOut = new ByteArrayOutputStream();
-        mockErr = new ByteArrayOutputStream();
+        mockOut = new ByteArrayOutputStream()
+        mockErr = new ByteArrayOutputStream()
         testio = new IO(
                 new ByteArrayInputStream(),
                 mockOut,
                 mockErr)
-        testio.out.println("mockResult")
-        assertTrue("stdout=" + mockOut.toString() + "\nstderr=" + mockErr.toString(), mockOut.toString().contains('mockResult'))
-        testio.err.println("mockErrResult")
-        assertTrue("stdout=" + mockOut.toString() + "\nstderr=" + mockErr.toString(), mockErr.toString().contains('mockErrResult'))
+        testio.out.println('mockResult')
+        assertTrue('stdout=' + mockOut.toString() + '\nstderr=' + mockErr.toString(), mockOut.toString().contains('mockResult'))
+        testio.err.println('mockErrResult')
+        assertTrue('stdout=' + mockOut.toString() + '\nstderr=' + mockErr.toString(), mockErr.toString().contains('mockErrResult'))
     }
 
     void testLiveClass() {
@@ -275,18 +345,37 @@ class GroovyshCompletorTest extends GroovyTestCase {
 -*/
         IO testio = new IO()
         Groovysh groovysh = new Groovysh(testio)
-        Object result = groovysh.interp.evaluate(["import " + ReflectionCompletor.getCanonicalName(), """class Foo extends HashSet implements Comparable {
-int compareTo(Object) {0}; int priv; static int priv2; public int foo; public static int bar; int foom(){1}; static int barm(){2}}""", "ReflectionCompletor.getPublicFieldsAndMethods(Foo, \"\")"])
-        assert result
-        assert result.size() > 0
-        assert [] == result.findAll({it.startsWith("_")})
-        assert [] == result.findAll({it.startsWith("super\$")})
-        assert [] == result.findAll({it.startsWith("this\$")})
-        assert ! ('foo' in result)
-        assert ! ('priv' in result)
-        assert ! ('priv2' in result)
+        List<ReflectionCompletionCandidate> candResult = (List<ReflectionCompletionCandidate>) groovysh.interp.evaluate([
+                """\
+import ${ReflectionCompletor.getCanonicalName()}
+class Foo extends HashSet implements Comparable {
+  int compareTo(Object) {0};
+  int priv;
+  static int priv2;
+  public int foo;
+  public static int bar;
+  int foom(){1};
+  static int barm(){2};
+  static int getPriv3(){3};
+  private int getPriv4(){4};
+  int getPriv5(){5};
+}
+ReflectionCompletor.getPublicFieldsAndMethods(Foo, '')
+"""])
+        assert candResult
+        assert candResult.size() > 0
+        List<String> result = candResult*.value
+        assert [] == result.findAll({ it.startsWith('_') })
+        assert [] == result.findAll({ it.startsWith('super$') })
+        assert [] == result.findAll({ it.startsWith('this$') })
+        assert !('foo' in result)
+        assert !('priv' in result)
+        assert ('priv2' in result)
+        assert ('priv3' in result)
+        assert !('priv4' in result)
+        assert !('priv5' in result)
         assert 'barm()' in result
-        assert ! ('foom()' in result)
+        assert !('foom()' in result)
 
     }
 
@@ -300,29 +389,88 @@ int compareTo(Object) {0}; int priv; static int priv2; public int foo; public st
 -*/
         IO testio = new IO()
         Groovysh groovysh = new Groovysh(testio)
-        Object result = groovysh.interp.evaluate(["import " + ReflectionCompletor.getCanonicalName(), """class Foo extends HashSet implements Comparable {
-int compareTo(Object) {0}; int priv; static int priv2; public int foo; public static int bar; int foom(){1}; static int barm(){2}}""",
-                "ReflectionCompletor.getPublicFieldsAndMethods(new Foo(), \"\")"])
-        assertNotNull(result)
-        assert result.size() > 0
-        assert [] == result.findAll({it.startsWith("_")})
-        assert [] == result.findAll({it.startsWith("super\$")})
-        assert [] == result.findAll({it.startsWith("this\$")})
-        assert 'bar' in result
-        assert ! ('priv' in result)
-        assert ! ('priv2' in result)
+        List<ReflectionCompletionCandidate> candResult = (List<ReflectionCompletionCandidate>) groovysh.interp.evaluate([
+                """\
+import ${ReflectionCompletor.getCanonicalName()}
+class Foo extends HashSet implements Comparable {
+  int compareTo(Object) {0};
+  int priv;
+  static int priv2;
+  private int foo;
+  static int bar;
+  int foom(){1};
+  static int barm(){2}
+  static int getPriv3(){3};
+  private int getPriv4(){4};
+  int getPriv5(){5};
+}
+ReflectionCompletor.getPublicFieldsAndMethods(new Foo(), '')
+"""])
+        assertNotNull(candResult)
+        assert candResult.size() > 0
+        List<String> result = candResult*.value
+        assert [] == result.findAll({ it.startsWith('_') })
+        assert [] == result.findAll({ it.startsWith('super$') })
+        assert [] == result.findAll({ it.startsWith('this$') })
+        assert !('bar' in result)
+        assert ('priv' in result)
+        assert !('priv2' in result)
+        assert !('priv3' in result)
+        assert !('priv4' in result)
+        assert ('priv5' in result)
         assert 'foom()' in result
-        assert 'barm()' in result
+        assert !('barm()' in result)
     }
 
     void testImportedClassStaticMember() {
         // tests that import are taken into account when evaluating for completion
         IO testio = new IO()
         Groovysh groovysh = new Groovysh(new URLClassLoader(), new Binding(), testio)
-        groovysh.run("import " + GroovyException.name)
-        ReflectionCompletor compl = new ReflectionCompletor(groovysh, 0)
+        def result = groovysh.execute('import ' + GroovyException.name)
+        assert result == GroovyException.canonicalName
+        ReflectionCompletor compl = new ReflectionCompletor(groovysh)
         def candidates = []
-        compl.complete(TokenUtilTest.tokenList("GroovyException."), candidates)
+
+        compl.complete(TokenUtilTest.tokenList('GroovyException.'), candidates)
+        assert candidates.size() == 0
+        compl.complete(TokenUtilTest.tokenList('GroovyException.find'), candidates)
         assert candidates.size() > 0
     }
+
+    void testSortCandidates() {
+        // tests that import are taken into account when evaluating for completion
+        IO testio = new IO()
+        Groovysh groovysh = new Groovysh(new URLClassLoader(), new Binding(), testio)
+        ReflectionCompletor compl = new ReflectionCompletor(groovysh)
+        def candidates = []
+        compl.complete(TokenUtilTest.tokenList(/['a':3, 'b':4]./), candidates)
+        assert candidates.size() > 1
+        assert candidates.reverse().subList(0, 3).collect({ String it -> JAnsiHelper.stripAnsi(it) }) == ['empty', 'b', 'a']
+    }
+}
+
+class GroovyshUtilsTest extends GroovyTestCase {
+
+    void testIsTypeOrMethodDeclaration() {
+        List<String> buffer = []
+        assert !Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['']
+        assert !Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['foo']
+        assert !Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['foo()']
+        assert !Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['123']
+        assert !Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['def foo() {}']
+        assert Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['public static void bar() {}']
+        assert Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['public class Foo {}']
+        assert Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['interface Foo {}']
+        assert Groovysh.isTypeOrMethodDeclaration(buffer)
+        buffer = ['enum Foo {VAL1, VAL2}']
+        assert Groovysh.isTypeOrMethodDeclaration(buffer)
+    }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ImportCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ImportCompletorTest.groovy
index aeb7b95..011186c 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ImportCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ImportCompletorTest.groovy
@@ -23,360 +23,349 @@ import org.codehaus.groovy.tools.shell.commands.ImportCompleter
 import org.codehaus.groovy.tools.shell.util.PackageHelper
 import org.codehaus.groovy.tools.shell.util.Preferences
 
-class ImportCompleterUnitTest
-extends GroovyTestCase {
+/**
+ * as opposed to MockFor, traditional custom mocking allows @CompileStatic for the class under Test
+ */
+class MockPackageHelper implements PackageHelper {
+    Set<String> mockContents
+    MockPackageHelper(Collection<String> mockContents) {
+        this.mockContents = new HashSet<String>(mockContents)
+    }
+
+    @Override
+    Set<String> getContents(String packagename) {
+        return mockContents
+    }
+}
+
+class ImportCompleterUnitTest extends GroovyTestCase {
+
+    private MockFor preferencesMocker
 
-    MockFor helperMocker
-    MockFor preferencesMocker
 
+    @Override
     void setUp() {
         super.setUp()
-        helperMocker = new MockFor(PackageHelper)
-        helperMocker.demand.initializePackages(0..1) {}
-        helperMocker.demand.getClass(0..1) {PackageHelper}
         preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) { "true" }
-        preferencesMocker.demand.addChangeListener(1) {}
-    }
-
-    void testPattern() {
-        assertTrue("" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("j" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java." ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java.util" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java.util." ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java.util.T" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("org.w3c.T" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java.util.Test" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertTrue("java.util.Test123" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+    }
+
+    void testPatternPackOrClassname() {
+        assert ''.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'j'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.T'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'org.w3c.T'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.Test'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.Test123'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.Test$foo123'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert 'java.util.Test_foo123'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
         // inverse
-        assertFalse("." ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertFalse("Upper" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN )
-        assertFalse("java.util.Test123." ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-        assertFalse("java.util.Test123.foo" ==~ ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
-
-        assertTrue("" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("j" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java." ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util." ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util.T" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("org.w3c.T" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util.Test" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util.Test123" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util.Test123." ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertTrue("java.util.Test123.foo" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert !'.'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert !'Upper'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert !'java.util.Test123.'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+        assert !'java.util.Test123.foo'.matches(ImportCompleter.PACK_OR_CLASSNAME_PATTERN)
+    }
+
+    void testPatternPackOrSimpleClassname() {
+        assert ''.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'j'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.util'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.util.'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.util.T'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'org.w3c.T'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.util.Test'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert 'java.util.Test123'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        // inverse
+        assert !'.'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert !'Upper'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert !'java.util.Test123.'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+        assert !'java.util.Test123.foo'.matches(ImportCompleter.PACK_OR_SIMPLE_CLASSNAME_PATTERN)
+    }
+
+    void testPatternClassOrMethodName() {
+        assert ''.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'j'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.T'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'org.w3c.T'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.Test'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.Test123'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.Test123.'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert 'java.util.Test123.foo'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
         //inverse
-        assertFalse("." ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertFalse("Upper" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertFalse("java.util.Test123.foo." ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
-        assertFalse("java.util.Test123.Test.foo" ==~ ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert !'.'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert !'Upper'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert !'java.util.Test123.foo.'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
+        assert !'java.util.Test123.Test.foo'.matches(ImportCompleter.PACK_OR_CLASS_OR_METHODNAME_PATTERN)
     }
 
-    void testCompleteEmpty() {
+    void testPatternQualifiedClassDot() {
+        assert !''.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'j'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.T'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'org.w3c.T'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.Test'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.Test123'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert 'java.util.Test123.'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.Test123.foo'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'.'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'Upper'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.Test123.foo.'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+        assert !'java.util.Test123.Test.foo'.matches(ImportCompleter.QUALIFIED_CLASS_DOT_PATTERN)
+    }
 
-        helperMocker.demand.getContents(1) { str -> assert(str == '' ); ["java", "groovy"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = ""
-            assertEquals(0, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["groovy.", "java."], candidates.sort())
-        }}
+    void testLowercaseImportItem() {
+        assert !''.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert 'j'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert 'java.'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert 'java.util'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert 'java.util.'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert !'java.util.*'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+        assert !'java.util.T'.matches(ImportCompleter.LOWERCASE_IMPORT_ITEM_PATTERN)
+    }
+
+
+    private void assertCompletionCandidatesMatch(
+            final PackageHelper packageHelper,
+            final String buffer,
+            final boolean staticImport,
+            final List<String> expected) {
+        ImportCompleter compl = new ImportCompleter(packageHelper, null, staticImport)
+        def  candidates = []
+
+        assert (buffer.lastIndexOf('.') + 1) == compl.complete(buffer, buffer.length(), candidates)
+        assert expected == candidates.sort()
+    }
+
+    void testCompleteEmpty() {
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['java', 'groovy']), '', false, ['groovy.', 'java.'])
+        }
     }
 
     void testCompleteStaticEmpty() {
-        helperMocker.demand.getContents(1) { str -> assert(str == '' ); ["java", "groovy"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, true);
-            def candidates = []
-            String buffer = ""
-            assertEquals(0, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["groovy.", "java."], candidates.sort())
-        }}
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['java', 'groovy']), '', true, ['groovy.', 'java.'])
+        }
     }
 
     void testCompleteJ() {
-        helperMocker.demand.getContents(1) { str -> assert(str == '' ); ["java", "javax"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "j"
-            assertEquals(0, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["java.", "javax."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['java', 'javax']), 'j', false, ['java.', 'javax.'])
         }
-    }}
+    }
 
     void testCompleteStaticJ() {
-        helperMocker.demand.getContents(1) { str -> assert(str == '' ); ["java", "javax"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, true);
-            def candidates = []
-            String buffer = "j"
-            assertEquals(0, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["java.", "javax."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['java', 'javax']), 'j', true, ['java.', 'javax.'])
         }
-    }}
+    }
 
     void testCompleteCo() {
-        helperMocker.demand.getContents(1) { str -> assert(str == '' ); ["com", "org"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "co"
-            assertEquals(0, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["com."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['com', 'org']), 'co', false, ['com.'])
         }
-    }}
+    }
 
     void testCompleteJavaDot() {
-        helperMocker.demand.getContents(1) { ["util", "math"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java."
-            assertEquals(5, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["* ", "math.", "util."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['util', 'math']), 'java.', false, ['* ', 'math.', 'util.'])
         }
-    }}
+    }
 
     void testCompleteStaticJavaDot() {
-        helperMocker.demand.getContents(1) { ["util", "math"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, true);
-            def candidates = []
-            String buffer = "java."
-            assertEquals(5, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["math.", "util."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['util', 'math']), 'java.', true, ['math.', 'util.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotU() {
-        helperMocker.demand.getContents(1) { ["util", "math"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.u"
-            assertEquals(5, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["util."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['util', 'math']), 'java.u', false, ['util.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotUtil() {
-        helperMocker.demand.getContents(1) { ["util"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.util"
-            assertEquals(5, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["util."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['util']), 'java.util', false, ['util.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotUtilDot() {
-        helperMocker.demand.getContents(1) { ["zip", "jar"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.util."
-            assertEquals(10, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["* ", "jar.", "zip."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['zip', 'jar']), 'java.util.', false, ['* ', 'jar.', 'zip.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotUtilDotZip() {
-        helperMocker.demand.getContents(1) { ["zip"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.util.zip"
-            assertEquals(10, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["zip."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['zip']), 'java.util.zip', false, ['zip.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotUtilDotZipDot() {
-        helperMocker.demand.getContents(1) { ["Test1", "Test2"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.util.zip."
-            assertEquals(14, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["* ", "Test1 ", "Test2 "], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['Test1', 'Test2']), 'java.util.zip.', false, ['* ', 'Test1 ', 'Test2 '])
         }
-    }}
+    }
 
     void testCompleteStaticJavaDotUtilDotZipDot() {
-        helperMocker.demand.getContents(1) { ["Test1", "Test2"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, true);
-            def candidates = []
-            String buffer = "java.util.zip."
-            assertEquals(14, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["Test1.", "Test2."], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['Test1', 'Test2']), 'java.util.zip.', true, ['Test1.', 'Test2.'])
         }
-    }}
+    }
 
     void testCompleteJavaDotUtilDotZipDotT() {
-        helperMocker.demand.getContents(1) { ["Test", "NotThis"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, false);
-            def candidates = []
-            String buffer = "java.util.zip.T"
-            assertEquals(14, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["Test "], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['Test', 'NotThis']), 'java.util.zip.T', false, ['Test '])
         }
-    }}
+    }
 
     void testCompleteStaticJavaDotUtilDotZipDotT() {
-        helperMocker.demand.getContents(1) { ["Test", "NotThis"] }
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            ImportCompleter compl = new ImportCompleter(packageHelper2, null, true);
-            def candidates = []
-            String buffer = "java.util.zip.T"
-            assertEquals(14, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["Test "], candidates.sort())
+        preferencesMocker.use {
+            assertCompletionCandidatesMatch(new MockPackageHelper(['Test', 'NotThis']), 'java.util.zip.T', true, ['Test '])
         }
-    }}
+    }
 
     void testCompleteStaticJavaDotUtilDotZipDotTestDot() {
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            def mockInterp = [evaluate: {expr -> assert(expr == ['java.util.zip.Test']); Math}]
-            ImportCompleter compl = new ImportCompleter(packageHelper2, mockInterp, true);
+        preferencesMocker.use {
+            def evaluator = new Evaluator() {
+                @Override
+                def evaluate(Collection<String> buffer) {
+                    assert(buffer == ['java.util.zip.Test'])
+                    return Math
+                }
+            }
+            ImportCompleter compl = new ImportCompleter(new MockPackageHelper([]), evaluator, true)
+            String buffer = 'java.util.zip.Test.'
             def candidates = ['previousitem']
-            String buffer = "java.util.zip.Test."
-            assertEquals(19, compl.complete(buffer, buffer.length(), candidates))
-            // using Math as mock class
-            assertTrue('* ' in candidates)
-            assertTrue(candidates.toString(), 'abs ' in candidates)
-            assertTrue('previousitem' in candidates)
+            assert (buffer.lastIndexOf('.') + 1) == compl.complete(buffer, buffer.length(), candidates)
+            assert '* ' in candidates
+            assert candidates.toString(), 'abs ' in candidates
+            assert 'previousitem' in candidates
         }
-    }}
+    }
 
     void testCompleteStaticJavaDotUtilDotZipDotTestDotMa() {
-        helperMocker.use { preferencesMocker.use {
-            def packageHelper2 = new PackageHelper()
-            def mockInterp = [evaluate: {expr -> assert(expr == ['java.util.zip.Test']); Math}]
-            ImportCompleter compl = new ImportCompleter(packageHelper2, mockInterp, true);
+        preferencesMocker.use {
+            def evaluator = new Evaluator() {
+                @Override
+                def evaluate(Collection<String> buffer) {
+                    assert(buffer == ['java.util.zip.Test'])
+                    return Math
+                }
+            }
+            ImportCompleter compl = new ImportCompleter(new MockPackageHelper([]), evaluator, true)
             def candidates = []
-            String buffer = "java.util.zip.Test.ma"
-            assertEquals(19, compl.complete(buffer, buffer.length(), candidates))
-            assertEquals(["max "], candidates.sort())
+            String buffer = 'java.util.zip.Test.ma'
+            assert 19 == compl.complete(buffer, buffer.length(), candidates)
+            assert ['max '] == candidates.sort()
         }
-    }}
+    }
 }
 
-class ImportCompleterTest
-extends CompletorTestSupport {
+class ImportCompleterTest extends CompletorTestSupport {
 
     void testEmpty() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
-            assertEquals(0, completer.complete("", 0, candidates))
+            assert 0 == completer.complete('', 0, candidates)
             // order changed by sort
-            assertEquals([":i", ":i", "import", "import"], candidates.sort())
+            assert [':i', ':i', 'import', 'import'] == candidates.sort()
         }
     }
 
     void testUnknownVar() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
-            assertEquals(7, completer.complete("import ", "import ".length(), candidates))
+            assert 7 == completer.complete('import ', 'import '.length(), candidates)
             // order changed by sort, needed to make tests run on different JDks
-            assertEquals(["java.", "static ", "test."], candidates.sort())
+            assert ['java.', 'static ', 'test.'] == candidates.sort()
         }
     }
 
     void testJ() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
-            // argument completer completes after "import "
-            assertEquals(7, completer.complete("import j", "import j".length(), candidates))
-            assertEquals(["java."], candidates)
+            // argument completer completes after 'import '
+            assert 7 == completer.complete('import j', 'import j'.length(), candidates)
+            assert ['java.'] == candidates
         }
     }
 
     void testJavaDot() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
-            // argument completer completes after "import "
-            String buffer = "import java."
-            assertEquals(12, completer.complete(buffer, buffer.length(), candidates))
+            // argument completer completes after 'import '
+            String buffer = 'import java.'
+            assert 12 == completer.complete(buffer, buffer.length(), candidates)
             // order changed by sort, needed to run tests on different JDKs
-            assertEquals(["* ", "java.", "test."], candidates.sort())
+            assert ['* ', 'java.', 'test.'] == candidates.sort()
         }
     }
 
     void testJavaLangDot() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
-            // argument completer completes after "import "
-            String buffer = "import java.lang."
-            assertEquals(17, completer.complete(buffer, buffer.length(), candidates))
+            // argument completer completes after 'import '
+            String buffer = 'import java.lang.'
+            assert 17 == completer.complete(buffer, buffer.length(), candidates)
             // order changed by sort, needed to make tests run on different JDks
-            assertEquals(["* ", "java.", "test."], candidates.sort())
+            assert ['* ', 'java.', 'test.'] == candidates.sort()
         }
     }
 
     void testAs() {
-        mockPackageHelper = packageHelperMocker.proxyInstance()
+        mockPackageHelper = new MockPackageHelper(['java', 'test'])
         groovyshMocker.demand.getPackageHelper(1) { mockPackageHelper }
         groovyshMocker.demand.getInterp(1) {}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportCommand iCom = new ImportCommand(groovyshMock)
-            Completer completer = iCom.getCompleter()
+            Completer completer = iCom.completer
             def candidates = []
             // mock package
-            String buffer = "import java.test "
-            assertEquals(17, completer.complete(buffer, buffer.length(), candidates))
-            assertEquals(["as "], candidates)
+            String buffer = 'import java.test '
+            assert 17 == completer.complete(buffer, buffer.length(), candidates)
+            assert ['as '] == candidates
         }
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTest.groovy
index 2fe43ec..67eb6eb 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTest.groovy
@@ -17,16 +17,17 @@
 package org.codehaus.groovy.tools.shell
 
 import groovy.mock.interceptor.MockFor
-import jline.console.ConsoleReader
 import org.codehaus.groovy.tools.shell.util.Preferences
 
 class ShellRunnerTest extends GroovyTestCase {
 
-    Groovysh groovysh
+    private Groovysh groovysh
 
+    @Override
     void setUp() {
-        ByteArrayOutputStream mockOut = new ByteArrayOutputStream();
-        ByteArrayOutputStream mockErr = new ByteArrayOutputStream();
+        super.setUp()
+        ByteArrayOutputStream mockOut = new ByteArrayOutputStream()
+        ByteArrayOutputStream mockErr = new ByteArrayOutputStream()
 
         IO testio = new IO(new ByteArrayInputStream(),
                 mockOut,
@@ -35,15 +36,15 @@ class ShellRunnerTest extends GroovyTestCase {
     }
 
     void testReadLineIndentPreferenceOff() {
-        groovysh.buffers.buffers.add(["Foo {"])
+        groovysh.buffers.buffers.add(['Foo {'])
         groovysh.buffers.select(1)
 
         MockFor readerMocker = primedMockForConsoleReader()
         readerMocker.demand.readLine(1) {'Foo {'}
         MockFor preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) {"false"}
+        preferencesMocker.demand.get(1) {'false'}
         preferencesMocker.use {readerMocker.use {
-            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {">"})
+            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {'>'})
             runner.readLine()
             assertEquals(0, runner.wrappedInputStream.inserted.available())
         }}
@@ -53,45 +54,46 @@ class ShellRunnerTest extends GroovyTestCase {
         MockFor readerMocker = primedMockForConsoleReader()
         readerMocker.demand.readLine(1) {'Foo {'}
         MockFor preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) {"true"}
+        preferencesMocker.demand.get(1) {'true'}
         preferencesMocker.use {readerMocker.use {
-            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {">"})
+            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {'>'})
             runner.readLine()
             assertEquals(0, runner.wrappedInputStream.inserted.available())
         }}
     }
 
     void testReadLineIndentOne() {
-        groovysh.buffers.buffers.add(["Foo {"])
+        groovysh.buffers.buffers.add(['Foo {'])
         groovysh.buffers.select(1)
 
         MockFor readerMocker = primedMockForConsoleReader()
         readerMocker.demand.readLine(1) {'Foo {'}
         MockFor preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) {"true"}
+        preferencesMocker.demand.get(1) {'true'}
         preferencesMocker.use {readerMocker.use {
-            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {">"})
+            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {'>'})
             runner.readLine()
             assertEquals(groovysh.indentSize, runner.wrappedInputStream.inserted.available())
         }}
     }
 
     void testReadLineIndentTwo() {
-        groovysh.buffers.buffers.add(["Foo { {"])
+        groovysh.buffers.buffers.add(['Foo { {'])
         groovysh.buffers.select(1)
         MockFor readerMocker = primedMockForConsoleReader()
         readerMocker.demand.readLine(1) {'Foo { {'}
         MockFor preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) {"true"}
+        preferencesMocker.demand.get(1) {'true'}
         preferencesMocker.use {readerMocker.use {
-            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {">"})
+            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {'>'})
             runner.readLine()
             assertEquals(groovysh.indentSize * 2, runner.wrappedInputStream.inserted.available())
         }}
     }
 
     private MockFor primedMockForConsoleReader() {
-        def readerMocker = new MockFor(ConsoleReader)
+        def readerMocker = new MockFor(PatchedConsoleReader)
+        readerMocker.demand.setCompletionHandler {}
         readerMocker.demand.setExpandEvents {}
         readerMocker.demand.addCompleter(2) {}
         readerMocker
@@ -101,26 +103,27 @@ class ShellRunnerTest extends GroovyTestCase {
 class ShellRunnerTest2 extends GroovyTestCase {
 
     void testReadLinePaste() {
-        ByteArrayOutputStream mockOut = new ByteArrayOutputStream();
-        ByteArrayOutputStream mockErr = new ByteArrayOutputStream();
+        ByteArrayOutputStream mockOut = new ByteArrayOutputStream()
+        ByteArrayOutputStream mockErr = new ByteArrayOutputStream()
 
-        IO testio = new IO(new ByteArrayInputStream('Some Clipboard Content'.getBytes()),
+        IO testio = new IO(new ByteArrayInputStream('Some Clipboard Content'.bytes),
                 mockOut,
                 mockErr)
         Groovysh groovysh = new Groovysh(testio)
-        groovysh.buffers.buffers.add(["Foo { {"])
+        groovysh.buffers.buffers.add(['Foo { {'])
         groovysh.buffers.select(1)
 
-        MockFor readerMocker = new MockFor(ConsoleReader)
+        MockFor readerMocker = new MockFor(PatchedConsoleReader)
+        readerMocker.demand.setCompletionHandler {}
         readerMocker.demand.setExpandEvents {}
         readerMocker.demand.addCompleter(2) {}
         readerMocker.demand.readLine(1) {'Foo { {'}
         MockFor preferencesMocker = new MockFor(Preferences)
-        preferencesMocker.demand.get(1) {"true"}
+        preferencesMocker.demand.get(1) {'true'}
         preferencesMocker.use {readerMocker.use {
-            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {">"})
+            InteractiveShellRunner runner = new InteractiveShellRunner(groovysh, {'>'})
             runner.readLine()
             assertEquals(0, runner.wrappedInputStream.inserted.available())
         }}
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTestSupport.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTestSupport.groovy
index 1817a69..8af96d5 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTestSupport.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellRunnerTestSupport.groovy
@@ -26,16 +26,16 @@ import jline.console.ConsoleReader
  * @author <a href="mailto:jason at planet57.com">Jason Dillon</a>
  * @author tkruse
  */
-abstract class ShellRunnerTestSupport
-extends GroovyTestCase {
+abstract class ShellRunnerTestSupport extends GroovyTestCase {
 
-    IO testio
-    BufferedOutputStream mockOut
-    BufferedOutputStream mockErr
+    protected IO testio
+    protected BufferedOutputStream mockOut
+    protected BufferedOutputStream mockErr
 
-    MockFor shellMocker
-    StubFor readerStubber
+    protected MockFor shellMocker
+    protected StubFor readerStubber
 
+    @Override
     void setUp() {
         super.setUp()
         mockOut = new BufferedOutputStream(new ByteArrayOutputStream())
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellTest.groovy
index c6c069f..34700f3 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/ShellTest.groovy
@@ -18,16 +18,16 @@ package org.codehaus.groovy.tools.shell
 
 class ShellTest extends GroovyTestCase {
 
-    IO testio
-    ByteArrayOutputStream mockOut
-    ByteArrayOutputStream mockErr
+    private IO testio
+    private ByteArrayOutputStream mockOut
+    private ByteArrayOutputStream mockErr
 
+    @Override
     void setUp() {
         super.setUp()
 
-        mockOut = new ByteArrayOutputStream();
-
-        mockErr = new ByteArrayOutputStream();
+        mockOut = new ByteArrayOutputStream()
+        mockErr = new ByteArrayOutputStream()
 
         testio = new IO(
                 new ByteArrayInputStream(),
@@ -35,14 +35,10 @@ class ShellTest extends GroovyTestCase {
                 mockErr)
     }
 
-    void testParseLine() {
-        Shell shell = new Shell(testio)
-        assertEquals(['foo', 'bar'], shell.parseLine("  foo bar  "))
-        assertEquals([], shell.parseLine(""))
-    }
+
 
     void testFindCommandNull() {
         Shell shell = new Shell(testio)
-        assertEquals(null, shell.findCommand(" foo bar "))
+        assert null == shell.findCommand(' foo bar ')
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/CommandTestSupport.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/CommandTestSupport.groovy
index 6f9dade..3d293b0 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/CommandTestSupport.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/CommandTestSupport.groovy
@@ -26,10 +26,11 @@ import org.codehaus.groovy.tools.shell.Groovysh
 abstract class CommandTestSupport
     extends GroovyTestCase
 {
-    Groovysh shell
+    protected Groovysh shell
 
-    Object lastResult
+    protected Object lastResult
 
+    @Override
     void setUp() {
         super.setUp()
 
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ComplexCommandSupportTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ComplexCommandSupportTest.groovy
index 5a791ed..0c6e7d7 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ComplexCommandSupportTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ComplexCommandSupportTest.groovy
@@ -29,101 +29,98 @@ class ComplexCommandSupportTest
     extends CommandTestSupport
 {
     void testNew() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", null) {}
-        assertEquals("fcom", com.name)
-        assertEquals("f", com.shortcut)
-        assertEquals(null, com.functions)
-        assertEquals(null, com.getFunctions())
-        assertEquals(null, com.defaultFunction)
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', null) {}
+        assert 'fcom' == com.name
+        assert 'f' == com.shortcut
+        assert null == com.functions
+        assert null == com.defaultFunction
     }
 
     void testNewFunctions() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar"]) {}
-        assertEquals("fcom", com.name)
-        assertEquals("f", com.shortcut)
-        assertEquals(["foo", "bar"], com.functions)
-        assertEquals(["foo", "bar"], com.getFunctions())
-        assertEquals(null, com.defaultFunction)
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar']) {}
+        assert 'fcom' == com.name
+        assert 'f' == com.shortcut
+        assert ['foo', 'bar'] == com.functions
+        assert null == com.defaultFunction
     }
 
     void testNewFunctionsDefault() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar"], "foo") {}
-        assertEquals("fcom", com.name)
-        assertEquals("f", com.shortcut)
-        assertEquals(["foo", "bar"], com.functions)
-        assertEquals(["foo", "bar"], com.getFunctions())
-        assertEquals("foo", com.defaultFunction)
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar'], 'foo') {}
+        assert 'fcom' == com.name
+        assert 'f' == com.shortcut
+        assert ['foo', 'bar'] == com.functions
+        assert 'foo' == com.defaultFunction
     }
 
     void testNewFunctionsBadDefault() {
         try {
-            new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar"], "foo") {}
-            fail()
+            new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar'], 'foo') {}
+            fail('expected AssertionError')
         } catch (AssertionError e) {
             // pass
         }
     }
 
     void testCreateCompleters() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar", "baz"]) {}
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar', 'baz']) {}
         List<Completer> completors = com.createCompleters()
-        assertEquals(2, completors.size())
-        assertEquals(null, completors[-1])
+        assert 2 == completors.size()
+        assert null == completors[-1]
 
     }
 
     void testCompletor() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar", "baz"]) {}
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar', 'baz']) {}
         def candidates = []
-        Completer completor = com.getCompleter()
-        assertEquals(5, completor.complete("fcom ba", "fcom ba".length(), candidates))
-        assertEquals(["bar", "baz"], candidates)
-        assertEquals(-1, completor.complete("fcom bar ba", "fcom bar ba".length(), candidates))
+        Completer completor = com.completer
+        assert 5 == completor.complete('fcom ba', 'fcom ba'.length(), candidates)
+        assert ['bar', 'baz'] == candidates
+        assert -1 == completor.complete('fcom bar ba', 'fcom bar ba'.length(), candidates)
     }
 
     void testDoAll() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo", "bar", "all"]) {
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo', 'bar', 'all']) {
             def invoked = []
             def do_foo = {
-                invoked.add("foo");
+                invoked.add('foo')
                 return 1
             }
             def do_bar = {
-                invoked.add("bar");
+                invoked.add('bar')
                 return 2
             }
         }
-        assertEquals([1, 2], com.do_all().sort());
-        assertEquals(["bar", "foo"], com.invoked.sort())
+        assert [1, 2] == com.do_all().sort()
+        assert ['bar', 'foo'] == com.invoked.sort()
     }
 
     void testExecute() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo"]) {
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo']) {
             def invoked = []
             def do_foo = {arg1 -> invoked.addAll(arg1)}
         }
         try {
             com.execute([])
-            fail()
+            fail('expected CommandException ')
         } catch (CommandException e) {
             // pass
         }
 
-        com.execute(["foo"])
-        assertEquals([], com.invoked)
+        com.execute(['foo'])
+        assert [] == com.invoked
 
-        com.execute(["foo"])
-        assertEquals([], com.invoked)
+        com.execute(['foo'])
+        assert [] == com.invoked
 
-        com.execute(["foo", "bar"])
-        assertEquals(["bar"], com.invoked)
+        com.execute(['foo', 'bar'])
+        assert ['bar'] == com.invoked
 
-        com.execute(["foo", "bar", "baz"])
-        assertEquals(["bar", "bar", "baz"], com.invoked)
+        com.execute(['foo', 'bar', 'baz'])
+        assert ['bar', 'bar', 'baz'] == com.invoked
     }
 
     void testExecuteDefault() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo"], "foo") {
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo'], 'foo') {
             def invoked = []
             def do_foo = {arg1 -> invoked.addAll(arg1)}
         }
@@ -132,34 +129,34 @@ class ComplexCommandSupportTest
     }
 
     void testExecuteFunction() {
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo"]) {
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo']) {
             def invoked = []
             def do_foo = {arg1 -> invoked.addAll(arg1)}
         }
         try {
-            com.executeFunction("bar", ["baz"])
+            com.executeFunction('bar', ['baz'])
         }  catch (CommandException e) {
             // pass
         }
-        assertEquals([], com.invoked)
-        com.executeFunction("foo", ["baz"])
-        assertEquals(["baz"], com.invoked)
-        com.executeFunction("foo", ["bim", "bam"])
-        assertEquals(["baz", "bim", "bam"], com.invoked)
+        assert [] == com.invoked
+        com.executeFunction('foo', ['baz'])
+        assert ['baz'] == com.invoked
+        com.executeFunction('foo', ['bim', 'bam'])
+        assert ['baz', 'bim', 'bam'] == com.invoked
     }
 
     void testLoadFunction() {
         Closure fun = { x -> x+1}
-        ComplexCommandSupport com = new ComplexCommandSupport(shell, "fcom", "f", ["foo"], "foo") {
+        ComplexCommandSupport com = new ComplexCommandSupport(shell, 'fcom', 'f', ['foo'], 'foo') {
             def invoked = []
             def do_foo = fun
         }
-        assertEquals(fun, com.loadFunction("foo"))
+        assert fun == com.loadFunction('foo')
         try {
-            com.loadFunction("bar")
-            fail()
+            com.loadFunction('bar')
+            fail('expected CommandException')
         } catch(CommandException e) {
             // pass
         }
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/DocCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/DocCommandTest.groovy
index 4ab8d25..1dba26b 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/DocCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/DocCommandTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2015 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -27,74 +27,44 @@ import org.codehaus.groovy.tools.shell.Groovysh
 class DocCommandTest extends CommandTestSupport
 {
     void testInitializeAWTDesktopPlatformSupportFlag() {
-        boolean hasSupport
-        try {
-            def desktopClass = Class.forName('java.awt.Desktop')
-            hasSupport =
-                desktopClass.desktopSupported &&
-                        desktopClass.desktop.isSupported(desktopClass.declaredClasses.find { it.simpleName == "Action" }.BROWSE)
-        }
-        catch(ClassNotFoundException e) {
-            //We are using jdk 1.5 where 'java.awt.Desktop' does not exist
-            hasSupport = false
-        }
+        def desktopClass = Class.forName('java.awt.Desktop')
+        boolean hasSupport =
+            desktopClass.desktopSupported &&
+                    desktopClass.desktop.isSupported(desktopClass.declaredClasses.find { it.simpleName == 'Action' }.BROWSE)
 
         assert DocCommand.hasAWTDesktopPlatformSupport == hasSupport
     }
 
     void testUrlsForJavaOnlyClass() {
-        def urlsToLookup = []
-        def command = new DocCommand(new Groovysh()) {
-            @Override
-            protected boolean sendHEADRequest(final URL url) {
-                !url.host.contains('groovy.codehaus.org')
-            }
-        }
+        def command = docCommandWithSendHEADRequestReturnValueOf { !it.host.contains('docs.groovy-lang.org') }
 
         def urls = command.urlsFor('org.ietf.jgss.GSSContext')
 
         assert urls ==
-            [new URL("http://docs.oracle.com/javase/${simpleVersion()}/docs/api/org/ietf/jgss/GSSContext.html")]
+            [new URL("http://docs.oracle.com/javase/${simpleJavaVersion()}/docs/api/org/ietf/jgss/GSSContext.html")]
     }
 
     void testUrlsForJavaClass() {
-        def urlsToLookup = []
-        def command = new DocCommand(new Groovysh()) {
-            boolean sendHEADRequest(URL url) {
-                urlsToLookup << url
-                true
-            }
-        }
+        def command = docCommandWithSendHEADRequestReturnValueOf { true }
 
         def urls = command.urlsFor('java.util.List')
 
         assert urls ==
-                [new URL("http://docs.oracle.com/javase/${simpleVersion()}/docs/api/java/util/List.html"),
-                 new URL("http://groovy.codehaus.org/groovy-jdk/java/util/List.html")]
-
-        assert urls == urlsToLookup
+                [new URL("http://docs.oracle.com/javase/${simpleJavaVersion()}/docs/api/java/util/List.html"),
+                 new URL("http://docs.groovy-lang.org/$GroovySystem.version/html/groovy-jdk/java/util/List.html")]
     }
 
     void testUrlsForGroovyClass() {
-        def urlsToLookup = []
-        def command = new DocCommand(new Groovysh()) {
-            boolean sendHEADRequest(URL url) {
-                urlsToLookup << url
-                true
-            }
-        }
+        def command = docCommandWithSendHEADRequestReturnValueOf { true }
 
         def urls = command.urlsFor('groovy.Dummy')
 
         assert urls ==
-                [new URL('http://groovy.codehaus.org/gapi/groovy/Dummy.html')]
-
-        assert urls == urlsToLookup
+                [new URL("http://docs.groovy-lang.org/$GroovySystem.version/html/gapi/groovy/Dummy.html")]
     }
 
     void testUrlsForWithUnknownClass() {
-        def urlsToLookup = []
-        def command = new DocCommand(new Groovysh())
+        def command = docCommandWithSendHEADRequestReturnValueOf { false }
 
         def urls = command.urlsFor('com.dummy.List')
 
@@ -119,7 +89,7 @@ class DocCommandTest extends CommandTestSupport
         DocCommand.hasAWTDesktopPlatformSupport = true
         DocCommand.desktop = [:]
 
-        command.browse([new URL('http://docs.oracle.com/javase/${simpleVersion()}/docs/api/java/util/List.html')])
+        command.browse([new URL("http://docs.oracle.com/javase/${simpleJavaVersion()}/docs/api/java/util/List.html")])
 
         assert browseWithAWT
     }
@@ -140,7 +110,7 @@ class DocCommandTest extends CommandTestSupport
             }
         }
 
-        command.browse([new URL('http://docs.oracle.com/javase/${simpleVersion()}/docs/api/java/util/List.html')])
+        command.browse([new URL("http://docs.oracle.com/javase/${simpleJavaVersion()}/docs/api/java/util/List.html")])
 
         assert browseWithNativeBrowser
     }
@@ -148,9 +118,9 @@ class DocCommandTest extends CommandTestSupport
     void testNormalizeClassName() {
         def command = new DocCommand(new Groovysh())
 
-        assert 'java.util.List' == command.normalizeClassName('"java.util.List"')
-        assert 'java.util.List' == command.normalizeClassName("'java.util.List'")
-        assert 'java.util.List' == command.normalizeClassName("java.util.List")
+        assert 'java.util.List' == command.normalizeClassName(/java.util.List'/)
+        assert 'java.util.List' == command.normalizeClassName(/'java.util.List'/)
+        assert 'java.util.List' == command.normalizeClassName('java.util.List')
     }
 
     void testGetBrowserEnvironmentVariable() {
@@ -169,7 +139,16 @@ class DocCommandTest extends CommandTestSupport
         assert command.browserEnvironmentVariable == 'chrome'
     }
 
-    private static simpleVersion() {
-        System.getProperty("java.version").tokenize('_')[0]
+    private DocCommand docCommandWithSendHEADRequestReturnValueOf(Closure returnValue) {
+        new DocCommand(new Groovysh()) {
+            @Override
+            boolean sendHEADRequest(URL url) {
+                returnValue(url)
+            }
+        }
+    }
+
+    private simpleJavaVersion() {
+        System.getProperty('java.version').split(/\./)[1]
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/EditCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/EditCommandTest.groovy
index b892116..7c76b67 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/EditCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/EditCommandTest.groovy
@@ -26,14 +26,14 @@ class EditCommandTest
 {
     void testProcessBuilderInit() {
         def mockEdit = new EditCommand(shell)
-        ProcessBuilder pb = mockEdit.getEditorProcessBuilder("/usr/bin/vim", 
-                "/var/folders/tu/tuATI/-Tmp-/groovysh-buffer1761911.groovy")
+        ProcessBuilder pb = mockEdit.getEditorProcessBuilder('/usr/bin/vim',
+                '/var/folders/tu/tuATI/-Tmp-/groovysh-buffer1761911.groovy')
 
         assert pb.redirectErrorStream()
 
         // GROOVY-6201: Editor should inherit I/O from the current process.
         //    Fixed only for java >= 1.7 using new ProcessBuilder api
-        def javaVer = Double.valueOf(System.getProperty("java.specification.version"));
+        def javaVer = Double.valueOf(System.getProperty('java.specification.version'))
         if (javaVer >= 1.7) {
             assert pb.redirectInput() == ProcessBuilder.Redirect.INHERIT
             assert pb.redirectOutput() == ProcessBuilder.Redirect.INHERIT
@@ -44,12 +44,12 @@ class EditCommandTest
         String partialExpression1 = 'x = {'
         String partialExpression2 = '  println 2+2'
         String partialExpression3 = '}'
-        
+
         def mockEdit = new EditCommand(shell)
-        
+
         // type an incomplete groovy expression
         shell << partialExpression1
-        
+
         // simulate a user launching an editor and completing the expression
         List<String> mockEditorContents = [partialExpression1, partialExpression2, partialExpression3]
         mockEdit.replaceCurrentBuffer(mockEditorContents)
@@ -61,12 +61,12 @@ class EditCommandTest
     void testEditorReplacingPartialGroovyExpression() {
         String partialExpression1 = 'x = {'
         String partialExpression2 = '  println 2+2'
-        
+
         def mockEdit = new EditCommand(shell)
-        
+
         // type an incomplete groovy expression
         shell << partialExpression1
-        
+
         // simulate a user launching an editor and adding to, but not completing, the expression
         List<String> mockEditorContents = [partialExpression1, partialExpression2]
         mockEdit.replaceCurrentBuffer(mockEditorContents)
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommandTest.groovy
index bec2d54..c3b900a 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ExitCommandTest.groovy
@@ -29,7 +29,7 @@ class ExitCommandTest
     void testWithNoArgs() {
         try {
             shell.execute(ExitCommand.COMMAND_NAME)
-            fail()
+            fail('expected Exception')
         }
         catch (ExitNotification e) {
             // expected
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommandTest.groovy
index 7e5c6b8..4e4a9d8 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/HistoryCommandTest.groovy
@@ -38,11 +38,12 @@ class HistoryCommandTest extends CommandTestSupport
 
 class HistoryCommandIntegrationTest extends CompletorTestSupport
 {
-    File filemock
+    private File filemock
 
+    @Override
     void setUp() {
         super.setUp()
-        filemock = new File("aaaa") {
+        filemock = new File('aaaa') {
             @Override
             boolean delete() {
                 return true
@@ -61,43 +62,43 @@ class HistoryCommandIntegrationTest extends CompletorTestSupport
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             HistoryCommand command = new HistoryCommand(groovyshMock)
-            command.do_show();
-            assertEquals('', mockOut.toString())
+            command.do_show()
+            assert '' == mockOut.toString()
         }
     }
 
     void testShowLines() {
         FileHistory history = new FileHistory(filemock)
-        history.add("test1")
-        history.add("test2")
-        assertEquals(2, history.size())
+        history.add('test1')
+        history.add('test2')
+        assert 2 == history.size()
         groovyshMocker.demand.getHistory(1) {history}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             HistoryCommand command = new HistoryCommand(groovyshMock)
-            command.do_show();
-            assertTrue(mockOut.toString(), 'test1' in mockOut.toString().split())
-            assertTrue(mockOut.toString(), 'test2' in mockOut.toString().split())
+            command.do_show()
+            assert 'test1' in mockOut.toString().split()
+            assert 'test2' in mockOut.toString().split()
         }
     }
 
     void testClear() {
         FileHistory history = new FileHistory(filemock)
-        history.add("test1")
-        history.add("test2")
+        history.add('test1')
+        history.add('test2')
         groovyshMocker.demand.getHistory(1) {history}
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             HistoryCommand command = new HistoryCommand(groovyshMock)
-            command.do_clear();
-            assertEquals(0, history.size())
+            command.do_clear()
+            assert 0 == history.size()
         }
     }
 
     void testRecall() {
         FileHistory history = new FileHistory(filemock)
-        history.add("test1")
-        history.add("test2")
+        history.add('test1')
+        history.add('test2')
         groovyshMocker.demand.getHistoryFull(1) {false}
         groovyshMocker.demand.getHistory(1) {history}
         groovyshMocker.demand.execute(1) {String it -> assert(it == 'test1'); 34}
@@ -108,17 +109,17 @@ class HistoryCommandIntegrationTest extends CompletorTestSupport
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             HistoryCommand command = new HistoryCommand(groovyshMock)
-            def result = command.do_recall(['0']);
-            assertEquals(34, result)
-            result = command.do_recall(['1']);
-            assertEquals(56, result)
+            def result = command.do_recall(['0'])
+            assert 34 == result
+            result = command.do_recall(['1'])
+            assert 56 == result
         }
     }
 
     void testRecallHistoryFull() {
         FileHistory history = new FileHistory(filemock)
-        history.add("test1")
-        history.add("test2")
+        history.add('test1')
+        history.add('test2')
         groovyshMocker.demand.getHistoryFull(1) {true}
         groovyshMocker.demand.getHistory(1) {history}
         groovyshMocker.demand.getEvictedLine(1) {'test3'}
@@ -130,10 +131,10 @@ class HistoryCommandIntegrationTest extends CompletorTestSupport
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             HistoryCommand command = new HistoryCommand(groovyshMock)
-            def result = command.do_recall(['0']);
-            assertEquals(45, result)
-            result = command.do_recall(['1']);
-            assertEquals(56, result)
+            def result = command.do_recall(['0'])
+            assert 45 == result
+            result = command.do_recall(['1'])
+            assert 56 == result
         }
     }
 
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommandTest.groovy
index da8e6be..cb0cab7 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/ImportCommandTest.groovy
@@ -24,6 +24,15 @@ package org.codehaus.groovy.tools.shell.commands
 class ImportCommandTest
     extends CommandTestSupport
 {
+    void testPatternClassOrMethodName() {
+        assert 'java.util.*'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+        assert 'java.util.Pattern'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+        assert 'static java.util.Pattern.match'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+        assert 'java.util.Pattern as Fattern'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+        assert 'java.util.Pattern'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+        assert 'java.util.P_attern'.matches(ImportCommand.IMPORTED_ITEM_PATTERN)
+    }
+
     void testImport() {
         assert null == shell << 'import'
         assert 'java.awt.TextField' == shell << 'import java.awt.TextField'
@@ -40,4 +49,4 @@ class ImportCommandTest
         assert 'java.awt.TextArea, java.awt.TextField, java.awt.*, org.w3c.dom.*' == shell << 'import org.w3c.dom.*'
         assert 'java.awt.TextArea, java.awt.TextField, java.awt.*, org.w3c.dom.*, java.awt.Graphics2D' == shell << 'import java.awt.Graphics2D'
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommandTest.groovy
index 1b0b074..f81368c 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/RecordCommandTest.groovy
@@ -46,7 +46,7 @@ class RecordCommandTest
         try {
             // too many args
             command.do_start(['1', '2', '3'])
-            fail()
+            fail('expected Exception')
         } catch (CommandException e) {
             // pass
         }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/SetCommandTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/SetCommandTest.groovy
index f3925ab..81616cf 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/SetCommandTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/commands/SetCommandTest.groovy
@@ -38,14 +38,14 @@ class SetCommandTest
         List<String> candidates = []
         SetCommand command = new SetCommand(shell)
         ArrayList<SimpleCompletor> completors = command.createCompleters()
-        assertEquals(2, completors.size())
-        assertEquals(0, completors[0].complete("", 0, candidates))
-        assertTrue(Groovysh.AUTOINDENT_PREFERENCE_KEY in candidates);
-        assertTrue(PackageHelper.IMPORT_COMPLETION_PREFERENCE_KEY in candidates);
-        assertTrue(Preferences.EDITOR_KEY in candidates);
-        assertTrue(Preferences.PARSER_FLAVOR_KEY in candidates);
-        assertTrue(Preferences.SANITIZE_STACK_TRACE_KEY in candidates);
-        assertTrue(Preferences.SHOW_LAST_RESULT_KEY in candidates);
-        assertTrue(Preferences.VERBOSITY_KEY in candidates);
+        assert 2 == completors.size()
+        assert 0 == completors[0].complete('', 0, candidates)
+        assert Groovysh.AUTOINDENT_PREFERENCE_KEY in candidates
+        assert PackageHelper.IMPORT_COMPLETION_PREFERENCE_KEY in candidates
+        assert Preferences.EDITOR_KEY in candidates
+        assert Preferences.PARSER_FLAVOR_KEY in candidates
+        assert Preferences.SANITIZE_STACK_TRACE_KEY in candidates
+        assert Preferences.SHOW_LAST_RESULT_KEY in candidates
+        assert Preferences.VERBOSITY_KEY in candidates
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassCompletorTest.groovy
index fd282ad..8b6a808 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/CustomClassCompletorTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.tools.shell.completion
 
 import org.codehaus.groovy.tools.shell.CompletorTestSupport
@@ -14,8 +29,8 @@ class CustomClassCompletorTest extends CompletorTestSupport {
             CustomClassSyntaxCompletor completor = new CustomClassSyntaxCompletor(groovyshMock)
             def candidates = []
             // in the shell, only Classes in the default package occur,but well...
-            assertEquals(true, completor.complete(tokenList("jav"), candidates))
-            assertEquals(["java.lang.String"], candidates)
+            assert completor.complete(tokenList('jav'), candidates)
+            assert ['java.lang.String'] == candidates
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleterTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleterTest.groovy
new file mode 100644
index 0000000..eaabb08
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/FileNameCompleterTest.groovy
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.completion
+
+class FileNameCompleterTest extends GroovyTestCase {
+
+    void testRender() {
+        FileNameCompleter completer = new FileNameCompleter()
+        assert completer.render('foo', null) == 'foo'
+        assert completer.render('foo bar', null) == '\'foo bar\''
+        assert completer.render('foo \'bar', null) == '\'foo \\\'bar\''
+        assert completer.render('foo \'bar', '\'') == '\'foo \\\'bar\''
+        assert completer.render('foo " \'bar', '"') == '"foo \\" \'bar"'
+    }
+
+    void testMatchFiles_Unix() {
+        if(! System.getProperty('os.name').startsWith('Windows')) {
+            FileNameCompleter completer = new FileNameCompleter()
+            List<String> candidates = []
+            int resultIndex = completer.matchFiles('foo/bar', '/foo/bar', [new File('/foo/baroo'), new File('/foo/barbee')] as File[], candidates, null)
+            assert resultIndex == 'foo/'.length()
+            assert candidates == ['baroo', 'barbee']
+        }
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletorTest.groovy
index 206b5cf..7dc4606 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/GroovySyntaxCompletorTest.groovy
@@ -29,101 +29,131 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
-            assert -1 == completor.complete("", 0, [])
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
+            assert -1 == completor.complete('', 0, [])
         }
     }
 
     void testIdentifier() {
         idCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["jav"]); candidates << "javup"; candidates << "java.lang.String" ; true}
+            assert(tokens*.text == ['jav']); candidates << 'javup'; candidates << 'java.lang.String' ; true}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "jav"
+            String buffer = 'jav'
             // in the shell, only Classes in the default package occur,but well...
             assert 0 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["javup", "java.lang.String"] == candidates
+            assert ['javup', 'java.lang.String'] == candidates
         }
     }
 
     void testIdentifierAfterLCurly() {
         idCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["{", "jav"]); candidates << "javup"; candidates << "java.lang.String" ; true}
+            assert(tokens*.text == ['{', 'jav']); candidates << 'javup'; candidates << 'java.lang.String' ; true}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "{jav"
+            String buffer = '{jav'
             // in the shell, only Classes in the default package occur,but well...
             assert 1 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["javup", "java.lang.String"] == candidates
+            assert ['javup', 'java.lang.String'] == candidates
         }
     }
 
     void testMember() {
         reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["Math", ".", "ma"]); candidates << "max("; 5}
+            assert(tokens*.text == ['Math', '.', 'ma']); candidates << 'max('; 5}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "Math.ma"
+            String buffer = 'Math.ma'
             assert 5 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["max("] == candidates
+            assert ['max('] == candidates
+        }
+    }
+
+    void testMemberOptionalDot() {
+        reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
+            assert(tokens*.text == ['Math', '?.', 'ma']); candidates << 'max('; 6}
+        IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
+        groovyshMocker.use {
+            Groovysh groovyshMock = new Groovysh()
+            ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
+            def candidates = []
+            String buffer = 'Math?.ma'
+            assert 6 == completor.complete(buffer, buffer.length(), candidates)
+            assert ['max('] == candidates
+        }
+    }
+
+    void testMemberSpreadDot() {
+        reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
+            assert(tokens*.text == ['[', 'foo', ']', '*.', 'len']); candidates << 'length()'; 9}
+        IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
+        groovyshMocker.use {
+            Groovysh groovyshMock = new Groovysh()
+            ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
+            def candidates = []
+            String buffer = '[\'foo\']*.len'
+            assert 9 == completor.complete(buffer, buffer.length(), candidates)
+            assert ['length()'] == candidates
         }
     }
 
     void testMemberAfterMethod() {
         reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["Fo", ".", "ba", "(", ")", ".", "xyz"]); candidates << "xyzabc"; 0}
+            assert(tokens*.text == ['Fo', '.', 'ba', '(', ')', '.', 'xyz']); candidates << 'xyzabc'; 0}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "Fo.ba().xyz"
+            String buffer = 'Fo.ba().xyz'
             // xyz cannot be not a var here
             assert 0 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["xyzabc"] == candidates
+            assert ['xyzabc'] == candidates
         }
     }
 
     void testIdentfierAfterDotAfterParens() {
         idCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["Foo", ".", "bar", "(", "xyz"]); candidates << "xyzabc"; true}
+            assert(tokens*.text == ['Foo', '.', 'bar', '(', 'xyz']); candidates << 'xyzabc'; true}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "Foo.bar(xyz"
+            String buffer = 'Foo.bar(xyz'
             assert 8 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["xyzabc"] == candidates
+            assert ['xyzabc'] == candidates
         }
     }
 
     void testIndentifierAfterParensBeforeDot() {
         idCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["Foo", ".", "bar", "(", "xyz"]); candidates << "xyzabc"; true}
+            assert(tokens*.text == ['Foo', '.', 'bar', '(', 'xyz']); candidates << 'xyzabc'; true}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
             // cursor is BEFORE dot
-            assert 8 == completor.complete("Foo.bar(xyz.", "Foo.bar(xyz".length(), candidates)
-            assert ["xyzabc"] == candidates
+            assert 8 == completor.complete('Foo.bar(xyz.', 'Foo.bar(xyz'.length(), candidates)
+            assert ['xyzabc'] == candidates
         }
     }
 
@@ -132,9 +162,9 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "String jav"
+            String buffer = 'String jav'
             assert -1 == completor.complete(buffer, buffer.length(), candidates)
             assert [] == candidates
         }
@@ -145,48 +175,64 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "class Foo ext"
+            String buffer = 'class Foo ext'
             assert 10 == completor.complete(buffer, buffer.length(), candidates)
             assert ['extends'] == candidates
         }
     }
 
+    void testInstanceof() {
+        idCompletorMocker.demand.complete(1) { tokens, candidates ->
+            assert(tokens*.text == ['x', 'instanceof', 'P']); candidates << 'Property'; 13}
+        IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
+
+        groovyshMocker.use {
+            Groovysh groovyshMock = new Groovysh()
+            ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
+            def candidates = []
+            String buffer = 'x instanceof P'
+            assert 13 == completor.complete(buffer, buffer.length(), candidates)
+            assert 'Property' in candidates
+        }
+    }
+
 
     void testAfterSemi() {
         // evaluation of all is dangerous, but the reflectionCompletor has to deal with this
         reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["deletehardDisk", "(", ")", ";", "foo", ".", "subs"]); candidates << "substring("; 22}
+            assert(tokens*.text == ['deletehardDisk', '(', ')', ';', 'foo', '.', 'subs']); candidates << 'substring('; 22}
 
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         // mock doing the right thing
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "deletehardDisk(); foo.subs"
+            String buffer = 'deletehardDisk(); foo.subs'
             assert 22 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["substring("] == candidates
+            assert ['substring('] == candidates
         }
     }
 
     void testAfterOperator() {
         // evaluation of all is dangerous, but the reflectionCompletor has to deal with this
         reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["a", "=", "foo", ".", "subs"]); candidates << "substring("; 9}
+            assert(tokens*.text == ['a', '=', 'foo', '.', 'subs']); candidates << 'substring('; 9}
 
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         // mock doing the right thing
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "a = foo.subs"
+            String buffer = 'a = foo.subs'
             assert 9 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["substring("] == candidates
+            assert ['substring('] == candidates
         }
     }
 
@@ -199,9 +245,9 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
             // import command prevents reflection completion
             registry.register(new ImportCommand(groovyshMock))
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "import foo"
+            String buffer = 'import foo'
             assert -1 == completor.complete(buffer, buffer.length(), candidates)
             assert [] == candidates
         }
@@ -213,9 +259,9 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "\"\${foo.delete()}\".subs"
+            String buffer = '"\${foo.delete()}".subs'
             assert -1 == completor.complete(buffer, buffer.length(), candidates)
             assert [] == candidates
         }
@@ -224,21 +270,21 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
     void testInStringFilename() {
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         MockFor filenameCompletorMocker = new MockFor(FileNameCompleter)
-        String linestart = "foo('" // ends with single hyphen
-        String pathstart = "/usr/foobar"
+        String linestart = /foo('/ // ends with single hyphen
+        String pathstart = '/usr/foobar'
         String buffer = linestart + pathstart
         filenameCompletorMocker.demand.complete(1) {bufferline, cursor, candidates ->
-            assert(bufferline == pathstart);
-            assert(cursor == pathstart.length());
-            candidates << "foobar"; 5}
+            assert(bufferline == pathstart)
+            assert(cursor == pathstart.length())
+            candidates << 'foobar'; 5}
         groovyshMocker.use { filenameCompletorMocker.use {
             FileNameCompleter mockFileComp = new FileNameCompleter()
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], mockFileComp)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], mockFileComp)
             def candidates = []
-            assert "foo('/usr/".length() == completor.complete(buffer, buffer.length(), candidates)
-            assert ["foobar"] == candidates
+            assert 'foo(\'/usr/'.length() == completor.complete(buffer, buffer.length(), candidates)
+            assert ['foobar'] == candidates
         }}
     }
 
@@ -246,54 +292,54 @@ class GroovySyntaxCompletorTest extends CompletorTestSupport {
         // test with blanks (non-tokens) before the first hyphen
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         MockFor filenameCompletorMocker = new MockFor(FileNameCompleter)
-        String linestart = "x = '" // ends with single hyphen
-        String pathstart = "/usr/foobar"
+        String linestart = 'x = \'' // ends with single hyphen
+        String pathstart = '/usr/foobar'
         String buffer = linestart + pathstart
         filenameCompletorMocker.demand.complete(1) {bufferline, cursor, candidates ->
-            assert(bufferline == pathstart);
-            assert(cursor == pathstart.length());
-            candidates << "foobar"; 5}
+            assert bufferline == pathstart
+            assert cursor == pathstart.length()
+            candidates << 'foobar'; 5}
         groovyshMocker.use { filenameCompletorMocker.use {
             FileNameCompleter mockFileComp = new FileNameCompleter()
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], mockFileComp)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], mockFileComp)
             def candidates = []
-            assert "x = '/usr/".length() == completor.complete(buffer, buffer.length(), candidates)
-            assert ["foobar"] == candidates
+            assert 'x = \'/usr/'.length() == completor.complete(buffer, buffer.length(), candidates)
+            assert ['foobar'] == candidates
         }}
     }
 
     void testInGString() {
         idCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["", "{", "foo"]); candidates << "foobar"; true}
+            assert(tokens*.text == ['', '{', 'foo']); candidates << 'foobar'; true}
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         // mock asserting GString is not evaluated
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "\"\${foo"
+            String buffer = '"\${foo'
             assert 3 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["foobar"] == candidates
+            assert ['foobar'] == candidates
         }
     }
 
     void testMultilineComplete() {
         reflectionCompletorMocker.demand.complete(1) { tokens, candidates ->
-            assert(tokens.collect{it.getText()} == ["xyz\nabc", ".", "subs"]); candidates << "substring("; 7}
-        bufferManager.buffers.add(["\"\"\"xyz"])
+            assert(tokens*.text == ['xyz\nabc', '.', 'subs']); candidates << 'substring('; 7}
+        bufferManager.buffers.add(['"""xyz'])
         bufferManager.setSelected(1)
         IdentifierCompletor mockIdCompletor = idCompletorMocker.proxyDelegateInstance()
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ReflectionCompletor mockReflComp = reflectionCompletorMocker.proxyInstance(groovyshMock)
-            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, [mockIdCompletor], null)
+            GroovySyntaxCompletor completor = new GroovySyntaxCompletor(groovyshMock, mockReflComp, mockIdCompletor, [mockIdCompletor], null)
             def candidates = []
-            String buffer = "abc\"\"\".subs"
+            String buffer = 'abc""".subs'
             assert 7 == completor.complete(buffer, buffer.length(), candidates)
-            assert ["substring("] == candidates
+            assert ['substring('] == candidates
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletorTest.groovy
index fe35f67..973e709 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ImportsSyntaxCompletorTest.groovy
@@ -24,12 +24,12 @@ import static org.codehaus.groovy.tools.shell.completion.TokenUtilTest.tokenList
 class ImportsSyntaxCompletorTest extends CompletorTestSupport {
 
     void testPackagePattern() {
-        assertTrue('import static java.lang.Math' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
-        assertTrue('import static java.lang.Math.max' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
-        assertTrue('import static java.lang.Math.max2' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
-        assertTrue('import static java.lang.Math.*' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
-        assertTrue('import static org.w3c.Math.*' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
-        assertFalse('import static java lang' ==~ ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert 'import static java.lang.Math'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert 'import static java.lang.Math.max'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert 'import static java.lang.Math.max2'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert 'import static java.lang.Math.*'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert 'import static org.w3c.Math.*'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN)
+        assert !('import static java lang'.matches(ImportsSyntaxCompletor.STATIC_IMPORT_PATTERN))
     }
 
     void testPreImported() {
@@ -38,9 +38,9 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
-            assertEquals(true, completor.findMatchingPreImportedClasses('Foo', candidates))
+            assert completor.findMatchingPreImportedClasses('Foo', candidates)
             // once for each standard package
-            assertEquals(['prefill', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo'], candidates)
+            assert ['prefill', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo', 'Foo'] == candidates
         }
     }
 
@@ -50,11 +50,11 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
-            assertEquals(true, completor.findMatchingPreImportedClasses('Big', candidates))
-            assertEquals(['prefill', 'BigInteger', 'BigDecimal'], candidates)
+            assert completor.findMatchingPreImportedClasses('Big', candidates)
+            assert ['prefill', 'BigInteger', 'BigDecimal'] == candidates
             // test again without invoking pakage Helper
-            assertEquals(true, completor.findMatchingPreImportedClasses('Big', candidates))
-            assertEquals(['prefill', 'BigInteger', 'BigDecimal', 'BigInteger', 'BigDecimal'], candidates)
+            assert completor.findMatchingPreImportedClasses('Big', candidates)
+            assert ['prefill', 'BigInteger', 'BigDecimal', 'BigInteger', 'BigDecimal'] == candidates
         }
     }
 
@@ -64,7 +64,7 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.Bbb', candidates)
-            assertEquals(['prefill'], candidates)
+            assert ['prefill'] == candidates
         }
     }
 
@@ -74,7 +74,7 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.Abcdef', candidates)
-            assertEquals(['prefill', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef'] == candidates
         }
     }
 
@@ -84,7 +84,7 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.collectImportedSymbols('import foo.lang.Xxxxx as Abcdef', candidates)
-            assertEquals(['prefill', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef'] == candidates
         }
     }
 
@@ -96,32 +96,32 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.*', candidates)
-            assertEquals(['prefill', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef'] == candidates
             // test again without invoking packageHelper
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.*', candidates)
-            assertEquals(['prefill', 'Abcdef', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef', 'Abcdef'] == candidates
         }
     }
 
     void testImportedStaticCachedNone() {
-        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ["foo.lang.Math"]); Math}] }
+        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ['foo.lang.Math']); Math}] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('ma', 'import static foo.lang.Math.max', candidates)
-            assertEquals(['prefill', 'max('], candidates)
+            assert ['prefill', 'max('] == candidates
         }
     }
 
     void testImportedStaticCachedStar() {
-        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ["foo.lang.Math"]); Math}] }
+        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ['foo.lang.Math']); Math}] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('ma', 'import static foo.lang.Math.*', candidates)
-            assertEquals(['prefill', 'max('], candidates)
+            assert ['prefill', 'max('] == candidates
         }
     }
 
@@ -131,18 +131,18 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('Y', 'import foo.lang.Abcdef as Xxxxxx', candidates)
-            assertEquals(['prefill'], candidates)
+            assert ['prefill'] == candidates
         }
     }
 
     void testImportedStaticCached() {
-        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ["foo.lang.Math"]); Math}] }
+        groovyshMocker.demand.getInterp(1) { [evaluate: {expr -> assert (expr == ['foo.lang.Math']); Math}] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('ma', 'import static foo.lang.Math.max', candidates)
-            assertEquals(['prefill', 'max('], candidates)
+            assert ['prefill', 'max('] == candidates
         }
     }
 
@@ -153,9 +153,9 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.*', candidates)
-            assertEquals(['prefill'], candidates)
+            assert ['prefill'] == candidates
             completor.findMatchingImportedClassesCached('B', 'import foo.lang.*', candidates)
-            assertEquals(['prefill', 'Bbbb'], candidates)
+            assert ['prefill', 'Bbbb'] == candidates
         }
     }
 
@@ -166,10 +166,10 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
             completor.findMatchingImportedClassesCached('A','import foo.lang.*', candidates)
-            assertEquals(['prefill', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef'] == candidates
             // test again without invoking packageHelper
             completor.findMatchingImportedClassesCached('A', 'import foo.lang.*', candidates)
-            assertEquals(['prefill', 'Abcdef', 'Abcdef'], candidates)
+            assert ['prefill', 'Abcdef', 'Abcdef'] == candidates
         }
     }
 
@@ -181,41 +181,41 @@ class ImportsSyntaxCompletorTest extends CompletorTestSupport {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
-            assertEquals(false, completor.complete(tokenList("xyz"), candidates))
-            assertEquals(['prefill'], candidates)
+            assert !completor.complete(tokenList('xyz'), candidates)
+            assert ['prefill'] == candidates
         }
     }
 
     void testSimpleImport() {
         groovyshMocker.demand.getPackageHelper(6) { [getContents: {[]}] }
-        groovyshMocker.demand.getImports(1) { ["import xyzabc.*", "import xxxx.*"] }
+        groovyshMocker.demand.getImports(1) { ['import xyzabc.*', 'import xxxx.*'] }
         groovyshMocker.demand.getPackageHelper(1) { [getContents: { ['Xyzabc']}] }
         groovyshMocker.demand.getPackageHelper(1) { [getContents: { ['Xyz123']}] }
         // second call
-        groovyshMocker.demand.getImports(2) { ["import xyzabc.*", "import xxxx.*"] }
+        groovyshMocker.demand.getImports(2) { ['import xyzabc.*', 'import xxxx.*'] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
-            assertEquals(true, completor.complete(tokenList("Xyz"), candidates))
-            assertEquals(['prefill', "Xyzabc", "Xyz123"], candidates)
+            assert completor.complete(tokenList('Xyz'), candidates)
             // try again to check cache is used
-            assertEquals(true, completor.complete(tokenList("Xyz1"), candidates))
-            assertEquals(['prefill', "Xyzabc", "Xyz123", "Xyz123"], candidates)
-            assertEquals(true, completor.complete(tokenList("Xyz"), candidates))
-            assertEquals(['prefill', "Xyzabc", "Xyz123", "Xyz123", "Xyzabc", "Xyz123"], candidates)
+            assert ['prefill', 'Xyzabc', 'Xyz123'] == candidates
+            assert completor.complete(tokenList('Xyz1'), candidates)
+            assert ['prefill', 'Xyzabc', 'Xyz123', 'Xyz123'] == candidates
+            assert completor.complete(tokenList('Xyz'), candidates)
+            assert ['prefill', 'Xyzabc', 'Xyz123', 'Xyz123', 'Xyzabc', 'Xyz123'] == candidates
         }
     }
 
     void testUnknownImport() {
         groovyshMocker.demand.getPackageHelper(6) { [getContents: {[]}] }
-        groovyshMocker.demand.getImports(1) { ["import xxxx"] }
+        groovyshMocker.demand.getImports(1) { ['import xxxx'] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             ImportsSyntaxCompletor completor = new ImportsSyntaxCompletor(groovyshMock)
             def candidates = ['prefill']
-            assertEquals(false, completor.complete(tokenList("xyz"), candidates))
-            assertEquals(['prefill'], candidates)
+            assert ! completor.complete(tokenList('xyz'), candidates)
+            assert ['prefill'] == candidates
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/KeywordCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/KeywordCompletorTest.groovy
index 0b6ff41..e607cd0 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/KeywordCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/KeywordCompletorTest.groovy
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.codehaus.groovy.tools.shell.completion
 
 import static org.codehaus.groovy.tools.shell.completion.TokenUtilTest.tokenList
@@ -7,48 +23,48 @@ class KeywordCompletorTest extends GroovyTestCase {
     void testKeywordModifier() {
         KeywordSyntaxCompletor completor = new KeywordSyntaxCompletor()
         def candidates = []
-        String buffer = "pub"
-        assertEquals(true, completor.complete(tokenList(buffer), candidates))
-        assertEquals(['public '], candidates)
+        String buffer = 'pub'
+        assert completor.complete(tokenList(buffer), candidates)
+        assert ['public '] == candidates
     }
 
     void testInfixKeywordNotCompleted() {
         // extends, implements, instanceof are not to kbe completed when at start of line
         KeywordSyntaxCompletor completor = new KeywordSyntaxCompletor()
         def candidates = []
-        String buffer = "ext"
-        assertEquals(false, completor.complete(tokenList(buffer), candidates))
-        buffer = "imple"
-        assertEquals(false, completor.complete(tokenList(buffer), candidates))
-        buffer = "inst"
-        assertEquals(false, completor.complete(tokenList(buffer), candidates))
+        String buffer = 'ext'
+        assert !completor.complete(tokenList(buffer), candidates)
+        buffer = 'imple'
+        assert !completor.complete(tokenList(buffer), candidates)
+        buffer = 'inst'
+        assert !completor.complete(tokenList(buffer), candidates)
     }
 
     void testKeywordModifierSecond() {
         KeywordSyntaxCompletor completor = new KeywordSyntaxCompletor()
         def candidates = []
-        String buffer = "public sta"
-        assertEquals(true, completor.complete(tokenList(buffer), candidates))
-        assertEquals(['static '], candidates)
+        String buffer = 'public sta'
+        assert completor.complete(tokenList(buffer), candidates)
+        assert ['static '] == candidates
         candidates = []
-        buffer = "public swi" // don't suggest switch keyword here
-        assertEquals(true, completor.complete(tokenList(buffer), candidates))
-        assertEquals(["switch ("], candidates)
+        buffer = 'public swi' // don't suggest switch keyword here
+        assert completor.complete(tokenList(buffer), candidates)
+        assert ['switch ('] == candidates
     }
 
     void testKeywordModifierThird() {
         KeywordSyntaxCompletor completor = new KeywordSyntaxCompletor()
         def candidates = []
-        String buffer = "public static inter"
-        assertEquals(true, completor.complete(tokenList(buffer), candidates))
-        assertEquals(['interface '], candidates)
+        String buffer = 'public static inter'
+        assert completor.complete(tokenList(buffer), candidates)
+        assert ['interface '] == candidates
     }
 
     void testKeywordModifierFor() {
         KeywordSyntaxCompletor completor = new KeywordSyntaxCompletor()
         def candidates = []
-        String buffer = "fo"
-        assertEquals(true, completor.complete(tokenList(buffer), candidates))
-        assertEquals(['for ('], candidates)
+        String buffer = 'fo'
+        assert completor.complete(tokenList(buffer), candidates)
+        assert ['for ('] == candidates
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleterTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleterTest.groovy
index 1645e8e..c786696 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleterTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/NavigablePropertiesCompleterTest.groovy
@@ -1,13 +1,40 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.codehaus.groovy.tools.shell.completion
 
-import org.codehaus.groovy.antlr.GroovySourceToken
-import org.codehaus.groovy.tools.shell.util.CurlyCountingGroovyLexer
 
 /**
  * Defines method tokenList for other Unit tests and tests it
  */
 class NavigablePropertiesCompleterTest extends GroovyTestCase {
 
+    void testPatternNoControlChars() {
+        assert !'java\bCfoo'.matches(NavigablePropertiesCompleter.NO_CONTROL_CHARS_PATTERN)
+        assert !'java\u001BCfoo'.matches(NavigablePropertiesCompleter.NO_CONTROL_CHARS_PATTERN)
+        assert 'ja12_<!$%&_?§'.matches(NavigablePropertiesCompleter.NO_CONTROL_CHARS_PATTERN)
+    }
+
+    void testPatternInvalidIdentifierChar() {
+        assert 'java at foo'.find(NavigablePropertiesCompleter.INVALID_CHAR_FOR_IDENTIFIER_PATTERN)
+        assert 'java&bar'.find(NavigablePropertiesCompleter.INVALID_CHAR_FOR_IDENTIFIER_PATTERN)
+        assert 'java~bar'.find(NavigablePropertiesCompleter.INVALID_CHAR_FOR_IDENTIFIER_PATTERN)
+        assert !'javaBar$foo_b2'.find(NavigablePropertiesCompleter.INVALID_CHAR_FOR_IDENTIFIER_PATTERN)
+    }
+
     void testSet() {
         NavigablePropertiesCompleter completer = new NavigablePropertiesCompleter()
         completer.addCompletions(null, '', [] as Set)
@@ -46,6 +73,7 @@ class NavigablePropertiesCompleterTest extends GroovyTestCase {
                 '_ !@#$%^&*()_+={}[]~`<>,./?:;|' : 'operators',
                 'snowman ☃' : 'Olaf',
                 'Japan ぁ' : '77',
+                'ぁJapanstart' : '77',
                 'a☃$4ä_' : 'no hypehns',
                 '$123' : 'digits',
                 '123$' : 'digits',
@@ -54,7 +82,7 @@ class NavigablePropertiesCompleterTest extends GroovyTestCase {
 
         Set candidates = [] as Set
         Set expected = ['id', 'name', '\'a b\'', '\'a.b\'', '\'a\\\'b\'', '\'a\\\\b\'', '\'G$\\\\"tring\'',
-                        '\'_ !@#$%^&*()_+={}[]~`<>,./?:;|\'', '\'snowman ☃\'', '\'Japan ぁ\'', 'a☃$4ä_', '$123', '\'123$\'' ] as Set
+                        '\'_ !@#$%^&*()_+={}[]~`<>,./?:;|\'', '\'snowman ☃\'', '\'Japan ぁ\'', 'ぁJapanstart', 'a☃$4ä_', '$123', '\'123$\'' ] as Set
         completer.addCompletions(map, '', candidates)
         assert expected == candidates
     }
@@ -63,11 +91,11 @@ class NavigablePropertiesCompleterTest extends GroovyTestCase {
         NavigablePropertiesCompleter completer = new NavigablePropertiesCompleter()
         completer.addCompletions(null, '', [] as Set)
         NodeBuilder someBuilder = new NodeBuilder()
-        Node node = someBuilder.foo(){[bar(){[bam(7)]}, baz()]}
+        Node node = someBuilder.foo {[bar {[bam(7)]}, baz()]}
 
         Set candidates = [] as Set
         completer.addCompletions(node, 'ba', candidates)
         assert ['bar', 'baz'] as Set == candidates
 
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletorTest.groovy
index 9db5b3e..86ac771 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/ReflectionCompletorTest.groovy
@@ -24,182 +24,202 @@ import static org.codehaus.groovy.tools.shell.completion.TokenUtilTest.tokensStr
 
 class ReflectionCompletorTest extends GroovyTestCase {
 
+    void testBeanAccessorPattern() {
+        assert 'getX'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN)
+        assert 'setX'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN)
+        assert 'isX'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN)
+        assert !('get'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN))
+        assert !('getx'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN))
+        assert !('foo'.matches(ReflectionCompletor.BEAN_ACCESSOR_PATTERN))
+    }
+
     void testAddDefaultMethods() {
-        List<String> result = []
-        ReflectionCompletor.addDefaultMethods(3, '', result)
+        List<String> result = ReflectionCompletor.getDefaultMethods(3, '')
         assert 'abs()' in result
         assert 'times(' in result
 
-        result = []
-        ReflectionCompletor.addDefaultMethods([1, 2, 3], '', result)
+        result = ReflectionCompletor.getDefaultMethods([1, 2, 3], '')
         assert 'any(' in result
         assert 'count(' in result
         assert 'take(' in result
         assert 'unique()' in result
 
-        result = []
-        ReflectionCompletor.addDefaultMethods(new String[2], '', result)
+        result = ReflectionCompletor.getDefaultMethods(new String[2], '')
         assert 'any(' in result
         assert 'collect(' in result
         assert 'count(' in result
         assert 'take(' in result
 
-        result = []
-        ReflectionCompletor.addDefaultMethods(['a': 1, 'b': 2], '', result)
+        result = ReflectionCompletor.getDefaultMethods(['a': 1, 'b': 2], '')
         assert 'any(' in result
         assert 'spread()' in result
     }
 
 
     void testGetFieldsAndMethodsArray() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(([] as String[]), "")
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(([] as String[]), '')*.value
         assert 'length' in result
         assert 'clone()' in result
-        result = ReflectionCompletor.getMetaclassMethods(([] as String[]), "", true)
+        result = ReflectionCompletor.getMetaclassMethods(([] as String[]), '', true)
         assert 'size()' in result
         assert 'any()' in result
         assert 'take(' in result
-        result = ReflectionCompletor.getMetaclassMethods([] as String[], "size", true)
-        assert ["size()"] == result
-        result = ReflectionCompletor.getPublicFieldsAndMethods([] as String[], "le")
-        assert ["length"] == result
+        result = ReflectionCompletor.getMetaclassMethods([] as String[], 'size', true)
+        assert ['size()'] == result
+        result = ReflectionCompletor.getPublicFieldsAndMethods([] as String[], 'le')*.value
+        assert ['length'] == result
     }
 
     void testGetFieldsAndMethodsMap() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(['id': '42'], "")
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(['id': '42'], '')*.value
         assert 'clear()' in result
         assert 'containsKey(' in result
         assert 'clear()' in result
         // 'class' as key can cause bugs where .class is used instead of getClass()
-        result = ReflectionCompletor.getPublicFieldsAndMethods(['class': '42', 'club': 53], "")
+        result = ReflectionCompletor.getPublicFieldsAndMethods(['class': '42', 'club': 53], '')*.value
         assert 'clear()' in result
         assert 'containsKey(' in result
         assert 'class' in result
         assert 'club' in result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(['id': '42'], "size")
+        result = ReflectionCompletor.getPublicFieldsAndMethods(['id': '42'], 'size')*.value
         // e.g. don't show non-public inherited size field
-        assert ["size()"] == result
+        assert ['size()'] == result
     }
 
     void testGetFieldsAndMethodsString() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods("foo", "")
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods('foo', '')*.value
         assert 'charAt(' in result
         assert 'contains(' in result
-        assert 'format(' in result
-        result = ReflectionCompletor.getMetaclassMethods("foo", "", true)
+        assert ! ('format(' in result)
+        result = ReflectionCompletor.getMetaclassMethods('foo', '', true)
         assert 'normalize()' in result
         int foo = 3
-        result = ReflectionCompletor.getPublicFieldsAndMethods("$foo", "")
+        result = ReflectionCompletor.getPublicFieldsAndMethods("$foo", '')*.value
         assert 'build(' in result
-        result = ReflectionCompletor.getMetaclassMethods("foo", "tok", true)
-        assert ["tokenize(", "tokenize()"] == result
-        result = ReflectionCompletor.getMetaclassMethods(String, "tok", true)
-        assert ["tokenize(", "tokenize()"] == result
+        result = ReflectionCompletor.getMetaclassMethods('foo', 'tok', true)
+        assert ['tokenize(', 'tokenize()'] == result
+        result = ReflectionCompletor.getMetaclassMethods(String, 'tok', true)
+        assert ['tokenize(', 'tokenize()'] == result
     }
 
     void testGetFieldsAndMethodsPrimitive() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(3, "")
-        assert "byteValue()" in result
-        assert "MAX_VALUE" in result
-        assert "valueOf(" in result
-        assert "bitCount(" in result
-        result = ReflectionCompletor.getMetaclassMethods(3, "", true)
-        assert "abs()" in result
-        result = ReflectionCompletor.getMetaclassMethods(3, "una", true)
-        assert ["unaryMinus()", "unaryPlus()"] == result
-        result = ReflectionCompletor.getMetaclassMethods(Integer, "una", true)
-        assert ["unaryMinus()", "unaryPlus()"] == result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(Integer, "MA")
-        assert ["MAX_VALUE"] == result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(Integer, "getI")
-        assert ["getInteger("] == result
-    }
-
-    interface ForTestInterface extends Comparable {
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(3, '')*.value
+        assert 'byteValue()' in result
+        assert ! ('MAX_VALUE' in result)
+        assert ! ('valueOf(' in result)
+        assert ! ('bitCount(' in result)
+        result = ReflectionCompletor.getMetaclassMethods(3, '', true)
+        assert 'abs()' in result
+        result = ReflectionCompletor.getMetaclassMethods(3, 'una', true)
+        assert ['unaryMinus()', 'unaryPlus()'] == result
+        result = ReflectionCompletor.getMetaclassMethods(Integer, 'una', true)
+        assert ['unaryMinus()', 'unaryPlus()'] == result
+        result = ReflectionCompletor.getPublicFieldsAndMethods(Integer, 'MA')*.value
+        assert ['MAX_VALUE'] == result
+        result = ReflectionCompletor.getPublicFieldsAndMethods(Integer, 'getI')*.value
+        assert ['getInteger('] == result
+    }
+
+    interface ForTestInterface extends Comparable<Object> {
         static final int FOR_TEST_FIELD = 1
         void forTestMethod()
     }
 
     void testGetFieldsAndMethodsAnonymousClass() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(new ForTestInterface(){
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(new ForTestInterface() {
             @Override
             void forTestMethod() {}
 
             @Override
             int compareTo(Object o) {return 0}
-        }, "")
-        assert 'FOR_TEST_FIELD' in result
+        }, '')*.value
+        assert ! ('FOR_TEST_FIELD' in result)
         assert 'forTestMethod()' in result
         assert 'compareTo(' in result
         GroovyLexer
-        result = ReflectionCompletor.getPublicFieldsAndMethods(Set, "toA")
+        result = ReflectionCompletor.getPublicFieldsAndMethods(Set, 'toA')
         assert []== result
     }
 
     enum ForTestEnum {
-        val1, val2
+        VAL1, VAL2
         static final ForTestEnum VAL_3
         int enumMethod() {return 0}
         static int staticMethod() {return 1}
     }
 
     void testEnum() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(ForTestEnum, "")
-        assert 'val1' in result
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(ForTestEnum, '')
+        result = result*.value
+        assert 'VAL1' in result
         assert ! ( 'enumMethod()' in result)
         assert 'staticMethod()' in result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(ForTestEnum.val1, "")
+        result = ReflectionCompletor.getPublicFieldsAndMethods(ForTestEnum.VAL1, '')
+        result = result*.value
         // User will probably not want this
-        assert ! ( 'val1' in result)
+        assert ! ( 'VAL1' in result)
         assert 'enumMethod()' in result
-        assert 'staticMethod()' in result
+        assert ! ('staticMethod()' in result)
     }
 
     void testGetAbstractClassFields() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(GroovyLexer, "")
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(GroovyLexer, '')
+        result = result*.value
         assert 'ABSTRACT' in result
         assert 'tracing' in result
-        result = ReflectionCompletor.getMetaclassMethods(GroovyLexer, "", true)
+        result = ReflectionCompletor.getMetaclassMethods(GroovyLexer, '', true)
         assert 'collect()' in result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(new GroovyLexer(new ByteArrayInputStream()), "")
-        assert 'ABSTRACT' in result
-        assert 'tracing' in result
-        result = ReflectionCompletor.getMetaclassMethods(new GroovyLexer(new ByteArrayInputStream()), "", true)
+        result = ReflectionCompletor.getPublicFieldsAndMethods(new GroovyLexer(new ByteArrayInputStream()), '')
+        result = result*.value
+        assert ! ('ABSTRACT' in result)
+        assert ! ('tracing' in result)
+        result = ReflectionCompletor.getMetaclassMethods(new GroovyLexer(new ByteArrayInputStream()), '', true)
         assert 'isCase(' in result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(GroovyLexer, "LITERAL_as")
-        assert ["LITERAL_as", "LITERAL_assert"]== result
-        GroovyLexer lexer = new GroovyLexer(new ByteArrayInputStream("".getBytes()))
-        result = ReflectionCompletor.getPublicFieldsAndMethods(lexer, "LITERAL_as")
-        assert ["LITERAL_as", "LITERAL_assert"]== result
+        result = ReflectionCompletor.getPublicFieldsAndMethods(GroovyLexer, 'LITERAL_as')
+        result = result*.value
+        assert ['LITERAL_as', 'LITERAL_assert'] == result
+        // static members only shown for prefix of sufficient length
+        GroovyLexer lexer = new GroovyLexer(new ByteArrayInputStream(''.bytes))
+        result = ReflectionCompletor.getPublicFieldsAndMethods(lexer, 'LI')
+        result = result*.value
+        assert !('LITERAL_as' in result)
+        result = ReflectionCompletor.getPublicFieldsAndMethods(lexer, 'LITERAL_as')
+        result = result*.value
+        assert ['LITERAL_as', 'LITERAL_assert'] == result
     }
 
     void testGetFieldsAndMethodsClass() {
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(Arrays, "")
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(Arrays, '')
+        result = result*.value
         assert 'sort(' in result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(HashSet, "pro")
-        assert []== result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(HashSet, "toA")
-        assert []== result
-        result = ReflectionCompletor.getPublicFieldsAndMethods(new HashSet(), "toA")
-        assert ["toArray(", "toArray()"]== result
+        result = ReflectionCompletor.getPublicFieldsAndMethods(HashSet, 'pro')
+        result = result*.value
+        assert [] == result
+        result = ReflectionCompletor.getPublicFieldsAndMethods(HashSet, 'to')
+        result = result*.value
+        assert !('toArray(' in result)
+        result = ReflectionCompletor.getPublicFieldsAndMethods(new HashSet(), 'toA')
+        result = result*.value
+        assert ['toArray(', 'toArray()'] == result
     }
 
     void testSuppressMetaAndDefaultMethods() {
-        Collection<String> result = ReflectionCompletor.getMetaclassMethods("foo", "", true)
+        Collection<String> result = ReflectionCompletor.getMetaclassMethods('foo', '', true)
         assert 'getMetaClass()' in result
         assert 'asBoolean()' in result
-        result = ReflectionCompletor.getMetaclassMethods("foo", "", false)
+        result = ReflectionCompletor.getMetaclassMethods('foo', '', false)
+        result = result*.value
         assert ! ('getMetaClass()' in result)
         assert ! ('asBoolean()' in result)
     }
 
     void testGetFieldsAndMethodsCustomClass() {
         Interpreter interp = new Interpreter(Thread.currentThread().contextClassLoader, new Binding())
-        Object instance = interp.evaluate(["class Foo extends HashSet implements Comparable {int compareTo(Object) {0}}; Foo"])
-        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(instance, "")
+        Object instance = interp.evaluate(['class Foo extends HashSet implements Comparable {int compareTo(Object) {0}}; Foo'])
+        Collection<String> result = ReflectionCompletor.getPublicFieldsAndMethods(instance, '')*.value
         assertFalse('compareTo(' in result)
-        instance = interp.evaluate(["class Foo extends HashSet implements Comparable {int compareTo(Object) {0}}; new Foo()"])
-        result = ReflectionCompletor.getPublicFieldsAndMethods(instance, "")
+        instance = interp.evaluate(['class Foo extends HashSet implements Comparable {int compareTo(Object) {0}}; new Foo()'])
+        result = ReflectionCompletor.getPublicFieldsAndMethods(instance, '')*.value
         assert 'compareTo(' in result
     }
 }
@@ -208,11 +228,11 @@ class ReflectionCompletorTest extends GroovyTestCase {
 class InvokerParsingTest extends GroovyTestCase {
 
     void testTokenListToEvalString() {
-        assert '' == ReflectionCompletor.tokenListToEvalString(tokenList(""))
-        assert '1' == ReflectionCompletor.tokenListToEvalString(tokenList("1"))
-        assert '1.' == ReflectionCompletor.tokenListToEvalString(tokenList("1."))
-        assert 'foo' == ReflectionCompletor.tokenListToEvalString(tokenList("foo"))
-        assert '"foo"' == ReflectionCompletor.tokenListToEvalString(tokenList("'foo'"))
+        assert '' == ReflectionCompletor.tokenListToEvalString(tokenList(''))
+        assert '1' == ReflectionCompletor.tokenListToEvalString(tokenList('1'))
+        assert '1.' == ReflectionCompletor.tokenListToEvalString(tokenList('1.'))
+        assert 'foo' == ReflectionCompletor.tokenListToEvalString(tokenList('foo'))
+        assert '\'foo\'' == ReflectionCompletor.tokenListToEvalString(tokenList('\'foo\''))
     }
 
     void testGetInvokerTokens() {
@@ -252,4 +272,14 @@ class InvokerParsingTest extends GroovyTestCase {
         assert null == tokensString(ReflectionCompletor.getInvokerTokens(tokenList('foo.each bar')))
         assert null == tokensString(ReflectionCompletor.getInvokerTokens(tokenList('foo++')))
     }
+
+    void testGetFieldnameForAccessor() {
+        assert 'foo' == ReflectionCompletor.getFieldnameForAccessor('getFoo', 0)
+        assert 'foo' == ReflectionCompletor.getFieldnameForAccessor('setFoo', 1)
+        assert 'foo' == ReflectionCompletor.getFieldnameForAccessor('isFoo', 0)
+
+        assert null == ReflectionCompletor.getFieldnameForAccessor('getFoo', 1)
+        assert null == ReflectionCompletor.getFieldnameForAccessor('setFoo', 0)
+        assert null == ReflectionCompletor.getFieldnameForAccessor('isFoo', 1)
+    }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/TokenUtilTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/TokenUtilTest.groovy
index 685a260..d383688 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/TokenUtilTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/TokenUtilTest.groovy
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.codehaus.groovy.tools.shell.completion
 
 import org.codehaus.groovy.antlr.GroovySourceToken
@@ -21,18 +37,18 @@ class TokenUtilTest extends GroovyTestCase {
     }
 
     void testTokenList() {
-        assertEquals([], tokenList(""))
-        assertEquals('foo', tokenList("foo")[0].getText())
-        assertEquals(['foo'], tokenList("foo").collect { it.getText()})
-        assertEquals(['foo', '{', 'bar'], tokenList("foo{bar").collect { it.getText()})
-        assertEquals(['1', '..', '2'], tokenList("1..2").collect { it.getText()})
+        assert [] == tokenList('')
+        assert 'foo' == tokenList('foo')[0].text
+        assert ['foo'] == tokenList('foo')*.text
+        assert ['foo', '{', 'bar'] == tokenList('foo{bar')*.text
+        assert ['1', '..', '2'] == tokenList('1..2')*.text
     }
 
     static tokensString(List<GroovySourceToken> tokens) {
-        if (tokens == null) {
+        if (tokens == null || tokens.size() == 0) {
             return null
         }
-        return tokens.collect {it.getText()}.join()
+        return tokens*.text.join()
     }
 
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/VariableCompletorTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/VariableCompletorTest.groovy
index 83bcfba..7dbaf60 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/VariableCompletorTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/completion/VariableCompletorTest.groovy
@@ -1,3 +1,19 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
 package org.codehaus.groovy.tools.shell.completion
 
 import org.codehaus.groovy.tools.shell.CompletorTestSupport
@@ -7,24 +23,24 @@ import static org.codehaus.groovy.tools.shell.completion.TokenUtilTest.tokenList
 class VariableCompletorTest extends CompletorTestSupport {
 
     void testKnownVar() {
-        groovyshMocker.demand.getInterp(1) { [context: [variables: [xyzabc: ""]]] }
+        groovyshMocker.demand.getInterp(1) { [context: [variables: [xyzabc: '']]] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             VariableSyntaxCompletor completor = new VariableSyntaxCompletor(groovyshMock)
             def candidates = []
-            assertEquals(true, completor.complete(tokenList("xyz"), candidates))
-            assertEquals(["xyzabc"], candidates)
+            assert completor.complete(tokenList('xyz'), candidates)
+            assert ['xyzabc'] == candidates
         }
     }
 
     void testKnownVarMultiple() {
-        groovyshMocker.demand.getInterp(1) { [context: [variables: [bad: "", xyzabc: "", xyzfff: "", nope: ""]]] }
+        groovyshMocker.demand.getInterp(1) { [context: [variables: [bad: '', xyzabc: '', xyzfff: '', nope: '']]] }
         groovyshMocker.use {
             Groovysh groovyshMock = new Groovysh()
             VariableSyntaxCompletor completor = new VariableSyntaxCompletor(groovyshMock)
             def candidates = []
-            assertEquals(true, completor.complete(tokenList("xyz"), candidates))
-            assertEquals(["xyzabc", "xyzfff"], candidates)
+            assert completor.complete(tokenList('xyz'), candidates)
+            assert ['xyzabc', 'xyzfff'] == candidates
         }
     }
 
@@ -34,8 +50,8 @@ class VariableCompletorTest extends CompletorTestSupport {
             Groovysh groovyshMock = new Groovysh()
             VariableSyntaxCompletor completor = new VariableSyntaxCompletor(groovyshMock)
             def candidates = []
-            assertEquals([], candidates)
-            assertEquals(false, completor.complete(tokenList("xyz"), candidates))
+            assert [] == candidates
+            assert !completor.complete(tokenList('xyz'), candidates)
         }
     }
 }
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/expr/ExprTestSupport.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/expr/ExprTestSupport.groovy
index 7e87db0..825e8dd 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/expr/ExprTestSupport.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/expr/ExprTestSupport.groovy
@@ -27,9 +27,10 @@ abstract class ExprTestSupport
     extends GroovyTestCase
 {
     Groovysh shell
-    
+
     Object lastResult
 
+    @Override
     void setUp() {
         super.setUp()
 
@@ -43,4 +44,4 @@ abstract class ExprTestSupport
             lastResult = result
         }
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParserTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParserTest.groovy
new file mode 100644
index 0000000..8035503
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CommandArgumentParserTest.groovy
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+
+class CommandArgumentParserTest extends GroovyTestCase {
+
+    void testParseLine() {
+        // empty
+        assert [] == CommandArgumentParser.parseLine('')
+
+        // blanks
+        assert ['foo', 'bar'] == CommandArgumentParser.parseLine('  foo bar  ')
+
+        // empties
+        assert ['', '', '', ''] == CommandArgumentParser.parseLine('\'\'\'\' \'\'  \'\'')
+        assert ['', '', '', ''] == CommandArgumentParser.parseLine('"""" ""  ""')
+
+        // hyphen groups
+        assert ['foo bar', 'baz bam'] == CommandArgumentParser.parseLine(' \'foo bar\' \'baz bam\'')
+        assert ['foo bar', 'baz bam'] == CommandArgumentParser.parseLine(' "foo bar" "baz bam"')
+
+        // escaped hyphens and escape signs
+        assert ['foo \\ "\' bar'] == CommandArgumentParser.parseLine('\'foo \\\\ "\\\' bar\'')
+        // no space between hyphentokens
+        assert ['bar', 'foo', 'bam', 'baz'] == CommandArgumentParser.parseLine('bar"foo"\'bam\'\'baz\'')
+
+        // limited number of tokens
+        assert ['foo'] == CommandArgumentParser.parseLine('  foo bar  ', 1)
+        assert ['bar', 'foo'] == CommandArgumentParser.parseLine('bar"foo"\'bam\'\'baz\'', 2)
+
+        assert ['map.put('] == CommandArgumentParser.parseLine('map.put(\'a\': 2)', 1)
+        assert ['map.put('] == CommandArgumentParser.parseLine('map.put(\'a\'', 1)
+
+    }
+
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexerTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexerTest.groovy
index 911b044..8be04a3 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexerTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/CurlyCountingGroovyLexerTest.groovy
@@ -23,37 +23,37 @@ class CurlyCountingGroovyLexerTest
     extends GroovyTestCase
 {
    void testLexerEmpty() {
-       CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer("")
-       assertEquals(0, it.getParenLevel())
-       assertEquals([''], it.toList().collect {it.getText()})
-       assertEquals(0, it.getParenLevel())
+       CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer('')
+       assert 0 == it.parenLevel
+       assert [''] == it.toList()*.text
+       assert 0 == it.parenLevel
    }
 
     void testLexerText() {
-        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer("foo bar baz")
-        assertEquals(0, it.getParenLevel())
-        assertEquals(['foo', 'bar', 'baz', ''], it.toList().collect {it.getText()})
-        assertEquals(0, it.getParenLevel())
+        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer('foo bar baz')
+        assert 0 == it.parenLevel
+        assert ['foo', 'bar', 'baz', ''] == it.toList()*.text
+        assert 0 == it.parenLevel
     }
 
     void testLexerCurly() {
-        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer("Foo{")
-        assertEquals(0, it.getParenLevel())
-        assertEquals(['Foo', '{', ''], it.toList().collect {it.getText()})
-        assertEquals(1, it.getParenLevel())
+        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer('Foo{')
+        assert 0 == it.parenLevel
+        assert ['Foo', '{', ''] == it.toList()*.text
+        assert 1 == it.parenLevel
     }
 
     void testLexerCurlyMore() {
-        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer("Foo{Baz{Bar{")
-        assertEquals(0, it.getParenLevel())
-        assertEquals(['Foo', '{', 'Baz', '{', 'Bar', '{', ''], it.toList().collect {it.getText()})
-        assertEquals(3, it.getParenLevel())
+        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer('Foo{Baz{Bar{')
+        assert 0 == it.parenLevel
+        assert ['Foo', '{', 'Baz', '{', 'Bar', '{', ''] == it.toList()*.text
+        assert 3 == it.parenLevel
     }
 
     void testLexerCurlyMany() {
-        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer("Foo{Bar{}}{")
-        assertEquals(0, it.getParenLevel())
-        assertEquals(['Foo', '{', 'Bar', '{', '}', '}', '{',''], it.toList().collect {it.getText()})
-        assertEquals(1, it.getParenLevel())
+        CurlyCountingGroovyLexer it = CurlyCountingGroovyLexer.createGroovyLexer('Foo{Bar{}}{')
+        assert 0 == it.parenLevel
+        assert ['Foo', '{', 'Bar', '{', '}', '}', '{',''] == it.toList()*.text
+        assert 1 == it.parenLevel
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/MessageSourceTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/MessageSourceTest.groovy
index ce54095..9755f75 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/MessageSourceTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/MessageSourceTest.groovy
@@ -24,12 +24,14 @@ package org.codehaus.groovy.tools.shell.util
 class MessageSourceTest
     extends GroovyTestCase
 {
-    MessageSource messages
+    private MessageSource messages
 
+    @Override
     void setUp() {
+        super.setUp()
         messages = new MessageSource(this.class)
     }
-    
+
     void testLoadAndGetMessage() {
         def a = messages['a']
         assert '1' == a
@@ -43,4 +45,4 @@ class MessageSourceTest
         def f = messages.format('f', a, b, c)
         assert '1 2 3' == f
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImplTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImplTest.groovy
new file mode 100644
index 0000000..1d951d1
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperImplTest.groovy
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2003-2007 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+/**
+ * Unit tests for the {@link PackageHelperImpl} class.
+ */
+class PackageHelperImplTest
+    extends GroovyTestCase
+{
+
+    void testLoadAndGetPackagesEmpty() {
+        PackageHelperImpl helper = new PackageHelperImpl(null)
+        Set<String> rootPackages = helper.getContents('')
+        assertNotNull(rootPackages)
+        assert rootPackages.contains('java')
+        assert rootPackages.contains('javax')
+        assert rootPackages.contains('groovy')
+    }
+
+    void testLoadAndGetPackagesJava() {
+        PackageHelperImpl helper = new PackageHelperImpl(null)
+        Set<String> names = helper.getContents('java')
+        assertNotNull(names)
+        assert names.contains('io')
+    }
+
+    void testLoadAndGetPackagesJavaUtil() {
+        PackageHelperImpl helper = new PackageHelperImpl(null)
+        Set<String> names = helper.getContents('java.util')
+        assertNotNull(names)
+        assert names.contains('zip')
+        assert names.contains('Set')
+    }
+
+    void testLoadAndGetPackagesInvalid() {
+        PackageHelperImpl helper = new PackageHelperImpl(null)
+        assert [] as Set<String> == helper.getContents('invalid:name')
+    }
+
+    void testLoadAndGetPackagesUnknown() {
+        PackageHelperImpl helper = new PackageHelperImpl(null)
+        assert [] as Set<String> == helper.getContents('java.util.regex.tools')
+    }
+}
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperTest.groovy
deleted file mode 100644
index b7cfaff..0000000
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/PackageHelperTest.groovy
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright 2003-2007 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.codehaus.groovy.tools.shell.util
-
-/**
- * Unit tests for the {@link PackageHelper} class.
- */
-class PackageHelperTest
-    extends GroovyTestCase
-{
-
-    void testLoadAndGetPackagesEmpty() {
-        PackageHelper helper = new PackageHelper(null)
-        Set<String> rootPackages = helper.getContents("")
-        assertNotNull(rootPackages)
-        assert rootPackages.contains("java")
-        assert rootPackages.contains("javax")
-        assert rootPackages.contains("groovy")
-    }
-
-    void testLoadAndGetPackagesJava() {
-        PackageHelper helper = new PackageHelper(null)
-        Set<String> names = helper.getContents("java")
-        assertNotNull(names)
-        assert names.contains('io')
-    }
-
-    void testLoadAndGetPackagesJavaUtil() {
-        PackageHelper helper = new PackageHelper(null)
-        Set<String> names = helper.getContents("java.util")
-        assertNotNull(names)
-        assert names.contains('zip')
-        assert names.contains('Set')
-    }
-
-    void testLoadAndGetPackagesInvalid() {
-        PackageHelper helper = new PackageHelper(null)
-        assert null == helper.getContents("invalid:name")
-    }
-
-    void testLoadAndGetPackagesUnknown() {
-        PackageHelper helper = new PackageHelper(null)
-        assert null == helper.getContents("java.util.regex.tools")
-    }
-}
\ No newline at end of file
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzerTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzerTest.groovy
new file mode 100644
index 0000000..b36ba3e
--- /dev/null
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/ScriptVariableAnalyzerTest.groovy
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.codehaus.groovy.tools.shell.util
+
+/**
+ * Unit tests for the {@link ScriptVariableAnalyzer} class.
+ *
+ */
+class ScriptVariableAnalyzerTest extends GroovyTestCase {
+
+    void testEmptyScript() {
+        assert [] as Set == ScriptVariableAnalyzer.getBoundVars('')
+    }
+
+    void testBound() {
+        def scriptText = '''
+   int a = 6
+   String b = "7"
+'''
+        assert ['a', 'b'] as Set == ScriptVariableAnalyzer.getBoundVars(scriptText)
+    }
+
+    void testUnBound() {
+        def scriptText = '''
+   a = 6
+   b = "7"
+'''
+        assert [] as Set == ScriptVariableAnalyzer.getBoundVars(scriptText)
+    }
+
+    void testMixed() {
+        def scriptText = '''
+   def foo(args) { args && !d }
+   Closure c = { 4 }
+   int b = 6
+   try {
+       println(a + 5 - b + c() / foo(a))
+   } catch (Throwable t) {
+       println b
+   } finally {
+       throw d
+   }
+   assert b
+'''
+        assert ['b', 'c'] as Set == ScriptVariableAnalyzer.getBoundVars(scriptText)
+    }
+}
\ No newline at end of file
diff --git a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStreamTest.groovy b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStreamTest.groovy
index b3ab523..787c30e 100644
--- a/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStreamTest.groovy
+++ b/subprojects/groovy-groovysh/src/test/groovy/org/codehaus/groovy/tools/shell/util/WrappedInputStreamTest.groovy
@@ -26,51 +26,51 @@ class WrappedInputStreamTest
     void testWrapEmpty() {
         ByteArrayInputStream mockStream = new ByteArrayInputStream()
         WrappedInputStream stream = new WrappedInputStream(mockStream)
-        assertEquals(0, stream.available())
-        assertEquals(false, stream.markSupported())
+        assert 0 == stream.available()
+        assert !stream.markSupported()
     }
 
     void testWrapStream() {
-        ByteArrayInputStream mockStream = new ByteArrayInputStream("abc".getBytes())
+        ByteArrayInputStream mockStream = new ByteArrayInputStream('abc'.bytes)
         WrappedInputStream stream = new WrappedInputStream(mockStream)
-        assertEquals(3, stream.available())
-        assertEquals(false, stream.markSupported())
-        assertEquals('a', stream.read())
-        assertEquals(2, stream.available())
+        assert 3 == stream.available()
+        assert !stream.markSupported()
+        assert 'a' == stream.read()
+        assert 2 == stream.available()
         byte[] bytes = [0, 0, 0, 0] as byte[]
-        assertEquals(2, stream.read(bytes))
-        assertEquals(['b', 'c', 0, 0], bytes)
-        assertEquals(0, stream.available())
+        assert 2 == stream.read(bytes)
+        assert ['b', 'c', 0, 0] == bytes
+        assert 0 == stream.available()
     }
 
     void testWrapInserted() {
         ByteArrayInputStream mockStream = new ByteArrayInputStream()
         WrappedInputStream stream = new WrappedInputStream(mockStream)
-        stream.insert("xyz")
-        assertEquals(3, stream.available())
-        assertEquals(false, stream.markSupported())
-        assertEquals('x', stream.read())
-        assertEquals(2, stream.available())
+        stream.insert('xyz')
+        assert 3 == stream.available()
+        assert !stream.markSupported()
+        assert 'x' == stream.read()
+        assert 2 == stream.available()
         byte[] bytes = [0, 0, 0, 0] as byte[]
-        assertEquals(2, stream.read(bytes))
-        assertEquals(['y', 'z', 0, 0], bytes)
-        assertEquals(0, stream.available())
+        assert 2 == stream.read(bytes)
+        assert ['y', 'z', 0, 0] == bytes
+        assert 0 == stream.available()
     }
 
     void testWrapBoth() {
-        ByteArrayInputStream mockStream = new ByteArrayInputStream("abc".getBytes())
+        ByteArrayInputStream mockStream = new ByteArrayInputStream('abc'.bytes)
         WrappedInputStream stream = new WrappedInputStream(mockStream)
-        stream.insert("xyz")
+        stream.insert('xyz')
         // wrapped stream first counts inserted chars, which will be read
-        assertEquals(3, stream.available())
-        assertEquals(false, stream.markSupported())
-        assertEquals('x', stream.read())
+        assert 3 == stream.available()
+        assert !stream.markSupported()
+        assert 'x' == stream.read()
         byte[] bytes = [0, 0, 0] as byte[]
         // wrapped stream reads wrapped stream first
-        assertEquals(2, stream.read(bytes))
-        assertEquals(['y', 'z', 0], bytes)
-        assertEquals(3, stream.read(bytes))
-        assertEquals(['a', 'b', 'c'], bytes)
-        assertEquals(0, stream.available())
+        assert 2 == stream.read(bytes)
+        assert ['y', 'z', 0] == bytes
+        assert 3 == stream.read(bytes)
+        assert ['a', 'b', 'c'] == bytes
+        assert 0 == stream.available()
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-jmx/src/spec/doc/jmx.adoc b/subprojects/groovy-jmx/src/spec/doc/jmx.adoc
index 48258ea..264c4c6 100644
--- a/subprojects/groovy-jmx/src/spec/doc/jmx.adoc
+++ b/subprojects/groovy-jmx/src/spec/doc/jmx.adoc
@@ -3,18 +3,18 @@
 
 == Introduction
 
-Given that Groovy sits directly on top of Java, Groovy can leverage the tremendous amount of work already done for http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX] with Java. In addition, Groovy provides a ++GroovyMBean++ class which makes an MBean look like a normal Groovy object. This simplifies Groovy code for interacting with __MBeans__. For example, the following code:
+Given that Groovy sits directly on top of Java, Groovy can leverage the tremendous amount of work already done for http://www.oracle.com/technetwork/java/javase/tech/javamanagement-140525.html[JMX] with Java. In addition, Groovy provides a `GroovyMBean` class which makes an MBean look like a normal Groovy object. This simplifies Groovy code for interacting with __MBeans__. For example, the following code:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=introduction_example,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=introduction_example,indent=0]
 ----
 
 can be simplified to:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=introduction_simplified_example,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=introduction_simplified_example,indent=0]
 ----
 
 The remainder of this page shows you how to:
@@ -25,8 +25,6 @@ The remainder of this page shows you how to:
 - Monitor BEA WebLogic and display information
 - Leverage Spring's MBean annotation support to export your Groovy beans as MBeans
 
-Note: many of the examples on this page use Java 5 which incorporates JMX 1.2 (more recent versions if JMX or Java will also work). In some cases, you can run some of these examples using Java 1.4 by including a version of JMX on your ++CLASSPATH++. MX4J is bundled with the full distribution of Groovy. In most cases, you can delete this jar from your distribution ++lib++ directory if you are running with Java 5 or above (in fact you might have to - see the Troubleshooting section below).
-
 == Monitoring the JVM
 
 MBeans are not accessed directly by an application but are managed by a repository called an __MBean server__. Java 5 and above includes a special MBean server called the __platform MBean server__, which is built into the JVM. Platform MBeans are registered in this server using unique names.
@@ -35,7 +33,7 @@ You can monitor the JVM through its platform MBeans with the following code:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=the_jvm,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=the_jvm,indent=0]
 ----
 
 When run, you will see something like this:
@@ -136,7 +134,7 @@ The following code uses JMX to discover the available MBeans in the running Tomc
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=tomcat,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=tomcat,indent=0]
 ----
 
 When run, we will see a trace of progress being made:
@@ -260,7 +258,7 @@ This script prints out information about the server followed by information abou
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=weblogic,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=weblogic,indent=0]
 ----
 
 Here is the output:
@@ -284,7 +282,7 @@ Here is an example class (Calculator.groovy):
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=spring_classes,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=spring_classes,indent=0]
 ----
 
 Here is the Spring configuration file (beans.xml):
@@ -340,7 +338,7 @@ Here is a script which uses this bean and configuration:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=spring_usage,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=spring_usage,indent=0]
 ----
 
 And here is the resulting output:
@@ -365,7 +363,7 @@ You can even attach to the process while it is running with http://docs.oracle.c
 
 image:assets/img/jconsole.gif[]
 
-We started the Groovy application with the ++-Dcom.sun.management.jmxremote++ JVM argument using a Java 5 JVM.
+We started the Groovy application with the `-Dcom.sun.management.jmxremote` JVM argument.
 
 See also:
 
@@ -375,25 +373,6 @@ See also:
 
 == Troubleshooting
 
-=== groovy.lang.MissingMethodException or groovy.lang.GroovyRuntimeException
-
-If you get an error like this:
-
-----
-groovy.lang.MissingMethodException: No signature of method:
-javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection.queryMBeans()
-is applicable for argument types: (javax.management.ObjectName, null)
-values: {Catalina:*, null}
-----
-
-or like this:
-
-----
-Caught: groovy.lang.GroovyRuntimeException: Could not find matching constructor for: groovy.util.GroovyMBean(javax.management.remote.rmi.RMIConnector$RemoteMBeanServerConnection, java.lang.String)
-----
-
-you have to move away or delete "mx4j-*.jar" from ++$GROOVY_HOME/lib++. MX4J is designed to add ++javax.management++ classes to 1.4 JVMs. If you already have a newer JMX jar on your classpath or are using a Java 5 or higher JVM, the MX4J classes will be incompatible with the ones from the newer Sun JVMs or newer versions of JMX.
-
 === java.lang.SecurityException
 
 If you get the following error, your container's JMX access is password protected:
@@ -406,11 +385,12 @@ To fix that, add an environment with the credentials when connecting, like this
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=troubleshooting,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=troubleshooting,indent=0]
 ----
 
 Details for the software you are trying to monitor/manage may differ slightly. Check out the other examples using credentials above if appropriate (e.g. OC4J and WebLogic). If you still have troubles, you will have to consult the documentation for the software you are trying to monitor/manage for details on how to provide credentials.
 
+[[jmx_jmxbuilder]]
 == JmxBuilder
 
 **JmxBuilder is a Groovy-based domain specific language for the Java Management Extension (JMX) API**. It uses the builder pattern (FactoryBuilder) to create an internal DSL that facilitates the exposure of POJO's and Groovy beans as management components via the MBean server. JmxBuilder hides the complexity of creating and exporting management beans via the JMX API and provides a set of natural Groovy constructs to interact with the JMX infrastructure.
@@ -421,7 +401,7 @@ To start using JmxBuilder, simply make sure the jar file is on your class path.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=instantiating_jmxbuilder,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=instantiating_jmxbuilder,indent=0]
 ----
 
 **That's it!** You are now ready to use the JmxBuilder.
@@ -465,7 +445,7 @@ Note that the serverConnector node will accept four ServerConnector property ali
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=connector_server,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=connector_server,indent=0]
 ----
 
 The snippet above returns an RMI connector that will start listening on port 9000. By default, the builder will internally generate URL **"service:jmx:rmi:///jndi/rmi://localhost:9000/jmxrmi"**.
@@ -484,11 +464,11 @@ NOTE: __The correct example is shown below.__
 
 **Connector Example (Corrected) - Connector Server**
 
-The example above does not create the RMI registry. So, in order to export, you have to first export the RMI object registry (make sure to import ++java.rmi.registry.LocateRegistry++).
+The example above does not create the RMI registry. So, in order to export, you have to first export the RMI object registry (make sure to import `java.rmi.registry.LocateRegistry`).
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=connector_server_and_local_registry,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=connector_server_and_local_registry,indent=0]
 ----
 
 ==== Connector Client
@@ -512,14 +492,14 @@ Creating a connector client can be done just as easily. With one line of code, y
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=client_connector,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=client_connector,indent=0]
 ----
 
 You can then access the MBeanServerConnection associated with the connector using:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=client_connector_usage,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=client_connector_usage,indent=0]
 ----
 
 === JmxBuilder MBean Export
@@ -536,7 +516,7 @@ The **JmxBuilder.export() node provides a container** where all management entit
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=jmxbuilder_export,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=jmxbuilder_export,indent=0]
 ----
 
 In the code snippet above, **JmxBuilder.export() will export three management beans** to the MBean server.
@@ -551,7 +531,7 @@ or
 jmx.export(regPolicy:"replace|ignore|error")
 ----
 
-- **replace** - JmxBuilder.export() will replance any bean already registered with the MBean during export.
+- **replace** - JmxBuilder.export() will replace any bean already registered with the MBean during export.
 - **ignore** - The bean being exported will be ignored if the same bean is already registered.
 - **error** - JmxBuilder.export() throws an error upon bean name collision during registration.
 
@@ -567,7 +547,7 @@ This portion of this reference uses class **RequestController** to illustrate ho
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=request_controller,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=request_controller,indent=0]
 ----
 
 ===== Implicit Export
@@ -578,7 +558,7 @@ The simplest way to export a POJO or POGO is listed below.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=implicit_export,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=implicit_export,indent=0]
 ----
 
 **What this does:**
@@ -665,7 +645,7 @@ Using the bean() node descriptors, you can specify your own MBean ObjectName.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=using_bean,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=using_bean,indent=0]
 ----
 
 The ObjectName can be specified as a String or an instance of the ObjectName.
@@ -680,7 +660,7 @@ The following code snippet **will describe and export all attributes** on the be
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_attributes,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_attributes,indent=0]
 ----
 
 ==== Export Attribute List
@@ -689,7 +669,7 @@ JmxBuilder will let you specify a list of attributes to export.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_attribute_list,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_attribute_list,indent=0]
 ----
 
 In the snippet above, **only the "Resource" and "RequestCount" attributes will be exported**. Again, since no descriptors are provided, **JmxBuilder will use sensible defaults** to describe the exported attributes.
@@ -700,7 +680,7 @@ One of the strengths of JmxBuilder is its flexibility in describing MBean. With
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_attribute_with_explicit_descriptors,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_attribute_with_explicit_descriptors,indent=0]
 ----
 
 In the snippet above, attribute **"Resource" is fully-described** using all supported descriptors (i.e. desc, readable, writable, defaultValue) for a JMX attribute. However, we use the wildcard to describe attribute **RequestCount** and it will be exported and described using defaults.
@@ -715,7 +695,7 @@ You can use the builder's special '""' **notation to *export all constructors**
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_constructors,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_constructors,indent=0]
 ----
 
 ==== Export Constructors using Parameter Descriptor
@@ -724,7 +704,7 @@ JmxBuilder lets you **target specific constructor** to export **by describing th
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_constructors_using_parameter_descriptor,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_constructors_using_parameter_descriptor,indent=0]
 ----
 
 Here, JmxBuilder will **export a constructor that takes one parameter of type "Object"**. Again, JmxBuilder will use default values to fill in the description of the constructor and the parameters.
@@ -735,7 +715,7 @@ JmxBuilder allows you to **fully-describe** the constructor that you want to tar
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_constructor_with_explicit_descriptors,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_constructor_with_explicit_descriptors,indent=0]
 ----
 
 In the code above, JmxBuilder will target a constructor that takes one parameter for export to the MBeanServer. Notice how the constructor can be fully-described using all optional descriptor keys including parameter descriptors.
@@ -750,7 +730,7 @@ You can use the builder's special '""'' **notation to *export all operations** d
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_operations,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_all_operations,indent=0]
 ----
 
 In this snippet, JmxBuilder will **export all bean operations** and will use default values to describe them in the MBeanServer.
@@ -761,7 +741,7 @@ JmxBuilder has a shorthand notation that lets you quickly target operations to b
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operation_list,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operation_list,indent=0]
 ----
 
 In the snippet above, the **builder will only export methods start() and stop()**. All other methods will be ignored. JmxBuilder will use default descriptor values to describe the operations being exported.
@@ -772,7 +752,7 @@ Using JmxBuilder, you can target methods to export for management using the meth
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operations_by_signature,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operations_by_signature,indent=0]
 ----
 
 In the snipet above, JmxBuilder would **select method makeRequest(String)** to be exported instead of the other version makeRequest() which takes no parameter. In this shorthand context, the signature is specified as a list of type (i.e. "String").
@@ -783,7 +763,7 @@ JmxBuilder supports detailed descriptors for bean operations. You can supply dee
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operations_with_explicit_descriptors,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=export_operations_with_explicit_descriptors,indent=0]
 ----
 
 The snippet above shows all of the ways JmxBuilder allows you to describe an operation targeted for management:
@@ -794,13 +774,13 @@ The snippet above shows all of the ways JmxBuilder allows you to describe an ope
 
 === Embedding Descriptor
 
-JmxBuilder supports the ability to **embed descriptors directly in your Groovy class**. So, instead of wrapping your description around the declared object (as we've seen here), you can ebmed your JMX descriptors directly in your class.
+JmxBuilder supports the ability to **embed descriptors directly in your Groovy class**. So, instead of wrapping your description around the declared object (as we've seen here), you can embed your JMX descriptors directly in your class.
 
 **RequestControllerGroovy**
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=embedding_descriptor,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=embedding_descriptor,indent=0]
 ----
 
 There are two things going on in the code above:
@@ -810,7 +790,7 @@ There are two things going on in the code above:
 
 === Timer Export
 
-JMX standards mandate that the implementation of the API makes available a timer service. Since JMX is a component-based architecture, timers provide an excellent signaling mechanism to communicate to registered listener components in the MBeanServer. JmxBuilder supports the creation and export of timers using the same easy syntax we've seen so far.
+JMX standards mandate that the implementation of the API makes available a timer service. Since JMX is a component-based architecture, timers provide an excellent signalling mechanism to communicate to registered listener components in the MBeanServer. JmxBuilder supports the creation and export of timers using the same easy syntax we've seen so far.
 
 ==== Timer Node Syntax
 
@@ -822,7 +802,7 @@ timer(
     data:dataValue
     startDate:"now"|dateValue
     period:"99d"|"99h"|"99m"|"99s"|99
-    occurences:long
+    occurrences:long
 )
 ----
 
@@ -830,17 +810,17 @@ The timer() node supports several attributes:
 
 - **name**: - Required The qualified JMX ObjectName instance (or String) for the timer.
 - **event**: - The JMX event type string that will be broadcast with every timing signal (default **"jmx.builder.event"**).
-- **message**: - An optional string value that can be sent to listneners.
+- **message**: - An optional string value that can be sent to listeners.
 - **data**: - An optional object that can be sent to listeners of timing signal.
 - **startDate**: - When to start timer. Set of valid values [ "now", date object ]. Default is "now"
 - **period**: - A timer's period expressed as either a number of millisecond or time unit (day, hour, minute, second). See description below.
-- **occurences**: - A number indicating the number of time to repeat timer. Default is forever.
+- **occurrences**: - A number indicating the number of time to repeat timer. Default is forever.
 
 ==== Exporting a Timer
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=exporting_timer,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=exporting_timer,indent=0]
 ----
 
 This snippet above **describes, creates, and exports a standard JMX Timer** component. Here, the **timer()** node **returns a GroovyMBean** that represents the registered timer MBean in the MBeanServer.
@@ -849,7 +829,7 @@ An **alternative way of exporting timers** is within the JmxBuilder.export() nod
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=exporting_timer_beans,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=exporting_timer_beans,indent=0]
 ----
 
 ==== Timer Period
@@ -876,7 +856,7 @@ JmxBuilder leverages Groovy's use of closures to provide simple, yet elegant, me
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handling_closures,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handling_closures,indent=0]
 ----
 
 JmxBuilder executes the closure and passes no information about the event that was captured on the bus.
@@ -885,7 +865,7 @@ JmxBuilder executes the closure and passes no information about the event that w
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handling_closures_event,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handling_closures_event,indent=0]
 ----
 
 JmxBuilder will pass an **"event" object to the closure** using this format. The event object contains information about the event was intercepted so that it can be handled by the handler. The parameter will contain different set of info depending on the event that was captured.
@@ -896,7 +876,7 @@ When describing attributes (see bean() node section above), you can **provide a
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=handling_attribute_onchange_event,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=handling_attribute_onchange_event,indent=0]
 ----
 
 The sample snippet above shows how to **specify an "onChange" callback closure** when describing MBean attributes. In this sample code, whenever attribute "Resource" is updated via the exported MBean, the **onChange event will be executed**.
@@ -907,23 +887,23 @@ When handling the attribute onChange event, the handler closure will receive an
 
 - event.**oldValue** - the previous attribute value before the change event.
 - event.**newValue** - the new value of the attribute after the change.
-- event.**attribute** - the name of the attribute on which the event occured.
+- event.**attribute** - the name of the attribute on which the event occurred.
 - event.**attributeType** - the data type of the attribute that causes the event.
 - event.**sequenceNumber** - a numeric value representing the sequence number of event.
-- event.**timeStamp** - a time stamp for the event occurence.
+- event.**timeStamp** - a time stamp for the event occurrence.
 
 ==== Handling Operation onCall Event
 
-Similar to mbean attributes, JmxBuilder affords developers the **ability to listen for operation invokation** on an MBean registered in the MBeaServer. JmxBuilder accepts a **callback closure that will be executed after the MBean method has invoked**.
+Similar to mbean attributes, JmxBuilder affords developers the **ability to listen for operation invocation** on an MBean registered in the MBeaServer. JmxBuilder accepts a **callback closure that will be executed after the MBean method has invoked**.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handler,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handler,indent=0]
 ----
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handler_usage,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=event_handler_usage,indent=0]
 ----
 
 The snippet above **shows how to declare an "onCall" closure to be used as listener** when operation "start()" is invoked on the MBean. This sample **uses the method pointer syntax** to illustrate the versatility of JmxBuilder.
@@ -936,7 +916,7 @@ When handling the operation onCall event, the callback closure will receive an e
 - event.**source** - The object on which the method was invoked.
 - event.**data** - the data type of the attribute that causes the event.
 - event.**sequenceNumber** - a numeric value representing the sequence number of event.
-- event.**timeStamp** - a time stamp for the event occurence.
+- event.**timeStamp** - a time stamp for the event occurrence.
 
 === Listener MBean
 
@@ -944,7 +924,7 @@ When you export an MBean with the bean() node, you can define events the MBean c
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=listener_mbean,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=listener_mbean,indent=0]
 ----
 
 In the sample above, we see the **syntax for adding listeners to an exported MBean**.
@@ -958,7 +938,7 @@ You can also specify an **event type** you are interested in receiving from a br
 
 ==== Listening to JMX Events
 
-In some cases, you will want to create stand-alone event listensers (not attached to exported MBeans). JmxBuilder provides the Listener() node to let you create JMX listeners that can listen to MBeanServer events. This is useful when creating JMX client applications to monitor/manage JMX agents on remote JMX MBeanServers.
+In some cases, you will want to create stand-alone event listeners (not attached to exported MBeans). JmxBuilder provides the Listener() node to let you create JMX listeners that can listen to MBeanServer events. This is useful when creating JMX client applications to monitor/manage JMX agents on remote JMX MBeanServers.
 
 ==== Listener Node Syntax
 
@@ -970,7 +950,7 @@ jmx.listener(
 )
 ----
 
-Here is the description of the **lisetener()** node attributes:
+Here is the description of the **listener()** node attributes:
 
 - event: An optional string that identifies the JMX event type to listen for.
 - from (required): The JMX ObjectName of the component to listen to. This can be specified as a string or an instance of ObjectName
@@ -980,7 +960,7 @@ Here is an example of JmxBuilder's listener node:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=jmxbuilders_listener,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=jmxbuilders_listener,indent=0]
 ----
 
 This example shows how you can use a stand alone listener (outside of an MBean export). Here, we **export a timer with a 1 second** resolution. Then, we specify a listener to that timer that will print "beep" every second.
@@ -1004,7 +984,7 @@ The attributes for the node Emitter() can be summarized as follows:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=declare_emitter,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=declare_emitter,indent=0]
 ----
 
 The snippet **declares the emitter using implicit descriptor syntax**. JmxBuilder will do the followings:
@@ -1021,7 +1001,7 @@ Once you have declared your emitter, you can broadcast your event.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=emitter_broadcast_event,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=emitter_broadcast_event,indent=0]
 ----
 
 The sample above shows the **emitter sending an event**, once it has been declared. Any JMX component registered in the MBeanServer can register to receive message from this emitter.
@@ -1032,10 +1012,10 @@ You can optionally pass data to the receiver when you send the message.
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=emitter_broadcast_event_with_objects,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy[tags=emitter_broadcast_event_with_objects,indent=0]
 ----
 
-If you use an **event listener closure (see above) that accpets a parameter**, you can access that value.
+If you use an **event listener closure (see above) that accepts a parameter**, you can access that value.
 
 == Further JMX Information
 
@@ -1046,4 +1026,3 @@ If you use an **event listener closure (see above) that accpets a parameter**, y
 - https://blogs.oracle.com/sundararajan/entry/groovier_jconsole[Groovier jconsole!]
 - http://jmesnil.net/weblog/2007/05/23/jmx-scripts-with-eclipse-monkey[JMX Scripts with Eclipse Monkey]
 - http://activemq.apache.org/jmx.html[Using JMX to monitor Apache ActiveMQ]
-- http://jagger.berlios.de[Jagger project (JMX application monitoring with Groovy)]
\ No newline at end of file
diff --git a/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy b/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy
index 1b26de9..f9d7d94 100644
--- a/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy
+++ b/subprojects/groovy-jmx/src/spec/test/JmxTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import gls.CompilableTestSupport
 
 class JmxTest extends CompilableTestSupport {
diff --git a/subprojects/groovy-jmx/src/test/java/groovy/jmx/builder/MockJmxListener.java b/subprojects/groovy-jmx/src/test/java/groovy/jmx/builder/MockJmxListener.java
index 11a0237..7fde106 100644
--- a/subprojects/groovy-jmx/src/test/java/groovy/jmx/builder/MockJmxListener.java
+++ b/subprojects/groovy-jmx/src/test/java/groovy/jmx/builder/MockJmxListener.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.jmx.builder;
 
 import javax.management.Notification;
diff --git a/subprojects/groovy-json/src/main/groovy/groovy/json/JsonBuilder.groovy b/subprojects/groovy-json/src/main/groovy/groovy/json/JsonBuilder.groovy
deleted file mode 100644
index 83396e2..0000000
--- a/subprojects/groovy-json/src/main/groovy/groovy/json/JsonBuilder.groovy
+++ /dev/null
@@ -1,311 +0,0 @@
-/*
- * Copyright 2003-2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package groovy.json
-
-/**
- * A builder for creating JSON payloads.
- * <p>
- * This builder supports the usual builder syntax made of nested method calls and closures,
- * but also some specific aspects of JSON data structures, such as list of values, etc.
- * Please make sure to have a look at the various methods provided by this builder
- * to be able to learn about the various possibilities of usage.
- * <p>
- * Example:
- * <pre><code>
- *       def builder = new groovy.json.JsonBuilder()
- *       def root = builder.people {
- *           person {
- *               firstName 'Guillame'
- *               lastName 'Laforge'
- *               // Named arguments are valid values for objects too
- *               address(
- *                       city: 'Paris',
- *                       country: 'France',
- *                       zip: 12345,
- *               )
- *               married true
- *               // a list of values
- *               conferences 'JavaOne', 'Gr8conf'
- *           }
- *       }
- *
- *       // creates a data structure made of maps (Json object) and lists (Json array)
- *       assert root instanceof Map
- *
- *       assert builder.toString() == '{"people":{"person":{"firstName":"Guillame","lastName":"Laforge","address":{"city":"Paris","country":"France","zip":12345},"married":true,"conferences":["JavaOne","Gr8conf"]}}}'
- * </code></pre>
- *
- * @author Guillaume Laforge
- * @since 1.8.0
- */
-class JsonBuilder implements Writable {
-
-    /**
-     * Resulting data structure made of lists and maps, representing a JSON payload
-     */
-    def content
-
-    /**
-     * Instanciates a JSON builder, possibly with some existing data structure.
-     *
-     * @param content a pre-existing data structure, default to null
-     */
-    JsonBuilder(content = null) {
-        this.content = content
-    }
-
-    /**
-     * Named arguments can be passed to the JSON builder instance to create a root JSON object
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json name: "Guillaume", age: 33
-     *
-     * assert json.toString() == '{"name":"Guillaume","age":33}'
-     * </code></pre>
-     *
-     * @param m a map of key / value pairs
-     * @return a map of key / value pairs
-     */
-    def call(Map m) {
-        this.content = m
-        return content
-    }
-
-    /**
-     * A list of elements as arguments to the JSON builder creates a root JSON array
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * def result = json([1, 2, 3])
-     *
-     * assert result instanceof List
-     * assert json.toString() == "[1,2,3]"
-     * </code></pre>
-     *
-     * @param l a list of values
-     * @return a list of values
-     */
-    def call(List l) {
-        this.content = l
-        return content
-    }
-
-    /**
-     * Varargs elements as arguments to the JSON builder create a root JSON array
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * def result = json 1, 2, 3
-     *
-     * assert result instanceof List
-     * assert json.toString() == "[1,2,3]"
-     * </code></pre>
-
-     * @param args an array of values
-     * @return a list of values
-     */
-    def call(Object... args) {
-        this.content = args.toList()
-        return this.content
-    }
-
-    /**
-     * A collection and closure passed to a JSON builder will create a root JSON array applying
-     * the closure to each object in the collection
-     * <p>
-     * Example:
-     * <pre><code>
-     * class Author {
-     *      String name
-     * }
-     * def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
-     *
-     * def json = new JsonBuilder()
-     * json authors, { Author author ->
-     *      name author.name
-     * }
-     *
-     * assert json.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
-     * </code></pre>
-     * @param coll a collection
-     * @param c a closure used to convert the objects of coll
-     * @return a list of values
-     */
-    def call(Collection coll, Closure c) {
-        this.content = coll.collect {JsonDelegate.curryDelegateAndGetContent(c, it)}
-        return content
-    }
-
-    /**
-     * A closure passed to a JSON builder will create a root JSON object
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * def result = json {
-     *      name "Guillaume"
-     *      age 33
-     * }
-     *
-     * assert result instanceof Map
-     * assert json.toString() == '{"name":"Guillaume","age":33}'
-     * </code></pre>
-     *
-     * @param c a closure whose method call statements represent key / values of a JSON object
-     * @return a map of key / value pairs
-     */
-    def call(Closure c) {
-        this.content = JsonDelegate.cloneDelegateAndGetContent(c)
-        return content
-    }
-
-    /**
-     * A method call on the JSON builder instance will create a root object with only one key
-     * whose name is the name of the method being called.
-     * This method takes as arguments:
-     * <ul>
-     *     <li>a closure</li>
-     *     <li>a map (ie. named arguments)</li>
-     *     <li>a map and a closure</li>
-     *     <li>or no argument at all</li>
-     * </ul>
-     * <p>
-     * Example with a classicala builder-style:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * def result = json.person {
-     *      name "Guillaume"
-     *      age 33
-     * }
-     *
-     * assert result instanceof Map
-     * assert json.toString() == '{"person":{"name":"Guillaume","age":33}}'
-     * </code></pre>
-     *
-     * Or alternatively with a method call taking named arguments:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json.person name: "Guillaume", age: 33
-     *
-     * assert json.toString() == '{"person":{"name":"Guillaume","age":33}}'
-     * </code></pre>
-     *
-     * If you use named arguments and a closure as last argument,
-     * the key/value pairs of the map (as named arguments)
-     * and the key/value pairs represented in the closure
-     * will be merged together —
-     * the closure properties overriding the map key/values
-     * in case the same key is used.
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json.person(name: "Guillaume", age: 33) { town "Paris" }
-     *
-     * assert json.toString() == '{"person":{"name":"Guillaume","age":33,"town":"Paris"}}'
-     * </code></pre>
-     *
-     * The empty args call will create a key whose value will be an empty JSON object:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json.person()
-     *
-     * assert json.toString() == '{"person":{}}'
-     * </code></pre>
-     *
-     * @param name the single key
-     * @param args the value associated with the key
-     * @return a map with a single key
-     */
-    def invokeMethod(String name, Object args) {
-        if (args?.size() == 0) {
-            this.content = [(name): [:]]
-            return content
-        } else if (args?.size() == 1) {
-            if (args[0] instanceof Closure) {
-                this.content = [(name): JsonDelegate.cloneDelegateAndGetContent(args[0])]
-                return content
-            } else if (args[0] instanceof Map) {
-                this.content = [(name): args[0]]
-                return content
-            }
-        } else if (args?.size() == 2) {
-            if (args[0] instanceof Map && args[1] instanceof Closure) {
-                this.content = [(name): [*:args[0], *:JsonDelegate.cloneDelegateAndGetContent(args[1])]]
-                return content
-            } else if (args[0] instanceof Collection && args[1] instanceof Closure) {
-                this.content = [(name): args[0].collect {JsonDelegate.curryDelegateAndGetContent(args[1],it)}]
-                return content
-            }
-        }
-        throw new JsonException("Expected no arguments, a single map, a single closure, or a map and closure as arguments.")
-    }
-
-    /**
-     * Serializes the internal data structure built with the builder to a conformant JSON payload string
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json { temperature 37 }
-     * 
-     * assert json.toString() == '{"temperature":37}'
-     * </code></pre>
-     *
-     * @return a JSON output
-     */
-    String toString() {
-        JsonOutput.toJson(content)
-    }
-
-    /**
-     * Pretty-prints and formats the JSON payload.
-     * <p>
-     * This method calls the JsonLexer to parser the output of the builder,
-     * so this may not be an optimal method to call,
-     * and should be used mainly for debugging purpose
-     * for a human-readable output of the JSON content.
-     *
-     * @return a pretty printed JSON output
-     */
-    String toPrettyString() {
-        JsonOutput.prettyPrint(toString())
-    }
-
-    /**
-     * The JSON builder implements the <code>Writable</code> interface,
-     * so that you can have the builder serialize itself the JSON payload to a writer.
-     * <p>
-     * Example:
-     * <pre><code>
-     * def json = new JsonBuilder()
-     * json { temperature 37 }
-     *
-     * def out = new StringWriter()
-     * out << json
-     *
-     * assert out.toString() == '{"temperature":37}' 
-     * </code></pre>
-     *
-     * @param out a writer on which to serialize the JSON payload
-     * @return the writer
-     */
-    Writer writeTo(Writer out) {
-        out << toString()
-    }
-}
diff --git a/subprojects/groovy-json/src/main/groovy/groovy/json/StreamingJsonBuilder.groovy b/subprojects/groovy-json/src/main/groovy/groovy/json/StreamingJsonBuilder.groovy
deleted file mode 100644
index ca36f91..0000000
--- a/subprojects/groovy-json/src/main/groovy/groovy/json/StreamingJsonBuilder.groovy
+++ /dev/null
@@ -1,349 +0,0 @@
-/*
- * Copyright 2003-2012 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package groovy.json
-
-/**
- * A builder for creating JSON payloads.
- * <p>
- * This builder supports the usual builder syntax made of nested method calls and closures,
- * but also some specific aspects of JSON data structures, such as list of values, etc.
- * Please make sure to have a look at the various methods provided by this builder
- * to be able to learn about the various possibilities of usage.
- * <p>
- * Unlike the JsonBuilder class which creates a data structure in memory,
- * which is handy in those situations where you want to alter the structure programmatically before output,
- * the StreamingJsonBuilder streams to a writter directly without any memory data structure.
- * So if you don't need to modify the structure, and want a more memory-efficient approach,
- * please use the StreamingJsonBuilder.
- * <p>
- * Example:
- * <pre class="groovyTestCase">
- *     new StringWriter().with { w ->
- *         def builder = new groovy.json.StreamingJsonBuilder( w )
- *         builder.people {
- *             person {
- *                 firstName 'Tim'
- *                 lastName 'Yates'
- *                 // Named arguments are valid values for objects too
- *                 address(
- *                     city: 'Manchester',
- *                     country: 'UK',
- *                     zip: 'M1 2AB',
- *                 )
- *                 living true
- *                 eyes 'left', 'right'
- *             }
- *         }
- *
- *         assert w.toString() == '{"people":{"person":{"firstName":"Tim","lastName":"Yates","address":{"city":"Manchester","country":"UK","zip":"M1 2AB"},"living":true,"eyes":["left","right"]}}}'
- *    }
- * </pre>
- *
- * @author Tim Yates
- * @since 1.8.1
- */
-class StreamingJsonBuilder {
-
-    Writer writer
-    
-    /**
-     * Instantiates a JSON builder, possibly with some existing data structure.
-     *
-     * @param writer A writer to which Json will be written
-     * @param content a pre-existing data structure, default to null
-     */
-    StreamingJsonBuilder( Writer writer, content = null) {
-        this.writer = writer
-        if( content ) writer.write( JsonOutput.toJson( content ) )
-    }
-
-    /**
-     * Named arguments can be passed to the JSON builder instance to create a root JSON object
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *   def json = new groovy.json.StreamingJsonBuilder( w )
-     *   json name: "Tim", age: 31
-     *
-     *   assert w.toString() == '{"name":"Tim","age":31}'
-     * }
-     * </pre>
-     *
-     * @param m a map of key / value pairs
-     * @return a map of key / value pairs
-     */
-    def call(Map m) {
-        writer.write JsonOutput.toJson( m )
-        return m
-    }
-
-    /**
-     * A list of elements as arguments to the JSON builder creates a root JSON array
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *   def json = new groovy.json.StreamingJsonBuilder( w )
-     *   def result = json([1, 2, 3])
-     *
-     *   assert result == [ 1, 2, 3 ]
-     *   assert w.toString() == "[1,2,3]"
-     * }
-     * </pre>
-     *
-     * @param l a list of values
-     * @return a list of values
-     */
-    def call(List l) {
-        writer.write( JsonOutput.toJson( l ) )
-        return l
-    }
-
-    /**
-     * Varargs elements as arguments to the JSON builder create a root JSON array
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *   def json = new groovy.json.StreamingJsonBuilder( w )
-     *   def result = json 1, 2, 3
-     *
-     *   assert result instanceof List
-     *   assert w.toString() == "[1,2,3]"
-     * }
-     * </pre>
-
-     * @param args an array of values
-     * @return a list of values
-     */
-    def call(Object... args) {
-        def l = args.toList()
-        writer.write JsonOutput.toJson( l )
-        return l
-    }
-
-    /**
-     * A collection and closure passed to a JSON builder will create a root JSON array applying
-     * the closure to each object in the collection
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * class Author {
-     *      String name
-     * }
-     * def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
-     *
-     * new StringWriter().with { w ->
-     *     def json = new groovy.json.StreamingJsonBuilder( w )
-     *     json authors, { Author author ->
-     *         name author.name
-     *     }
-     *
-     *     assert w.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
-     * }
-     * </pre>
-     * @param coll a collection
-     * @param c a closure used to convert the objects of coll
-     */
-    def call (Collection coll, Closure c) {
-        StreamingJsonDelegate.writeCollectionWithClosure( writer, coll, c)
-    }
-
-    /**
-     * A closure passed to a JSON builder will create a root JSON object
-     * <p>
-     * Example:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *   def json = new groovy.json.StreamingJsonBuilder( w )
-     *   json {
-     *      name "Tim"
-     *      age 39
-     *   }
-     *
-     *   assert w.toString() == '{"name":"Tim","age":39}'
-     * }
-     * </pre>
-     *
-     * @param c a closure whose method call statements represent key / values of a JSON object
-     */
-    def call(Closure c) {
-        writer.write( '{' )
-        StreamingJsonDelegate.cloneDelegateAndGetContent( writer, c )
-        writer.write( '}' )
-    }
-
-    /**
-     * A method call on the JSON builder instance will create a root object with only one key
-     * whose name is the name of the method being called.
-     * This method takes as arguments:
-     * <ul>
-     *     <li>a closure</li>
-     *     <li>a map (ie. named arguments)</li>
-     *     <li>a map and a closure</li>
-     *     <li>or no argument at all</li>
-     * </ul>
-     * <p>
-     * Example with a classicala builder-style:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *     def json = new groovy.json.StreamingJsonBuilder( w )
-     *     json.person {
-     *         name "Tim"
-     *          age 28
-     *     }
-     *
-     *     assert w.toString() == '{"person":{"name":"Tim","age":28}}'
-     * }
-     * </pre>
-     *
-     * Or alternatively with a method call taking named arguments:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *     def json = new groovy.json.StreamingJsonBuilder( w )
-     *     json.person name: "Tim", age: 32
-     *
-     *     assert w.toString() == '{"person":{"name":"Tim","age":32}}'
-     * }
-     * </pre>
-     *
-     * If you use named arguments and a closure as last argument,
-     * the key/value pairs of the map (as named arguments)
-     * and the key/value pairs represented in the closure
-     * will be merged together —
-     * the closure properties overriding the map key/values
-     * in case the same key is used.
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *     def json = new groovy.json.StreamingJsonBuilder( w )
-     *     json.person(name: "Tim", age: 35) { town "Manchester" }
-     *
-     *     assert w.toString() == '{"person":{"name":"Tim","age":35,"town":"Manchester"}}'
-     * }
-     * </pre>
-     *
-     * The empty args call will create a key whose value will be an empty JSON object:
-     * <pre class="groovyTestCase">
-     * new StringWriter().with { w ->
-     *     def json = new groovy.json.StreamingJsonBuilder( w )
-     *     json.person()
-     *
-     *     assert w.toString() == '{"person":{}}'
-     * }
-     * </pre>
-     *
-     * @param name the single key
-     * @param args the value associated with the key
-     */
-    def invokeMethod(String name, Object args) {
-        if (args?.size() == 0) {
-            writer.write JsonOutput.toJson( [(name): [:]] )
-        } else if (args?.size() == 1) {
-            if (args[0] instanceof Closure) {
-                writer.write "{${JsonOutput.toJson( name )}:"
-                this.call( args[0] )
-                writer.write '}'
-            } else if (args[0] instanceof Map) {
-                writer.write JsonOutput.toJson( [(name): args[0]] )
-            }
-            else {
-                throw new JsonException("Expected no arguments, a single map, a single closure, or a map and closure as arguments.")
-            }
-        } else if (args?.size() == 2 && args[0] instanceof Map && args[1] instanceof Closure) {
-            writer.write "{${JsonOutput.toJson( name )}:{"
-            args[0].eachWithIndex { it, idx ->
-                if( idx > 0 ) writer.write ','
-                writer.write JsonOutput.toJson( it.key )
-                writer.write ':'
-                writer.write JsonOutput.toJson( it.value )
-            }
-            StreamingJsonDelegate.cloneDelegateAndGetContent( writer, args[1], !args[0].size() )
-            writer.write '}}'
-        } else if (StreamingJsonDelegate.isCollectionWithClosure( args )) {
-            writer.write "{${JsonOutput.toJson( name )}:"
-            call( args[0], args[1] )
-            writer.write '}'
-        }
-        else {
-            throw new JsonException("Expected no arguments, a single map, a single closure, or a map and closure as arguments.")
-        }
-    }
-}
-
-class StreamingJsonDelegate {
-    Writer writer
-    boolean first
-    
-    StreamingJsonDelegate( Writer w, boolean first ) {
-        this.writer = w
-        this.first = first
-    }
-
-    def invokeMethod(String name, Object args) {
-        if (args) {
-            if( !first ) {
-                writer.write ','
-            }
-            writer.write JsonOutput.toJson( name )
-            writer.write ':'
-
-            if (args.size() == 1) {
-                writer.write JsonOutput.toJson( args[0] )
-            } else if (isCollectionWithClosure( args )) {
-                writeCollectionWithClosure ( writer, args[0], args[1] )
-            } else {
-                writer.write JsonOutput.toJson( args.toList() )
-            }
-
-            first = false
-        }
-    }
-
-    static boolean isCollectionWithClosure (Object[] args) {
-        args.size() == 2 && args[0] instanceof Collection && args[1] instanceof Closure
-    }
-
-    static def writeCollectionWithClosure (Writer writer, Collection coll, Closure closure) {
-        writer.write '['
-        coll.eachWithIndex { it, idx ->
-            if (idx > 0) {
-                writer.write ','
-            }
-
-            writer.write '{'
-            curryDelegateAndGetContent (writer, closure, it)
-            writer.write '}'
-        }
-        writer.write ']'
-    }
-
-    static cloneDelegateAndGetContent(Writer w, Closure c, boolean first=true ) {
-        def delegate = new StreamingJsonDelegate( w, first )
-        Closure cloned = c.clone()
-        cloned.delegate = delegate
-        cloned.resolveStrategy = Closure.DELEGATE_FIRST
-        cloned()
-    }
-
-    static curryDelegateAndGetContent(Writer w, Closure c, Object o, boolean first=true) {
-        def delegate = new StreamingJsonDelegate( w, first )
-        Closure curried = c.curry (o)
-        curried.delegate = delegate
-        curried.resolveStrategy = Closure.DELEGATE_FIRST
-        curried()
-    }
-}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/DateFormatThreadLocal.java b/subprojects/groovy-json/src/main/java/groovy/json/DateFormatThreadLocal.java
deleted file mode 100644
index feb8cdb..0000000
--- a/subprojects/groovy-json/src/main/java/groovy/json/DateFormatThreadLocal.java
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2003-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package groovy.json;
-
-import java.text.SimpleDateFormat;
-import java.util.Locale;
-import java.util.TimeZone;
-
-/**
- * Custom thread local holding a <code>SimpleDateFormat</code>,
- * so that the <code>JsonOutput</code> class used by <code>JsonBuilder</code>
- * can be thread-safe when outputting dates and calendars.
- *
- * @author Guillaume Laforge
- */
-public class DateFormatThreadLocal extends ThreadLocal<SimpleDateFormat> {
-    @Override
-    protected SimpleDateFormat initialValue() {
-        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
-        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
-
-        return formatter;
-    }
-}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonBuilder.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonBuilder.java
new file mode 100644
index 0000000..f7da6e6
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonBuilder.java
@@ -0,0 +1,360 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.json;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+import groovy.lang.Writable;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+
+/**
+ * A builder for creating JSON payloads.
+ * <p>
+ * This builder supports the usual builder syntax made of nested method calls and closures,
+ * but also some specific aspects of JSON data structures, such as list of values, etc.
+ * Please make sure to have a look at the various methods provided by this builder
+ * to be able to learn about the various possibilities of usage.
+ * <p>
+ * Example:
+ * <pre><code>
+ *       def builder = new groovy.json.JsonBuilder()
+ *       def root = builder.people {
+ *           person {
+ *               firstName 'Guillame'
+ *               lastName 'Laforge'
+ *               // Named arguments are valid values for objects too
+ *               address(
+ *                       city: 'Paris',
+ *                       country: 'France',
+ *                       zip: 12345,
+ *               )
+ *               married true
+ *               // a list of values
+ *               conferences 'JavaOne', 'Gr8conf'
+ *           }
+ *       }
+ *
+ *       // creates a data structure made of maps (Json object) and lists (Json array)
+ *       assert root instanceof Map
+ *
+ *       assert builder.toString() == '{"people":{"person":{"firstName":"Guillame","lastName":"Laforge","address":{"city":"Paris","country":"France","zip":12345},"married":true,"conferences":["JavaOne","Gr8conf"]}}}'
+ * </code></pre>
+ *
+ * @author Guillaume Laforge
+ * @author Andrey Bloshetsov
+ * @since 1.8.0
+ */
+public class JsonBuilder extends GroovyObjectSupport implements Writable {
+
+    private Object content;
+
+    /**
+     * Instantiates a JSON builder.
+     */
+    public JsonBuilder() {
+    }
+
+    /**
+     * Instantiates a JSON builder with some existing data structure.
+     *
+     * @param content a pre-existing data structure
+     */
+    public JsonBuilder(Object content) {
+        this.content = content;
+    }
+
+    public Object getContent() {
+        return content;
+    }
+
+    /**
+     * Named arguments can be passed to the JSON builder instance to create a root JSON object
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json name: "Guillaume", age: 33
+     *
+     * assert json.toString() == '{"name":"Guillaume","age":33}'
+     * </code></pre>
+     *
+     * @param m a map of key / value pairs
+     * @return a map of key / value pairs
+     */
+    public Object call(Map m) {
+        content = m;
+
+        return content;
+    }
+
+    /**
+     * A list of elements as arguments to the JSON builder creates a root JSON array
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * def result = json([1, 2, 3])
+     *
+     * assert result instanceof List
+     * assert json.toString() == "[1,2,3]"
+     * </code></pre>
+     *
+     * @param l a list of values
+     * @return a list of values
+     */
+    public Object call(List l) {
+        content = l;
+
+        return content;
+    }
+
+    /**
+     * Varargs elements as arguments to the JSON builder create a root JSON array
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * def result = json 1, 2, 3
+     *
+     * assert result instanceof List
+     * assert json.toString() == "[1,2,3]"
+     * </code></pre>
+     *
+     * @param args an array of values
+     * @return a list of values
+     */
+    public Object call(Object... args) {
+        List<Object> listContent = new ArrayList<Object>();
+        for (Object it : args) {
+            listContent.add(it);
+        }
+        content = listContent;
+
+        return content;
+    }
+
+    /**
+     * A collection and closure passed to a JSON builder will create a root JSON array applying
+     * the closure to each object in the collection
+     * <p>
+     * Example:
+     * <pre><code>
+     * class Author {
+     *      String name
+     * }
+     * def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+     *
+     * def json = new JsonBuilder()
+     * json authors, { Author author ->
+     *      name author.name
+     * }
+     *
+     * assert json.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
+     * </code></pre>
+     * @param coll a collection
+     * @param c a closure used to convert the objects of coll
+     * @return a list of values
+     */
+    public Object call(Collection coll, Closure c) {
+        List<Object> listContent = new ArrayList<Object>();
+        if (coll != null) {
+            for (Object it : coll) {
+                listContent.add(JsonDelegate.curryDelegateAndGetContent(c, it));
+            }
+        }
+        content = listContent;
+
+        return content;
+    }
+
+    /**
+     * A closure passed to a JSON builder will create a root JSON object
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * def result = json {
+     *      name "Guillaume"
+     *      age 33
+     * }
+     *
+     * assert result instanceof Map
+     * assert json.toString() == '{"name":"Guillaume","age":33}'
+     * </code></pre>
+     *
+     * @param c a closure whose method call statements represent key / values of a JSON object
+     * @return a map of key / value pairs
+     */
+    public Object call(Closure c) {
+        content = JsonDelegate.cloneDelegateAndGetContent(c);
+
+        return content;
+    }
+
+    /**
+     * A method call on the JSON builder instance will create a root object with only one key
+     * whose name is the name of the method being called.
+     * This method takes as arguments:
+     * <ul>
+     *     <li>a closure</li>
+     *     <li>a map (ie. named arguments)</li>
+     *     <li>a map and a closure</li>
+     *     <li>or no argument at all</li>
+     * </ul>
+     * <p>
+     * Example with a classicala builder-style:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * def result = json.person {
+     *      name "Guillaume"
+     *      age 33
+     * }
+     *
+     * assert result instanceof Map
+     * assert json.toString() == '{"person":{"name":"Guillaume","age":33}}'
+     * </code></pre>
+     *
+     * Or alternatively with a method call taking named arguments:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json.person name: "Guillaume", age: 33
+     *
+     * assert json.toString() == '{"person":{"name":"Guillaume","age":33}}'
+     * </code></pre>
+     *
+     * If you use named arguments and a closure as last argument,
+     * the key/value pairs of the map (as named arguments)
+     * and the key/value pairs represented in the closure
+     * will be merged together —
+     * the closure properties overriding the map key/values
+     * in case the same key is used.
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json.person(name: "Guillaume", age: 33) { town "Paris" }
+     *
+     * assert json.toString() == '{"person":{"name":"Guillaume","age":33,"town":"Paris"}}'
+     * </code></pre>
+     *
+     * The empty args call will create a key whose value will be an empty JSON object:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json.person()
+     *
+     * assert json.toString() == '{"person":{}}'
+     * </code></pre>
+     *
+     * @param name the single key
+     * @param args the value associated with the key
+     * @return a map with a single key
+     */
+    public Object invokeMethod(String name, Object args) {
+        if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
+            Object[] arr = (Object[]) args;
+            if (arr.length == 0) {
+                return setAndGetContent(name, new HashMap<String, Object>());
+            } else if (arr.length == 1) {
+                if (arr[0] instanceof Closure) {
+                    return setAndGetContent(name, JsonDelegate.cloneDelegateAndGetContent((Closure) arr[0]));
+                } else if (arr[0] instanceof Map) {
+                    return setAndGetContent(name, arr[0]);
+                }
+            } else if (arr.length == 2) {
+                if (arr[0] instanceof Map && arr[1] instanceof Closure) {
+                    Map subMap = new LinkedHashMap();
+                    subMap.putAll((Map) arr[0]);
+                    subMap.putAll(JsonDelegate.cloneDelegateAndGetContent((Closure) arr[1]));
+
+                    return setAndGetContent(name, subMap);
+                } else if (arr[0] instanceof Collection && arr[1] instanceof Closure) {
+                    List<Map<String, Object>> list = new ArrayList<Map<String, Object>>();
+                    for (Object it : (Collection) arr[0]) {
+                        list.add(JsonDelegate.curryDelegateAndGetContent((Closure) arr[1], it));
+                    }
+
+                    return setAndGetContent(name, list);
+                }
+            }
+
+            throw new JsonException("Expected no arguments, a single map, a single closure, or a map and closure as arguments.");
+        } else {
+            return setAndGetContent(name, new HashMap<String, Object>());
+        }
+    }
+
+    private Object setAndGetContent(String name, Object value) {
+        Map<String, Object> contentMap = new LinkedHashMap<String, Object>();
+        contentMap.put(name, value);
+        content = contentMap;
+
+        return content;
+    }
+
+    /**
+     * Serializes the internal data structure built with the builder to a conformant JSON payload string
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json { temperature 37 }
+     *
+     * assert json.toString() == '{"temperature":37}'
+     * </code></pre>
+     *
+     * @return a JSON output
+     */
+    public String toString() {
+        return JsonOutput.toJson(content);
+    }
+
+    /**
+     * Pretty-prints and formats the JSON payload.
+     * <p>
+     * This method calls the JsonLexer to parser the output of the builder,
+     * so this may not be an optimal method to call,
+     * and should be used mainly for debugging purpose
+     * for a human-readable output of the JSON content.
+     *
+     * @return a pretty printed JSON output
+     */
+    public String toPrettyString() {
+        return JsonOutput.prettyPrint(toString());
+    }
+
+    /**
+     * The JSON builder implements the <code>Writable</code> interface,
+     * so that you can have the builder serialize itself the JSON payload to a writer.
+     * <p>
+     * Example:
+     * <pre><code>
+     * def json = new JsonBuilder()
+     * json { temperature 37 }
+     *
+     * def out = new StringWriter()
+     * out << json
+     *
+     * assert out.toString() == '{"temperature":37}'
+     * </code></pre>
+     *
+     * @param out a writer on which to serialize the JSON payload
+     * @return the writer
+     */
+    public Writer writeTo(Writer out) throws IOException {
+        return out.append(toString());
+    }
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonLexer.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonLexer.java
index 695bf58..72fe507 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonLexer.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonLexer.java
@@ -31,6 +31,7 @@ import java.util.regex.Pattern;
  * @since 1.8.0
  */
 public class JsonLexer implements Iterator<JsonToken> {
+
     private static final char SPACE    = ' ';
     private static final char DOT      = '.';
     private static final char MINUS    = '-';
@@ -55,7 +56,6 @@ public class JsonLexer implements Iterator<JsonToken> {
 
     private JsonToken currentToken = null;
 
-
     /**
      * Instanciates a lexer with a reader from which to read JSON tokens.
      * Under the hood, the reader is wrapped in a <code>LineColumnReader</code>,
@@ -64,7 +64,7 @@ public class JsonLexer implements Iterator<JsonToken> {
      * @param reader underlying reader
      */
     public JsonLexer(Reader reader) {
-        this.reader = reader instanceof LineColumnReader ? (LineColumnReader)reader : new LineColumnReader(reader);
+        this.reader = reader instanceof LineColumnReader ? (LineColumnReader) reader : new LineColumnReader(reader);
     }
 
     /**
@@ -186,7 +186,7 @@ public class JsonLexer implements Iterator<JsonToken> {
      */
     private JsonToken readingConstant(JsonTokenType type, JsonToken token) {
         try {
-            int numCharsToRead = ((String)type.getValidator()).length();
+            int numCharsToRead = ((String) type.getValidator()).length();
             char[] chars = new char[numCharsToRead];
             reader.read(chars);
             String stringRead = new String(chars);
@@ -211,10 +211,10 @@ public class JsonLexer implements Iterator<JsonToken> {
         try {
             int readChar = 20;
             char c = SPACE;
-            while(Character.isWhitespace(c)) {
+            while (Character.isWhitespace(c)) {
                 reader.mark(1);
                 readChar = reader.read();
-                c = (char)readChar;
+                c = (char) readChar;
             }
             reader.reset();
             return readChar;
@@ -251,5 +251,4 @@ public class JsonLexer implements Iterator<JsonToken> {
     public void remove() {
         throw new UnsupportedOperationException("The method remove() is not supported on this lexer.");
     }
-
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
index 9862048..59a15f1 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonOutput.java
@@ -25,6 +25,7 @@ import java.io.StringReader;
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.net.URL;
+import java.text.SimpleDateFormat;
 import java.util.*;
 
 /**
@@ -41,13 +42,6 @@ import java.util.*;
 public class JsonOutput {
 
     /**
-     * Date formatter for outputting dates to a string
-     * that can be parsed back from JavaScript with:
-     * <code>Date.parse(stringRepresentation)</code>
-     */
-    private static final DateFormatThreadLocal dateFormatter = new DateFormatThreadLocal();
-
-    /**
      * @return "true" or "false" for a boolean value
      */
     public static String toJson(Boolean bool) {
@@ -256,7 +250,7 @@ public class JsonOutput {
         } else {
             Class<?> objectClass = object.getClass();
 
-            if (CharSequence.class.isAssignableFrom(objectClass)) { // Handle String, StringBuilder, GString and other CharSequence implemenations
+            if (CharSequence.class.isAssignableFrom(objectClass)) { // Handle String, StringBuilder, GString and other CharSequence implementations
                 writeCharSequence((CharSequence) object, buffer);
             } else if (objectClass == Boolean.class) {
                 buffer.addBoolean((Boolean) object);
@@ -316,7 +310,9 @@ public class JsonOutput {
      * Serializes date and writes it into specified buffer.
      */
     private static void writeDate(Date date, CharBuf buffer) {
-        buffer.addQuoted(dateFormatter.get().format(date));
+        SimpleDateFormat formatter = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssZ", Locale.US);
+        formatter.setTimeZone(TimeZone.getTimeZone("GMT"));
+        buffer.addQuoted(formatter.format(date));
     }
 
     /**
@@ -538,4 +534,4 @@ public class JsonOutput {
         return indent;
     }
 
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonParser.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonParser.java
index 7662237..9746a01 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonParser.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonParser.java
@@ -29,13 +29,13 @@ import java.io.Reader;
  */
 public interface JsonParser {
 
-    Object parse(  String jsonString );
-    Object parse(  byte[] bytes );
-    Object parse(  byte[] bytes, String charset );
-    Object parse(  CharSequence charSequence );
-    Object parse(  char[] chars );
-    Object parse(  Reader reader );
-    Object parse(  InputStream input );
-    Object parse(  InputStream input, String charset );
-    Object parse(  File file, String charset);
+    Object parse(String jsonString);
+    Object parse(byte[] bytes);
+    Object parse(byte[] bytes, String charset);
+    Object parse(CharSequence charSequence);
+    Object parse(char[] chars);
+    Object parse(Reader reader);
+    Object parse(InputStream input);
+    Object parse(InputStream input, String charset);
+    Object parse(File file, String charset);
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonParserType.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonParserType.java
index 96ef3da..fd1169b 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonParserType.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonParserType.java
@@ -21,7 +21,7 @@ package groovy.json;
  * To enable the INDEX_OVERLAY parser do this:
  *
  * <code><pre>
- *             parser = new JsonSlurper().setType( JsonParserType.INDEX_OVERLAY );
+ *             parser = new JsonSlurper().setType(JsonParserType.INDEX_OVERLAY);
  * </pre></code>
  *
  * INDEX_OVERLAY should be your parser of choice.
@@ -54,7 +54,8 @@ package groovy.json;
  */
 public enum JsonParserType {
 
-    /** Fastest parser, but has pointers (indexes really) to original char buffer.
+    /**
+     * Fastest parser, but has pointers (indexes really) to original char buffer.
      * Care must be used if putting parse maps into a long term cache as members of map
      * maybe index overlay objects pointing to original buffer.
      * You can mitigate these risks by using chop and lazy chop.
@@ -66,7 +67,7 @@ public enum JsonParserType {
      * You do not need chop or lazy chop if you are not putting the map into a long term cache.
      * You do not need chop or lazy chop if you are doing object de-serialization.
      * Recommendation is to use this for JSON buffers under 2MB.
-     * */
+     */
     INDEX_OVERLAY,
     /**
      * Parser uses an abstraction that allows it to handle any size file by using a char [] windowing,
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
index 97df4c0..716da68 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurper.java
@@ -76,7 +76,7 @@ import java.util.*;
  * To enable the INDEX_OVERLAY parser do this:
  *
  * <code><pre>
- *             parser = new JsonSlurper().setType( JsonParserType.INDEX_OVERLAY );
+ *             parser = new JsonSlurper().setType(JsonParserType.INDEX_OVERLAY);
  * </pre></code>
  *
  * @see groovy.json.JsonParserType
@@ -87,7 +87,6 @@ import java.util.*;
  */
 public class JsonSlurper {
 
-
     private int maxSizeForInMemory = 2000000;
     private boolean chop = false;
     private boolean lazyChop = true;
@@ -104,13 +103,12 @@ public class JsonSlurper {
         return maxSizeForInMemory;
     }
 
-
     /**
      * Max size before Slurper starts to use windowing buffer parser.
      * @since 2.3
      * @return JsonSlurper
      */
-    public JsonSlurper setMaxSizeForInMemory( int maxSizeForInMemory ) {
+    public JsonSlurper setMaxSizeForInMemory(int maxSizeForInMemory) {
         this.maxSizeForInMemory = maxSizeForInMemory;
         return this;
     }
@@ -124,13 +122,12 @@ public class JsonSlurper {
         return type;
     }
 
-
     /** Parser type.
      * @since 2.3
      * @see groovy.json.JsonParserType
      * @return  JsonSlurper
      */
-    public JsonSlurper setType( JsonParserType type ) {
+    public JsonSlurper setType(JsonParserType type) {
         this.type = type;
         return this;
     }
@@ -149,12 +146,11 @@ public class JsonSlurper {
      * @see groovy.json.JsonParserType
      * @return  JsonSlurper
      */
-    public JsonSlurper setChop( boolean chop ) {
+    public JsonSlurper setChop(boolean chop) {
         this.chop = chop;
         return this;
     }
 
-
     /** Turns on buffer lazy chopping for index overlay.
      * @see groovy.json.JsonParserType
      * @return  on or off
@@ -164,13 +160,12 @@ public class JsonSlurper {
         return lazyChop;
     }
 
-
     /** Turns on buffer lazy chopping for index overlay.
      * @see groovy.json.JsonParserType
      * @return  JsonSlurper
      * @since 2.3
      */
-    public JsonSlurper setLazyChop( boolean lazyChop ) {
+    public JsonSlurper setLazyChop(boolean lazyChop) {
         this.lazyChop = lazyChop;
         return this;
     }
@@ -184,13 +179,12 @@ public class JsonSlurper {
         return checkDates;
     }
 
-
     /**
      * Determine if slurper will automatically parse strings it recognizes as dates. Index overlay only.
      * @return on or off
      * @since 2.3
      */
-    public JsonSlurper setCheckDates( boolean checkDates ) {
+    public JsonSlurper setCheckDates(boolean checkDates) {
         this.checkDates = checkDates;
         return this;
     }
@@ -202,10 +196,10 @@ public class JsonSlurper {
      * @return a data structure of lists and maps
      */
     public Object parseText(String text) {
-        if (text == null || "".equals ( text )) {
-            throw new IllegalArgumentException ( "Text must not be null"  );
+        if (text == null || "".equals(text)) {
+            throw new IllegalArgumentException("Text must not be null");
         }
-        return createParser().parse( text );
+        return createParser().parse(text);
     }
 
     /**
@@ -215,8 +209,8 @@ public class JsonSlurper {
      * @return a data structure of lists and maps
      */
     public Object parse(Reader reader) {
-        if (reader == null ) {
-            throw new IllegalArgumentException ( "Reader must not be null"  );
+        if (reader == null) {
+            throw new IllegalArgumentException("Reader must not be null");
         }
 
         Object content;
@@ -225,8 +219,6 @@ public class JsonSlurper {
         return content;
     }
 
-
-
     /**
      * Parse a JSON data structure from content from an inputStream
      *
@@ -235,13 +227,13 @@ public class JsonSlurper {
      * @since 2.3
      */
     public Object parse(InputStream inputStream) {
-        if (inputStream == null ) {
-            throw new IllegalArgumentException ( "inputStream must not be null"  );
+        if (inputStream == null) {
+            throw new IllegalArgumentException("inputStream must not be null");
         }
 
         Object content;
         JsonParser parser = createParser();
-        content = parser.parse( inputStream );
+        content = parser.parse(inputStream);
         return content;
     }
 
@@ -254,11 +246,11 @@ public class JsonSlurper {
      * @since 2.3
      */
     public Object parse(InputStream inputStream, String charset) {
-        if (inputStream == null ) {
-            throw new IllegalArgumentException ( "inputStream must not be null"  );
+        if (inputStream == null) {
+            throw new IllegalArgumentException("inputStream must not be null");
         }
-        if ( charset == null ) {
-            throw new IllegalArgumentException ( "charset must not be null"  );
+        if (charset == null) {
+            throw new IllegalArgumentException("charset must not be null");
         }
 
         Object content;
@@ -266,7 +258,6 @@ public class JsonSlurper {
         return content;
     }
 
-
     /**
      * Parse a JSON data structure from content from a byte array.
      *
@@ -276,21 +267,19 @@ public class JsonSlurper {
      * @since 2.3
      */
     public Object parse(byte [] bytes, String charset) {
-        if ( bytes == null ) {
-            throw new IllegalArgumentException ( "bytes must not be null"  );
+        if (bytes == null) {
+            throw new IllegalArgumentException("bytes must not be null");
         }
 
-        if ( charset == null ) {
-            throw new IllegalArgumentException ( "charset must not be null"  );
+        if (charset == null) {
+            throw new IllegalArgumentException("charset must not be null");
         }
 
-
         Object content;
         content = createParser().parse(bytes, charset);
         return content;
     }
 
-
     /**
      * Parse a JSON data structure from content from a byte array.
      *
@@ -299,8 +288,8 @@ public class JsonSlurper {
      * @since 2.3
      */
     public Object parse(byte [] bytes) {
-        if ( bytes == null ) {
-            throw new IllegalArgumentException ( "bytes must not be null"  );
+        if (bytes == null) {
+            throw new IllegalArgumentException("bytes must not be null");
         }
 
         Object content;
@@ -316,8 +305,8 @@ public class JsonSlurper {
      * @since 2.3
      */
     public Object parse(char [] chars) {
-        if ( chars == null ) {
-            throw new IllegalArgumentException ( "chars must not be null"  );
+        if (chars == null) {
+            throw new IllegalArgumentException("chars must not be null");
         }
 
         Object content;
@@ -325,10 +314,8 @@ public class JsonSlurper {
         return content;
     }
 
-
     private JsonParser createParser() {
         switch (type) {
-
             case LAX:
                 return new JsonParserLax(false, chop, lazyChop, checkDates);
 
@@ -371,11 +358,10 @@ public class JsonSlurper {
     }
 
     private Object parseFile(File file, String charset) {
-
-        if (file.length() < maxSizeForInMemory)  {
+        if (file.length() < maxSizeForInMemory) {
             return createParser().parse(file, charset);
         } else {
-            return new JsonParserUsingCharacterSource().parse ( file, charset );
+            return new JsonParserUsingCharacterSource().parse(file, charset);
         }
     }
 
@@ -422,8 +408,8 @@ public class JsonSlurper {
             } else {
                 reader = ResourceGroovyMethods.newReader(url, params);
             }
-            return createParser ().parse ( reader );
-        } catch(IOException ioe) {
+            return createParser().parse(reader);
+        } catch (IOException ioe) {
             throw new JsonException("Unable to process url: " + url.toString(), ioe);
         } finally {
             if (reader != null) {
@@ -479,7 +465,7 @@ public class JsonSlurper {
                 reader = ResourceGroovyMethods.newReader(url, params, charset);
             }
             return parse(reader);
-        } catch(IOException ioe) {
+        } catch (IOException ioe) {
             throw new JsonException("Unable to process url: " + url.toString(), ioe);
         } finally {
             if (reader != null) {
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurperClassic.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurperClassic.java
index 2dff8f4..7c7ccd7 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurperClassic.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonSlurperClassic.java
@@ -72,7 +72,7 @@ public class JsonSlurperClassic {
             throw new IllegalArgumentException("The JSON input text should neither be null nor empty.");
         }
 
-        return parse(new LineColumnReader (new StringReader (text)));
+        return parse(new LineColumnReader(new StringReader(text)));
     }
 
     /**
@@ -131,16 +131,16 @@ public class JsonSlurperClassic {
         Reader reader = null;
         try {
             if (charset == null || charset.length() == 0) {
-                reader = ResourceGroovyMethods.newReader ( file );
+                reader = ResourceGroovyMethods.newReader(file);
             } else {
                 reader = ResourceGroovyMethods.newReader(file, charset);
             }
             return parse(reader);
-        } catch(IOException ioe) {
+        } catch (IOException ioe) {
             throw new JsonException("Unable to process file: " + file.getPath(), ioe);
         } finally {
             if (reader != null) {
-                DefaultGroovyMethodsSupport.closeWithWarning ( reader );
+                DefaultGroovyMethodsSupport.closeWithWarning(reader);
             }
         }
     }
@@ -189,7 +189,7 @@ public class JsonSlurperClassic {
                 reader = ResourceGroovyMethods.newReader(url, params);
             }
             return parse(reader);
-        } catch(IOException ioe) {
+        } catch (IOException ioe) {
             throw new JsonException("Unable to process url: " + url.toString(), ioe);
         } finally {
             if (reader != null) {
@@ -245,7 +245,7 @@ public class JsonSlurperClassic {
                 reader = ResourceGroovyMethods.newReader(url, params, charset);
             }
             return parse(reader);
-        } catch(IOException ioe) {
+        } catch (IOException ioe) {
             throw new JsonException("Unable to process url: " + url.toString(), ioe);
         } finally {
             if (reader != null) {
@@ -261,7 +261,7 @@ public class JsonSlurperClassic {
      * @return a list of JSON values
      */
     private List parseArray(JsonLexer lexer) {
-        List content = new ArrayList ();
+        List content = new ArrayList();
 
         JsonToken currentToken;
 
@@ -329,7 +329,7 @@ public class JsonSlurperClassic {
      * @return a Map representing a JSON object
      */
     private Map parseObject(JsonLexer lexer) {
-        Map content = new HashMap ();
+        Map content = new HashMap();
 
         JsonToken previousToken = null;
         JsonToken currentToken = null;
@@ -378,7 +378,7 @@ public class JsonSlurperClassic {
                         "Expected " + COLON.getLabel() + " " +
                                 "on line: " + currentToken.getStartLine() + ", " +
                                 "column: " + currentToken.getStartColumn() + ".\n" +
-                                "But got '" + currentToken.getText() +  "' instead."
+                                "But got '" + currentToken.getText() + "' instead."
                 );
             }
 
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonToken.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonToken.java
index 5be65fc..ff20bec 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonToken.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonToken.java
@@ -27,6 +27,7 @@ import static groovy.json.JsonTokenType.*;
  * @since 1.8.0
  */
 public class JsonToken {
+
     private static final BigInteger MAX_LONG    = BigInteger.valueOf(Long.MAX_VALUE);
     private static final BigInteger MIN_LONG    = BigInteger.valueOf(Long.MIN_VALUE);
     private static final BigInteger MAX_INTEGER = BigInteger.valueOf(Integer.MAX_VALUE);
@@ -72,9 +73,9 @@ public class JsonToken {
             } else {
                 // an integer number
                 BigInteger v = new BigInteger(text);
-                if(v.compareTo(MAX_INTEGER) <= 0 && v.compareTo(MIN_INTEGER) >= 0 ) {
+                if (v.compareTo(MAX_INTEGER) <= 0 && v.compareTo(MIN_INTEGER) >= 0) {
                     return v.intValue();
-                } else if (v.compareTo(MAX_LONG) <= 0 && v.compareTo(MIN_LONG) >= 0 ) {
+                } else if (v.compareTo(MAX_LONG) <= 0 && v.compareTo(MIN_LONG) >= 0) {
                     return v.longValue();
                 } else {
                     return v;
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/JsonTokenType.java b/subprojects/groovy-json/src/main/java/groovy/json/JsonTokenType.java
index 01f31b2..6d9faad 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/JsonTokenType.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/JsonTokenType.java
@@ -88,10 +88,10 @@ public enum JsonTokenType {
      */
     public boolean matching(String input) {
         if (validator instanceof Pattern) {
-            Matcher matcher = ((Pattern)validator).matcher(input);
+            Matcher matcher = ((Pattern) validator).matcher(input);
             return matcher.matches();
         } else if (validator instanceof Closure) {
-            return (Boolean)((Closure) validator).call(input);
+            return (Boolean) ((Closure) validator).call(input);
         } else if (validator instanceof String) {
             return input.equals(validator);
         } else {
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java b/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
new file mode 100644
index 0000000..086e428
--- /dev/null
+++ b/subprojects/groovy-json/src/main/java/groovy/json/StreamingJsonBuilder.java
@@ -0,0 +1,421 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.json;
+
+import groovy.lang.Closure;
+import groovy.lang.GroovyObjectSupport;
+
+import java.io.IOException;
+import java.io.Writer;
+import java.util.*;
+
+/**
+ * A builder for creating JSON payloads.
+ * <p>
+ * This builder supports the usual builder syntax made of nested method calls and closures,
+ * but also some specific aspects of JSON data structures, such as list of values, etc.
+ * Please make sure to have a look at the various methods provided by this builder
+ * to be able to learn about the various possibilities of usage.
+ * <p>
+ * Unlike the JsonBuilder class which creates a data structure in memory,
+ * which is handy in those situations where you want to alter the structure programatically before output,
+ * the StreamingJsonBuilder streams to a writer directly without any memory data structure.
+ * So if you don't need to modify the structure, and want a more memory-efficient approach,
+ * please use the StreamingJsonBuilder.
+ * <p>
+ * Example:
+ * <pre class="groovyTestCase">
+ *     new StringWriter().with { w ->
+ *         def builder = new groovy.json.StreamingJsonBuilder(w)
+ *         builder.people {
+ *             person {
+ *                 firstName 'Tim'
+ *                 lastName 'Yates'
+ *                 // Named arguments are valid values for objects too
+ *                 address(
+ *                     city: 'Manchester',
+ *                     country: 'UK',
+ *                     zip: 'M1 2AB',
+ *                 )
+ *                 living true
+ *                 eyes 'left', 'right'
+ *             }
+ *         }
+ *
+ *         assert w.toString() == '{"people":{"person":{"firstName":"Tim","lastName":"Yates","address":{"city":"Manchester","country":"UK","zip":"M1 2AB"},"living":true,"eyes":["left","right"]}}}'
+ *    }
+ * </pre>
+ *
+ * @author Tim Yates
+ * @author Andrey Bloschetsov
+ * @since 1.8.1
+ */
+public class StreamingJsonBuilder extends GroovyObjectSupport {
+
+    private Writer writer;
+
+    /**
+     * Instantiates a JSON builder.
+     *
+     * @param writer A writer to which Json will be written
+     */
+    public StreamingJsonBuilder(Writer writer) {
+        this.writer = writer;
+    }
+
+    /**
+     * Instantiates a JSON builder, possibly with some existing data structure.
+     *
+     * @param writer  A writer to which Json will be written
+     * @param content a pre-existing data structure, default to null
+     */
+    public StreamingJsonBuilder(Writer writer, Object content) throws IOException {
+        this(writer);
+        if (content != null) {
+            writer.write(JsonOutput.toJson(content));
+        }
+    }
+
+    /**
+     * Named arguments can be passed to the JSON builder instance to create a root JSON object
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *   def json = new groovy.json.StreamingJsonBuilder(w)
+     *   json name: "Tim", age: 31
+     *
+     *   assert w.toString() == '{"name":"Tim","age":31}'
+     * }
+     * </pre>
+     *
+     * @param m a map of key / value pairs
+     * @return a map of key / value pairs
+     */
+    public Object call(Map m) throws IOException {
+        writer.write(JsonOutput.toJson(m));
+
+        return m;
+    }
+
+    /**
+     * A list of elements as arguments to the JSON builder creates a root JSON array
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *   def json = new groovy.json.StreamingJsonBuilder(w)
+     *   def result = json([1, 2, 3])
+     *
+     *   assert result == [ 1, 2, 3 ]
+     *   assert w.toString() == "[1,2,3]"
+     * }
+     * </pre>
+     *
+     * @param l a list of values
+     * @return a list of values
+     */
+    public Object call(List l) throws IOException {
+        writer.write(JsonOutput.toJson(l));
+
+        return l;
+    }
+
+    /**
+     * Varargs elements as arguments to the JSON builder create a root JSON array
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *   def json = new groovy.json.StreamingJsonBuilder(w)
+     *   def result = json 1, 2, 3
+     *
+     *   assert result instanceof List
+     *   assert w.toString() == "[1,2,3]"
+     * }
+     * </pre>
+
+     * @param args an array of values
+     * @return a list of values
+     */
+    public Object call(Object... args) throws IOException {
+        return call(Arrays.asList(args));
+    }
+
+    /**
+     * A collection and closure passed to a JSON builder will create a root JSON array applying
+     * the closure to each object in the collection
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * class Author {
+     *      String name
+     * }
+     * def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+     *
+     * new StringWriter().with { w ->
+     *     def json = new groovy.json.StreamingJsonBuilder(w)
+     *     json authors, { Author author ->
+     *         name author.name
+     *     }
+     *
+     *     assert w.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
+     * }
+     * </pre>
+     * @param coll a collection
+     * @param c a closure used to convert the objects of coll
+     */
+    public Object call(Collection coll, Closure c) throws IOException {
+        StreamingJsonDelegate.writeCollectionWithClosure(writer, coll, c);
+
+        return null;
+    }
+
+    /**
+     * A closure passed to a JSON builder will create a root JSON object
+     * <p>
+     * Example:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *   def json = new groovy.json.StreamingJsonBuilder(w)
+     *   json {
+     *      name "Tim"
+     *      age 39
+     *   }
+     *
+     *   assert w.toString() == '{"name":"Tim","age":39}'
+     * }
+     * </pre>
+     *
+     * @param c a closure whose method call statements represent key / values of a JSON object
+     */
+    public Object call(Closure c) throws IOException {
+        writer.write("{");
+        StreamingJsonDelegate.cloneDelegateAndGetContent(writer, c);
+        writer.write("}");
+
+        return null;
+    }
+
+    /**
+     * A method call on the JSON builder instance will create a root object with only one key
+     * whose name is the name of the method being called.
+     * This method takes as arguments:
+     * <ul>
+     *     <li>a closure</li>
+     *     <li>a map (ie. named arguments)</li>
+     *     <li>a map and a closure</li>
+     *     <li>or no argument at all</li>
+     * </ul>
+     * <p>
+     * Example with a classicala builder-style:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *     def json = new groovy.json.StreamingJsonBuilder(w)
+     *     json.person {
+     *         name "Tim"
+     *          age 28
+     *     }
+     *
+     *     assert w.toString() == '{"person":{"name":"Tim","age":28}}'
+     * }
+     * </pre>
+     *
+     * Or alternatively with a method call taking named arguments:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *     def json = new groovy.json.StreamingJsonBuilder(w)
+     *     json.person name: "Tim", age: 32
+     *
+     *     assert w.toString() == '{"person":{"name":"Tim","age":32}}'
+     * }
+     * </pre>
+     *
+     * If you use named arguments and a closure as last argument,
+     * the key/value pairs of the map (as named arguments)
+     * and the key/value pairs represented in the closure
+     * will be merged together —
+     * the closure properties overriding the map key/values
+     * in case the same key is used.
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *     def json = new groovy.json.StreamingJsonBuilder(w)
+     *     json.person(name: "Tim", age: 35) { town "Manchester" }
+     *
+     *     assert w.toString() == '{"person":{"name":"Tim","age":35,"town":"Manchester"}}'
+     * }
+     * </pre>
+     *
+     * The empty args call will create a key whose value will be an empty JSON object:
+     * <pre class="groovyTestCase">
+     * new StringWriter().with { w ->
+     *     def json = new groovy.json.StreamingJsonBuilder(w)
+     *     json.person()
+     *
+     *     assert w.toString() == '{"person":{}}'
+     * }
+     * </pre>
+     *
+     * @param name the single key
+     * @param args the value associated with the key
+     */
+    public Object invokeMethod(String name, Object args) {
+        boolean notExpectedArgs = false;
+        if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
+            Object[] arr = (Object[]) args;
+            try {
+                if (arr.length == 0) {
+                    writer.write(JsonOutput.toJson(Collections.singletonMap(name, Collections.emptyMap())));
+                } else if (arr.length == 1) {
+                    if (arr[0] instanceof Closure) {
+                        writer.write("{");
+                        writer.write(JsonOutput.toJson(name));
+                        writer.write(":");
+                        call((Closure) arr[0]);
+                        writer.write("}");
+                    } else if (arr[0] instanceof Map) {
+                        writer.write(JsonOutput.toJson(Collections.singletonMap(name, (Map) arr[0])));
+                    } else {
+                        notExpectedArgs = true;
+                    }
+                } else if (arr.length == 2 && arr[0] instanceof Map && arr[1] instanceof Closure) {
+                    writer.write("{");
+                    writer.write(JsonOutput.toJson(name));
+                    writer.write(":{");
+                    boolean first = true;
+                    Map map = (Map) arr[0];
+                    for (Object it : map.entrySet()) {
+                        if (!first) {
+                            writer.write(",");
+                        } else {
+                            first = false;
+                        }
+
+                        Map.Entry entry = (Map.Entry) it;
+                        writer.write(JsonOutput.toJson(entry.getKey()));
+                        writer.write(":");
+                        writer.write(JsonOutput.toJson(entry.getValue()));
+                    }
+                    StreamingJsonDelegate.cloneDelegateAndGetContent(writer, (Closure) arr[1], map.size() == 0);
+                    writer.write("}}");
+                } else if (StreamingJsonDelegate.isCollectionWithClosure(arr)) {
+                    writer.write("{");
+                    writer.write(JsonOutput.toJson(name));
+                    writer.write(":");
+                    call((Collection) arr[0], (Closure) arr[1]);
+                    writer.write("}");
+                } else {
+                    notExpectedArgs = true;
+                }
+            } catch (IOException ioe) {
+                throw new JsonException(ioe);
+            }
+        } else {
+            notExpectedArgs = true;
+        }
+
+        if (!notExpectedArgs) {
+            return this;
+        } else {
+            throw new JsonException("Expected no arguments, a single map, a single closure, or a map and closure as arguments.");
+        }
+    }
+}
+
+class StreamingJsonDelegate extends GroovyObjectSupport {
+
+    private Writer writer;
+    private boolean first;
+
+    public StreamingJsonDelegate(Writer w, boolean first) {
+        this.writer = w;
+        this.first = first;
+    }
+
+    public Object invokeMethod(String name, Object args) {
+        if (args != null && Object[].class.isAssignableFrom(args.getClass())) {
+            try {
+                if (!first) {
+                    writer.write(",");
+                } else {
+                    first = false;
+                }
+                writer.write(JsonOutput.toJson(name));
+                writer.write(":");
+                Object[] arr = (Object[]) args;
+
+                if (arr.length == 1) {
+                    writer.write(JsonOutput.toJson(arr[0]));
+                } else if (isCollectionWithClosure(arr)) {
+                    writeCollectionWithClosure(writer, (Collection) arr[0], (Closure) arr[1]);
+                } else {
+                    writer.write(JsonOutput.toJson(Arrays.asList(arr)));
+                }
+            } catch (IOException ioe) {
+                throw new JsonException(ioe);
+            }
+        }
+
+        return this;
+    }
+
+    public static boolean isCollectionWithClosure(Object[] args) {
+        return args.length == 2 && args[0] instanceof Collection && args[1] instanceof Closure;
+    }
+
+    public static Object writeCollectionWithClosure(Writer writer, Collection coll, Closure closure) throws IOException {
+        writer.write("[");
+        boolean first = true;
+        for (Object it : coll) {
+            if (!first) {
+                writer.write(",");
+            } else {
+                first = false;
+            }
+
+            writer.write("{");
+            curryDelegateAndGetContent(writer, closure, it);
+            writer.write("}");
+        }
+        writer.write("]");
+
+        return writer;
+    }
+
+    public static void cloneDelegateAndGetContent(Writer w, Closure c) {
+        cloneDelegateAndGetContent(w, c, true);
+    }
+
+    public static void cloneDelegateAndGetContent(Writer w, Closure c, boolean first) {
+        StreamingJsonDelegate delegate = new StreamingJsonDelegate(w, first);
+        Closure cloned = (Closure) c.clone();
+        cloned.setDelegate(delegate);
+        cloned.setResolveStrategy(Closure.DELEGATE_FIRST);
+        cloned.call();
+    }
+
+    public static void curryDelegateAndGetContent(Writer w, Closure c, Object o) {
+        curryDelegateAndGetContent(w, c, o, true);
+    }
+
+    public static void curryDelegateAndGetContent(Writer w, Closure c, Object o, boolean first) {
+        StreamingJsonDelegate delegate = new StreamingJsonDelegate(w, first);
+        Closure curried = c.curry(o);
+        curried.setDelegate(delegate);
+        curried.setResolveStrategy(Closure.DELEGATE_FIRST);
+        curried.call();
+    }
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/StringEscapeUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/StringEscapeUtils.java
index bef1b33..167d6ca 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/StringEscapeUtils.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/StringEscapeUtils.java
@@ -54,7 +54,7 @@ public class StringEscapeUtils {
      * instance to operate.
      */
     public StringEscapeUtils() {
-      super();
+        super();
     }
 
     // Java and JavaScript
@@ -191,27 +191,27 @@ public class StringEscapeUtils {
                 out.write("\\u00" + hex(ch));
             } else if (ch < 32) {
                 switch (ch) {
-                    case '\b' :
+                    case '\b':
                         out.write('\\');
                         out.write('b');
                         break;
-                    case '\n' :
+                    case '\n':
                         out.write('\\');
                         out.write('n');
                         break;
-                    case '\t' :
+                    case '\t':
                         out.write('\\');
                         out.write('t');
                         break;
-                    case '\f' :
+                    case '\f':
                         out.write('\\');
                         out.write('f');
                         break;
-                    case '\r' :
+                    case '\r':
                         out.write('\\');
                         out.write('r');
                         break;
-                    default :
+                    default:
                         if (ch > 0xf) {
                             out.write("\\u00" + hex(ch));
                         } else {
@@ -221,27 +221,27 @@ public class StringEscapeUtils {
                 }
             } else {
                 switch (ch) {
-                    case '\'' :
+                    case '\'':
                         if (escapeSingleQuote) {
                             out.write('\\');
                         }
                         out.write('\'');
                         break;
-                    case '"' :
+                    case '"':
                         out.write('\\');
                         out.write('"');
                         break;
-                    case '\\' :
+                    case '\\':
                         out.write('\\');
                         out.write('\\');
                         break;
-                    case '/' :
+                    case '/':
                         if (escapeForwardSlash) {
                             out.write('\\');
                         }
                         out.write('/');
                         break;
-                    default :
+                    default:
                         out.write(ch);
                         break;
                 }
@@ -252,7 +252,7 @@ public class StringEscapeUtils {
     /**
      * Returns an upper case hexadecimal <code>String</code> for the given
      * character.
-     * 
+     *
      * @param ch The character to convert.
      * @return An upper case hexadecimal <code>String</code>
      */
@@ -416,6 +416,4 @@ public class StringEscapeUtils {
     public static void unescapeJavaScript(Writer out, String str) throws IOException {
         unescapeJava(out, str);
     }
-
-
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
index b1359c6..18ee030 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/BaseJsonParser.java
@@ -108,7 +108,11 @@ public abstract class BaseJsonParser implements JsonParser {
     }
 
     public Object parse(byte[] bytes, String charset) {
-        return parse(bytes, charset);
+        try {
+            return parse(new String(bytes, charset));
+        } catch (UnsupportedEncodingException e) {
+            return Exceptions.handle(Object.class, e);
+        }
     }
 
     public Object parse(CharSequence charSequence) {
@@ -116,10 +120,8 @@ public abstract class BaseJsonParser implements JsonParser {
     }
 
     public Object parse(Reader reader) {
-
         fileInputBuf = IO.read(reader, fileInputBuf, bufSize);
         return parse(fileInputBuf.readForRecycle());
-
     }
 
     public Object parse(InputStream input) {
@@ -137,7 +139,6 @@ public abstract class BaseJsonParser implements JsonParser {
     private final CharBuf builder = CharBuf.create(20);
 
     public Object parse(File file, String charset) {
-
         Reader reader = null;
         try {
             if (charset == null || charset.length() == 0) {
@@ -153,7 +154,6 @@ public abstract class BaseJsonParser implements JsonParser {
                 DefaultGroovyMethodsSupport.closeWithWarning(reader);
             }
         }
-
     }
 
     protected static boolean isDecimalChar(int currentChar) {
@@ -166,11 +166,9 @@ public abstract class BaseJsonParser implements JsonParser {
                 return true;
         }
         return false;
-
     }
 
     protected static boolean isDelimiter(int c) {
-
         return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
     }
 
@@ -197,7 +195,6 @@ public abstract class BaseJsonParser implements JsonParser {
                 indexHolder[0] = index;
                 return true;
             }
-
         }
 
         indexHolder[0] = index;
@@ -229,5 +226,4 @@ public abstract class BaseJsonParser implements JsonParser {
         }
         return index;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
index ae4712f..13c62e7 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ByteScanner.java
@@ -31,7 +31,6 @@ public class ByteScanner {
      * @return the encoded nibble (1/2 byte).
      */
     protected static int encodeNibbleToHexAsciiCharByte(final int nibble) {
-
         switch (nibble) {
             case 0x00:
             case 0x01:
@@ -64,9 +63,7 @@ public class ByteScanner {
      * @param encoded the array to which each encoded nibbles are now ascii hex representations.
      */
     public static void encodeByteIntoTwoAsciiCharBytes(final int decoded, final byte[] encoded) {
-
         encoded[0] = (byte) encodeNibbleToHexAsciiCharByte((decoded >> 4) & 0x0F);
         encoded[1] = (byte) encodeNibbleToHexAsciiCharByte(decoded & 0x0F);
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
index 512fc6e..967eb33 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/Cache.java
@@ -25,6 +25,7 @@ package groovy.json.internal;
  * @author Rick Hightower
  */
 public interface Cache<KEY, VALUE> {
+
     void put(KEY key, VALUE value);
 
     VALUE get(KEY key);
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
index 2b9c78b..c95a7f4 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharBuf.java
@@ -29,6 +29,7 @@ import java.math.BigInteger;
  * @author Rick Hightower
  */
 public class CharBuf extends Writer implements CharSequence {
+
     protected int capacity = 16;
     protected int location = 0;
 
@@ -81,14 +82,12 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public void write(char[] cbuf, int off, int len) {
-
         if (off == 0 && cbuf.length == len) {
             this.add(cbuf);
         } else {
             char[] buffer = ArrayUtils.copyRange(cbuf, off, off + len);
             this.add(buffer);
         }
-
     }
 
     public void flush() throws IOException {
@@ -112,7 +111,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf add(int i) {
-
         add(Integer.toString(i));
         return this;
     }
@@ -138,7 +136,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addInt(Integer key) {
-
         if (icache == null) {
             icache = new SimpleCache<Integer, char[]>(20, CacheType.LRU);
         }
@@ -163,31 +160,26 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addBoolean(boolean b) {
-
         add(Boolean.toString(b));
         return this;
     }
 
     public final CharBuf add(byte i) {
-
         add(Byte.toString(i));
         return this;
     }
 
     public final CharBuf addByte(byte i) {
-
         addInt(i);
         return this;
     }
 
     public final CharBuf add(short i) {
-
         add(Short.toString(i));
         return this;
     }
 
     public final CharBuf addShort(short i) {
-
         addInt(i);
         return this;
     }
@@ -210,7 +202,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addDouble(Double key) {
-
         if (dcache == null) {
             dcache = new SimpleCache<Double, char[]>(20, CacheType.LRU);
         }
@@ -239,7 +230,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addFloat(Float key) {
-
         if (fcache == null) {
             fcache = new SimpleCache<Float, char[]>(20, CacheType.LRU);
         }
@@ -272,7 +262,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addChar(final char ch) {
-
         int _location = location;
         char[] _buffer = buffer;
         int _capacity = capacity;
@@ -280,7 +269,6 @@ public class CharBuf extends Writer implements CharSequence {
         if (1 + _location > _capacity) {
             _buffer = Chr.grow(_buffer);
             _capacity = _buffer.length;
-
         }
 
         _buffer[_location] = ch;
@@ -327,7 +315,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public final CharBuf addQuoted(char[] chars) {
-
         int _location = location;
         char[] _buffer = buffer;
         int _capacity = capacity;
@@ -355,7 +342,6 @@ public class CharBuf extends Writer implements CharSequence {
     public final CharBuf addJsonEscapedString(String jsonString) {
         char[] charArray = FastStringUtils.toCharArray(jsonString);
         return addJsonEscapedString(charArray);
-
     }
 
     private static boolean hasAnyJSONControlOrUnicodeChars(int c) {
@@ -375,7 +361,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     private static boolean hasAnyJSONControlChars(final char[] charArray) {
-
         int index = 0;
         char c;
         while (true) {
@@ -385,7 +370,6 @@ public class CharBuf extends Writer implements CharSequence {
             }
             if (++index >= charArray.length) return false;
         }
-
     }
 
     public final CharBuf addJsonEscapedString(final char[] charArray) {
@@ -402,7 +386,6 @@ public class CharBuf extends Writer implements CharSequence {
     final byte[] charTo = new byte[2];
 
     private final CharBuf doAddJsonEscapedString(char[] charArray) {
-
         char[] _buffer = buffer;
         int _location = this.location;
 
@@ -414,7 +397,6 @@ public class CharBuf extends Writer implements CharSequence {
 
         int sizeNeeded = (ensureThisMuch) + _location;
         if (sizeNeeded > capacity) {
-
             int growBy = (_buffer.length * 2) < sizeNeeded ? sizeNeeded : (_buffer.length * 2);
             _buffer = Chr.grow(buffer, growBy);
             capacity = _buffer.length;
@@ -425,11 +407,9 @@ public class CharBuf extends Writer implements CharSequence {
 
         int index = 0;
         while (true) {
-
             char c = charArray[index];
 
             if (hasAnyJSONControlOrUnicodeChars(c)) {
-
                    /* We are covering our bet with a safety net.
                       otherwise we would have to have 5x buffer
                       allocated for control chars */
@@ -482,14 +462,12 @@ public class CharBuf extends Writer implements CharSequence {
                         _buffer[_location] = 'r';
                         _location++;
                         break;
-
                     case '\t':
                         _buffer[_location] = '\\';
                         _location++;
                         _buffer[_location] = 't';
                         _location++;
                         break;
-
                     default:
                         _buffer[_location] = '\\';
                         _location++;
@@ -504,7 +482,6 @@ public class CharBuf extends Writer implements CharSequence {
                             for (int b : _encoded) {
                                 _buffer[_location] = (char) b;
                                 _location++;
-
                             }
                         } else {
                             Byt.charTo(_charTo, c);
@@ -516,19 +493,14 @@ public class CharBuf extends Writer implements CharSequence {
                                     _location++;
                                 }
                             }
-
                         }
-
                 }
             } else {
-
                 _buffer[_location] = c;
                 _location++;
-
             }
 
             if (++index >= charArray.length) break;
-
         }
         _buffer[_location] = '"';
         _location++;
@@ -543,36 +515,16 @@ public class CharBuf extends Writer implements CharSequence {
         return addJsonFieldName(FastStringUtils.toCharArray(str));
     }
 
-    public final CharBuf addJsonFieldName(char[] chars) {
-        int _location = location;
-        char[] _buffer = buffer;
-        int _capacity = capacity;
-
-        try {
-
-            int sizeNeeded = chars.length + 3 + _location;
-            if (sizeNeeded > _capacity) {
-                _buffer = Chr.grow(_buffer, sizeNeeded * 2);
-                _capacity = _buffer.length;
-            }
-            _buffer[_location] = '"';
-            _location++;
-
-            arraycopy(chars, 0, _buffer, _location, chars.length);
-
-            _location += (chars.length);
-            _buffer[_location] = '"';
-            _location++;
-            _buffer[_location] = ':';
-            _location++;
+    private static final char[] EMPTY_STRING_CHARS = Chr.array('"', '"');
 
-            location = _location;
-            buffer = _buffer;
-            capacity = _capacity;
-            return this;
-        } catch (Exception ex) {
-            return Exceptions.handle(CharBuf.class, Exceptions.sputs(toDebugString(), new String(chars), "_location", _location), ex);
+    public final CharBuf addJsonFieldName(char[] chars) {
+        if (chars.length > 0) {
+            addJsonEscapedString(chars);
+        } else {
+            addChars(EMPTY_STRING_CHARS);
         }
+        addChar(':');
+        return this;
     }
 
     public final CharBuf addQuoted(String str) {
@@ -607,13 +559,10 @@ public class CharBuf extends Writer implements CharSequence {
 
     private static final void sysstemarraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
         System.arraycopy(src, srcPos, dest, destPos, length);
-
     }
 
     private static final void arraycopy(final char[] src, final int srcPos, final char[] dest, final int destPos, final int length) {
-
         sysstemarraycopy(src, srcPos, dest, destPos, length);
-
     }
 
     public CharBuf add(byte[] bytes, int start, int end) {
@@ -663,7 +612,6 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public String toStringAndRecycle() {
-
         String str = new String(buffer, 0, location);
         location = 0;
         return str;
@@ -715,13 +663,11 @@ public class CharBuf extends Writer implements CharSequence {
     }
 
     public Number toIntegerWrapper() {
-
         if (CharScanner.isInteger(buffer, 0, location)) {
             return intValue();
         } else {
             return longValue();
         }
-
     }
 
     static final char[] nullChars = "null".toCharArray();
@@ -751,7 +697,6 @@ public class CharBuf extends Writer implements CharSequence {
         add(chars);
 
         return this;
-
     }
 
     private Cache<BigInteger, char[]> bigICache;
@@ -771,19 +716,16 @@ public class CharBuf extends Writer implements CharSequence {
         add(chars);
 
         return this;
-
     }
 
     private Cache<Long, char[]> lcache;
 
     public final CharBuf addLong(long l) {
-
         addLong(Long.valueOf(l));
         return this;
     }
 
     public final CharBuf addLong(Long key) {
-
         if (lcache == null) {
             lcache = new SimpleCache<Long, char[]>(20, CacheType.LRU);
         }
@@ -856,7 +798,6 @@ public class CharBuf extends Writer implements CharSequence {
                             break;
 
                         case 'u':
-
                             if (index + 4 < to) {
                                 String hex = new String(chars, index + 1, 4);
                                 char unicode = (char) Integer.parseInt(hex, 16);
@@ -864,6 +805,7 @@ public class CharBuf extends Writer implements CharSequence {
                                 index += 4;
                             }
                             break;
+
                         default:
                             throw new JsonException("Unable to decode string");
                     }
@@ -877,9 +819,7 @@ public class CharBuf extends Writer implements CharSequence {
         this.location = location;
 
         return this;
-
     }
-
 }
 
 
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
index 958499c..bda2875 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharScanner.java
@@ -26,6 +26,7 @@ import static groovy.json.internal.Exceptions.handle;
  * @author Richard Hightower
  */
 public class CharScanner {
+
     protected static final int COMMA = ',';
     protected static final int CLOSED_CURLY = '}';
     protected static final int CLOSED_BRACKET = ']';
@@ -46,10 +47,12 @@ public class CharScanner {
     protected static final int PLUS = '+';
     protected static final int DOUBLE_QUOTE = '"';
     protected static final int ESCAPE = '\\';
+
     static final String MIN_LONG_STR_NO_SIGN = String.valueOf(Long.MIN_VALUE);
     static final String MAX_LONG_STR = String.valueOf(Long.MAX_VALUE);
     static final String MIN_INT_STR_NO_SIGN = String.valueOf(Integer.MIN_VALUE);
     static final String MAX_INT_STR = String.valueOf(Integer.MAX_VALUE);
+
     private static double powersOf10[] = {
             1.0,
             10.0,
@@ -70,7 +73,6 @@ public class CharScanner {
             10000000000000000.0,
             100000000000000000.0,
             1000000000000000000.0,
-
     };
 
     public static boolean isDigit(int c) {
@@ -109,7 +111,6 @@ public class CharScanner {
             }
         }
         return false;
-
     }
 
     public static boolean isDigits(final char[] inputArray) {
@@ -149,7 +150,6 @@ public class CharScanner {
         }
 
         if (c != split) {
-
             results[resultIndex] = Chr.copy(
                     inputArray, startCurrentLineIndex, currentLineLength - 1);
             resultIndex++;
@@ -183,8 +183,8 @@ public class CharScanner {
             inner:
             for (j = 0; j < delims.length; j++) {
                 split = delims[j];
-                if (c == split) {
 
+                if (c == split) {
                     results[resultIndex] = Chr.copy(
                             inputArray, startCurrentLineIndex, currentLineLength - 1);
                     startCurrentLineIndex = index + 1; //skip the char
@@ -197,7 +197,6 @@ public class CharScanner {
         }
 
         if (!Chr.in(c, delims)) {
-
             results[resultIndex] = Chr.copy(
                     inputArray, startCurrentLineIndex, currentLineLength - 1);
             resultIndex++;
@@ -226,9 +225,7 @@ public class CharScanner {
         for (; index < inputArray.length; index++, currentLineLength++) {
             c = inputArray[index];
             if (c == split) {
-
                 if (resultIndex == results.length) {
-
                     results = _grow(results);
                 }
 
@@ -242,7 +239,6 @@ public class CharScanner {
         }
 
         if (c != split) {
-
             results[resultIndex] = Chr.copy(
                     inputArray, startCurrentLineIndex, currentLineLength - 1);
             resultIndex++;
@@ -271,16 +267,13 @@ public class CharScanner {
         char split;
 
         for (; index < inputArray.length; index++, currentLineLength++) {
-
             c = inputArray[index];
 
             inner:
             for (j = 0; j < delims.length; j++) {
                 split = delims[j];
                 if (c == split) {
-
                     if (resultIndex == results.length) {
-
                         results = _grow(results);
                     }
 
@@ -296,7 +289,6 @@ public class CharScanner {
         }
 
         if (!Chr.in(c, delims)) {
-
             results[resultIndex] = Chr.copy(
                     inputArray, startCurrentLineIndex, currentLineLength - 1);
             resultIndex++;
@@ -327,16 +319,13 @@ public class CharScanner {
         char split;
 
         for (; index < length; index++, currentLineLength++) {
-
             c = inputArray[index];
 
             inner:
             for (j = 0; j < delims.length; j++) {
                 split = delims[j];
                 if (c == split) {
-
                     if (resultIndex == results.length) {
-
                         results = _grow(results);
                     }
 
@@ -352,7 +341,6 @@ public class CharScanner {
         }
 
         if (!Chr.in(c, delims)) {
-
             results[resultIndex] = Chr.copy(
                     inputArray, startCurrentLineIndex, currentLineLength - 1);
             resultIndex++;
@@ -381,10 +369,8 @@ public class CharScanner {
     }
 
     public static char[][] compact(char[][] array) {
-
         int nullCount = 0;
         for (char[] ch : array) {
-
             if (ch == null || ch.length == 0) {
                 nullCount++;
             }
@@ -393,7 +379,6 @@ public class CharScanner {
 
         int j = 0;
         for (char[] ch : array) {
-
             if (ch == null || ch.length == 0) {
                 continue;
             }
@@ -405,7 +390,6 @@ public class CharScanner {
     }
 
     private static char[][] _grow(char[][] array) {
-
         char[][] newArray = new char[array.length * 2][];
         System.arraycopy(array, 0, newArray, 0, array.length);
         return newArray;
@@ -413,7 +397,6 @@ public class CharScanner {
 
     private static char[][] __shrink(char[][] array, int size) {
         char[][] newArray = new char[array.length - size][];
-
         System.arraycopy(array, 0, (char[][]) newArray, 0, array.length - size);
         return newArray;
     }
@@ -422,8 +405,7 @@ public class CharScanner {
         return isLong(digitChars, 0, digitChars.length);
     }
 
-    public static boolean isLong(char[] digitChars, int offset, int len
-    ) {
+    public static boolean isLong(char[] digitChars, int offset, int len) {
         String cmpStr = digitChars[offset] == '-' ? MIN_LONG_STR_NO_SIGN : MAX_LONG_STR;
         int cmpLen = cmpStr.length();
         if (len < cmpLen) return true;
@@ -443,7 +425,6 @@ public class CharScanner {
     }
 
     public static boolean isInteger(char[] digitChars, int offset, int len) {
-
         String cmpStr = (digitChars[offset] == '-') ? MIN_INT_STR_NO_SIGN : MAX_INT_STR;
         int cmpLen = cmpStr.length();
         if (len < cmpLen) return true;
@@ -463,9 +444,7 @@ public class CharScanner {
     }
 
     public static int parseIntFromTo(char[] digitChars, int offset, int to) {
-
         try {
-
             int num;
             boolean negative = false;
             char c = digitChars[offset];
@@ -540,7 +519,6 @@ public class CharScanner {
     }
 
     public static int parseIntFromToIgnoreDot(char[] digitChars, int offset, int to) {
-
         int num;
         boolean negative = false;
         char c = digitChars[offset];
@@ -558,14 +536,12 @@ public class CharScanner {
             if (c != '.') {
                 num = (num * 10) + (c - '0');
             }
-
         }
 
         return negative ? num * -1 : num;
     }
 
     public static long parseLongFromToIgnoreDot(char[] digitChars, int offset, int to) {
-
         long num;
         boolean negative = false;
         char c = digitChars[offset];
@@ -583,14 +559,12 @@ public class CharScanner {
             if (c != '.') {
                 num = (num * 10) + (c - '0');
             }
-
         }
 
         return negative ? num * -1 : num;
     }
 
     public static long parseLongFromTo(char[] digitChars, int offset, int to) {
-
         long num;
         boolean negative = false;
         char c = digitChars[offset];
@@ -612,7 +586,6 @@ public class CharScanner {
         }
 
         return negative ? num * -1 : num;
-
     }
 
     public static long parseLong(char[] digitChars) {
@@ -632,7 +605,6 @@ public class CharScanner {
     }
 
     protected static boolean isDelimiter(int c) {
-
         return c == COMMA || c == CLOSED_CURLY || c == CLOSED_BRACKET;
     }
 
@@ -651,13 +623,15 @@ public class CharScanner {
         for (; index < max; index++) {
             char ch = buffer[index];
             if (isNumberDigit(ch)) {
-
                 if (foundDot == true) {
                     digitsPastPoint++;
                 }
             } else if (ch <= 32 || isDelimiter(ch)) {
                 break;
             } else if (ch == '.') {
+                if (foundDot) {
+                    die("unexpected character " + ch);
+                }
                 foundDot = true;
             } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
                 simple = false;
@@ -682,7 +656,6 @@ public class CharScanner {
             BigDecimal lvalue;
 
             if (length < powersOf10.length) {
-
                 if (isInteger(buffer, from, length)) {
                     lvalue = new BigDecimal(parseIntFromToIgnoreDot(buffer, from, index));
                 } else {
@@ -691,12 +664,9 @@ public class CharScanner {
 
                 BigDecimal power = new BigDecimal(powersOf10[digitsPastPoint]);
                 value = lvalue.divide(power);
-
             } else {
                 value = new BigDecimal(new String(buffer, from, length));
-
             }
-
         } else {
             value = new BigDecimal(new String(buffer, from, index - from));
         }
@@ -739,11 +709,13 @@ public class CharScanner {
         for (; index < to; index++) {
             char ch = buffer[index];
             if (isNumberDigit(ch)) {
-
                 if (foundDot == true) {
                     digitsPastPoint++;
                 }
             } else if (ch == '.') {
+                if (foundDot) {
+                    die("unexpected character " + ch);
+                }
                 foundDot = true;
             } else if (ch == 'E' || ch == 'e' || ch == '-' || ch == '+') {
                 simple = false;
@@ -768,7 +740,6 @@ public class CharScanner {
             long lvalue;
 
             if (length < powersOf10.length) {
-
                 if (isInteger(buffer, from, length)) {
                     lvalue = parseIntFromToIgnoreDot(buffer, from, index);
                 } else {
@@ -777,12 +748,9 @@ public class CharScanner {
 
                 double power = powersOf10[digitsPastPoint];
                 value = lvalue / power;
-
             } else {
                 value = Double.parseDouble(new String(buffer, from, length));
-
             }
-
         } else {
             value = Double.parseDouble(new String(buffer, from, index - from));
         }
@@ -795,7 +763,6 @@ public class CharScanner {
         for (; index < array.length; index++) {
             c = array[index];
             if (c > 32) {
-
                 return index;
             }
         }
@@ -807,7 +774,6 @@ public class CharScanner {
         for (; index < length; index++) {
             c = array[index];
             if (c > 32) {
-
                 return index;
             }
         }
@@ -827,7 +793,6 @@ public class CharScanner {
         }
 
         return ArrayUtils.copyRange(array, startIndex, idx);
-
     }
 
     public static char[] readNumber(char[] array, int idx, final int len) {
@@ -843,7 +808,6 @@ public class CharScanner {
         }
 
         return ArrayUtils.copyRange(array, startIndex, idx);
-
     }
 
     public static int skipWhiteSpaceFast(char[] array) {
@@ -852,7 +816,6 @@ public class CharScanner {
         for (; index < array.length; index++) {
             c = array[index];
             if (c > 32) {
-
                 return index;
             }
         }
@@ -864,7 +827,6 @@ public class CharScanner {
         for (; index < array.length; index++) {
             c = array[index];
             if (c > 32) {
-
                 return index;
             }
         }
@@ -905,7 +867,6 @@ public class CharScanner {
         try {
             buf.addLine(new String(array, lastLineIndex, count));
         } catch (Exception ex) {
-
             try {
                 int start = index = (index - 10 < 0) ? 0 : index - 10;
 
@@ -928,10 +889,8 @@ public class CharScanner {
             charString = "[SPACE]";
         } else if (c == '\t') {
             charString = "[TAB]";
-
         } else if (c == '\n') {
             charString = "[NEWLINE]";
-
         } else {
             charString = "'" + (char) c + "'";
         }
@@ -939,5 +898,4 @@ public class CharScanner {
         charString = charString + " with an int value of " + ((int) c);
         return charString;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
index a78ada2..b775c60 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/CharSequenceValue.java
@@ -57,7 +57,6 @@ public class CharSequenceValue implements Value, CharSequence {
             this.startIndex = 0;
             this.endIndex = this.buffer.length;
             this.chopped = true;
-
         } else {
             this.startIndex = startIndex;
             this.endIndex = endIndex;
@@ -78,7 +77,6 @@ public class CharSequenceValue implements Value, CharSequence {
     }
 
     public <T extends Enum> T toEnum(Class<T> cls) {
-
         switch (type) {
             case STRING:
                 return toEnum(cls, stringValue());
@@ -100,7 +98,6 @@ public class CharSequenceValue implements Value, CharSequence {
     }
 
     public static <T extends Enum> T toEnum(Class<T> cls, int value) {
-
         T[] enumConstants = cls.getEnumConstants();
         for (T e : enumConstants) {
             if (e.ordinal() == value) {
@@ -116,12 +113,10 @@ public class CharSequenceValue implements Value, CharSequence {
     }
 
     private final Object doToValue() {
-
         switch (type) {
             case DOUBLE:
                 return doubleValue();
             case INTEGER:
-
                 if (isInteger(buffer, startIndex, endIndex - startIndex)) {
                     return intValue();
                 } else {
@@ -209,7 +204,6 @@ public class CharSequenceValue implements Value, CharSequence {
     }
 
     public Date dateValue() {
-
         if (type == Type.STRING) {
 
             if (Dates.isISO8601QuickCheck(buffer, startIndex, endIndex)) {
@@ -223,11 +217,9 @@ public class CharSequenceValue implements Value, CharSequence {
                     throw new JsonException("Unable to convert " + stringValue() + " to date ");
                 }
             } else {
-
                 throw new JsonException("Unable to convert " + stringValue() + " to date ");
             }
         } else {
-
             return new Date(Dates.utc(longValue()));
         }
     }
@@ -237,13 +229,11 @@ public class CharSequenceValue implements Value, CharSequence {
         if (buffer[startIndex] == '-') {
             startIndex++;
             sign = -1;
-
         }
         return parseIntFromTo(buffer, startIndex, endIndex) * sign;
     }
 
     public long longValue() {
-
         if (isInteger(buffer, startIndex, endIndex - startIndex)) {
             return parseIntFromTo(buffer, startIndex, endIndex);
         } else {
@@ -268,7 +258,6 @@ public class CharSequenceValue implements Value, CharSequence {
     }
 
     public float floatValue() {
-
         return CharScanner.parseFloat(this.buffer, startIndex, endIndex);
     }
 
@@ -285,4 +274,3 @@ public class CharSequenceValue implements Value, CharSequence {
         return buffer[startIndex];
     }
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
index 7a32a92..a4b2096 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/Chr.java
@@ -124,7 +124,6 @@ public class Chr {
     }
 
     public static char[] lpad(final char[] in, final int size, char pad) {
-
         if (in.length >= size) {
             return in;
         }
@@ -165,7 +164,6 @@ public class Chr {
 
     public static void _idx(final char[] array, int startIndex, char[] input) {
         try {
-
             arraycopy(input, 0, array, startIndex, input.length);
         } catch (Exception ex) {
             Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
@@ -179,7 +177,6 @@ public class Chr {
 
     public static void _idx(final char[] array, int startIndex, char[] input, final int inputLength) {
         try {
-
             arraycopy(input, 0, array, startIndex, inputLength);
         } catch (Exception ex) {
             Exceptions.handle(String.format("array size %d, startIndex %d, input length %d",
@@ -188,13 +185,11 @@ public class Chr {
     }
 
     public static void _idx(char[] buffer, int location, byte[] chars, int start, int end) {
-
         int index2 = start;
         int endLocation = (location + (end - start));
         for (int index = location; index < endLocation; index++, index2++) {
             buffer[index] = (char) chars[index2];
         }
-
     }
 
     public static char[] add(char[]... strings) {
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
index e9c5cf0..b29b951 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/Dates.java
@@ -37,7 +37,6 @@ public class Dates {
     }
 
     private static Date internalDate(TimeZone tz, int year, int month, int day, int hour, int minute, int second) {
-
         Calendar calendar = Calendar.getInstance();
 
         calendar.set(Calendar.YEAR, year);
@@ -84,7 +83,6 @@ public class Dates {
     public static final int JSON_TIME_LENGTH = "2013-12-14T01:55:33.412Z".length();
 
     public static Date fromISO8601(char[] charArray, int from, int to) {
-
         try {
             if (isISO8601(charArray, from, to)) {
                 int year = CharScanner.parseIntFromTo(charArray, from + 0, from + 4);
@@ -98,27 +96,21 @@ public class Dates {
                 TimeZone tz = null;
 
                 if (charArray[from + 19] == 'Z') {
-
                     tz = TimeZone.getTimeZone("GMT");
-
                 } else {
-
                     StringBuilder builder = new StringBuilder(9);
                     builder.append("GMT");
                     builder.append(charArray, from + 19, 6);
                     String tzStr = builder.toString();
                     tz = TimeZone.getTimeZone(tzStr);
-
                 }
                 return toDate(tz, year, month, day, hour, minute, second);
-
             } else {
                 return null;
             }
         } catch (Exception ex) {
             return null;
         }
-
     }
 
     public static Date fromJsonDate(char[] charArray, int from, int to) {
@@ -138,14 +130,12 @@ public class Dates {
                 TimeZone tz = TimeZone.getTimeZone("GMT");
 
                 return toDate(tz, year, month, day, hour, minute, second, miliseconds);
-
             } else {
                 return null;
             }
         } catch (Exception ex) {
             return null;
         }
-
     }
 
     public static boolean isISO8601(char[] charArray, int start, int to) {
@@ -154,11 +144,9 @@ public class Dates {
 
         if (length == SHORT_ISO_8601_TIME_LENGTH) {
             valid &= (charArray[start + 19] == 'Z');
-
         } else if (length == LONG_ISO_8601_TIME_LENGTH) {
             valid &= (charArray[start + 19] == '-' || charArray[start + 19] == '+');
             valid &= (charArray[start + 22] == ':');
-
         } else {
             return false;
         }
@@ -179,7 +167,6 @@ public class Dates {
         final int length = to - start;
 
         try {
-
             if (length == JSON_TIME_LENGTH || length == LONG_ISO_8601_TIME_LENGTH
                     || length == SHORT_ISO_8601_TIME_LENGTH || (length >= 17 && (charArray[start + 16] == ':'))
                     ) {
@@ -191,7 +178,6 @@ public class Dates {
             ex.printStackTrace();
             return false;
         }
-
     }
 
     public static boolean isJsonDate(char[] charArray, int start, int to) {
@@ -216,5 +202,4 @@ public class Dates {
 
         return valid;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
index f1c58f1..16ca13b 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/Exceptions.java
@@ -45,7 +45,6 @@ public class Exceptions {
     }
 
     public static <T> T handle(Class<T> clazz, java.lang.Exception e) {
-
         if (e instanceof JsonInternalException) {
             throw (JsonInternalException) e;
         }
@@ -53,7 +52,6 @@ public class Exceptions {
     }
 
     public static <T> T handle(Class<T> clazz, String message, Throwable e) {
-
         throw new JsonInternalException(message, e);
     }
 
@@ -76,7 +74,6 @@ public class Exceptions {
         }
 
         public void printStackTrace(PrintStream s) {
-
             s.println(this.getMessage());
             if (getCause() != null) {
                 s.println("This Exception was wrapped, the original exception\n" +
@@ -85,7 +82,6 @@ public class Exceptions {
             } else {
                 super.printStackTrace(s);
             }
-
         }
 
         public String getMessage() {
@@ -108,7 +104,6 @@ public class Exceptions {
             } else {
                 return super.getStackTrace();
             }
-
         }
 
         public Throwable getCause() {
@@ -116,7 +111,6 @@ public class Exceptions {
         }
 
         public void printStackTrace(PrintWriter s) {
-
             s.println(this.getMessage());
 
             if (getCause() != null) {
@@ -129,7 +123,6 @@ public class Exceptions {
         }
 
         public void printStackTrace() {
-
             System.err.println(this.getMessage());
 
             if (getCause() != null) {
@@ -154,11 +147,9 @@ public class Exceptions {
         }
 
         return buffer.toString();
-
     }
 
     public static String sputs(CharBuf buf, Object... messages) {
-
         int index = 0;
         for (Object message : messages) {
             if (index != 0) {
@@ -177,13 +168,10 @@ public class Exceptions {
         buf.add('\n');
 
         return buf.toString();
-
     }
 
     public static String sputs(Object... messages) {
         CharBuf buf = CharBuf.create(100);
         return sputs(buf, messages);
     }
-
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
index 8e1c71b..39feaee 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/FastStringUtils.java
@@ -32,6 +32,7 @@ public class FastStringUtils {
     public static final long STRING_OFFSET_FIELD_OFFSET;
     public static final long STRING_COUNT_FIELD_OFFSET;
     public static final boolean ENABLED;
+
     private static final boolean WRITE_TO_FINAL_FIELDS = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.write.to.final.fields", "false"));
     private static final boolean DISABLE = Boolean.parseBoolean(System.getProperty("groovy.json.faststringutils.disable", "false"));
 
@@ -151,11 +152,9 @@ public class FastStringUtils {
      * @return correct string implementation
      */
     private static StringImplementation computeStringImplementation() {
-
         if (STRING_VALUE_FIELD_OFFSET != -1L) {
             if (STRING_OFFSET_FIELD_OFFSET != -1L && STRING_COUNT_FIELD_OFFSET != -1L) {
                 return StringImplementation.OFFSET;
-
             } else if (STRING_OFFSET_FIELD_OFFSET == -1L && STRING_COUNT_FIELD_OFFSET == -1L) {
                 return StringImplementation.DIRECT_CHARS;
             } else {
@@ -173,7 +172,6 @@ public class FastStringUtils {
      */
     public static char[] toCharArray(final String string) {
         return STRING_IMPLEMENTATION.toCharArray(string);
-
     }
 
     /**
@@ -196,4 +194,4 @@ public class FastStringUtils {
          */
         return STRING_IMPLEMENTATION.noCopyStringFromChars(chars);
     }
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
index f33859c..ad193be 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/IO.java
@@ -31,7 +31,6 @@ public class IO {
     private static final int DEFAULT_BUFFER_SIZE = 1024 * 4;
 
     public static CharBuf read(Reader input, CharBuf charBuf, final int bufSize) {
-
         if (charBuf == null) {
             charBuf = CharBuf.create(bufSize);
         } else {
@@ -39,18 +38,16 @@ public class IO {
         }
 
         try {
-
             char[] buffer = charBuf.toCharArray();
             int size = input.read(buffer);
             if (size != -1) {
                 charBuf._len(size);
             }
-            if (size < buffer.length) {
+            if (size < 0) {
                 return charBuf;
             }
 
             copy(input, charBuf);
-
         } catch (IOException e) {
             Exceptions.handle(e);
         } finally {
@@ -62,7 +59,6 @@ public class IO {
         }
 
         return charBuf;
-
     }
 
     public static int copy(Reader input, Writer output) {
@@ -91,5 +87,4 @@ public class IO {
         }
         return count;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
index 7d8ad35..f75ad62 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonFastParser.java
@@ -57,7 +57,6 @@ public class JsonFastParser extends JsonParserCharArray {
     }
 
     protected final Value decodeJsonObjectLazyFinalParse() {
-
         char[] array = charArray;
 
         if (__currentChar == '{')
@@ -102,7 +101,6 @@ public class JsonFastParser extends JsonParserCharArray {
 
                     complain(
                             "expecting '}' or ',' but got current char " + charDescription(__currentChar));
-
             }
         }
         return value;
@@ -113,11 +111,9 @@ public class JsonFastParser extends JsonParserCharArray {
     }
 
     private Value decodeValueOverlay() {
-
         skipWhiteSpace();
 
         switch (__currentChar) {
-
             case '"':
                 return decodeStringOverlay();
 
@@ -159,13 +155,13 @@ public class JsonFastParser extends JsonParserCharArray {
     }
 
     private final Value decodeNumberOverlay(final boolean minus) {
-
         char[] array = charArray;
 
         final int startIndex = __index;
         int index = __index;
         char currentChar;
         boolean doubleFloat = false;
+        boolean foundDot = false;
 
         if (minus && index + 1 < array.length) {
             index++;
@@ -179,6 +175,12 @@ public class JsonFastParser extends JsonParserCharArray {
                 break;
             } else if (isDelimiter(currentChar)) {
                 break;
+            } else if (currentChar == '.') {
+                if (foundDot) {
+                    complain("unexpected character " + currentChar);
+                }
+                foundDot = true;
+                doubleFloat = true;
             } else if (isDecimalChar(currentChar)) {
                 doubleFloat = true;
             }
@@ -197,7 +199,6 @@ public class JsonFastParser extends JsonParserCharArray {
     }
 
     private Value decodeStringOverlay() {
-
         char[] array = charArray;
         int index = __index;
         char currentChar = charArray[index];
@@ -226,7 +227,6 @@ public class JsonFastParser extends JsonParserCharArray {
     }
 
     private Value decodeJsonArrayOverlay() {
-
         char[] array = charArray;
         if (__currentChar == '[') {
             __index++;
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
index e606669..8a222a5 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserCharArray.java
@@ -66,11 +66,9 @@ public class JsonParserCharArray extends BaseJsonParser {
             this.__currentChar = this.charArray[ix];
             __index = ix;
         }
-
     }
 
     protected final char nextChar() {
-
         try {
             if (hasMore()) {
                 __index++;
@@ -93,7 +91,6 @@ public class JsonParserCharArray extends BaseJsonParser {
         for (; index < array.length; index++) {
             c = array[index];
             if (c > 32) {
-
                 return index;
             }
         }
@@ -101,7 +98,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     }
 
     protected final Object decodeJsonObject() {
-
         if (__currentChar == '{') {
             __index++;
         }
@@ -109,13 +105,10 @@ public class JsonParserCharArray extends BaseJsonParser {
         LazyMap map = new LazyMap();
 
         for (; __index < this.charArray.length; __index++) {
-
             skipWhiteSpace();
 
             if (__currentChar == '"') {
-
-                String key =
-                        decodeString();
+                String key = decodeString();
 
                 if (internKeys) {
                     String keyPrime = internedKeysCache.get(key);
@@ -130,7 +123,6 @@ public class JsonParserCharArray extends BaseJsonParser {
                 skipWhiteSpace();
 
                 if (__currentChar != ':') {
-
                     complain("expecting current character to be " + charDescription(__currentChar) + "\n");
                 }
                 __index++;
@@ -141,8 +133,8 @@ public class JsonParserCharArray extends BaseJsonParser {
 
                 skipWhiteSpace();
                 map.put(key, value);
-
             }
+
             if (__currentChar == '}') {
                 __index++;
                 break;
@@ -151,7 +143,6 @@ public class JsonParserCharArray extends BaseJsonParser {
             } else {
                 complain(
                         "expecting '}' or ',' but got current char " + charDescription(__currentChar));
-
             }
         }
 
@@ -171,7 +162,6 @@ public class JsonParserCharArray extends BaseJsonParser {
         skipWhiteSpace();
 
         switch (__currentChar) {
-
             case '"':
                 value = decodeString();
                 break;
@@ -215,7 +205,6 @@ public class JsonParserCharArray extends BaseJsonParser {
             default:
                 throw new JsonException(exceptionDetails("Unable to determine the " +
                         "current character, it is not a string, number, array, or object"));
-
         }
 
         return value;
@@ -224,7 +213,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     int[] endIndex = new int[1];
 
     private final Object decodeNumber() {
-
         Number num = CharScanner.parseJsonNumber(charArray, __index, charArray.length, endIndex);
         __index = endIndex[0];
 
@@ -234,7 +222,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     protected static final char[] NULL = Chr.chars("null");
 
     protected final Object decodeNull() {
-
         if (__index + NULL.length <= charArray.length) {
             if (charArray[__index] == 'n' &&
                     charArray[++__index] == 'u' &&
@@ -250,7 +237,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     protected static final char[] TRUE = Chr.chars("true");
 
     protected final boolean decodeTrue() {
-
         if (__index + TRUE.length <= charArray.length) {
             if (charArray[__index] == 't' &&
                     charArray[++__index] == 'r' &&
@@ -259,7 +245,6 @@ public class JsonParserCharArray extends BaseJsonParser {
 
                 __index++;
                 return true;
-
             }
         }
 
@@ -269,7 +254,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     protected static char[] FALSE = Chr.chars("false");
 
     protected final boolean decodeFalse() {
-
         if (__index + FALSE.length <= charArray.length) {
             if (charArray[__index] == 'f' &&
                     charArray[++__index] == 'a' &&
@@ -286,7 +270,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     private CharBuf builder = CharBuf.create(20);
 
     private String decodeString() {
-
         char[] array = charArray;
         int index = __index;
         char currentChar = array[index];
@@ -317,7 +300,6 @@ public class JsonParserCharArray extends BaseJsonParser {
     }
 
     protected final List decodeJsonArray() {
-
         ArrayList<Object> list = null;
 
         boolean foundEnd = false;
@@ -332,7 +314,6 @@ public class JsonParserCharArray extends BaseJsonParser {
 
             skipWhiteSpace();
 
-
         /* the list might be empty  */
             if (__currentChar == ']') {
                 __index++;
@@ -342,7 +323,6 @@ public class JsonParserCharArray extends BaseJsonParser {
             list = new ArrayList();
 
             while (this.hasMore()) {
-
                 Object arrayItem = decodeValueInternal();
 
                 list.add(arrayItem);
@@ -371,7 +351,6 @@ public class JsonParserCharArray extends BaseJsonParser {
                     foundEnd = true;
                     break;
                 } else {
-
                     String charString = charDescription(c);
 
                     complain(
@@ -379,10 +358,8 @@ public class JsonParserCharArray extends BaseJsonParser {
                                     " but got \nthe current character of  %s " +
                                     " on array index of %s \n", charString, list.size())
                     );
-
                 }
             }
-
         } catch (Exception ex) {
             if (ex instanceof JsonException) {
                 JsonException jsonException = (JsonException) ex;
@@ -394,7 +371,6 @@ public class JsonParserCharArray extends BaseJsonParser {
             complain("Did not find end of Json Array");
         }
         return list;
-
     }
 
     protected final char currentChar() {
@@ -408,5 +384,4 @@ public class JsonParserCharArray extends BaseJsonParser {
     public Object parse(char[] chars) {
         return this.decodeFromChars(chars);
     }
-
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
index 8834d2a..2665193 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserLax.java
@@ -54,7 +54,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     private Value decodeJsonObjectLax() {
-
         if (__currentChar == '{')
             this.nextChar();
 
@@ -69,7 +68,6 @@ public class JsonParserLax extends JsonParserCharArray {
 
         done:
         for (; __index < this.charArray.length; __index++) {
-
             skipWhiteSpace();
 
             switch (__currentChar) {
@@ -110,18 +108,17 @@ public class JsonParserLax extends JsonParserCharArray {
                 case '\'':
                     key = decodeStringSingle();
 
-                    //puts ( "key with quote", key );
+                    //puts ("key with quote", key);
 
                     skipWhiteSpace();
 
                     if (__currentChar != ':') {
-
                         complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
                     }
                     __index++;
                     item = decodeValueInternal();
 
-                    //puts ( "key", "#" + key + "#", value );
+                    //puts ("key", "#" + key + "#", value);
 
                     skipWhiteSpace();
 
@@ -139,18 +136,17 @@ public class JsonParserLax extends JsonParserCharArray {
                 case '"':
                     key = decodeStringDouble();
 
-                    //puts ( "key with quote", key );
+                    //puts ("key with quote", key);
 
                     skipWhiteSpace();
 
                     if (__currentChar != ':') {
-
                         complain("expecting current character to be ':' but got " + charDescription(__currentChar) + "\n");
                     }
                     __index++;
                     item = decodeValueInternal();
 
-                    //puts ( "key", "#" + key + "#", value );
+                    //puts ("key", "#" + key + "#", value);
 
                     skipWhiteSpace();
 
@@ -331,7 +327,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     private void handleComment() {
-
         if (hasMore()) {
             __index++;
             __currentChar = charArray[__index];
@@ -375,7 +370,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     protected final Value decodeNumberLax(boolean minus) {
-
         char[] array = charArray;
 
         final int startIndex = __index;
@@ -471,7 +465,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     private Value decodeStringDouble() {
-
         __currentChar = charArray[__index];
 
         if (__index < charArray.length && __currentChar == '"') {
@@ -518,7 +511,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     private Value decodeStringSingle() {
-
         __currentChar = charArray[__index];
 
         if (__index < charArray.length && __currentChar == '\'') {
@@ -536,7 +528,6 @@ public class JsonParserLax extends JsonParserCharArray {
         for (; __index < this.charArray.length; __index++) {
             __currentChar = charArray[__index];
             switch (__currentChar) {
-
                 case '\'':
                     if (!escape) {
                         break done;
@@ -553,6 +544,7 @@ public class JsonParserLax extends JsonParserCharArray {
                 case '-':
                     minusCount++;
                     break;
+
                 case ':':
                     colonCount++;
                     break;
@@ -572,7 +564,6 @@ public class JsonParserLax extends JsonParserCharArray {
     }
 
     private Value decodeJsonArrayLax() {
-
         if (__currentChar == '[') {
             __index++;
         }
@@ -595,32 +586,45 @@ public class JsonParserLax extends JsonParserCharArray {
         Value value = new ValueContainer(list);
 
         do {
-
             skipWhiteSpace();
 
             Object arrayItem = decodeValueInternal();
 
             list.add(arrayItem);
 
-            skipWhiteSpace();
+            boolean doStop = false;
 
-            char c = __currentChar;
+            done:
+            do { // Find either next array element or end of array while ignoring comments
+                skipWhiteSpace();
+
+                switch (__currentChar) {
+                    case '/':
+                        handleComment();
+                        continue;
+                    case '#':
+                        handleBashComment();
+                        continue;
+                    case ',':
+                        __index++;
+                        break done;
+                    case ']':
+                        __index++;
+                        doStop = true;
+                        break done;
+                    default:
+                        String charString = charDescription(__currentChar);
+
+                        complain(
+                                String.format("expecting a ',' or a ']', " +
+                                        " but got \nthe current character of  %s " +
+                                        " on array index of %s \n", charString, list.size())
+                        );
+                }
+            } while (this.hasMore());
+
+            if (doStop) break;
 
-            if (c == ',') {
-                __index++;
-                continue;
-            } else if (c == ']') {
-                __index++;
-                break;
-            } else {
-                String charString = charDescription(c);
-
-                complain(
-                        String.format("expecting a ',' or a ']', " +
-                                " but got \nthe current character of  %s " +
-                                " on array index of %s \n", charString, list.size())
-                );
-            }
         } while (this.hasMore());
 
         return value;
@@ -635,4 +639,3 @@ public class JsonParserLax extends JsonParserCharArray {
         }
     }
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
index d538f21..a20c2e0 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonParserUsingCharacterSource.java
@@ -44,7 +44,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
         LazyMap map = new LazyMap();
 
         try {
-
             CharacterSource characterSource = this.characterSource;
 
             if (characterSource.currentChar() == '{') {
@@ -52,11 +51,9 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
             }
 
             while (characterSource.hasChar()) {
-
                 characterSource.skipWhiteSpace();
 
                 if (characterSource.currentChar() == DOUBLE_QUOTE) {
-
                     String key = decodeString();
                     //puts ("key", key);
 
@@ -72,12 +69,10 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
 
                     characterSource.skipWhiteSpace();
                     if (characterSource.currentChar() != COLON) {
-
                         complain("expecting current character to be : but was " + charDescription(characterSource.currentChar()) + "\n");
                     }
 
                     characterSource.nextChar();
-
                     characterSource.skipWhiteSpace();
 
                     Object value = decodeValue();
@@ -87,7 +82,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
                     characterSource.skipWhiteSpace();
 
                     map.put(key, value);
-
                 }
 
                 int ch = characterSource.currentChar();
@@ -100,7 +94,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
                 } else {
                     complain(
                             "expecting '}' or ',' but got current char " + charDescription(ch));
-
                 }
             }
         } catch (Exception ex) {
@@ -120,7 +113,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
         characterSource.skipWhiteSpace();
 
         switch (characterSource.currentChar()) {
-
             case '"':
                 value = decodeString();
                 break;
@@ -165,7 +157,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
             default:
                 throw new JsonException(exceptionDetails("Unable to determine the " +
                         "current character, it is not a string, number, array, or object"));
-
         }
 
         return value;
@@ -198,7 +189,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
     protected static final char[] TRUE = Chr.chars("true");
 
     protected final boolean decodeTrue() {
-
         if (characterSource.consumeIfMatch(TRUE)) {
             return true;
         } else {
@@ -209,19 +199,16 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
     protected static char[] FALSE = Chr.chars("false");
 
     protected final boolean decodeFalse() {
-
         if (characterSource.consumeIfMatch(FALSE)) {
             return false;
         } else {
             throw new JsonException(exceptionDetails("false not parsed properly"));
         }
-
     }
 
     private CharBuf builder = CharBuf.create(20);
 
     private String decodeString() {
-
         CharacterSource characterSource = this.characterSource;
 
         characterSource.nextChar();
@@ -240,12 +227,10 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
     }
 
     protected final List decodeJsonArray() {
-
         ArrayList<Object> list = null;
 
         boolean foundEnd = false;
         try {
-
             CharacterSource characterSource = this.characterSource;
 
             if (this.characterSource.currentChar() == '[') {
@@ -254,8 +239,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
 
             characterSource.skipWhiteSpace();
 
-
-
         /* the list might be empty  */
             if (this.characterSource.currentChar() == ']') {
                 characterSource.nextChar();
@@ -265,7 +248,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
             list = new ArrayList();
 
             do {
-
                 characterSource.skipWhiteSpace();
 
                 Object arrayItem = decodeValue();
@@ -284,7 +266,6 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
                     characterSource.nextChar();
                     break;
                 } else {
-
                     String charString = charDescription(c);
 
                     complain(
@@ -295,28 +276,22 @@ public class JsonParserUsingCharacterSource extends BaseJsonParser {
 
                 }
             } while (characterSource.hasChar());
-
         } catch (Exception ex) {
             throw new JsonException(exceptionDetails("Unexpected issue"), ex);
         }
 
         if (!foundEnd) {
             throw new JsonException(exceptionDetails("Could not find end of JSON array"));
-
         }
         return list;
-
     }
 
     public Object parse(Reader reader) {
-
         characterSource = new ReaderCharacterSource(reader);
         return this.decodeValue();
-
     }
 
     public Object parse(char[] chars) {
         return parse(new StringReader(new String(chars)));
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
index c3d6b40..7cefb94 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/JsonStringDecoder.java
@@ -23,7 +23,6 @@ package groovy.json.internal;
 public class JsonStringDecoder {
 
     public static String decode(char[] chars, int start, int to) {
-
         if (!Chr.contains(chars, '\\', start, to - start)) {
             return new String(chars, start, to - start);
         }
@@ -31,11 +30,8 @@ public class JsonStringDecoder {
     }
 
     public static String decodeForSure(char[] chars, int start, int to) {
-
         CharBuf builder = CharBuf.create(to - start);
         builder.decodeJsonString(chars, start, to);
         return builder.toString();
-
     }
-
-}
\ No newline at end of file
+}
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
index edf96b8..9d0d89d 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyMap.java
@@ -28,6 +28,8 @@ import java.util.*;
  */
 public class LazyMap extends AbstractMap<String, Object> {
 
+    private static final String JDK_MAP_ALTHASHING_SYSPROP = System.getProperty("jdk.map.althashing.threshold");
+
     /* Holds the actual map that will be lazily created. */
     private Map<String, Object> map;
     /* The size of the map. */
@@ -45,11 +47,20 @@ public class LazyMap extends AbstractMap<String, Object> {
     public LazyMap(int initialSize) {
         keys = new String[initialSize];
         values = new Object[initialSize];
-
     }
 
     public Object put(String key, Object value) {
         if (map == null) {
+            for (int i = 0; i < size; i++) {
+                String curKey = keys[i];
+                if ((key == null && curKey == null)
+                     || (key != null && key.equals(curKey))) {
+                    Object val = values[i];
+                    keys[i] = key;
+                    values[i] = value;
+                    return val;
+                }
+            }
             keys[size] = key;
             values[size] = value;
             size++;
@@ -101,9 +112,8 @@ public class LazyMap extends AbstractMap<String, Object> {
 
     private void buildIfNeeded() {
         if (map == null) {
-
             /** added to avoid hash collision attack. */
-            if (Sys.is1_7OrLater() && System.getProperty("jdk.map.althashing.threshold") != null) {
+            if (Sys.is1_7OrLater() && JDK_MAP_ALTHASHING_SYSPROP != null) {
                 map = new LinkedHashMap<String, Object>(size, 0.01f);
             } else {
                 map = new TreeMap<String, Object>();
@@ -138,15 +148,11 @@ public class LazyMap extends AbstractMap<String, Object> {
     public Set<String> keySet() {
         buildIfNeeded();
         return map.keySet();
-
     }
 
     public Collection<Object> values() {
-
         buildIfNeeded();
-
         return map.values();
-
     }
 
     public boolean equals(Object o) {
@@ -160,13 +166,11 @@ public class LazyMap extends AbstractMap<String, Object> {
     }
 
     public String toString() {
-
         buildIfNeeded();
         return map.toString();
     }
 
     protected Object clone() throws CloneNotSupportedException {
-
         if (map == null) {
             return null;
         } else {
@@ -188,11 +192,8 @@ public class LazyMap extends AbstractMap<String, Object> {
     }
 
     public static <V> V[] grow(V[] array) {
-        Object newArray = Array.newInstance(array.getClass().getComponentType(),
-                array.length * 2);
+        Object newArray = Array.newInstance(array.getClass().getComponentType(), array.length * 2);
         System.arraycopy(array, 0, newArray, 0, array.length);
         return (V[]) newArray;
     }
-
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
index 39e5289..ae7bb8f 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/LazyValueMap.java
@@ -66,7 +66,6 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
     boolean mapChopped = false;
 
     public LazyValueMap(boolean lazyChop) {
-
         this.items = new Entry[5];
         this.lazyChop = lazyChop;
     }
@@ -87,7 +86,6 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
         }
         items[len] = miv;
         len++;
-
     }
 
     /**
@@ -96,9 +94,7 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
      * @param key to lookup
      * @return the item for the given key
      */
-
     public final Object get(Object key) {
-
         Object object = null;
 
         /* if the map is null, then we create it. */
@@ -125,7 +121,6 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
                 list.chopList();
             }
         }
-
     }
 
     /**
@@ -138,7 +133,6 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
         }
         mapChopped = true;
 
-
         /* If the internal map was not create yet, don't. We can chop the value w/o creating the internal map.*/
         if (this.map == null) {
             for (int index = 0; index < len; index++) {
@@ -173,7 +167,6 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
                 }
             }
         }
-
     }
 
     /* We need to chop up this child container. */
@@ -201,21 +194,18 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
     }
 
     private final void buildMap() {
-
-
         /** added to avoid hash collision attack. */
         if (Sys.is1_7OrLater() && System.getProperty("jdk.map.althashing.threshold") != null) {
-            map = new HashMap<String, Object>( items.length );
+            map = new HashMap<String, Object>(items.length);
         } else {
             map = new TreeMap<String, Object>();
         }
 
-
-        for ( Entry<String, Value> miv : items ) {
-            if ( miv == null ) {
+        for (Entry<String, Value> miv : items) {
+            if (miv == null) {
                 break;
             }
-            map.put( miv.getKey(), miv.getValue().toValue() );
+            map.put(miv.getKey(), miv.getValue().toValue());
         }
 
         len = 0;
@@ -233,10 +223,8 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
     }
 
     public String toString() {
-
         if (map == null) buildMap();
         return map.toString();
-
     }
 
     public int len() {
@@ -250,5 +238,4 @@ public class LazyValueMap extends AbstractMap<String, Object> implements ValueMa
     public Entry<String, Value>[] items() {
         return items;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
index 90f2bd9..c87145c 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/MapItemValue.java
@@ -47,13 +47,11 @@ public class MapItemValue implements Map.Entry<String, Value> {
     public MapItemValue(Value name, Value value) {
         this.name = name;
         this.value = value;
-
     }
 
     public String getKey() {
         if (key == null) {
             if (internKeys) {
-
                 key = name.toString();
 
                 String keyPrime = internedKeysCache.get(key);
@@ -64,7 +62,6 @@ public class MapItemValue implements Map.Entry<String, Value> {
                     key = keyPrime;
                 }
             } else {
-
                 key = name.toString();
             }
         }
@@ -79,5 +76,4 @@ public class MapItemValue implements Map.Entry<String, Value> {
         die("not that kind of Entry");
         return null;
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
index 3deb7ff..be0c397 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/NumberValue.java
@@ -17,6 +17,8 @@
  */
 package groovy.json.internal;
 
+import groovy.json.JsonException;
+
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.Arrays;
@@ -51,7 +53,6 @@ public class NumberValue extends java.lang.Number implements Value {
 
         try {
             if (chop) {
-
                 this.buffer = ArrayUtils.copyRange(buffer, startIndex, endIndex);
                 this.startIndex = 0;
                 this.endIndex = this.buffer.length;
@@ -62,9 +63,7 @@ public class NumberValue extends java.lang.Number implements Value {
                 this.buffer = buffer;
             }
         } catch (Exception ex) {
-            Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex),
-                    ex);
-
+            Exceptions.handle(sputs("exception", ex, "start", startIndex, "end", endIndex), ex);
         }
     }
 
@@ -81,12 +80,10 @@ public class NumberValue extends java.lang.Number implements Value {
     }
 
     public <T extends Enum> T toEnum(Class<T> cls) {
-
         return toEnum(cls, intValue());
     }
 
     public static <T extends Enum> T toEnum(Class<T> cls, int value) {
-
         T[] enumConstants = cls.getEnumConstants();
         for (T e : enumConstants) {
             if (e.ordinal() == value) {
@@ -102,12 +99,10 @@ public class NumberValue extends java.lang.Number implements Value {
     }
 
     private final Object doToValue() {
-
         switch (type) {
             case DOUBLE:
                 return bigDecimalValue();
             case INTEGER:
-
                 int sign = 1;
                 boolean negative = false;
                 if (buffer[startIndex] == '-') {
@@ -152,7 +147,11 @@ public class NumberValue extends java.lang.Number implements Value {
     }
 
     public BigDecimal bigDecimalValue() {
-        return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+        try {
+            return new BigDecimal(buffer, startIndex, endIndex - startIndex);
+        } catch (NumberFormatException e) {
+            throw new JsonException("unable to parse " + new String(buffer, startIndex, endIndex - startIndex), e);
+        }
     }
 
     public BigInteger bigIntegerValue() {
@@ -176,13 +175,11 @@ public class NumberValue extends java.lang.Number implements Value {
         if (buffer[startIndex] == '-') {
             startIndex++;
             sign = -1;
-
         }
         return parseIntFromTo(buffer, startIndex, endIndex) * sign;
     }
 
     public long longValue() {
-
         if (isInteger(buffer, startIndex, endIndex - startIndex)) {
             return parseIntFromTo(buffer, startIndex, endIndex);
         } else {
@@ -235,6 +232,4 @@ public class NumberValue extends java.lang.Number implements Value {
     public char charValue() {
         return buffer[startIndex];
     }
-
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
index c30e7b0..ad39936 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ReaderCharacterSource.java
@@ -68,7 +68,6 @@ public class ReaderCharacterSource implements CharacterSource {
     }
 
     private void ensureBuffer() {
-
         try {
             if (index >= length && !done) {
                 readNextBuffer();
@@ -114,7 +113,6 @@ public class ReaderCharacterSource implements CharacterSource {
 
     public final boolean consumeIfMatch(char[] match) {
         try {
-
             char[] _chars = readBuf;
             int i = 0;
             int idx = index;
@@ -139,7 +137,6 @@ public class ReaderCharacterSource implements CharacterSource {
             String str = CharScanner.errorDetails("consumeIfMatch issue", readBuf, index, ch);
             return Exceptions.handle(boolean.class, str, ex);
         }
-
     }
 
     public final int location() {
@@ -226,10 +223,13 @@ public class ReaderCharacterSource implements CharacterSource {
                 }
                 return results;
             } else {
-
                 if (index >= length && !done) {
                     ensureBuffer();
+                    boolean hasAlreadyFoundEscape = foundEscape;
                     char results2[] = findNextChar(match, esc);
+                    if (hasAlreadyFoundEscape) {
+                        foundEscape = true; //restore foundEscapeState
+                    }
                     return Chr.add(results, results2);
                 } else {
                     return Exceptions.die(char[].class, "Unable to find close char " + (char) match + " " + new String(results));
@@ -239,7 +239,6 @@ public class ReaderCharacterSource implements CharacterSource {
             String str = CharScanner.errorDetails("findNextChar issue", readBuf, index, ch);
             return Exceptions.handle(char[].class, str, ex);
         }
-
     }
 
     public boolean hadEscape() {
@@ -250,7 +249,6 @@ public class ReaderCharacterSource implements CharacterSource {
         try {
             index = CharScanner.skipWhiteSpace(readBuf, index, length);
             if (index >= length && more) {
-
                 ensureBuffer();
 
                 skipWhiteSpace();
@@ -283,12 +281,9 @@ public class ReaderCharacterSource implements CharacterSource {
             String str = CharScanner.errorDetails("readNumber issue", readBuf, index, ch);
             return Exceptions.handle(char[].class, str, ex);
         }
-
     }
 
     public String errorDetails(String message) {
-
         return CharScanner.errorDetails(message, readBuf, index, ch);
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
index 6e13cae..4948d29 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/SimpleCache.java
@@ -41,7 +41,6 @@ public class SimpleCache<K, V> implements Cache<K, V> {
     }
 
     public SimpleCache(final int limit, CacheType type) {
-
         if (type.equals(CacheType.LRU)) {
             map = new InternalCacheLinkedList<K, V>(limit, true);
         } else {
@@ -50,9 +49,7 @@ public class SimpleCache<K, V> implements Cache<K, V> {
     }
 
     public SimpleCache(final int limit) {
-
         map = new InternalCacheLinkedList<K, V>(limit, true);
-
     }
 
     public void put(K key, V value) {
@@ -85,5 +82,4 @@ public class SimpleCache<K, V> implements Cache<K, V> {
     public String toString() {
         return map.toString();
     }
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
index fa43c6a..25faddb 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/Sys.java
@@ -17,13 +17,10 @@
  */
 package groovy.json.internal;
 
-
-
 import java.math.BigDecimal;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-
 class Sys {
 
     private static final boolean is1_7OorLater;
@@ -31,39 +28,36 @@ class Sys {
     private static final boolean is1_7;
     private static final boolean is1_8;
 
-
     static {
-        BigDecimal v = new BigDecimal ( "-1" );
-        String sversion = System.getProperty ( "java.version" );
-        if ( sversion.indexOf ( "_" ) != -1 ) {
-            final String[] split = sversion.split ( "_" );
+        BigDecimal v = new BigDecimal("-1");
+        String sversion = System.getProperty("java.version");
+        if (sversion.indexOf("_") != -1) {
+            final String[] split = sversion.split("_");
             try {
+                String ver = split[0];
 
-                String ver = split [0];
-                if (ver.startsWith ( "1.8" )) {
-                    v = new BigDecimal ("1.8" );
-                }
-                if (ver.startsWith ( "1.7" )) {
-                    v = new BigDecimal ("1.7" );
+                if (ver.startsWith("1.8")) {
+                    v = new BigDecimal("1.8");
                 }
 
-                if (ver.startsWith ( "1.6" )) {
-                    v = new BigDecimal ("1.6" );
+                if (ver.startsWith("1.7")) {
+                    v = new BigDecimal("1.7");
                 }
 
-
-                if (ver.startsWith ( "1.5" )) {
-                    v = new BigDecimal ("1.5" );
+                if (ver.startsWith("1.6")) {
+                    v = new BigDecimal("1.6");
                 }
 
-
-                if (ver.startsWith ( "1.9" )) {
-                    v = new BigDecimal ("1.9" );
+                if (ver.startsWith("1.5")) {
+                    v = new BigDecimal("1.5");
                 }
 
-            } catch ( Exception ex ) {
-                ex.printStackTrace ();
-                System.err.println ( "Unable to determine build number or version" );
+                if (ver.startsWith("1.9")) {
+                    v = new BigDecimal("1.9");
+                }
+            } catch (Exception ex) {
+                ex.printStackTrace();
+                System.err.println("Unable to determine build number or version");
             }
         } else if ("1.8.0".equals(sversion)) {
             v = new BigDecimal("1.8");
@@ -71,26 +65,25 @@ class Sys {
             Pattern p = Pattern.compile("^([1-9]\\.[0-9]+)");
             Matcher matcher = p.matcher(sversion);
             if (matcher.find()) {
-                v = new BigDecimal ( matcher.group(0) );
+                v = new BigDecimal(matcher.group(0));
             }
         }
 
         version = v;
 
-        is1_7OorLater = version.compareTo ( new BigDecimal ( "1.7" )) >=0;
-        is1_7 = version.compareTo ( new BigDecimal ( "1.7" ))==0;
-        is1_8 = version.compareTo ( new BigDecimal ( "1.8" ))==0;
+        is1_7OorLater = version.compareTo(new BigDecimal("1.7")) >= 0;
+        is1_7 = version.compareTo(new BigDecimal("1.7")) == 0;
+        is1_8 = version.compareTo(new BigDecimal("1.8")) == 0;
     }
 
-
-
-    public static boolean is1_7OrLater () {
+    public static boolean is1_7OrLater() {
         return is1_7OorLater;
     }
 
     public static boolean is1_7() {
         return is1_7;
     }
+
     public static boolean is1_8() {
         return is1_8;
     }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
index 5a3bf58..4e11752 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueContainer.java
@@ -73,7 +73,6 @@ public class ValueContainer implements CharSequence, Value {
     }
 
     public boolean booleanValue() {
-
         switch (type) {
             case FALSE:
                 return false;
@@ -82,7 +81,6 @@ public class ValueContainer implements CharSequence, Value {
         }
         die();
         return false;
-
     }
 
     public String stringValue() {
@@ -116,7 +114,6 @@ public class ValueContainer implements CharSequence, Value {
         }
         die();
         return null;
-
     }
 
     public <T extends Enum> T toEnum(Class<T> cls) {
@@ -173,6 +170,4 @@ public class ValueContainer implements CharSequence, Value {
     public float floatValue() {
         return 0;
     }
-
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
index f1f06a8..d41555d 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueList.java
@@ -37,7 +37,6 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
     }
 
     public Object get(int index) {
-
         Object obj = list.get(index);
 
         if (obj instanceof Value) {
@@ -47,7 +46,6 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
 
         chopIfNeeded(obj);
         return obj;
-
     }
 
     private Object convert(Value value) {
@@ -70,7 +68,6 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
                 this.get(index);
             }
         }
-
     }
 
     public void clear() {
@@ -82,7 +79,6 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
     }
 
     public void chopList() {
-
         for (Object obj : list) {
             if (obj == null) continue;
 
@@ -107,7 +103,6 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
                 list.chopList();
             }
         }
-
     }
 
     void chopContainer(Value value) {
@@ -125,4 +120,3 @@ public class ValueList extends AbstractList<Object> implements List<Object> {
         return this.list;
     }
 }
-
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
index 8c6e4e5..f74c51a 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMap.java
@@ -42,5 +42,4 @@ public interface ValueMap<K, V> extends Map<K, V> {
      * Realize that the array is likely larger than the length so array items can be null.
      */
     Entry<String, Value>[] items();
-
 }
diff --git a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
index 004d964..9d1ae76 100644
--- a/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
+++ b/subprojects/groovy-json/src/main/java/groovy/json/internal/ValueMapImpl.java
@@ -139,6 +139,4 @@ public class ValueMapImpl extends AbstractMap<String, Value> implements ValueMap
         this.buildIfNeededMap();
         return map.size();
     }
-
 }
-
diff --git a/subprojects/groovy-json/src/spec/doc/json-builder.adoc b/subprojects/groovy-json/src/spec/doc/json-builder.adoc
new file mode 100644
index 0000000..d1463d2
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/doc/json-builder.adoc
@@ -0,0 +1,22 @@
+= JsonBuilder
+
+Groovys `JsonBuilder` makes it easy to create Json. For example to create this Json string:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy[tags=json_string,indent=0]
+----
+
+you can use a `JsonBuilder` like this:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy[tags=json_builder,indent=0]
+----
+
+We use https://github.com/lukas-krecan/JsonUnit[JsonUnit] to check that the builder produced the expected result:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy[tags=json_assert,indent=0]
+----
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/spec/doc/json-userguide.adoc b/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
index ec8a764..c1558f5 100644
--- a/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
+++ b/subprojects/groovy-json/src/spec/doc/json-userguide.adoc
@@ -1,6 +1,173 @@
-= Processing JSON (TBD)
-:toc:
-:icons:
-:linkcss!:
+= Processing JSON
 
+Groovy comes with integrated support for converting between Groovy objects and JSON. The classes dedicated to
+JSON serialisation and parsing are found in the `groovy.json` package.
 
+[[json_jsonslurper]]
+== JsonSlurper
+
+`JsonSlurper` is a class that parses JSON text or reader content into Groovy data structures (objects) such as maps, lists and
+primitive types like `Integer`, `Double`, `Boolean` and `String`.
+
+The class comes with a bunch of overloaded `parse` methods plus some special methods such as `parseText`,
+`parseFile` and others. For the next example we will use the `parseText` method. It parses a JSON `String` and recursively converts it to a
+list or map of objects. The other `parse*` methods are similar in that they return a JSON `String` but for different parameter
+types.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=parse_text,indent=0]
+----
+
+Notice the result is a plain map and can be handled like a normal Groovy object instance. `JsonSlurper` parses the
+given JSON as defined by the http://www.ecma-international.org/publications/files/ECMA-ST/ECMA-404.pdf[ECMA-404 JSON Interchange Standard]
+plus support for JavaScript comments and dates.
+
+In addition to maps `JsonSlurper` supports JSON arrays which are being converted to lists.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=parse_list,indent=0]
+----
+
+The JSON standard supports the following primitive data types: string, number, object, `true`, `false` and `null`. `JsonSlurper`
+converts these JSON types into corresponding Groovy types.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=parse_number,indent=0]
+----
+
+As `JsonSlurper` is returning pure Groovy object instances without any special JSON classes in the back, its usage
+is transparent. In fact, `JsonSlurper` results conform to GPath expressions. GPath is a powerful expression language
+that is supported by multiple slurpers for different data formats (`XmlSlurper` for XML being one example).
+
+[NOTE]
+For more details please have a look at the section on <<core-semantics.adoc#gpath_expressions,GPath expressions>>.
+
+The following table gives an overview of the JSON types and the corresponding Groovy data types:
+
+[cols="1,3" options="header"]
+|===
+|JSON
+|Groovy
+
+|string
+|`java.lang.String`
+
+|number
+|`java.lang.BigDecimal` or `java.lang.Integer`
+
+|object
+|`java.util.LinkedHashMap`
+
+|array
+|`java.util.ArrayList`
+
+|true
+|`true`
+
+|false
+|`false`
+
+|null
+|`null`
+
+|date
+|`java.util.Date` based on the `yyyy-MM-dd'T'HH:mm:ssZ` date format
+|===
+
+[NOTE]
+Whenever a value in JSON is `null`, `JsonSlurper` supplements it with the Groovy `null` value. This is in contrast to other
+JSON parsers that represent a `null` value with a library-provided singleton object.
+
+=== Parser Variants
+
+`JsonSlurper` comes with a couple of parser implementations. Each parser fits different requirements, it could well be that for certain
+scenarios the `JsonSlurper` default parser is not the best bet for all situations. Here is an overview of the shipped parser implementations:
+
+* The `JsonParserCharArray` parser basically takes a JSON string and operates on the underlying character array. During value
+conversion it copies character sub-arrays (a mechanism known as "chopping") and operates on them.
+
+* The `JsonFastParser` is a special variant of the `JsonParserCharArray` and is the fastest parser. However, it is not the
+default parser for a reason. `JsonFastParser` is a so-called index-overlay parser. During parsing of the given JSON `String` it
+tries as hard as possible to avoid creating new char arrays or `String` instances. It keeps pointers to
+the underlying original character array only. In addition, it defers object creation as late as possible. If parsed maps are
+put into long-term caches care must be taken as the map objects might not be created and still consist of pointer to the
+original char buffer only. However, `JsonFastParser` comes with a special chop mode which dices up the char buffer
+early to keep a small copy of the original buffer. Recommendation is to use the `JsonFastParser` for JSON buffers
+under 2MB and keeping the long-term cache restriction in mind.
+
+* The `JsonParserLax` is a special variant of the `JsonParserCharArray` parser. It has similar performance characteristics as `JsonFastParser`
+ but differs in that it isn't exclusively relying on the ECMA-404 JSON grammar. For example it allows for comments, no quote strings etc.
+
+* The `JsonParserUsingCharacterSource` is a special parser for very large files. It uses a technique called "character windowing" to
+parse large JSON files (large means files over 2MB size in this case) with constant performance characteristics.
+
+The default parser implementation for `JsonSlurper` is `JsonParserCharArray`. The `JsonParserType` enumeration contains constants for
+the parser implementations described above:
+
+[cols="1,3" options="header"]
+|===
+|Implementation
+|Constant
+
+|`JsonParserCharArray`
+|`JsonParserType#CHAR_BUFFER`
+
+|`JsonFastParser`
+|`JsonParserType#INDEX_OVERLAY`
+
+|`JsonParserLax`
+|`JsonParserType#LAX`
+
+|`JsonParserUsingCharacterSource`
+|`JsonParserType#CHARACTER_SOURCE`
+|===
+
+Changing the parser implementation is as easy as setting the `JsonParserType` with a call to `JsonSlurper#setType()`.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=set_type,indent=0]
+----
+
+== JsonOutput
+
+`JsonOutput` is responsible for serialising Groovy objects into JSON strings. It can be seen as companion object to
+<<json-userguide.adoc#json_jsonslurper,JsonSlurper>>, being a JSON parser.
+
+`JsonOutput` comes with overloaded, static `toJson` methods. Each `toJson` implementation takes a different parameter type.
+The static method can either be used directly or by importing the methods with a static import statement.
+
+The result of a `toJson` call is a `String` containing the JSON code.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=json_output,indent=0]
+----
+
+`JsonOutput` does not only support primitive, maps or list data types to be serialized to JSON, it goes further and even
+has support for serialising POGOs, that is, plain-old Groovy objects.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=json_output_pogo,indent=0]
+----
+
+As we saw in previous examples, the JSON output is not pretty printed per default. However, the `prettyPrint` method in `JsonSlurper` comes
+to rescue for this task.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy[tags=pretty_print,indent=0]
+----
+
+`prettyPrint` takes a `String` as single parameter. It must not be used in conjunction with the other `JsonOutput` methods,
+it can be applied on arbitrary JSON `String` instances.
+
+Another way to create JSON from Groovy is to use the `JsonBuilder` or `StreamingJsonBuilder`. Both builders provide a
+DSL which allows to formulate an object graph which is then converted to JSON at some point.
+
+[NOTE]
+For more details on builders, have a look at the builders chapter which covers both JSON builders in great depth.
diff --git a/subprojects/groovy-json/src/spec/doc/streaming-jason-builder.adoc b/subprojects/groovy-json/src/spec/doc/streaming-jason-builder.adoc
new file mode 100644
index 0000000..1ac5787
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/doc/streaming-jason-builder.adoc
@@ -0,0 +1,26 @@
+= StreamingJsonBuilder
+
+Unlike `JsonBuilder` which creates a data structure in memory, which is handy in those situations where you want to alter the structure programmatically before output,
+`StreamingJsonBuilder` directly streams to a writer without any intermediate memory data structure.
+If you do not need to modify the structure and want a more memory-efficient approach, use `StreamingJsonBuilder`.
+
+The usage of `StreamingJsonBuilder` is similar to `JsonBuilder`. In order to create this Json string:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy[tags=json_string,indent=0]
+----
+
+you use a `StreamingJsonBuilder` like this:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy[tags=streaming_json_builder,indent=0]
+----
+
+We use https://github.com/lukas-krecan/JsonUnit[JsonUnit] to check the expected result:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy[tags=json_assert,indent=0]
+----
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/spec/test/JsonBuilderTest2.groovy b/subprojects/groovy-json/src/spec/test/JsonBuilderTest2.groovy
new file mode 100644
index 0000000..178ff70
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/test/JsonBuilderTest2.groovy
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.json
+import groovy.util.GroovyTestCase
+import org.junit.Test
+//import groovy.json.JsonBuilder
+
+/**
+* Tests for JsonBuilder. The tests directly in this file are specific
+* to JsonBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class JsonBuilderTest2  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::jsonbuilder_nullobject1[]
+    JsonBuilder jsonbuilder;
+    
+    // jsonbuilder should be null when not initialized
+    assert jsonbuilder == null;
+// end::jsonbuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::jsonbuilder_nullobject2[]
+    JsonBuilder jsonbuilder = null;
+    
+    // jsonbuilder should be null when initialized to null
+    assert jsonbuilder == null;
+// end::jsonbuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::jsonbuilder_object_exists1[]
+    JsonBuilder jsonbuilder = new JsonBuilder();
+    
+    // jsonbuilder should not be null after construction
+    assert jsonbuilder != null;
+// end::jsonbuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::jsonbuilder_object_exists2[]
+    JsonBuilder jsonbuilder = new JsonBuilder();
+    
+    // jsonbuilder should be an instance of correct JsonBuilder class
+    assert jsonbuilder instanceof JsonBuilder, 'default JsonBuilder constructor did not build a version of JsonBuilder'
+// end::jsonbuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::jsonbuilder_object_exists3[]
+        // jsonbuilder does not throw an exception when null parm used in constructor
+        JsonBuilder jsonbuilder = new JsonBuilder(null);
+// end::jsonbuilder_object_exists3[]
+    } // end of method
+
+} // end of JsonBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/spec/test/StreamingJsonBuilderTest2.groovy b/subprojects/groovy-json/src/spec/test/StreamingJsonBuilderTest2.groovy
new file mode 100644
index 0000000..c2fc7e7
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/test/StreamingJsonBuilderTest2.groovy
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.json
+import groovy.util.GroovyTestCase
+import org.junit.Test
+//import groovy.json.StreamingJsonBuilder
+
+/**
+* Tests for StreamingJsonBuilder. The tests directly in this file are specific
+* to StreamingJsonBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class StreamingJsonBuilderTest2  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::streamingjsonbuilder_nullobject1[]
+    StreamingJsonBuilder streamingjsonbuilder;
+    
+    // streamingjsonbuilder should be null when not initialized
+    assert streamingjsonbuilder == null;
+// end::streamingjsonbuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::streamingjsonbuilder_nullobject2[]
+    StreamingJsonBuilder streamingjsonbuilder = null;
+    
+    // streamingjsonbuilder should be null when initialized to null
+    assert streamingjsonbuilder == null;
+// end::streamingjsonbuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::streamingjsonbuilder_object_exists1[]
+    shouldFail 
+    {
+        // streamingjsonbuilder should not be null after construction
+        StreamingJsonBuilder streamingjsonbuilder = new StreamingJsonBuilder();
+    }
+// end::streamingjsonbuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::streamingjsonbuilder_object_exists2[]
+    shouldFail 
+    {
+        // streamingjsonbuilder should be an instance of correct StreamingJsonBuilder class
+        StreamingJsonBuilder streamingjsonbuilder = new StreamingJsonBuilder();
+    }
+// end::streamingjsonbuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::streamingjsonbuilder_object_exists3[]
+    // streamingjsonbuilder should throw an exception when null parm used in constructor
+        StreamingJsonBuilder streamingjsonbuilder = new StreamingJsonBuilder(null);
+// end::streamingjsonbuilder_object_exists3[]
+    } // end of method
+
+} // end of StreamingJsonBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy b/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy
new file mode 100644
index 0000000..e2838d3
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/test/json/JsonBuilderTest.groovy
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package json
+
+class JsonBuilderTest extends GroovyTestCase {
+
+    void testJsonBuilder() {
+        assertScript """
+            import groovy.json.*
+            @Grapes([
+                @Grab('com.google.code.gson:gson:2.3.1'), //required by json-unit
+                @Grab('net.javacrumbs.json-unit:json-unit:1.5.2')])
+            import net.javacrumbs.jsonunit.JsonAssert
+
+            // tag::json_string[]
+            String carRecords = '''
+                {
+                    "records": {
+                    "car": {
+                        "name": "HSV Maloo",
+                        "make": "Holden",
+                        "year": 2006,
+                        "country": "Australia",
+                        "record": {
+                          "type": "speed",
+                          "description": "production pickup truck with speed of 271kph"
+                        }
+                      }
+                  }
+                }
+            '''
+            // end::json_string[]
+            
+            // tag::json_builder[]
+            JsonBuilder builder = new JsonBuilder()
+            builder.records {
+              car {
+                    name 'HSV Maloo'
+                    make 'Holden'
+                    year 2006 
+                    country 'Australia'
+                    record {
+                        type 'speed'
+                        description 'production pickup truck with speed of 271kph'
+                    }
+              }
+            }
+            String json = JsonOutput.prettyPrint(builder.toString())
+            // end::json_builder[]
+            
+            // tag::json_assert[]
+            JsonAssert.assertJsonEquals(json, carRecords)
+            // end::json_assert[]
+       """
+    }
+}
diff --git a/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
new file mode 100644
index 0000000..3da75b7
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/test/json/JsonTest.groovy
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package json
+
+import groovy.json.JsonOutput
+import groovy.json.JsonParserType
+import groovy.json.JsonSlurper
+
+class JsonTest extends GroovyTestCase {
+
+    void testParseText() {
+        // tag::parse_text[]
+        def jsonSlurper = new JsonSlurper()
+        def object = jsonSlurper.parseText('{ "name": "John Doe" } /* some comment */')
+
+        assert object instanceof Map
+        assert object.name == 'John Doe'
+        // end::parse_text[]
+    }
+
+    void testParseTextWithNumber() {
+        // tag::parse_number[]
+        def jsonSlurper = new JsonSlurper()
+        def object = jsonSlurper.parseText '''
+            { "simple": 123,
+              "fraction": 123.66,
+              "exponential": 123e12
+            }'''
+
+        assert object instanceof Map
+        assert object.simple.class == Integer
+        assert object.fraction.class == BigDecimal
+        assert object.exponential.class == BigDecimal
+        // end::parse_number[]
+    }
+
+    void testParseTextWithList() {
+        // tag::parse_list[]
+        def jsonSlurper = new JsonSlurper()
+        def object = jsonSlurper.parseText('{ "myList": [4, 8, 15, 16, 23, 42] }')
+
+        assert object instanceof Map
+        assert object.myList instanceof List
+        assert object.myList == [4, 8, 15, 16, 23, 42]
+        // end::parse_list[]
+    }
+
+    void testSetType() {
+        // tag::set_type[]
+        def jsonSlurper = new JsonSlurper(type: JsonParserType.INDEX_OVERLAY)
+        def object = jsonSlurper.parseText('{ "myList": [4, 8, 15, 16, 23, 42] }')
+
+        assert object instanceof Map
+        assert object.myList instanceof List
+        assert object.myList == [4, 8, 15, 16, 23, 42]
+        // end::set_type[]
+    }
+
+    void testJsonOutput() {
+        // tag::json_output[]
+        def json = JsonOutput.toJson([name: 'John Doe', age: 42])
+
+        assert json == '{"name":"John Doe","age":42}'
+        // end::json_output[]
+    }
+
+    void testJsonOutputPogo() {
+        assertScript '''
+        import groovy.json.*
+
+        // tag::json_output_pogo[]
+        class Person { String name }
+
+        def json = JsonOutput.toJson([ new Person(name: 'John'), new Person(name: 'Max') ])
+
+        assert json == '[{"name":"John"},{"name":"Max"}]'
+        // end::json_output_pogo[]
+        '''
+    }
+
+    void testPrettyPrint() {
+        // tag::pretty_print[]
+        def json = JsonOutput.toJson([name: 'John Doe', age: 42])
+
+        assert json == '{"name":"John Doe","age":42}'
+
+        assert JsonOutput.prettyPrint(json) == '''\
+        {
+            "name": "John Doe",
+            "age": 42
+        }'''.stripIndent()
+        // end::pretty_print[]
+    }
+
+}
diff --git a/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy b/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy
new file mode 100644
index 0000000..678f8b7
--- /dev/null
+++ b/subprojects/groovy-json/src/spec/test/json/StreamingJsonBuilderTest.groovy
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package json
+
+import groovy.util.GroovyTestCase
+
+class StreamingJsonBuilderTest extends GroovyTestCase {
+
+    void testStreamingJsonBuilder() {
+        assertScript """
+            import groovy.json.*
+            @Grapes([
+                @Grab('com.google.code.gson:gson:2.3.1'), //required by json-unit
+                @Grab('net.javacrumbs.json-unit:json-unit:1.5.2')])
+            import net.javacrumbs.jsonunit.JsonAssert
+
+            // tag::json_string[]
+            String carRecords = '''
+                {
+                    "records": {
+                    "car": {
+                        "name": "HSV Maloo",
+                        "make": "Holden",
+                        "year": 2006,
+                        "country": "Australia",
+                        "record": {
+                          "type": "speed",
+                          "description": "production pickup truck with speed of 271kph"
+                        }
+                      }
+                  }
+                }
+            '''
+            // end::json_string[]
+            
+            // tag::streaming_json_builder[]
+            StringWriter writer = new StringWriter()
+            StreamingJsonBuilder builder = new StreamingJsonBuilder(writer)
+            builder.records {
+              car {
+                    name 'HSV Maloo'
+                    make 'Holden'
+                    year 2006 
+                    country 'Australia'
+                    record {
+                        type 'speed'
+                        description 'production pickup truck with speed of 271kph'
+                    }
+              }
+            }
+            String json = JsonOutput.prettyPrint(writer.toString())
+            // end::streaming_json_builder[]
+            
+            // tag::json_assert[]
+            JsonAssert.assertJsonEquals(json, carRecords)
+            // end::json_assert[]
+       """
+    }
+}
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
index d4160b9..8c3bb7a 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/CharBufTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.json
 
 import groovy.json.internal.CharBuf
@@ -13,35 +28,35 @@ class CharBufTest extends GroovyTestCase {
     void testUnicodeAndControl() {
         String str = CharBuf.create(0).addJsonEscapedString("\u0001").toString()
         assert str == '"\\u0001"'
-        
-        str =  CharBuf.create(0).addJsonEscapedString("\u00ff").toString()
+
+        str = CharBuf.create(0).addJsonEscapedString("\u00ff").toString()
         assert str == '"\\u00ff"'
 
-        str =  CharBuf.create(0).addJsonEscapedString("\u0fff").toString()
+        str = CharBuf.create(0).addJsonEscapedString("\u0fff").toString()
         assert str == '"\\u0fff"'
 
-        str =  CharBuf.create(0).addJsonEscapedString("\uefef").toString()
+        str = CharBuf.create(0).addJsonEscapedString("\uefef").toString()
         assert str == '"\\uefef"'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \b ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \b ").toString()
         assert str == '" \\b "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \r ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \r ").toString()
         assert str == '" \\r "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \n ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \n ").toString()
         assert str == '" \\n "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \n ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \n ").toString()
         assert str == '" \\n "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \f ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \f ").toString()
         assert str == '" \\f "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(' " Hi mom " ').toString()
+        str = CharBuf.create(0).addJsonEscapedString(' " Hi mom " ').toString()
         assert str == '" \\" Hi mom \\" "'
 
-        str =  CharBuf.create(0).addJsonEscapedString(" \\ ").toString()
+        str = CharBuf.create(0).addJsonEscapedString(" \\ ").toString()
         assert str == '" \\\\ "'
     }
 
@@ -57,7 +72,7 @@ class CharBufTest extends GroovyTestCase {
         // CharBuf used underneath through JsonBuilder and JsonOutput
         def obj = [
                 "\u0391\u03a6\u039f\u0399 \u039a\u039f\u039b\u039b\u0399\u0391 \u039a\u03a1\u0395\u03a9\u03a0\u039f\u039b\u0395\u0399\u039f \u03a4\u0391\u0392\u0395\u03a1\u039d\u0391",
-                   "\u039a\u03b1\u03bb\u03cd\u03b2\u03b9\u03b1 \u0398\u03bf\u03c1\u03b9\u03ba\u03bf\u03cd"
+                "\u039a\u03b1\u03bb\u03cd\u03b2\u03b9\u03b1 \u0398\u03bf\u03c1\u03b9\u03ba\u03bf\u03cd"
         ]
         def result = new JsonBuilder(obj).toString()
         assert result == '["\\u0391\\u03a6\\u039f\\u0399 \\u039a\\u039f\\u039b\\u039b\\u0399\\u0391 \\u039a\\u03a1\\u0395\\u03a9\\u03a0\\u039f\\u039b\\u0395\\u0399\\u039f \\u03a4\\u0391\\u0392\\u0395\\u03a1\\u039d\\u0391","\\u039a\\u03b1\\u03bb\\u03cd\\u03b2\\u03b9\\u03b1 \\u0398\\u03bf\\u03c1\\u03b9\\u03ba\\u03bf\\u03cd"]'
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/DateFormatThreadLocalTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/DateFormatThreadLocalTest.groovy
deleted file mode 100644
index 1033bc4..0000000
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/DateFormatThreadLocalTest.groovy
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright 2003-2014 the original author or authors.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-package groovy.json
-
-import java.text.SimpleDateFormat
-
-/**
- * @author Andrey Bloschetsov
- */
-class DateFormatThreadLocalTest extends GroovyTestCase {
-
-    void testFormat() {
-        // 14 March 2014, 9:18:12 in Moscow
-        Calendar now = Calendar.getInstance(TimeZone.getTimeZone('Europe/Moscow'))
-        now.set(year: 2014, month: Calendar.MARCH, date: 14, hourOfDay: 9, minute: 18, second: 12)
-
-        SimpleDateFormat formatter = new DateFormatThreadLocal().get()
-        assert formatter.format(now.getTime()) == '2014-03-14T05:18:12+0000' // When in Moscow 9am in London 5am
-    }
-}
\ No newline at end of file
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
new file mode 100644
index 0000000..96ded55
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/IOTest.groovy
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.json
+
+import groovy.json.internal.CharBuf
+import groovy.json.internal.IO
+
+/**
+ * Test the internal IO class
+ *
+ * @author Martin Stockhammer
+ */
+class IOTest extends GroovyTestCase {
+
+    public static final String TEST_STRING = '{"results":[{"columns":["n"],"data":[{"row":[{"name":"Alin Coen Band","type":"group"}]}]}],"errors":[]}'
+
+    int bufSize = 256
+
+    void testReadProper() {
+        IO io = new IO()
+        ProperReader reader = new ProperReader();
+        CharBuf buffer = io.read(reader, null, bufSize)
+        int len = buffer.len()
+        char[] rbuf = buffer.readForRecycle()
+        String result = new String(rbuf, 0, len)
+        assertEquals(TEST_STRING, result)
+    }
+
+    /**
+     * See https://jira.codehaus.org/browse/GROOVY-7132
+     */
+    void testReadBumpy() {
+        IO io = new IO()
+        BumpyReader reader = new BumpyReader();
+        CharBuf buffer = io.read(reader, null, bufSize)
+        int len = buffer.len()
+        char[] rbuf = buffer.readForRecycle()
+        String result = new String(rbuf, 0, len)
+        assertEquals(TEST_STRING, result)
+    }
+}
+
+/**
+ * This reader fills the char array at certain points only partially
+ * and returns a value < char_array.length
+ */
+class BumpyReader extends Reader {
+
+    int index = 0;
+    def stopIndex = [69, 84, 500]
+    int nextStop = 0;
+
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        if (index >= IOTest.TEST_STRING.size()) {
+            return -1
+        }
+        int num = 0
+        while (num < len && index < stopIndex[nextStop] && index < IOTest.TEST_STRING.size()) {
+            cbuf[off + num] = IOTest.TEST_STRING[index]
+            num++
+            index++
+        }
+        if (index == stopIndex[nextStop]) {
+            nextStop++
+        }
+        return num;
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+}
+
+/**
+ * This reader fills always the char array completely until reaching the end
+ * of the string.
+ */
+class ProperReader extends Reader {
+
+    int index = 0;
+
+    @Override
+    public int read(char[] cbuf, int off, int len) throws IOException {
+        if (index >= IOTest.TEST_STRING.size()) {
+            return -1
+        }
+        int num = 0
+        while (num < len && index < IOTest.TEST_STRING.size()) {
+            cbuf[off + num] = IOTest.TEST_STRING[index]
+            num++
+            index++
+        }
+        return num;
+    }
+
+    @Override
+    public void close() throws IOException {
+    }
+}
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy
index 73098b7..35fdef5 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonBuilderTest.groovy
@@ -138,7 +138,7 @@ class JsonBuilderTest extends GroovyTestCase {
     }
 
     void testCollectionAndClosure() {
-        def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         def json = new JsonBuilder()
         json authors, { Author author ->
@@ -149,7 +149,7 @@ class JsonBuilderTest extends GroovyTestCase {
     }
 
     void testMethodWithCollectionAndClosure() {
-        def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         def json = new JsonBuilder()
         json.authors authors, { Author author ->
@@ -160,7 +160,7 @@ class JsonBuilderTest extends GroovyTestCase {
     }
 
     void testNestedMethodWithCollectionAndClosure() {
-        def theAuthors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def theAuthors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         def json = new JsonBuilder()
         json {
@@ -210,7 +210,7 @@ class JsonBuilderTest extends GroovyTestCase {
     void testNestedListMap() {
         def json = new JsonBuilder()
         json.content {
-            list([:],[another:[a:[1,2,3]]])
+            list([:], [another: [a: [1, 2, 3]]])
         }
 
         assert json.toString() == '''{"content":{"list":[{},{"another":{"a":[1,2,3]}}]}}'''
@@ -305,7 +305,7 @@ class JsonBuilderTest extends GroovyTestCase {
     void testStringEscape() {
         def original, serialized, deserialized
 
-        original = [elem:"\\n"]
+        original = [elem: "\\n"]
         serialized = (new JsonBuilder(original)).toString()
         deserialized = (new JsonSlurper()).parseText(serialized)
         assert original.elem == deserialized.elem
@@ -324,6 +324,17 @@ class JsonBuilderTest extends GroovyTestCase {
         serialized = (new JsonBuilder(original)).toString()
         deserialized = (new JsonSlurper()).parseText(serialized)
         assert original.elem == deserialized.elem
+    }
 
+    void testSpecialCharEscape() {
+        assert new JsonBuilder({'"' 0}).toString() == '{"\\"":0}'
+        assert new JsonBuilder({'\b' 0}).toString() == '{"\\b":0}'
+        assert new JsonBuilder({'\f' 0}).toString() == '{"\\f":0}'
+        assert new JsonBuilder({'\n' 0}).toString() == '{"\\n":0}'
+        assert new JsonBuilder({'\r' 0}).toString() == '{"\\r":0}'
+        assert new JsonBuilder({'\t' 0}).toString() == '{"\\t":0}'
+        assert new JsonBuilder({'\\' 0}).toString() == '{"\\\\":0}'
+        assert new JsonBuilder({'\1' 0}).toString() == '{"\\u0001":0}'
+        assert new JsonBuilder({'\u0002' 0}).toString() == '{"\\u0002":0}'
     }
 }
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonLexerTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonLexerTest.groovy
index 729c72e..4e72e96 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonLexerTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonLexerTest.groovy
@@ -16,8 +16,8 @@
 package groovy.json
 
 import static groovy.json.JsonTokenType.*
-import groovy.io.LineColumnReader
 
+import groovy.io.LineColumnReader
 
 /**
  * @author Guillaume Laforge
@@ -112,7 +112,7 @@ class JsonLexerTest extends GroovyTestCase {
     void testUnescapingWithLexer() {
         // use string concatenation so that the unicode escape characters are not decoded 
         // by Groovy's lexer but by the JsonLexer
-        def lexer = new JsonLexer(new StringReader('"\\' + 'u004A\\' + 'u0053\\' + 'u004F\\' + 'u004E"')) 
+        def lexer = new JsonLexer(new StringReader('"\\' + 'u004A\\' + 'u0053\\' + 'u004F\\' + 'u004E"'))
 
         assert lexer.nextToken().value == 'JSON'
     }
@@ -129,7 +129,7 @@ class JsonLexerTest extends GroovyTestCase {
 
         // use string concatenation so that the unicode escape characters are not decoded
         // by Groovy's lexer but by the JsonLexer
-        assert JsonLexer.unescape('\\' + 'u004A\\' + 'u0053\\' + 'u004F\\' + 'u004E') == 'JSON' 
+        assert JsonLexer.unescape('\\' + 'u004A\\' + 'u0053\\' + 'u004F\\' + 'u004E') == 'JSON'
     }
 
     void testBackSlashEscaping() {
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
index 6376af3..6e16b30 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonOutputTest.groovy
@@ -16,6 +16,7 @@
 package groovy.json
 
 import static groovy.json.JsonOutput.toJson
+
 import groovy.transform.Canonical
 
 /**
@@ -23,11 +24,11 @@ import groovy.transform.Canonical
  * @author Andrey Bloschetsov
  */
 class JsonOutputTest extends GroovyTestCase {
-    
+
     // Check for GROOVY-5918
     void testExpando() {
-        assert toJson( new Expando( a:42 ) ) == '{"a":42}'
-        assert new JsonBuilder( new Expando( a:42 ) ).toString() == '{"a":42}'
+        assert toJson(new Expando(a: 42)) == '{"a":42}'
+        assert new JsonBuilder(new Expando(a: 42)).toString() == '{"a":42}'
     }
 
     void testBooleanValues() {
@@ -61,24 +62,25 @@ class JsonOutputTest extends GroovyTestCase {
         assert toJson(100) == "100"
         assert toJson(100) == "100"
 
-        assert toJson((short)100) == "100"
-        assert toJson((byte)100) == "100"
+        assert toJson((short) 100) == "100"
+        assert toJson((byte) 100) == "100"
 
         // Long
         assert toJson(1000000000000000000) == "1000000000000000000"
+
         // BigInteger
         assert toJson(1000000000000000000000000) == "1000000000000000000000000"
 
         // BigDecimal
         assert toJson(0.0) == "0.0"
-        assert toJson(0.0) == "0.0"
 
         // Double
         assert toJson(Math.PI) == "3.141592653589793"
+
         // Float
         assert toJson(1.2345f) == "1.2345"
 
-        // exponant
+        // exponent
         assert toJson(1234.1234e12) == "1.2341234E+15"
 
         shouldFail { toJson(Double.NaN) }
@@ -132,7 +134,7 @@ class JsonOutputTest extends GroovyTestCase {
 //        assert toJson("/") == '"\\/"'
         assert toJson("\\") == '"\\\\"'
 
-        assert toJson("\u0001") == '"\\u0001"' 
+        assert toJson("\u0001") == '"\\u0001"'
         assert toJson("\u0002") == '"\\u0002"'
         assert toJson("\u0003") == '"\\u0003"'
         assert toJson("\u0004") == '"\\u0004"'
@@ -189,7 +191,7 @@ class JsonOutputTest extends GroovyTestCase {
         assert toJson([name: 'Guillaume', age: 33, address: [line1: "1 main street", line2: "", zip: 1234], pets: ['dog', 'cat']]) ==
                 '{"name":"Guillaume","age":33,"address":{"line1":"1 main street","line2":"","zip":1234},"pets":["dog","cat"]}'
 
-        assert toJson([[:],[:]]) == '[{},{}]'
+        assert toJson([[:], [:]]) == '[{},{}]'
     }
 
     void testClosure() {
@@ -265,14 +267,15 @@ class JsonOutputTest extends GroovyTestCase {
             }""".stripIndent()
     }
 
-    private stripWhiteSpace( String str ) {
-      return str.replaceAll( ~/\s/, '' )
+    private stripWhiteSpace(String str) {
+        return str.replaceAll(~/\s/, '')
     }
+
     void testPrettyPrintStringZeroLen() {
-      def tree = [ myStrings: [ str3:'abc', str0:'' ] ]
-      def result   = stripWhiteSpace( new JsonBuilder( tree ).toPrettyString() )
-      def expected = stripWhiteSpace( '{ "myStrings":{ "str3":"abc","str0":"" } }' )
-      assert result == expected
+        def tree = [myStrings: [str3: 'abc', str0: '']]
+        def result = stripWhiteSpace(new JsonBuilder(tree).toPrettyString())
+        def expected = stripWhiteSpace('{ "myStrings":{ "str3":"abc","str0":"" } }')
+        assert result == expected
     }
 
     void testPrettyPrintDoubleQuoteEscape() {
@@ -290,10 +293,10 @@ class JsonOutputTest extends GroovyTestCase {
         def city = new JsonCity("Paris", [
                 new JsonDistrict(1, [
                         new JsonStreet("Saint-Honore", JsonStreetKind.street),
-                        new JsonStreet("de l'Opera",   JsonStreetKind.avenue)
+                        new JsonStreet("de l'Opera", JsonStreetKind.avenue)
                 ] as JsonStreet[]),
                 new JsonDistrict(2, [
-                        new JsonStreet("des Italiens",   JsonStreetKind.boulevard),
+                        new JsonStreet("des Italiens", JsonStreetKind.boulevard),
                         new JsonStreet("Bonne Nouvelle", JsonStreetKind.boulevard)
                 ] as JsonStreet[])
         ])
@@ -344,16 +347,16 @@ class JsonOutputTest extends GroovyTestCase {
         assert toJson(m) == '{"a":1}'
     }
 
-	void testObjectWithDeclaredPropertiesField() {
-		def person = new JsonObject(name: "pillow", properties: [state: "fluffy", color: "white"])
-		def json = toJson(person)
-		assert json == '{"properties":{"state":"fluffy","color":"white"},"name":"pillow"}'
-	}
-	
-	void testGROOVY5494() {
-		def json = toJson(new JsonFoo(name: "foo"))
-		assert json == '{"properties":0,"name":"foo"}'
-	}
+    void testObjectWithDeclaredPropertiesField() {
+        def person = new JsonObject(name: "pillow", properties: [state: "fluffy", color: "white"])
+        def json = toJson(person)
+        assert json == '{"properties":{"state":"fluffy","color":"white"},"name":"pillow"}'
+    }
+
+    void testGROOVY5494() {
+        def json = toJson(new JsonFoo(name: "foo"))
+        assert json == '{"properties":0,"name":"foo"}'
+    }
 
     void testCharacter() {
         assert toJson('a' as char) == '"a"'
@@ -367,6 +370,48 @@ class JsonOutputTest extends GroovyTestCase {
         assert toJson(1 as char) == '"\\u0001"'
         assert toJson('\u0002' as char) == '"\\u0002"'
     }
+
+    void testEmptyValue() {
+        assert toJson('') == '""'
+        assert toJson(['']) == '[""]'
+        assert toJson(['': '']) == '{"":""}'
+        assert toJson(new Expando('': '')) == '{"":""}'
+    }
+
+    void testSpecialCharEscape() {
+        // Map
+        assert toJson(['"': 0]) == '{"\\"":0}'
+        assert toJson(['\b': 0]) == '{"\\b":0}'
+        assert toJson(['\f': 0]) == '{"\\f":0}'
+        assert toJson(['\n': 0]) == '{"\\n":0}'
+        assert toJson(['\r': 0]) == '{"\\r":0}'
+        assert toJson(['\t': 0]) == '{"\\t":0}'
+        assert toJson(['\\': 0]) == '{"\\\\":0}'
+        assert toJson([(1 as char): 0]) == '{"\\u0001":0}'
+        assert toJson(['\u0002': 0]) == '{"\\u0002":0}'
+
+        // Expando
+        assert toJson(new Expando('"': 0)) == '{"\\"":0}'
+        assert toJson(new Expando('\b': 0)) == '{"\\b":0}'
+        assert toJson(new Expando('\f': 0)) == '{"\\f":0}'
+        assert toJson(new Expando('\n': 0)) == '{"\\n":0}'
+        assert toJson(new Expando('\r': 0)) == '{"\\r":0}'
+        assert toJson(new Expando('\t': 0)) == '{"\\t":0}'
+        assert toJson(new Expando('\\': 0)) == '{"\\\\":0}'
+        assert toJson(new Expando((1 as char): 0)) == '{"\\u0001":0}'
+        assert toJson(new Expando('\u0002': 0)) == '{"\\u0002":0}'
+
+        // Closure
+        assert toJson({'"' 0}) == '{"\\"":0}'
+        assert toJson({'\b' 0}) == '{"\\b":0}'
+        assert toJson({'\f' 0}) == '{"\\f":0}'
+        assert toJson({'\n' 0}) == '{"\\n":0}'
+        assert toJson({'\r' 0}) == '{"\\r":0}'
+        assert toJson({'\t' 0}) == '{"\\t":0}'
+        assert toJson({'\\' 0}) == '{"\\\\":0}'
+        assert toJson({'\1' 0}) == '{"\\u0001":0}'
+        assert toJson({'\u0002' 0}) == '{"\\u0002":0}'
+    }
 }
 
 @Canonical
@@ -388,13 +433,13 @@ class JsonStreet {
 }
 
 class JsonObject {
-	String name
-	Map properties
+    String name
+    Map properties
 }
 
 class JsonFoo {
-	String name
-	int getProperties() { return 0 }
+    String name
+    int getProperties() { return 0 }
 }
 
 enum JsonStreetKind {
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperCharSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperCharSourceTest.groovy
index edf58d2..d9c6b46 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperCharSourceTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperCharSourceTest.groovy
@@ -1,7 +1,20 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.json
 
-
-
 /**
  * Created by Richard on 2/2/14.
  */
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperIndexOverlayTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperIndexOverlayTest.groovy
index 58cdb4c..7de6a2a 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperIndexOverlayTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperIndexOverlayTest.groovy
@@ -1,7 +1,20 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.json
 
-
-
 /**
  * Created by Richard on 2/2/14.
  */
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
index 60c0e6f..a3f5d15 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperLaxTest.groovy
@@ -1,6 +1,20 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.json
 
-
 /**
  * Created by Richard on 2/2/14.
  */
@@ -11,27 +25,26 @@ class JsonSlurperLaxTest extends JsonSlurperTest {
     }
 
     void testNullEmptyMalformedPayloads() {
-        shouldFail(IllegalArgumentException) { parser.parseText(null)   }
-        shouldFail(IllegalArgumentException) { parser.parseText("")     }
-
-        shouldFail(JsonException) { parser.parseText("[")           }
-        shouldFail(JsonException) { parser.parseText('{"')          }
-        shouldFail(JsonException) { parser.parseText("[a")           }
-        shouldFail(JsonException) { parser.parseText('{a"')          }
-        shouldFail(JsonException) { parser.parseText("[\"a\"")           }
-        shouldFail(JsonException) { parser.parseText('{"a"')          }
-
+        shouldFail(IllegalArgumentException) { parser.parseText(null) }
+        shouldFail(IllegalArgumentException) { parser.parseText("") }
+
+        shouldFail(JsonException) { parser.parseText("[") }
+        shouldFail(JsonException) { parser.parseText('{"') }
+        shouldFail(JsonException) { parser.parseText("[a") }
+        shouldFail(JsonException) { parser.parseText('{a"') }
+        shouldFail(JsonException) { parser.parseText("[\"a\"") }
+        shouldFail(JsonException) { parser.parseText('{"a"') }
     }
 
     void testObjectWithSimpleValues() {
         assert parser.parseText('{"a": 1, "b" : true , "c":false, "d": null}') == [a: 1, b: true, c: false, d: null]
 
-         parser.parseText('{true}')
-         shouldFail { parser.parseText('{"a"}') }
-         parser.parseText('{"a":true')
-         parser.parseText('{"a":}')
-         shouldFail {parser.parseText('{"a":"b":"c"}') }
-         parser.parseText('{:true}')
+        parser.parseText('{true}')
+        shouldFail { parser.parseText('{"a"}') }
+        parser.parseText('{"a":true')
+        parser.parseText('{"a":}')
+        shouldFail {parser.parseText('{"a":"b":"c"}') }
+        parser.parseText('{:true}')
     }
 
     void testArrayOfArrayWithSimpleValues() {
@@ -69,9 +82,7 @@ class JsonSlurperLaxTest extends JsonSlurperTest {
     }
 
     void testLaxCommentsAndKeys() {
-
         String jsonString = """
-
             {
             foo:bar,    //look mom no quotes
             'foo1': 'bar1',  //I can do single quotes if I want to
@@ -84,11 +95,18 @@ class JsonSlurperLaxTest extends JsonSlurperTest {
             flag2 : false,
             strings : [we, are, string, here, us, roar],
             he said : '"fire all your guns at once baby, and explode into the night"',
+            "going deeper" : [
+                "nestedArrays", // needs comments
+                "anotherThing" // commented
+                // only one comment
+                ,
+                "a last thing" // explain that too
+            ],
             the : end
             }
         """
 
-        Map <String, Object> map = parser.parseText(jsonString)
+        Map<String, Object> map = parser.parseText(jsonString)
         assert map.foo == "bar"
         assert map.foo1 == "bar1"
         assert map.foo2 == "bar2"
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
index ebe0a47..351c24b 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonSlurperTest.groovy
@@ -31,7 +31,6 @@ class JsonSlurperTest extends GroovyTestCase {
     void testJsonShouldStartWithCurlyOrBracket() {
         /* We can handle parsing boolean, numbers, and such. */
         parser.parseText("true")
-
     }
 
     void testEmptyStructures() {
@@ -55,7 +54,7 @@ class JsonSlurperTest extends GroovyTestCase {
         def list = parser.parseText('[]')
         list << "Hello"
         list << "World"
-        assert list == [ "Hello", "World" ]
+        assert list == ["Hello", "World"]
     }
 
     void testParseNum() {
@@ -68,56 +67,48 @@ class JsonSlurperTest extends GroovyTestCase {
         int i = parser.parseText('-123')
         int i2 = -123
         assert i == i2
-
     }
 
     void testNegNumWithSpace() {
         int i = parser.parseText('   -123')
         int i2 = -123
         assert i == i2
-
     }
 
     void testLargeNegNumWithSpace() {
         int i = parser.parseText('   -1234567891')
         int i2 = -1234567891
         assert i == i2
-
     }
 
     void testWithSpaces() {
-        int num = ((Number)parser.parseText( "           123")).intValue()
+        int num = ((Number) parser.parseText("           123")).intValue()
         int num2 = 123
-        boolean ok = num == num2 || die ( "" + num)
-
+        boolean ok = num == num2 || die("" + num)
     }
 
     void testParseLargeNum() {
-        long num = parser.parseText(""+Long.MAX_VALUE)
+        long num = parser.parseText("" + Long.MAX_VALUE)
         long num2 = Long.MAX_VALUE
         assert num == num2
-
     }
 
     void testParseSmallNum() {
-        long num = parser.parseText(""+Long.MIN_VALUE)
+        long num = parser.parseText("" + Long.MIN_VALUE)
         long num2 = Long.MIN_VALUE
         assert num == num2
-
     }
 
     void testParseLargeDecimal() {
-        double num  = parser.parseText(""+Double.MAX_VALUE)
+        double num = parser.parseText("" + Double.MAX_VALUE)
         double num2 = Double.MAX_VALUE
         assert num == num2
-
     }
 
     void testParseSmallDecimal() {
-        double num  = parser.parseText(""+Double.MIN_VALUE)
+        double num = parser.parseText("" + Double.MIN_VALUE)
         double num2 = Double.MIN_VALUE
         assert num == num2
-
     }
 
     void testOutputTypes() {
@@ -280,6 +271,7 @@ class JsonSlurperTest extends GroovyTestCase {
         shouldFail(JsonException) { parser.parseText('["a"')        }
         shouldFail(JsonException) { parser.parseText('["a", ')      }
         shouldFail(JsonException) { parser.parseText('["a", true')  }
+        shouldFail(JsonException) { parser.parseText('[1.1.1]')     }
     }
 
     void testBackSlashEscaping() {
@@ -306,4 +298,11 @@ class JsonSlurperTest extends GroovyTestCase {
             parser.parseText('{"a":"c:\\\"}')
         }
     }
+
+    void testParseWithByteArray() {
+        def slurper = new JsonSlurper()
+
+        assert slurper.parse('{"a":true}'.bytes) == [a: true]
+
+    }
 }
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenTypeTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenTypeTest.groovy
index dc46835..dca7a9c 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenTypeTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenTypeTest.groovy
@@ -84,33 +84,33 @@ class JsonTokenTypeTest extends GroovyTestCase {
     }
 
     void testMatchingLongStringWithBackslashes() {
-        assert STRING.matching('"a' + '\\"'*10000 + '"')
+        assert STRING.matching('"a' + '\\"' * 10000 + '"')
     }
 
     void testTokenStartingWithChar() {
-        assert startingWith('{' as char)      == OPEN_CURLY
-        assert startingWith('}' as char)      == CLOSE_CURLY
-        assert startingWith('[' as char)      == OPEN_BRACKET
-        assert startingWith(']' as char)      == CLOSE_BRACKET
-        assert startingWith(',' as char)      == COMMA
-        assert startingWith(':' as char)      == COLON
-
-        assert startingWith('t' as char)      == TRUE
-        assert startingWith('f' as char)      == FALSE
-        assert startingWith('n' as char)      == NULL
-
-        assert startingWith('"' as char)      == STRING
-
-        assert startingWith('-' as char)      == NUMBER
-        assert startingWith('1' as char)      == NUMBER
-        assert startingWith('2' as char)      == NUMBER
-        assert startingWith('3' as char)      == NUMBER
-        assert startingWith('4' as char)      == NUMBER
-        assert startingWith('5' as char)      == NUMBER
-        assert startingWith('6' as char)      == NUMBER
-        assert startingWith('7' as char)      == NUMBER
-        assert startingWith('8' as char)      == NUMBER
-        assert startingWith('9' as char)      == NUMBER
-        assert startingWith('0' as char)      == NUMBER
+        assert startingWith('{' as char) == OPEN_CURLY
+        assert startingWith('}' as char) == CLOSE_CURLY
+        assert startingWith('[' as char) == OPEN_BRACKET
+        assert startingWith(']' as char) == CLOSE_BRACKET
+        assert startingWith(',' as char) == COMMA
+        assert startingWith(':' as char) == COLON
+
+        assert startingWith('t' as char) == TRUE
+        assert startingWith('f' as char) == FALSE
+        assert startingWith('n' as char) == NULL
+
+        assert startingWith('"' as char) == STRING
+
+        assert startingWith('-' as char) == NUMBER
+        assert startingWith('1' as char) == NUMBER
+        assert startingWith('2' as char) == NUMBER
+        assert startingWith('3' as char) == NUMBER
+        assert startingWith('4' as char) == NUMBER
+        assert startingWith('5' as char) == NUMBER
+        assert startingWith('6' as char) == NUMBER
+        assert startingWith('7' as char) == NUMBER
+        assert startingWith('8' as char) == NUMBER
+        assert startingWith('9' as char) == NUMBER
+        assert startingWith('0' as char) == NUMBER
     }
 }
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenValueTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenValueTest.groovy
index c1403f7..4c0c6a3 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenValueTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/JsonTokenValueTest.groovy
@@ -17,9 +17,6 @@ package groovy.json
 
 import static JsonTokenType.*
 
-
-import groovy.util.GroovyTestCase
-
 /**
  * @author Guillaume Laforge
  */
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/RealJsonPayloadsTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/RealJsonPayloadsTest.groovy
index 0414716..fcc8cd8 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/RealJsonPayloadsTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/RealJsonPayloadsTest.groovy
@@ -15,8 +15,6 @@
  */
 package groovy.json
 
-
-
 /**
  * @author Guillaume Laforge
  */
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
index 699d1f7..8000a37 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/StreamingJsonBuilderTest.groovy
@@ -15,7 +15,6 @@
  */
 package groovy.json
 
-
 /**
  * @author Tim Yates
  * @author Guillaume Laforge
@@ -24,14 +23,14 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testJsonBuilderConstructor() {
         new StringWriter().with { w ->
-            new StreamingJsonBuilder( w, [a: 1, b: true])
+            new StreamingJsonBuilder(w, [a: 1, b: true])
             assert w.toString() == '{"a":1,"b":true}'
         }
     }
 
     void testEmptyArray() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json([])
             assert w.toString() == '[]'
         }
@@ -39,7 +38,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testSimpleArray() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json 1, 2, "a", "b"
 
             assert w.toString() == '[1,2,"a","b"]'
@@ -48,7 +47,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testComplexArray() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json 1, 2, [k: true], "a", "b", [3, "c"]
 
             assert w.toString() == '[1,2,{"k":true},"a","b",[3,"c"]]'
@@ -57,7 +56,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testMap() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json a: 1, b: 2
 
             assert w.toString() == '{"a":1,"b":2}'
@@ -66,7 +65,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testEmptyObject() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json {}
 
             assert w.toString() == '{}'
@@ -75,7 +74,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testBasicObject() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json {
                 a 1
                 b true
@@ -88,7 +87,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
     
     void testNestedObjects() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json {
                 a {
                     b {
@@ -103,7 +102,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testStandardBuilderStyle() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.person {
                 name "Guillaume"
                 age 33
@@ -115,7 +114,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testMethodCallWithNamedArguments() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.person name: "Guillaume", age: 33
 
             assert w.toString() == '{"person":{"name":"Guillaume","age":33}}'
@@ -124,7 +123,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testThrowAnExceptionWhenPassingSomethingElseThanAClosure() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
 
             shouldFail(JsonException) {
                 json.something 1, 2, 3
@@ -134,7 +133,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testListWithAnEmptyObject() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json([[:]])
 
             assert w.toString() == '[{}]'
@@ -143,7 +142,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testListOfObjects() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json([name: "Guillaume"], [name: "Jochen"], [name: "Paul"])
 
             assert w.toString() == '[{"name":"Guillaume"},{"name":"Jochen"},{"name":"Paul"}]'
@@ -152,7 +151,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testElementHasListOfObjects() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.response {
                 results 1, [a: 2]
             }
@@ -166,10 +165,10 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
     }
 
     void testCollectionAndClosure() {
-        def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json authors, { Author author ->
                 name author.name
             }
@@ -179,10 +178,10 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
     }
 
     void testMethodWithCollectionAndClosure() {
-        def authors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def authors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.authors authors, { Author author ->
                 name author.name
             }
@@ -192,10 +191,10 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
     }
 
     void testNestedMethodWithCollectionAndClosure() {
-        def theAuthors = [new Author (name: "Guillaume"), new Author (name: "Jochen"), new Author (name: "Paul")]
+        def theAuthors = [new Author(name: "Guillaume"), new Author(name: "Jochen"), new Author(name: "Paul")]
 
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json {
                 authors theAuthors, { Author author ->
                     name author.name
@@ -208,7 +207,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testComplexStructureFromTheGuardian() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.response {
                 status "ok"
                 userTier "free"
@@ -245,9 +244,9 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testNestedListMap() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.content {
-                list([:],[another:[a:[1,2,3]]])
+                list([:], [another: [a: [1, 2, 3]]])
             }
 
             assert w.toString() == '''{"content":{"list":[{},{"another":{"a":[1,2,3]}}]}}'''
@@ -256,7 +255,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testEmptyList() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json()
 
             assert w.toString() == '''[]'''
@@ -265,7 +264,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testTrendsFromTwitter() {
         new StringWriter().with { w ->
-            def json = new StreamingJsonBuilder( w )
+            def json = new StreamingJsonBuilder(w)
             json.trends {
                 "2010-06-22 17:20" ([
                         name: "Groovy rules",
@@ -291,7 +290,7 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testExampleFromTheGep7Page() {
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
+            def builder = new StreamingJsonBuilder(w)
             builder.people {
                 person {
                     firstName 'Guillame'
@@ -313,37 +312,35 @@ class StreamingJsonBuilderTest extends GroovyTestCase {
 
     void testEdgeCases() {
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
+            def builder = new StreamingJsonBuilder(w)
             builder { elem 1, 2, 3 }
             
             assert w.toString() == '{"elem":[1,2,3]}'
         }
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
+            def builder = new StreamingJsonBuilder(w)
             builder.elem()
-            
+
             assert w.toString() == '{"elem":{}}'
         }
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
+            def builder = new StreamingJsonBuilder(w)
             builder.elem(a: 1, b: 2) { c 3 }
             
             assert w.toString() == '{"elem":{"a":1,"b":2,"c":3}}'
         }
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
-            builder.elem( [:] ) { c 3 }
+            def builder = new StreamingJsonBuilder(w)
+            builder.elem([:]) { c 3 }
             
             assert w.toString() == '{"elem":{"c":3}}'
         }
         new StringWriter().with { w ->
-            def builder = new StreamingJsonBuilder( w )
+            def builder = new StreamingJsonBuilder(w)
+
             shouldFail(JsonException) {
                 builder.elem(a: 1, b: 2, "ABCD")
             }
         }
     }
-
-
-
 }
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
index 5caafd1..dba7a26 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/CharScannerTest.groovy
@@ -60,7 +60,6 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testParseIntMax() {
-
         int i = 0
         i = CharScanner.parseInt(("" + Integer.MAX_VALUE).toCharArray())
         assert i == Integer.MAX_VALUE
@@ -85,7 +84,6 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testParseDouble() {
-
         String str = "123456789"
         double num =
             CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length()).doubleValue()
@@ -93,7 +91,6 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testParseDoubleNegative() {
-
         String str = "-1.23456789E8"
         double num =
             (Double) CharScanner.parseJsonNumber(str.toCharArray(), 0, str.length())
@@ -227,7 +224,6 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testParseLong() {
-
         String str = "12345678910"
         long l1 = CharScanner.parseLongFromTo(str.toCharArray(), 0, str.length())
         assert l1 == 12345678910L
@@ -246,7 +242,6 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testAutoSplitThisEndsInSpace() {
-
         def letters = chars("This is a string ")
         def splitted = CharScanner.split(letters, ' ' as char)
 
@@ -260,19 +255,16 @@ class CharScannerTest extends GroovyTestCase {
                 splitted[0] as char[]
         )
 
-
         assertArrayEquals(
                 chars("is"),
                 splitted[1] as char[]
         )
 
-
         assertArrayEquals(
                 chars("a"),
                 splitted[2] as char[]
         )
 
-
         assertArrayEquals(
                 chars("string"),
                 splitted[3] as char[]
@@ -285,9 +277,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testAutoSplitThis() {
-
-        def letters =
-            chars("This is a string")
+        def letters = chars("This is a string")
 
         def splitted = CharScanner.split(letters, ' ' as char)
 
@@ -301,19 +291,16 @@ class CharScannerTest extends GroovyTestCase {
                 splitted[0] as char[]
         )
 
-
         assertArrayEquals(
                 chars("is"),
                 splitted[1] as char[]
         )
 
-
         assertArrayEquals(
                 chars("a"),
                 splitted[2] as char[]
         )
 
-
         assertArrayEquals(
                 chars("string"),
                 splitted[3] as char[]
@@ -326,8 +313,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testAutoSplitThisStartSpace() {
-        def letters =
-            chars(" This is a string")
+        def letters = chars(" This is a string")
 
         def splitted = CharScanner.split(letters, ' ' as char)
 
@@ -368,9 +354,8 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testAutoSplitThisByTabOrSpace() {
+        def letters = chars("This\tis a string")
 
-        def letters =
-            chars("This\tis a string")
         def splitted = CharScanner.splitByChars(letters, '\t' as char, ' ' as char)
 
         assertEquals(
@@ -405,10 +390,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testAutoSplitThis3DoubleSpaceAfterA() {
-
-        def letters =
-            chars("This is a  string")
-
+        def letters = chars("This is a  string")
 
         def splitted = CharScanner.split(letters, ' ' as char)
 
@@ -449,9 +431,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testSplitThisEndsInSpace() {
-
-        def letters =
-            chars("This is a string ")
+        def letters = chars("This is a string ")
 
         def splitted = CharScanner.splitExact(letters, ' ' as char, 10)
 
@@ -487,9 +467,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testSplitThis() {
-
-        def letters =
-            chars("This is a string")
+        def letters = chars("This is a string")
 
         def splitted = CharScanner.splitExact(letters, ' ' as char, 10)
 
@@ -526,8 +504,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testSplitThisStartSpace() {
-        def letters =
-            chars(" This is a string")
+        def letters = chars(" This is a string")
 
         def splitted = CharScanner.splitExact(letters, ' ' as char, 10)
 
@@ -568,8 +545,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testSplitThisByTabOrSpace() {
-        def letters =
-            chars("This\tis a string")
+        def letters = chars("This\tis a string")
 
         def splitted = CharScanner.splitExact(letters, 10, '\t' as char, ' ' as char)
 
@@ -605,8 +581,7 @@ class CharScannerTest extends GroovyTestCase {
     }
 
     void testSplitThis3DoubleSpaceAfterA() {
-        def letters =
-            chars("This is a  string")
+        def letters = chars("This is a  string")
 
         def splitted = CharScanner.splitExact(letters, ' ' as char, 10)
 
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
index 0b1b5f5..0c30bfa 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ChrTest.groovy
@@ -109,7 +109,6 @@ class ChrTest extends GroovyTestCase {
     }
 
     void testByteCopyIntoCharArray() {
-
         def charArray = new char[1000]
         def bytes = "0123456789000".bytes
 
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
index e096618..c472ddc 100644
--- a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/FastStringUtilsUnsafeDisabledTest.groovy
@@ -16,6 +16,7 @@
 package groovy.json.internal
 
 class FastStringUtilsUnsafeDisabledTest extends GroovyTestCase {
+
     FastStringUtils.StringImplementation oldStringImplementation
 
     void setUp() {
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
new file mode 100644
index 0000000..0b3df0e
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/LazyMapTest.groovy
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.json.internal
+
+class LazyMapTest extends GroovyTestCase {
+
+    // GROOVY-7302
+    void testSizeWhenNoBackingMapCreated() {
+        def map = new LazyMap()
+        map.someProperty = "1"
+        map.someProperty = "2"
+        map.someProperty = "3"
+        assert map.size() == 1
+        map.someProperty2 = "4"
+        assert map.size() == 2
+    }
+
+    void testSizeWhenLazyCreated() {
+        def map = new LazyMap()
+        map.someProperty1 = '1'
+        assert map. at map == null
+        map.someProperty2 = '2'
+        assert map. at map == null
+        map.someProperty3 = '3'
+        assert map. at map == null
+        map.someProperty4 = '4'
+        assert map. at map == null
+        map.someProperty5 = '5'
+        assert map. at map == null
+        map.someProperty6 = '6'
+        assert map. at map == null
+        map.someProperty7 = '7'
+        assert map.someProperty6 == '6'
+        assert map. at map?.size() == 7
+    }
+}
diff --git a/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
new file mode 100644
index 0000000..e7852da
--- /dev/null
+++ b/subprojects/groovy-json/src/test/groovy/groovy/json/internal/ReaderCharacterSourceTest.groovy
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.json.internal;
+
+class ReaderCharacterSourceTest extends GroovyTestCase {
+
+    void testFindNextCharWithRecursionHadEscape() {
+        int[] control = '"\\'.toCharArray() as int[]
+
+        // create a ReaderCharacterSource with a very small buffer, findNextChar must be invoked recursive
+
+        // use a string where escape-character is in last invocation
+        ReaderCharacterSource cs = new ReaderCharacterSource(new StringReader('"value\\u0026"'), 6)
+        cs.findNextChar(control[0], control[1])
+
+        assert cs.hadEscape()
+
+        // use a string where escape-character is in first invocation
+        cs = new ReaderCharacterSource(new StringReader('"\\u0026value"'), 6)
+        cs.findNextChar(control[0], control[1])
+
+        assert cs.hadEscape()
+    }
+}
diff --git a/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java b/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java
index 8a48aab..28179d8 100644
--- a/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java
+++ b/subprojects/groovy-jsr223/src/main/java/org/codehaus/groovy/jsr223/GroovyScriptEngineImpl.java
@@ -290,8 +290,7 @@ public class GroovyScriptEngineImpl
                 return scriptClass;
             } else {
                 // it's a script
-                Script scriptObject = (Script) scriptClass.newInstance();
-                scriptObject.setBinding(binding);
+                Script scriptObject = InvokerHelper.createScript(scriptClass, binding);
 
                 // save all current closures into global closures map
                 Method[] methods = scriptClass.getMethods();
diff --git a/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc b/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc
index 270009a..036d96a 100644
--- a/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc
+++ b/subprojects/groovy-jsr223/src/spec/doc/integrating-jsr223.adoc
@@ -1,32 +1,32 @@
 [[jsr223]]
-= JSR 223 javax.script API (TBD)
+= JSR 223 javax.script API
 
 WARNING: JSR-223 is a standard API for calling scripting frameworks in Java. It is available since Java 6 and aims at
 providing a common framework for calling multiple languages from Java. Groovy provides its own richer integration mechanisms,
-and if you don't plan to use multiple languages in the same application, it is recommanded that you use the Groovy
+and if you don't plan to use multiple languages in the same application, it is recommended that you use the Groovy
 integration mechanisms instead of the limited JSR-223 API.
 
 Here is how you need to initialize the JSR-223 engine to talk to Groovy from Java:
 
 [source,java]
 --------------------------------------------------------------------------------------
-include::{rootDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_imports,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_imports,indent=0]
 ...
-include::{rootDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_init,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_init,indent=0]
 --------------------------------------------------------------------------------------
 
 Then you can execute Groovy scripts easily:
 
 [source,java]
 ----
-include::{rootDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_basic,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_basic,indent=0]
 ----
 
 It is also possible to share variables:
 
 [source,java]
 ----
-include::{rootDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_variables,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_variables,indent=0]
 ----
 
 This next example illustrates calling an invokable function:
@@ -35,7 +35,7 @@ This next example illustrates calling an invokable function:
 -------------------------------------------------------------------------------
 import javax.script.Invocable;
 ...
-include::{rootDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_invocable,indent=0]
+include::{rootProjectDir}/subprojects/groovy-jsr223/src/spec/test/JSR223SpecTest.java[tags=jsr223_invocable,indent=0]
 -------------------------------------------------------------------------------
 
 The engine keeps per default hard references to the script functions. To
diff --git a/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/SugarTest.groovy b/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/SugarTest.groovy
index 1a91783..0924619 100644
--- a/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/SugarTest.groovy
+++ b/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/SugarTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.jsr223
 
 import javax.script.ScriptEngineManager
diff --git a/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/vm6/JavascriptTest.groovy b/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/vm6/JavascriptTest.groovy
index 1c9af40..b2ee732 100644
--- a/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/vm6/JavascriptTest.groovy
+++ b/subprojects/groovy-jsr223/src/test/groovy/org/codehaus/groovy/jsr223/vm6/JavascriptTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.jsr223.vm6
 
 import javax.script.ScriptEngineManager
diff --git a/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java b/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
index 11217ea..331327e 100644
--- a/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
+++ b/subprojects/groovy-jsr223/src/test/java/org/codehaus/groovy/jsr223/JSR223SecurityTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package org.codehaus.groovy.jsr223;
 
 import groovy.lang.GroovyClassLoader;
diff --git a/subprojects/groovy-nio/build.gradle b/subprojects/groovy-nio/build.gradle
index 2e6098a..83d699c 100644
--- a/subprojects/groovy-nio/build.gradle
+++ b/subprojects/groovy-nio/build.gradle
@@ -12,7 +12,7 @@ task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorT
 
 compileJava.dependsOn moduleDescriptor
 
-tasks.withType(Compile) {
+tasks.withType(JavaCompile) {
         sourceCompatibility = 1.7
         targetCompatibility = 1.7
 }
diff --git a/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/NioGroovyMethods.java b/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/NioGroovyMethods.java
index 8967dd4..b6037cf 100644
--- a/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/NioGroovyMethods.java
+++ b/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/NioGroovyMethods.java
@@ -24,6 +24,7 @@ import java.io.BufferedInputStream;
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.Closeable;
 import java.io.DataInputStream;
 import java.io.DataOutputStream;
 import java.io.FileNotFoundException;
@@ -36,7 +37,6 @@ import java.io.OutputStreamWriter;
 import java.io.PrintWriter;
 import java.io.Reader;
 import java.io.Writer;
-import java.io.Closeable;
 import java.net.URI;
 import java.nio.charset.Charset;
 import java.nio.file.DirectoryStream;
@@ -128,7 +128,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static ObjectOutputStream newObjectOutputStream(Path self) throws IOException {
-        return new ObjectOutputStream( Files.newOutputStream(self) );
+        return new ObjectOutputStream(Files.newOutputStream(self));
     }
 
     /**
@@ -143,7 +143,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see IOGroovyMethods#withStream(java.io.OutputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withObjectOutputStream(Path self, @ClosureParams(value=SimpleType.class, options="java.io.ObjectOutputStream") Closure<T> closure) throws IOException {
+    public static <T> T withObjectOutputStream(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.ObjectOutputStream") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withStream(newObjectOutputStream(self), closure);
     }
 
@@ -156,7 +156,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static ObjectInputStream newObjectInputStream(Path self) throws IOException {
-        return new ObjectInputStream( Files.newInputStream(self) );
+        return new ObjectInputStream(Files.newInputStream(self));
     }
 
     /**
@@ -169,7 +169,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static ObjectInputStream newObjectInputStream(Path self, final ClassLoader classLoader) throws IOException {
-        return IOGroovyMethods.newObjectInputStream( Files.newInputStream(self), classLoader );
+        return IOGroovyMethods.newObjectInputStream(Files.newInputStream(self), classLoader);
     }
 
     /**
@@ -197,7 +197,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.InputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withObjectInputStream(Path path, @ClosureParams(value=SimpleType.class, options="java.io.ObjectInputStream") Closure<T> closure) throws IOException {
+    public static <T> T withObjectInputStream(Path path, @ClosureParams(value = SimpleType.class, options = "java.io.ObjectInputStream") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withStream(newObjectInputStream(path), closure);
     }
 
@@ -213,7 +213,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.InputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withObjectInputStream(Path self, ClassLoader classLoader, @ClosureParams(value=SimpleType.class, options="java.io.ObjectInputStream") Closure<T> closure) throws IOException {
+    public static <T> T withObjectInputStream(Path self, ClassLoader classLoader, @ClosureParams(value = SimpleType.class, options = "java.io.ObjectInputStream") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withStream(newObjectInputStream(self, classLoader), closure);
     }
 
@@ -229,7 +229,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachLine(Path, int, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T eachLine(Path self, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+    public static <T> T eachLine(Path self, @ClosureParams(value = FromString.class, options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
         return eachLine(self, 1, closure);
     }
 
@@ -246,7 +246,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachLine(Path, String, int, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T eachLine(Path self, String charset, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+    public static <T> T eachLine(Path self, String charset, @ClosureParams(value = FromString.class, options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
         return eachLine(self, charset, 1, closure);
     }
 
@@ -263,7 +263,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#eachLine(java.io.Reader, int, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T eachLine(Path self, int firstLine, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+    public static <T> T eachLine(Path self, int firstLine, @ClosureParams(value = FromString.class, options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
         return IOGroovyMethods.eachLine(newReader(self), firstLine, closure);
     }
 
@@ -281,7 +281,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#eachLine(java.io.Reader, int, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T eachLine(Path self, String charset, int firstLine, @ClosureParams(value=FromString.class,options={"String","String,Integer"}) Closure<T> closure) throws IOException {
+    public static <T> T eachLine(Path self, String charset, int firstLine, @ClosureParams(value = FromString.class, options = {"String", "String,Integer"}) Closure<T> closure) throws IOException {
         return IOGroovyMethods.eachLine(newReader(self, charset), firstLine, closure);
     }
 
@@ -302,7 +302,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#splitEachLine(java.io.Reader, String, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T splitEachLine(Path self, String regex, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+    public static <T> T splitEachLine(Path self, String regex, @ClosureParams(value = FromString.class, options = "List<String>") Closure<T> closure) throws IOException {
         return IOGroovyMethods.splitEachLine(newReader(self), regex, closure);
     }
 
@@ -321,7 +321,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#splitEachLine(java.io.Reader, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T splitEachLine(Path self, Pattern pattern, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+    public static <T> T splitEachLine(Path self, Pattern pattern, @ClosureParams(value = FromString.class, options = "List<String>") Closure<T> closure) throws IOException {
         return IOGroovyMethods.splitEachLine(newReader(self), pattern, closure);
     }
 
@@ -343,7 +343,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#splitEachLine(java.io.Reader, String, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T splitEachLine(Path self, String regex, String charset, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+    public static <T> T splitEachLine(Path self, String regex, String charset, @ClosureParams(value = FromString.class, options = "List<String>") Closure<T> closure) throws IOException {
         return IOGroovyMethods.splitEachLine(newReader(self, charset), regex, closure);
     }
 
@@ -363,7 +363,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#splitEachLine(java.io.Reader, java.util.regex.Pattern, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T splitEachLine(Path self, Pattern pattern, String charset, @ClosureParams(value=FromString.class,options="List<String>") Closure<T> closure) throws IOException {
+    public static <T> T splitEachLine(Path self, Pattern pattern, String charset, @ClosureParams(value = FromString.class, options = "List<String>") Closure<T> closure) throws IOException {
         return IOGroovyMethods.splitEachLine(newReader(self, charset), pattern, closure);
     }
 
@@ -429,7 +429,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static byte[] getBytes(Path self) throws IOException {
-        return IOGroovyMethods.getBytes( Files.newInputStream(self) );
+        return IOGroovyMethods.getBytes(Files.newInputStream(self));
     }
 
     /**
@@ -441,7 +441,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static void setBytes(Path self, byte[] bytes) throws IOException {
-        IOGroovyMethods.setBytes( Files.newOutputStream(self), bytes);
+        IOGroovyMethods.setBytes(Files.newOutputStream(self), bytes);
     }
 
     /**
@@ -765,15 +765,13 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws IllegalArgumentException if the provided Path object does not represent a directory
      * @since 2.3.0
      */
-    public static void eachFile(final Path self, final FileType fileType, @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") final Closure closure) throws IOException {
+    public static void eachFile(final Path self, final FileType fileType, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException {
             //throws FileNotFoundException, IllegalArgumentException {
         checkDir(self);
 
         // TODO GroovyDoc doesn't parse this file as our java.g doesn't handle this JDK7 syntax
-        try ( DirectoryStream<Path> stream = Files.newDirectoryStream(self) ) {
-            Iterator<Path> itr = stream.iterator();
-            while( itr.hasNext() ) {
-                Path path = itr.next();
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
+            for (Path path : stream) {
                 if (fileType == FileType.ANY ||
                         (fileType != FileType.FILES && Files.isDirectory(path)) ||
                         (fileType != FileType.DIRECTORIES && Files.isRegularFile(path))) {
@@ -809,7 +807,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachFile(Path, groovy.io.FileType, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachDir(Path self, @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
+    public static void eachDir(Path self, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
         eachFile(self, FileType.DIRECTORIES, closure);
     }
 
@@ -826,13 +824,11 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws IllegalArgumentException if the provided Path object does not represent a directory
      * @since 2.3.0
      */
-    public static void eachFileRecurse(final Path self, final FileType fileType, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
+    public static void eachFileRecurse(final Path self, final FileType fileType, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
             // throws FileNotFoundException, IllegalArgumentException {
         checkDir(self);
-        try ( DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
-            Iterator<Path> itr = stream.iterator();
-            while ( itr.hasNext() ) {
-                Path path = itr.next();
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
+            for (Path path : stream) {
                 if (Files.isDirectory(path)) {
                     if (fileType != FileType.FILES) closure.call(path);
                     eachFileRecurse(path, fileType, closure);
@@ -899,7 +895,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see groovy.io.FileType
      * @since 2.3.0
      */
-    public static void traverse(final Path self, final Map<String, Object> options, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure)
+    public static void traverse(final Path self, final Map<String, Object> options, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure)
             throws IOException {
             // throws FileNotFoundException, IllegalArgumentException {
         Number maxDepthNumber = DefaultGroovyMethods.asType(options.remove("maxDepth"), Number.class);
@@ -978,7 +974,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #traverse(Path, java.util.Map, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void traverse(final Path self, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure)
+    public static void traverse(final Path self, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure)
             throws IOException {
         traverse(self, new HashMap<String, Object>(), closure);
     }
@@ -1002,7 +998,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
         traverse(self, options, visit);
     }
 
-    private static FileVisitResult traverse(final Path self, final Map<String, Object> options, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure, final int maxDepth)
+    private static FileVisitResult traverse(final Path self, final Map<String, Object> options, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure, final int maxDepth)
             throws IOException {
         checkDir(self);
         final Closure pre = (Closure) options.get("preDir");
@@ -1014,11 +1010,12 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
         final Object excludeNameFilter = options.get("excludeNameFilter");
         final Closure sort = (Closure) options.get("sort");
 
-        try ( DirectoryStream<Path> stream = Files.newDirectoryStream(self) ) {
-
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
             final Iterator<Path> itr = stream.iterator();
             List<Path> files = new LinkedList<Path>();
-            while(itr.hasNext()) { files.add(itr.next()); }
+            while (itr.hasNext()) {
+                files.add(itr.next());
+            }
 
             if (sort != null) files = DefaultGroovyMethods.sort(files, sort);
 
@@ -1074,7 +1071,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachFileRecurse(Path, groovy.io.FileType, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachFileRecurse(Path self, @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
+    public static void eachFileRecurse(Path self, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") Closure closure) throws IOException { // throws FileNotFoundException, IllegalArgumentException {
         eachFileRecurse(self, FileType.ANY, closure);
     }
 
@@ -1090,7 +1087,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachFileRecurse(Path, groovy.io.FileType, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachDirRecurse(final Path self, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException { //throws FileNotFoundException, IllegalArgumentException {
+    public static void eachDirRecurse(final Path self, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException { //throws FileNotFoundException, IllegalArgumentException {
         eachFileRecurse(self, FileType.DIRECTORIES, closure);
     }
 
@@ -1122,17 +1119,16 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws IllegalArgumentException if the provided Path object does not represent a directory
      * @since 2.3.0
      */
-    public static void eachFileMatch(final Path self, final FileType fileType, final Object nameFilter, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException {
+    public static void eachFileMatch(final Path self, final FileType fileType, final Object nameFilter, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException {
             // throws FileNotFoundException, IllegalArgumentException {
         checkDir(self);
-        try ( DirectoryStream<Path> stream = Files.newDirectoryStream(self) ) {
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
             Iterator<Path> itr = stream.iterator();
             BooleanReturningMethodInvoker bmi = new BooleanReturningMethodInvoker("isCase");
-            while ( itr.hasNext() ) {
+            while (itr.hasNext()) {
                 Path currentPath = itr.next();
                 if ((fileType != FileType.FILES && Files.isDirectory(currentPath)) ||
-                        (fileType != FileType.DIRECTORIES && Files.isRegularFile(currentPath)))
-                {
+                        (fileType != FileType.DIRECTORIES && Files.isRegularFile(currentPath))) {
                     if (bmi.invoke(nameFilter, currentPath.getFileName().toString()))
                         closure.call(currentPath);
                 }
@@ -1154,7 +1150,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachFileMatch(Path, groovy.io.FileType, Object, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachFileMatch(final Path self, final Object nameFilter, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException {
+    public static void eachFileMatch(final Path self, final Object nameFilter, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException {
             // throws FileNotFoundException, IllegalArgumentException {
         eachFileMatch(self, FileType.ANY, nameFilter, closure);
     }
@@ -1173,7 +1169,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see #eachFileMatch(Path, groovy.io.FileType, Object, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachDirMatch(final Path self, final Object nameFilter, final @ClosureParams(value=SimpleType.class, options="java.nio.file.Path") Closure closure) throws IOException {  // throws FileNotFoundException, IllegalArgumentException {
+    public static void eachDirMatch(final Path self, final Object nameFilter, @ClosureParams(value = SimpleType.class, options = "java.nio.file.Path") final Closure closure) throws IOException {  // throws FileNotFoundException, IllegalArgumentException {
         eachFileMatch(self, FileType.DIRECTORIES, nameFilter, closure);
     }
 
@@ -1200,18 +1196,13 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
             return false;
 
         // delete contained files
-        try ( DirectoryStream<Path> stream = Files.newDirectoryStream(self) ) {
-
-            Iterator<Path> itr = stream.iterator();
-
-            while (itr.hasNext()) {
-                Path path = itr.next();
+        try (DirectoryStream<Path> stream = Files.newDirectoryStream(self)) {
+            for (Path path : stream) {
                 if (Files.isDirectory(path)) {
                     if (!deleteDir(path)) {
                         return false;
                     }
-                }
-                else {
+                } else {
                     Files.delete(path);
                 }
             }
@@ -1219,8 +1210,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
             // now delete directory itself
             Files.delete(self);
             return true;
-        }
-        catch( IOException e ) {
+        } catch (IOException e) {
             return false;
         }
     }
@@ -1238,7 +1228,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
         try {
             Files.move(self, Paths.get(newPathName));
             return true;
-        } catch(IOException e) {
+        } catch (IOException e) {
             return false;
         }
     }
@@ -1256,7 +1246,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
         try {
             Files.move(self, Paths.get(newPathName));
             return true;
-        } catch(IOException e) {
+        } catch (IOException e) {
             return false;
         }
     }
@@ -1340,7 +1330,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withReader(Path self, @ClosureParams(value=SimpleType.class, options="java.io.Reader") Closure<T> closure) throws IOException {
+    public static <T> T withReader(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.Reader") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withReader(newReader(self), closure);
     }
 
@@ -1356,7 +1346,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withReader(Path self, String charset, @ClosureParams(value=SimpleType.class, options="java.io.Reader") Closure<T> closure) throws IOException {
+    public static <T> T withReader(Path self, String charset, @ClosureParams(value = SimpleType.class, options = "java.io.Reader") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withReader(newReader(self, charset), closure);
     }
 
@@ -1369,7 +1359,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static BufferedOutputStream newOutputStream(Path self) throws IOException {
-        return new BufferedOutputStream( Files.newOutputStream(self) );
+        return new BufferedOutputStream(Files.newOutputStream(self));
     }
 
     /**
@@ -1395,7 +1385,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.OutputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static Object withOutputStream(Path self, @ClosureParams(value=SimpleType.class, options="java.io.OutputStream") Closure closure) throws IOException {
+    public static Object withOutputStream(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.OutputStream") Closure closure) throws IOException {
         return IOGroovyMethods.withStream(newOutputStream(self), closure);
     }
 
@@ -1410,7 +1400,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.InputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static Object withInputStream(Path self, @ClosureParams(value=SimpleType.class, options="java.io.InputStream") Closure closure) throws IOException {
+    public static Object withInputStream(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.InputStream") Closure closure) throws IOException {
         return IOGroovyMethods.withStream(newInputStream(self), closure);
     }
 
@@ -1425,7 +1415,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.OutputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withDataOutputStream(Path self, @ClosureParams(value=SimpleType.class, options="java.io.DataOutputStream") Closure<T> closure) throws IOException {
+    public static <T> T withDataOutputStream(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.DataOutputStream") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withStream(newDataOutputStream(self), closure);
     }
 
@@ -1440,7 +1430,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#withStream(java.io.InputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withDataInputStream(Path self, @ClosureParams(value=SimpleType.class, options="java.io.DataInputStream") Closure<T> closure) throws IOException {
+    public static <T> T withDataInputStream(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.DataInputStream") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withStream(newDataInputStream(self), closure);
     }
 
@@ -1467,12 +1457,10 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static BufferedWriter newWriter(Path self, boolean append) throws IOException {
-        if( append ) {
+        if (append) {
             return Files.newBufferedWriter(self, Charset.defaultCharset(), CREATE, APPEND);
         }
-        else {
-            return Files.newBufferedWriter(self, Charset.defaultCharset());
-        }
+        return Files.newBufferedWriter(self, Charset.defaultCharset());
     }
 
     /**
@@ -1491,9 +1479,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
         if (append) {
             return Files.newBufferedWriter(self, Charset.forName(charset), CREATE, APPEND);
         }
-        else {
-            return Files.newBufferedWriter(self, Charset.forName(charset) );
-        }
+        return Files.newBufferedWriter(self, Charset.forName(charset));
     }
 
     /**
@@ -1520,7 +1506,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withWriter(Path self, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+    public static <T> T withWriter(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.Writer") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newWriter(self), closure);
     }
 
@@ -1536,7 +1522,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withWriter(Path self, String charset, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+    public static <T> T withWriter(Path self, String charset, @ClosureParams(value = SimpleType.class, options = "java.io.Writer") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newWriter(self, charset), closure);
     }
 
@@ -1552,7 +1538,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withWriterAppend(Path self, String charset, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+    public static <T> T withWriterAppend(Path self, String charset, @ClosureParams(value = SimpleType.class, options = "java.io.Writer") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newWriter(self, charset, true), closure);
     }
 
@@ -1566,7 +1552,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withWriterAppend(Path self, @ClosureParams(value=SimpleType.class, options="java.io.Writer") Closure<T> closure) throws IOException {
+    public static <T> T withWriterAppend(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.Writer") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newWriter(self, true), closure);
     }
 
@@ -1607,7 +1593,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withPrintWriter(Path self, @ClosureParams(value=SimpleType.class, options="java.io.PrintWriter") Closure<T> closure) throws IOException {
+    public static <T> T withPrintWriter(Path self, @ClosureParams(value = SimpleType.class, options = "java.io.PrintWriter") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newPrintWriter(self), closure);
     }
 
@@ -1623,7 +1609,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @throws java.io.IOException if an IOException occurs.
      * @since 2.3.0
      */
-    public static <T> T withPrintWriter(Path self, String charset, @ClosureParams(value=SimpleType.class, options="java.io.PrintWriter") Closure<T> closure) throws IOException {
+    public static <T> T withPrintWriter(Path self, String charset, @ClosureParams(value = SimpleType.class, options = "java.io.PrintWriter") Closure<T> closure) throws IOException {
         return IOGroovyMethods.withWriter(newPrintWriter(self, charset), closure);
     }
 
@@ -1636,7 +1622,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static BufferedInputStream newInputStream(Path self) throws IOException { // throws FileNotFoundException {
-        return new BufferedInputStream( Files.newInputStream(self) );
+        return new BufferedInputStream(Files.newInputStream(self));
     }
 
     /**
@@ -1648,7 +1634,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @since 2.3.0
      */
     public static DataInputStream newDataInputStream(Path self) throws IOException { // throws FileNotFoundException {
-        return new DataInputStream( Files.newInputStream(self) );
+        return new DataInputStream(Files.newInputStream(self));
     }
 
     /**
@@ -1660,7 +1646,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#eachByte(java.io.InputStream, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachByte(Path self, @ClosureParams(value=SimpleType.class, options="byte") Closure closure) throws IOException {
+    public static void eachByte(Path self, @ClosureParams(value = SimpleType.class, options = "byte") Closure closure) throws IOException {
         BufferedInputStream is = newInputStream(self);
         IOGroovyMethods.eachByte(is, closure);
     }
@@ -1675,7 +1661,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#eachByte(java.io.InputStream, int, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void eachByte(Path self, int bufferLen, @ClosureParams(value=FromString.class, options="byte[],Integer") Closure closure) throws IOException {
+    public static void eachByte(Path self, int bufferLen, @ClosureParams(value = FromString.class, options = "byte[],Integer") Closure closure) throws IOException {
         BufferedInputStream is = newInputStream(self);
         IOGroovyMethods.eachByte(is, bufferLen, closure);
     }
@@ -1692,7 +1678,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#filterLine(java.io.Reader, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static Writable filterLine(Path self, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+    public static Writable filterLine(Path self, @ClosureParams(value = SimpleType.class, options = "java.lang.String") Closure closure) throws IOException {
         return IOGroovyMethods.filterLine(newReader(self), closure);
     }
 
@@ -1709,7 +1695,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#filterLine(java.io.Reader, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static Writable filterLine(Path self, String charset, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+    public static Writable filterLine(Path self, String charset, @ClosureParams(value = SimpleType.class, options = "java.lang.String") Closure closure) throws IOException {
         return IOGroovyMethods.filterLine(newReader(self, charset), closure);
     }
 
@@ -1725,7 +1711,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#filterLine(java.io.Reader, java.io.Writer, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void filterLine(Path self, Writer writer, @ClosureParams(value=SimpleType.class, options="java.lang.String")  Closure closure) throws IOException {
+    public static void filterLine(Path self, Writer writer, @ClosureParams(value = SimpleType.class, options = "java.lang.String")  Closure closure) throws IOException {
         IOGroovyMethods.filterLine(newReader(self), writer, closure);
     }
 
@@ -1742,7 +1728,7 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
      * @see org.codehaus.groovy.runtime.IOGroovyMethods#filterLine(java.io.Reader, java.io.Writer, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static void filterLine(Path self, Writer writer, String charset, @ClosureParams(value=SimpleType.class, options="java.lang.String") Closure closure) throws IOException {
+    public static void filterLine(Path self, Writer writer, String charset, @ClosureParams(value = SimpleType.class, options = "java.lang.String") Closure closure) throws IOException {
         IOGroovyMethods.filterLine(newReader(self, charset), writer, closure);
     }
 
@@ -1759,26 +1745,12 @@ public class NioGroovyMethods extends DefaultGroovyMethodsSupport {
     }
 
     /**
-     * Allows this closeable to be used within the closure, ensuring that it
-     * is closed once the closure has been executed and before this method returns.
-     *
-     * @param self the Closeable
-     * @param action the closure taking the Closeable as parameter
-     * @return the value returned by the closure
-     * @throws IOException if an IOException occurs.
+     * #deprecated use the variant in IOGroovyMethods
+     * @see org.codehaus.groovy.runtime.IOGroovyMethods#withCloseable(java.io.Closeable, groovy.lang.Closure)
      * @since 2.3.0
      */
-    public static <T> T withCloseable(Closeable self, @ClosureParams(value=SimpleType.class, options="java.io.Closeable") Closure<T> action) throws IOException {
-        try {
-            T result = action.call(self);
-
-            Closeable temp = self;
-            self = null;
-            temp.close();
-
-            return result;
-        } finally {
-            DefaultGroovyMethodsSupport.closeWithWarning(self);
-        }
+    @Deprecated
+    public static <T> T withCloseable(Closeable self, @ClosureParams(value = SimpleType.class, options = "java.io.Closeable") Closure<T> action) throws IOException {
+        return IOGroovyMethods.withCloseable(self, action);
     }
 }
diff --git a/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/WritablePath.java b/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/WritablePath.java
index c845b48..ab7d2c6 100644
--- a/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/WritablePath.java
+++ b/subprojects/groovy-nio/src/main/java/org/codehaus/groovy/runtime/WritablePath.java
@@ -68,8 +68,7 @@ public class WritablePath implements Path, Writable {
                 out.write(c);
                 c = reader.read();
             }
-        }
-        finally {
+        } finally {
             reader.close();
         }
         return out;
@@ -187,12 +186,12 @@ public class WritablePath implements Path, Writable {
 
     @Override
     public WatchKey register(WatchService watcher, WatchEvent.Kind<?>[] events, WatchEvent.Modifier... modifiers) throws IOException {
-        return delegate.register(watcher,events,modifiers);
+        return delegate.register(watcher, events, modifiers);
     }
 
     @Override
     public WatchKey register(WatchService watcher, WatchEvent.Kind<?>... events) throws IOException {
-        return delegate.register(watcher,events);
+        return delegate.register(watcher, events);
     }
 
     @Override
@@ -219,5 +218,4 @@ public class WritablePath implements Path, Writable {
     public String toString() {
         return delegate.toString();
     }
-
 }
diff --git a/subprojects/groovy-nio/src/test/groovy/org/codehaus/groovy/runtime/NioGroovyMethodsTest.groovy b/subprojects/groovy-nio/src/test/groovy/org/codehaus/groovy/runtime/NioGroovyMethodsTest.groovy
index 628890c..e9f4850 100644
--- a/subprojects/groovy-nio/src/test/groovy/org/codehaus/groovy/runtime/NioGroovyMethodsTest.groovy
+++ b/subprojects/groovy-nio/src/test/groovy/org/codehaus/groovy/runtime/NioGroovyMethodsTest.groovy
@@ -1,80 +1,89 @@
-/**
+/*
+ * Copyright 2003-2015 the original author or authors.
  *
- * @author Paolo Di Tommaso <paolo.ditommaso at gmail.com>
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
  */
 package org.codehaus.groovy.runtime
 
 import java.nio.file.Files
 import java.nio.file.Path
-import java.nio.file.Paths
 import java.nio.file.StandardCopyOption
 
 import groovy.io.FileType
+import org.junit.Rule
+import org.junit.rules.TemporaryFolder
 import spock.lang.Specification
 
+/**
+ * @author Paolo Di Tommaso <paolo.ditommaso at gmail.com>
+ */
 class NioGroovyMethodsTest extends Specification {
 
-    def testPathSize() {
+    @Rule
+    TemporaryFolder temporaryFolder
 
+    def testPathSize() {
         when:
         def str = 'Hello world!'
-        Path path = Files.createTempFile('test-size', null)
-        Files.copy( new ByteArrayInputStream(str.getBytes()), path, StandardCopyOption.REPLACE_EXISTING )
+        def path = temporaryFolder.newFile().toPath()
+        Files.copy(new ByteArrayInputStream(str.getBytes()), path, StandardCopyOption.REPLACE_EXISTING)
 
         then:
         path.size() == str.size()
-
-        cleanup:
-        Files.deleteIfExists(path)
     }
 
     def testNewObjectOutputStream() {
-
         setup:
         def str = 'Hello world!'
-        Path path = Paths.get('new_obj_out_stream')
+        def path = temporaryFolder.newFile().toPath()
 
         when:
-        def out = path.newObjectOutputStream()
-        out.writeObject(str)
-        out.flush()
-        def stream = new ObjectInputStream(new FileInputStream(path.toFile()))
+        def outputStream = path.newObjectOutputStream()
+        outputStream.writeObject(str)
+        outputStream.close()
+        def inputStream = new ObjectInputStream(new FileInputStream(path.toFile()))
 
         then:
-        stream.readObject() == str
+        inputStream.readObject() == str
 
         cleanup:
-        stream.close()
-        Files.deleteIfExists(path)
+        inputStream.close()
     }
 
     def testNewObjectInputStream() {
-
         setup:
         def str = 'Hello world!'
-        def path = Paths.get('new_obj_in_stream')
-        def stream = new ObjectOutputStream(new FileOutputStream(path.toFile()))
-        stream.writeObject(str)
-        stream.close()
+        def path = temporaryFolder.newFile().toPath()
+        def outputStream = new ObjectOutputStream(new FileOutputStream(path.toFile()))
+        outputStream.writeObject(str)
+        outputStream.close()
 
         when:
-        def obj = path.newObjectInputStream()
+        def inputStream = path.newObjectInputStream()
 
         then:
-        obj.readObject() == str
+        inputStream.readObject() == str
 
         cleanup:
-        obj.close()
-        Files.deleteIfExists(path)
+        inputStream.close()
     }
 
     def testEachObject() {
-
         setup:
         def str1 = 'alpha'
         def str2 = 'beta'
         def str3 = 'delta'
-        def path = Paths.get('new_obj_in_stream')
+        def path = temporaryFolder.newFile().toPath()
         def stream = new ObjectOutputStream(new FileOutputStream(path.toFile()))
         stream.writeObject(str1)
         stream.writeObject(str2)
@@ -83,42 +92,28 @@ class NioGroovyMethodsTest extends Specification {
 
         when:
         def list = []
-        path.eachObject() { list << it }
+        path.eachObject { list << it }
 
         then:
-        list.size()==3
-        list[0]==str1
-        list[1]==str2
-        list[2]==str3
-
-        cleanup:
-        Files.deleteIfExists(path)
+        list == [str1, str2, str3]
     }
 
-    def testEachLine() {
-
+    def testReadLines() {
         setup:
-        def file = new File('test_each_file')
+        def file = temporaryFolder.newFile()
         file.text = 'alpha\nbeta\ndelta'
 
         when:
         def lines = file.toPath().readLines()
 
         then:
-        lines.size()==3
-        lines[0]=='alpha'
-        lines[1]=='beta'
-        lines[2]=='delta'
-
-        cleanup:
-        file?.delete()
+        lines == ['alpha', 'beta', 'delta']
     }
 
     def testNewReader() {
-
         setup:
         final str = 'Hello world!'
-        def file = new File('test_new_reader')
+        def file = temporaryFolder.newFile()
         file.text = str
 
         when:
@@ -128,71 +123,51 @@ class NioGroovyMethodsTest extends Specification {
         then:
         line == str
         reader.readLine() == null
-
-        cleanup:
-        file?.delete()
     }
 
     def testGetBytes() {
-
         when:
-        def file = new File('test_getBytes')
+        def file = temporaryFolder.newFile()
         file.text = 'Hello world!'
-        def path = file.toPath()
 
         then:
-        path.getBytes() == 'Hello world!'.getBytes()
-
-        cleanup:
-        file?.delete()
+        file.toPath().getBytes() == 'Hello world!'.getBytes()
     }
 
     def testSetBytes() {
-
         when:
-        def file = new File('test_setBytes')
+        def file = temporaryFolder.newFile()
+        file.text = 'Hello world!'
         file.toPath().setBytes('Ciao mundo!'.getBytes())
 
         then:
         file.text == 'Ciao mundo!'
-
-        cleanup:
-        file?.delete()
     }
 
     def testSetText() {
-
         when:
-        def file = new File('test_setBytes')
+        def file = temporaryFolder.newFile()
         file.toPath().setText('Ciao mundo!')
         // invoke twice to make sure that the content is truncated by the setText method
         file.toPath().setText('Hello world!')
+
         then:
         file.text == 'Hello world!'
-
-        cleanup:
-        file?.delete()
-
     }
 
-    def testWrite( )  {
-
+    def testWrite()  {
         when:
-        String str = 'Hello there!'
-        def file = new File('test_write')
+        def str = 'Hello world!'
+        def file = temporaryFolder.newFile()
         file.toPath().write(str)
 
         then:
-        file.text == 'Hello there!'
-
-        cleanup:
-        file?.delete()
+        file.text == 'Hello world!'
     }
 
     def testAppendObject() {
-
         setup:
-        def file = new File('test_appendObject')
+        def file = temporaryFolder.newFile()
         file.text = 'alpha'
 
         when:
@@ -200,15 +175,11 @@ class NioGroovyMethodsTest extends Specification {
 
         then:
         file.text == 'alpha-gamma'
-
-        cleanup:
-        file.delete()
     }
 
     def testAppendBytes() {
-
         setup:
-        def file = new File('test_appendBytes')
+        def file = temporaryFolder.newFile()
         file.text = 'alpha'
 
         when:
@@ -216,201 +187,169 @@ class NioGroovyMethodsTest extends Specification {
 
         then:
         file.text == 'alpha-beta'
-
-        cleanup:
-        file.delete()
     }
 
     def testAppendInputStream() {
-
         setup:
-        def file = new File('test_appendStream')
+        def file = temporaryFolder.newFile()
         file.text = 'alpha'
 
         when:
-        file.toPath().append( new ByteArrayInputStream('-delta'.getBytes()) )
+        file.toPath().append(new ByteArrayInputStream('-delta'.getBytes()))
 
         then:
         file.text == 'alpha-delta'
-
-        cleanup:
-        file.delete()
     }
 
     def testLeftShift() {
         setup:
-        def file = Paths.get('test-shift')
-        Files.deleteIfExists(file)
+        def path = temporaryFolder.newFile().toPath()
+
         when:
-        file << 'Hello '
-        file << 'world!'
-        then:
-        file.text == 'Hello world!'
-        cleanup:
-        Files.deleteIfExists(file)
+        path << 'Hello '
+        path << 'world!'
 
+        then:
+        path.text == 'Hello world!'
     }
 
     def testEachFile() {
-
         setup:
-        def folder = Files.createTempDirectory('test')
+        def folder = temporaryFolder.newFolder('test').toPath()
         def file1 = Files.createTempFile(folder, 'file_1_', null)
         def file2 = Files.createTempFile(folder, 'file_2_', null)
         def file3 = Files.createTempFile(folder, 'file_X_', null)
-        // sub-folder with two files
         def sub1 = Files.createTempDirectory(folder, 'sub1_')
         def file4  = Files.createTempFile(sub1, 'file_4_', null)
         def file5  = Files.createTempFile(sub1, 'file_5_', null)
-        // sub-sub-folder with one file
         def sub2 = Files.createTempDirectory(sub1, 'sub2_')
         def file6  = Files.createTempFile(sub2, 'file_6_', null)
 
         when:
-        Set result = []
-        folder.eachFile() { result << it }
+        def result1 = []
+        folder.eachFile { result1 << it }
 
         then:
-        result == [file1, file2, file3, sub1] as Set
+        result1.sort() == [file1, file2, file3, sub1].sort()
 
         when:
-        Set result2 = []
+        def result2 = []
         folder.eachFile(FileType.FILES) { result2 << it }
 
         then:
-        result2 == [file1, file2, file3] as Set
+        result2.sort() == [file1, file2, file3].sort()
 
         when:
-        Set result3 = []
+        def result3 = []
         folder.eachFile(FileType.DIRECTORIES) { result3 << it }
 
         then:
-        result3 == [sub1]  as Set
+        result3 == [sub1]
 
         when:
-        Set result4 = []
+        def result4 = []
         folder.eachFileMatch(FileType.FILES, ~/file_\d_.*/) { result4 << it }
 
         then:
-        result4 == [file1, file2] as Set
+        result4.sort() == [file1, file2].sort()
 
         when:
-        Set result5 = []
+        def result5 = []
         folder.eachFileMatch(FileType.DIRECTORIES, ~/sub\d_.*/) { result5 << it }
 
         then:
-        result5 == [sub1] as Set
+        result5 == [sub1]
 
         when:
-        Set result6 = []
+        def result6 = []
         folder.eachFileRecurse(FileType.FILES) { result6 << it }
 
         then:
-        result6 == [file1, file2, file3, file4, file5, file6] as Set
+        result6.sort() == [file1, file2, file3, file4, file5, file6].sort()
 
         when:
-        Set result7 = []
+        def result7 = []
         folder.eachFileRecurse(FileType.DIRECTORIES) { result7 << it }
 
         then:
-        result7 == [sub1, sub2] as Set
-
-        cleanup:
-        folder?.toFile()?.deleteDir()
+        result7.sort() == [sub1, sub2].sort()
     }
 
     def testEachDir() {
-
         setup:
-        def folder = Files.createTempDirectory('test')
+        def folder = temporaryFolder.newFolder('test').toPath()
         def sub1 = Files.createTempDirectory(folder, 'sub_1_')
         def sub2 = Files.createTempDirectory(folder, 'sub_2_')
         def sub3 = Files.createTempDirectory(folder, 'sub_X_')
         def sub4 = Files.createTempDirectory(sub2, 'sub_2_4_')
         def sub5 = Files.createTempDirectory(sub2, 'sub_2_5_')
-        def file1 = Files.createTempFile(folder, 'file1', null)
-        def file2 = Files.createTempFile(folder, 'file2', null)
+        Files.createTempFile(folder, 'file1', null)
+        Files.createTempFile(folder, 'file2', null)
 
-        // test *eachDir*
         when:
-        def result = []
-        folder.eachDir { result << it }
+        def result1 = []
+        folder.eachDir { result1 << it }
 
         then:
-        result as Set == [ sub1, sub2, sub3 ] as Set
+        result1.sort() == [sub1, sub2, sub3].sort()
 
-        // test *eachMatchDir*
         when:
         def result2 = []
-        folder.eachDirMatch( ~/sub_\d_.*+/ ) { result2 << it }
+        folder.eachDirMatch(~/sub_\d_.*+/) { result2 << it }
 
         then:
-        result2 as Set == [ sub1, sub2 ] as Set
+        result2.sort() == [sub1, sub2].sort()
 
         when:
         def result3 = []
         folder.eachDirRecurse { result3 << it }
 
         then:
-        result3 as Set == [ sub1, sub2, sub4, sub5, sub3 ] as Set
-
-        cleanup:
-        folder?.deleteDir()
+        result3.sort() == [sub1, sub2, sub3, sub4, sub5].sort()
     }
 
-
     def testAppendUTF16LE() {
-
         setup:
-        final temp = Files.createTempDirectory('utf-test')
-        final path = temp.resolve('path_UTF-16LE.txt')
-        final file = new File( temp.toFile(), 'file_UTF-LE.txt')
-        final HELLO = 'Hello world!'
+        def path = temporaryFolder.newFile().toPath()
+        def file = temporaryFolder.newFile()
+        def str = 'Hello world!'
 
         // save using a File, thus uses ResourcesGroovyMethods
         when:
-        file.append( HELLO, 'UTF-16LE' )
+        file.append(str, 'UTF-16LE')
+
         then:
-        file.getText('UTF-16LE') == HELLO
+        file.getText('UTF-16LE') == str
 
         // now test append method using the Path
         when:
-        path.append('Hello ', 'UTF-16LE')
-        path.append('world!', 'UTF-16LE')
+        path.append(str, 'UTF-16LE')
+
         then:
-        path.getText('UTF-16LE') == HELLO
-        file.toPath().getText('UTF-16LE') == HELLO
+        path.getText('UTF-16LE') == str
+        file.toPath().getText('UTF-16LE') == str
 
         // append the content of a reader, thus using the 'appendBuffered' version
         when:
-        path.append( new StringReader(' - Hola Mundo!'), 'UTF-16LE' )
+        path.append(new StringReader(' - Hola Mundo!'), 'UTF-16LE')
+
         then:
         path.getText('UTF-16LE') == 'Hello world! - Hola Mundo!'
-
-        cleanup:
-        temp.toFile().deleteDir()
-
     }
 
     def testWriteUTF16BE() {
-
         setup:
-        final temp = Files.createTempDirectory('utf-test')
-        final path = temp.resolve('path_UTF-16BE.txt')
-        final HELLO = 'Hello world!'
+        def path = temporaryFolder.newFile().toPath()
+        def str = 'Hello world!'
 
         when:
-        path.write(HELLO, 'UTF-16BE')
-        then:
-        path.getText('UTF-16BE') == HELLO
-
-        cleanup:
-        temp.toFile().deleteDir()
+        path.write(str, 'UTF-16BE')
 
+        then:
+        path.getText('UTF-16BE') == str
     }
 
     def testWithCloseable() {
-
         setup:
         final closeable = new DummyCloseable()
 
@@ -418,7 +357,7 @@ class NioGroovyMethodsTest extends Specification {
         def closeableParam = null
         def result = closeable.withCloseable {
             closeableParam = it
-            return 123
+            123
         }
 
         then:
@@ -428,7 +367,6 @@ class NioGroovyMethodsTest extends Specification {
     }
 
     def testWithCloseableAndException() {
-
         setup:
         final closeable = new ExceptionDummyCloseable()
 
@@ -441,17 +379,17 @@ class NioGroovyMethodsTest extends Specification {
 }
 
 class DummyCloseable implements Closeable {
-    boolean closed = false;
+    boolean closed = false
 
     @Override
     void close() throws IOException {
-        closed = true;
+        closed = true
     }
 }
 
 class ExceptionDummyCloseable implements Closeable {
     @Override
     void close() throws IOException {
-        throw new IOException("boom badaboom")
+        throw new IOException('boom badaboom')
     }
 }
diff --git a/subprojects/groovy-servlet/build.gradle b/subprojects/groovy-servlet/build.gradle
index f0fd616..4731cfd 100644
--- a/subprojects/groovy-servlet/build.gradle
+++ b/subprojects/groovy-servlet/build.gradle
@@ -11,6 +11,7 @@ dependencies {
     compile project(':groovy-xml')
     // needed by TemplateServlet
     compile project(':groovy-templates')
+    testCompile rootProject.sourceSets.test.runtimeClasspath
     testCompile project(':groovy-test')
     // for compilation, dependency is not necessary because the classes are loaded using Class.forName
     testCompile project(':groovy-json')
diff --git a/subprojects/groovy-servlet/src/main/java/groovy/servlet/AbstractHttpServlet.java b/subprojects/groovy-servlet/src/main/java/groovy/servlet/AbstractHttpServlet.java
index 27fe455..65eedea 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/AbstractHttpServlet.java
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/AbstractHttpServlet.java
@@ -167,7 +167,6 @@ public abstract class AbstractHttpServlet extends HttpServlet implements Resourc
         this.logGROOVY861 = false;
     }
 
-
     protected void generateNamePrefixOnce () {
         URI uri = null;
 
@@ -176,7 +175,7 @@ public abstract class AbstractHttpServlet extends HttpServlet implements Resourc
 
         try {
             URL res = servletContext.getResource("/");
-            if (res != null) { uri = res.toURI();}
+            if (res != null) { uri = res.toURI(); }
         } catch (MalformedURLException ignore) {
         } catch (URISyntaxException ignore) {
         }
@@ -195,14 +194,14 @@ public abstract class AbstractHttpServlet extends HttpServlet implements Resourc
 
     protected String removeNamePrefix(String name) throws ResourceException {
         if (namePrefix == null) {
-          generateNamePrefixOnce();
+            generateNamePrefixOnce();
         }
         if (name.startsWith(namePrefix)) {//usualy name has text
-          return name.substring(namePrefix.length());
-        }//i else
+            return name.substring(namePrefix.length());
+        }
         return name;
     }
-    
+
     /**
      * Interface method for ResourceContainer. This is used by the GroovyScriptEngine.
      */
@@ -210,8 +209,11 @@ public abstract class AbstractHttpServlet extends HttpServlet implements Resourc
         name = removeNamePrefix(name).replace('\\', '/');
 
         //remove the leading / as we are trying with a leading / now
-        if (name.startsWith("WEB-INF/groovy/")) { name = name.substring(15);//just for uniformity
-        } else if (name.startsWith("/")) { name = name.substring(1);}
+        if (name.startsWith("WEB-INF/groovy/")) {
+            name = name.substring(15);//just for uniformity
+        } else if (name.startsWith("/")) {
+            name = name.substring(1);
+        }
 
         /*
         * Try to locate the resource and return an opened connection to it.
diff --git a/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletBinding.java b/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletBinding.java
index b5add85..d939ff6 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletBinding.java
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletBinding.java
@@ -128,8 +128,8 @@ public class ServletBinding extends Binding {
             this.response = response;
         }
         private ServletOutputStream getResponseStream() throws IOException {
-            if (writer!=null) throw new IllegalStateException("The variable 'out' or 'html' have been used already. Use either out/html or sout, not both.");
-            if (outputStream==null) outputStream = response.getOutputStream();
+            if (writer != null) throw new IllegalStateException("The variable 'out' or 'html' have been used already. Use either out/html or sout, not both.");
+            if (outputStream == null) outputStream = response.getOutputStream();
             return outputStream;
         }
         public ServletOutputStream getOutputStream() {
@@ -152,8 +152,8 @@ public class ServletBinding extends Binding {
             };
         }
         private PrintWriter getResponseWriter() {
-            if (outputStream!=null) throw new IllegalStateException("The variable 'sout' have been used already. Use either out/html or sout, not both.");
-            if (writer==null) {
+            if (outputStream != null) throw new IllegalStateException("The variable 'sout' have been used already. Use either out/html or sout, not both.");
+            if (writer == null) {
                 try {
                     writer = response.getWriter();
                 } catch (IOException ioe) {
@@ -360,4 +360,3 @@ public class ServletBinding extends Binding {
         response.sendRedirect(location);
     }    
 }
-
diff --git a/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletCategory.java b/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletCategory.java
index 6faa9ba..9ec50b5 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletCategory.java
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/ServletCategory.java
@@ -88,5 +88,4 @@ public class ServletCategory {
     public static void putAt(PageContext context, String key, Object value) {
         context.setAttribute(key, value);
     }
-
 }
diff --git a/subprojects/groovy-servlet/src/main/java/groovy/servlet/TemplateServlet.java b/subprojects/groovy-servlet/src/main/java/groovy/servlet/TemplateServlet.java
index 552c7b9..1a7b75c 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/TemplateServlet.java
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/TemplateServlet.java
@@ -167,7 +167,6 @@ public class TemplateServlet extends AbstractHttpServlet {
             }
             return "Hit #" + hit + " since " + date;
         }
-
     }
 
     /**
@@ -300,7 +299,6 @@ public class TemplateServlet extends AbstractHttpServlet {
      * @throws ServletException If the request specified an invalid template source file
      */
     protected Template getTemplate(File file) throws ServletException {
-
         String key = file.getAbsolutePath();
         Template template = findCachedTemplate(key, file);
 
@@ -332,7 +330,6 @@ public class TemplateServlet extends AbstractHttpServlet {
      * @throws ServletException If the request specified an invalid template source URL
      */
     protected Template getTemplate(URL url) throws ServletException {
-
         String key = url.toString();
         Template template = findCachedTemplate(key, null);
 
@@ -418,7 +415,6 @@ public class TemplateServlet extends AbstractHttpServlet {
      * @throws ServletException if the HTTP request cannot be handled
      */
     public void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
-
         if (verbose) {
             log("Creating/getting cached template...");
         }
@@ -503,6 +499,5 @@ public class TemplateServlet extends AbstractHttpServlet {
         if (verbose) {
             log("Template \"" + name + "\" request responded. [create/get=" + getMillis + " ms, make=" + makeMillis + " ms]");
         }
-
     }
 }
diff --git a/subprojects/groovy-servlet/src/main/java/groovy/servlet/package.html b/subprojects/groovy-servlet/src/main/java/groovy/servlet/package.html
index 134bc7c..ce73a60 100644
--- a/subprojects/groovy-servlet/src/main/java/groovy/servlet/package.html
+++ b/subprojects/groovy-servlet/src/main/java/groovy/servlet/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.servlet.*</title>
diff --git a/subprojects/groovy-servlet/src/spec/doc/servlet-userguide.adoc b/subprojects/groovy-servlet/src/spec/doc/servlet-userguide.adoc
new file mode 100644
index 0000000..1b474f9
--- /dev/null
+++ b/subprojects/groovy-servlet/src/spec/doc/servlet-userguide.adoc
@@ -0,0 +1,73 @@
+= Servlet support
+
+You can write (Java) Servlets in Groovy (called Groovlets).
+
+There is also a `GroovyServlet`.
+
+This feature will automatically compile your .groovy source files, turn them into bytecode, load the Class and cache it until you change the source file.
+
+Here's a simple example to show you the kind of things you can do from a Groovlet.
+
+Notice the use of implicit variables to access the session, output and request. Also notice that this is more like a script as it does not have a class wrapper.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-servlet/src/spec/test/servlet/GroovyServletTest.groovy[tags=example,indent=0]
+----
+
+Or, do the same thing using MarkupBuilder:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-servlet/src/spec/test/servlet/GroovyServletTest.groovy[tags=example_markup_builder,indent=0]
+----
+
+== Implicit variables
+
+The following variables are ready for use in Groovlets:
+
+[options="header",cols="1,1,1a"]
+|============================================
+|variable name|bound to|note
+|request|ServletRequest|-
+|response|ServletResponse|-
+|context|ServletContext|-
+|application|ServletContext|-
+|session|getSession(false)|can be null! see <1>
+|params||a Map object
+|headers||a Map object
+|out|response.getWriter()|see <2>
+|sout|response.getOutputStream()|see <2>
+|html|new MarkupBuilder(out)|see <2>
+|json|new StreamingJsonBuilder(out)|see <2>
+|============================================
+1. The session variable is only set, if there was already a session object. See the `if (session == null)` checks in the examples above.
+2. These variables cannot be re-assigned inside a `Groovlet`. They are bound on first access, allowing to e.g. calling methods on the `response` object before using `out`.
+
+== Setting up groovylets
+
+Add the following to your `web.xml`:
+[source,xml]
+--------------------------------------------------------------------------------------------------
+<servlet>
+    <servlet-name>Groovy</servlet-name>
+    <servlet-class>groovy.servlet.GroovyServlet</servlet-class>
+</servlet>
+
+<servlet-mapping>
+    <servlet-name>Groovy</servlet-name>
+    <url-pattern>*.groovy</url-pattern>
+</servlet-mapping>
+--------------------------------------------------------------------------------------------------
+
+Then put the required groovy jar files into `WEB-INF/lib`.
+
+Now put the .groovy files in, say, the root directory (i.e. where you would put your html files). The `GroovyServlet` takes care of compiling the .groovy files.
+
+So for example using tomcat you could edit `tomcat/conf/server.xml` like this:
+[source,xml]
+--------------------------------------------------------------------------------------------------
+<Context path="/groovy" docBase="c:/groovy-servlet"/>
+--------------------------------------------------------------------------------------------------
+
+Then access it with http://localhost:8080/groovy/hello.groovy
\ No newline at end of file
diff --git a/subprojects/groovy-servlet/src/spec/test/servlet/GroovyServletTest.groovy b/subprojects/groovy-servlet/src/spec/test/servlet/GroovyServletTest.groovy
new file mode 100644
index 0000000..eeb2a15
--- /dev/null
+++ b/subprojects/groovy-servlet/src/spec/test/servlet/GroovyServletTest.groovy
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package servlet
+
+import gls.CompilableTestSupport
+
+class GroovyServletTest extends CompilableTestSupport {
+
+    void testExample() {
+        shouldCompile '''
+            // tag::example[]
+            if (!session) {
+              session = request.getSession(true)
+            }
+
+            if (!session.counter) {
+              session.counter = 1
+            }
+
+            println """
+            <html>
+                <head>
+                    <title>Groovy Servlet</title>
+                </head>
+                <body>
+                    <p>
+            Hello, ${request.remoteHost}: ${session.counter}! ${new Date()}
+                    </p>
+                </body>
+            </html>
+            """
+            session.counter = session.counter + 1
+            // end::example[]
+        '''
+    }
+    
+    void testExampleMarkupBuilder() {
+        shouldCompile '''
+            // tag::example_markup_builder[]
+            if (!session) {
+                session = request.getSession(true)
+            }
+
+            if (!session.counter) {
+                session.counter = 1
+            }
+
+            html.html { // html is implicitly bound to new MarkupBuilder(out)
+              head {
+                  title('Groovy Servlet')
+              }
+              body {
+                p("Hello, ${request.remoteHost}: ${session.counter}! ${new Date()}")
+              }
+            }
+            session.counter = session.counter + 1
+            // end::example_markup_builder[]
+        '''
+    }
+}
diff --git a/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/AbstractHttpServletTest.groovy b/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/AbstractHttpServletTest.groovy
index 7c43777..87180b2 100644
--- a/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/AbstractHttpServletTest.groovy
+++ b/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/AbstractHttpServletTest.groovy
@@ -40,9 +40,8 @@ class AbstractHttpServletTest extends GroovyTestCase {
      * attributes if attributes exist on the http request.
      */
     void testGetScriptUri_AllAttributesExist() {
-
-        //just return whatever attributes were requested
-        def request = {attribute -> attribute}
+        // just return whatever attributes were requested
+        def request = { attribute -> attribute }
 
         assert servlet.getScriptUri(request as HttpServletRequest) ==
                 AbstractHttpServlet.INC_SERVLET_PATH + AbstractHttpServlet.INC_PATH_INFO
@@ -53,13 +52,9 @@ class AbstractHttpServletTest extends GroovyTestCase {
      * contains path but no path info attribute.
      */
     void testGetScriptUri_NoPathInfoAttribute() {
-
-        //just return whatever attributes were requested, except for path info attribute
-        def request = {attribute ->
-            if (attribute == AbstractHttpServlet.INC_PATH_INFO) {
-                return null
-            }
-            attribute
+        // just return whatever attributes were requested, except for path info attribute
+        def request = { attribute ->
+            attribute == AbstractHttpServlet.INC_PATH_INFO ? null : attribute
         }
 
         assert servlet.getScriptUri(request as HttpServletRequest) ==
@@ -72,13 +67,14 @@ class AbstractHttpServletTest extends GroovyTestCase {
      */
     void testGetScriptUri_NoAttributesPathInfoExists() {
         def request = [
-                getAttribute: {null},
-                getServletPath: {"servletPath"},
-                getPathInfo: {"pathInfo"}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { 'servletPath' },
+                getPathInfo: { 'pathInfo' }
+        ] as HttpServletRequest
 
         def servlet = new ConcreteHttpServlet()
-        assert servlet.getScriptUri(request) == "servletPathpathInfo"
 
+        assert servlet.getScriptUri(request) == 'servletPathpathInfo'
     }
 
     /**
@@ -87,56 +83,63 @@ class AbstractHttpServletTest extends GroovyTestCase {
      */
     void testGetScriptUri_NoAttributesPathInfoMissing() {
         def request = [
-                getAttribute: {null},
-                getServletPath: {"servletPath"},
-                getPathInfo: {null}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { 'servletPath' },
+                getPathInfo: { null }
+        ] as HttpServletRequest
 
         def servlet = new ConcreteHttpServlet()
-        assert servlet.getScriptUri(request) == "servletPath"
 
+        assert servlet.getScriptUri(request) == 'servletPath'
     }
 
     /**
      * Tests getting URIs as files.
      */
     void testGetScriptURIasFile() {
-
         def request = [
-                getAttribute: {null},
-                getServletPath: {"servletPath"},
-                getPathInfo: {"pathInfo"}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { 'servletPath' },
+                getPathInfo: { 'pathInfo' }
+        ] as HttpServletRequest
 
         def servletContext = [
-                getRealPath: { arg -> "realPath" + arg}] as ServletContext
+                getRealPath: { arg -> 'realPath' + arg }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {null}] as ServletConfig
+                getServletContext: { servletContext },
+                getInitParameter: { null }
+        ] as ServletConfig
 
         servlet.init(servletConfig)
         def file = servlet.getScriptUriAsFile(request)
-        assert file.getName() == "realPathservletPathpathInfo"
+
+        assert file.getName() == 'realPathservletPathpathInfo'
     }
 
     /**
      * Tests getting URIs as files where filename not available.
      */
     void testGetScriptURIasFileNoMapping() {
-
         def request = [
-                getAttribute: {null},
-                getServletPath: {"servletPath"},
-                getPathInfo: {"pathInfo"}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { 'servletPath' },
+                getPathInfo: { 'pathInfo' }
+        ] as HttpServletRequest
 
         def servletContext = [
-                getRealPath: { arg -> null}] as ServletContext
+                getRealPath: { arg -> null }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {null}] as ServletConfig
+                getServletContext: { servletContext },
+                getInitParameter: { null }
+        ] as ServletConfig
 
         servlet.init(servletConfig)
         def file = servlet.getScriptUriAsFile(request)
+
         assert file == null
     }
 
@@ -145,41 +148,42 @@ class AbstractHttpServletTest extends GroovyTestCase {
      */
     void testGetResourceConnection_MissingResource() {
         def servletContext = [
-                getRealPath: {arg -> "realPath" + arg},
-                getResource: {arg -> null}] as ServletContext
+                getRealPath: { arg -> 'realPath' + arg },
+                getResource: { arg -> null }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {null}] as ServletConfig
+                getServletContext: { servletContext },
+                getInitParameter: { null }
+        ] as ServletConfig
 
-        //servlet config is used to find resources
+        // servlet config is used to find resources
         servlet.init(servletConfig)
 
         shouldFail(groovy.util.ResourceException) {
-            servlet.getResourceConnection("someresource")
+            servlet.getResourceConnection('someresource')
         }
     }
 
     /**
      * Tests finding resource.
      */
-    public void testGetResourceConnection_FoundInCurrentDir() {
-        def urlStub = new java.net.URL("file:realPath/someresource")
+    void testGetResourceConnection_FoundInCurrentDir() {
+        def urlStub = new java.net.URL('file:realPath/someresource')
         def servletContext = [
-                getRealPath: { arg -> "realPath" + arg},
-                getResource: {arg ->
-                    if (arg == "/someresource") return urlStub
-                    return null
-                }] as ServletContext
+                getRealPath: { arg -> 'realPath' + arg },
+                getResource: { arg -> arg == '/someresource' ? urlStub : null }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {null}] as ServletConfig
+                getServletContext: { servletContext },
+                getInitParameter: { null }
+        ] as ServletConfig
 
-        //servlet config is used to find resources
+        // servlet config is used to find resources
         servlet.init(servletConfig)
 
-        def connection = servlet.getResourceConnection("someresource")
+        def connection = servlet.getResourceConnection('someresource')
 
         assert connection.getURL() == urlStub
     }
@@ -187,23 +191,22 @@ class AbstractHttpServletTest extends GroovyTestCase {
     /**
      * Tests finding resource in web-inf directory.
      */
-    public void testGetResourceConnection_FoundInWebInf() {
-        def urlStub = new java.net.URL("file:realPath/WEB-INF/groovy/someresource")
+    void testGetResourceConnection_FoundInWebInf() {
+        def urlStub = new java.net.URL('file:realPath/WEB-INF/groovy/someresource')
         def servletContext = [
-                getRealPath: { arg -> "realPath" + arg},
-                getResource: {arg ->
-                    if (arg == "/WEB-INF/groovy/someresource") return urlStub
-                    return null
-                }] as ServletContext
+                getRealPath: { arg -> 'realPath' + arg },
+                getResource: { arg -> arg == '/WEB-INF/groovy/someresource' ? urlStub : null }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {null}] as ServletConfig
+                getServletContext: { servletContext },
+                getInitParameter: { null }
+        ] as ServletConfig
 
-        //servlet config is used to find resources
+        // servlet config is used to find resources
         servlet.init(servletConfig)
 
-        def connection = servlet.getResourceConnection("someresource")
+        def connection = servlet.getResourceConnection('someresource')
 
         assert connection.getURL() == urlStub
     }
@@ -211,79 +214,79 @@ class AbstractHttpServletTest extends GroovyTestCase {
     /**
      * Tests regex style resource replacement for first occurrence.
      */
-    public void testGetResourceConnection_Replace1stFooWithBar() {
+    void testGetResourceConnection_Replace1stFooWithBar() {
         def servletContext = [
-                getRealPath: {arg -> "realPath" + arg},
-                getResource: {arg ->
-                    if (arg.startsWith("//")) arg = arg.substring(2)
-                    new URL("http://" + (arg == "/" ? "" : arg))
+                getRealPath: { arg -> 'realPath' + arg },
+                getResource: { arg ->
+                    if (arg.startsWith('//')) arg = arg.substring(2)
+                    new URL('http://' + (arg == '/' ? '' : arg))
                 }
         ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {arg ->
-                    //replace first occurrence of foo resources with bar resources
-                    if (arg == "resource.name.regex") return "foo"
-                    else if (arg == "resource.name.replacement") return "bar"
-                    else if (arg == "resource.name.replace.all") return "false"
+                getServletContext: { servletContext },
+                getInitParameter: { arg ->
+                    // replace first occurrence of foo resources with bar resources
+                    if (arg == 'resource.name.regex') return 'foo'
+                    else if (arg == 'resource.name.replacement') return 'bar'
+                    else if (arg == 'resource.name.replace.all') return 'false'
                     return null
-                }] as ServletConfig
+                }
+        ] as ServletConfig
 
         def request = [
-                getAttribute: {null},
-                getServletPath: {"/somefoo/foo"},
-                getPathInfo: {null}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { '/somefoo/foo' },
+                getPathInfo: { null }
+        ] as HttpServletRequest
 
-        //servlet config is used to find resources
+        // servlet config is used to find resources
         servlet.init(servletConfig)
 
-        //replace first foo with bar in resources
+        // replace first foo with bar in resources
         def connection = servlet.getResourceConnection(servlet.getScriptUri(request))
-        //expecting http://somebar/foo
-        def actual = connection.getURL().toExternalForm()
-        def expected = new URL("http:/somebar/foo").toExternalForm()
-        assert actual == expected
+
+        assert connection.getURL().toExternalForm() == new URL('http:/somebar/foo').toExternalForm()
     }
 
     /**
      * Tests regex style resource replacement for all occurrences.
      */
-    public void testGetResourceConnection_ReplaceAllFooWithBar() {
+    void testGetResourceConnection_ReplaceAllFooWithBar() {
         def servletContext = [
-                getRealPath: {arg -> "realPath" + arg},
-                getResource: {arg ->
-                    if (arg.startsWith("//")) arg = arg.substring(2)
-                    new URL("http://" + (arg == "/" ? "" : arg))
-                }] as ServletContext
+                getRealPath: { arg -> 'realPath' + arg },
+                getResource: { arg ->
+                    if (arg.startsWith('//')) arg = arg.substring(2)
+                    new URL('http://' + (arg == '/' ? '' : arg))
+                }
+        ] as ServletContext
 
         def servletConfig = [
-                getServletContext: {servletContext},
-                getInitParameter: {arg ->
-                    //replace all occurrences of foo resources with bar resources
-                    if (arg == "resource.name.regex") return "foo"
-                    else if (arg == "resource.name.replacement") return "bar"
-                    else if (arg == "resource.name.replace.all") return "true"
+                getServletContext: { servletContext },
+                getInitParameter: { arg ->
+                    // replace all occurrences of foo resources with bar resources
+                    if (arg == 'resource.name.regex') return 'foo'
+                    else if (arg == 'resource.name.replacement') return 'bar'
+                    else if (arg == 'resource.name.replace.all') return 'true'
                     return null
-                }] as ServletConfig
+                }
+        ] as ServletConfig
 
         def request = [
-                getAttribute: {null},
-                getServletPath: {"/somefoo/foo"},
-                getPathInfo: {null}] as HttpServletRequest
+                getAttribute: { null },
+                getServletPath: { '/somefoo/foo' },
+                getPathInfo: { null }
+        ] as HttpServletRequest
 
-        //servlet config is used to find resources
+        // servlet config is used to find resources
         servlet.init(servletConfig)
 
-        //replace all foo(s) with bar in resources
+        // replace all foo(s) with bar in resources
         def connection = servlet.getResourceConnection(servlet.getScriptUri(request))
-        //expecting http://somebar/foo
-        def actual = connection.getURL().toExternalForm()
-        def expected = new URL("http:/somebar/bar").toExternalForm()
-        assert actual == expected
+
+        assert connection.getURL().toExternalForm() == new URL('http:/somebar/bar').toExternalForm()
     }
 }
 
-//test specific subclass
+// test specific subclass
 class ConcreteHttpServlet extends AbstractHttpServlet {}
-
diff --git a/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/ServletBindingTest.groovy b/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/ServletBindingTest.groovy
index 458e979..272b83b 100644
--- a/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/ServletBindingTest.groovy
+++ b/subprojects/groovy-servlet/src/test/groovy/groovy/servlet/ServletBindingTest.groovy
@@ -33,11 +33,7 @@ class ServletBindingTest extends GroovyTestCase {
     def response = {} as HttpServletResponse
     def context = {} as ServletContext
 
-    void setUp() {
-        super.setUp()
-    }
-
-    def makeDefaultBinding = {request ->
+    def makeDefaultBinding = { request ->
         new ServletBinding(
                 request as HttpServletRequest,
                 response as HttpServletResponse,
@@ -46,9 +42,11 @@ class ServletBindingTest extends GroovyTestCase {
     }
 
     def makeDefaultRequest = {
-        [getSession: {session},
-                getParameterNames: {new Vector().elements()},
-                getHeaderNames: {new Vector().elements()}] as HttpServletRequest
+        [
+            getSession: { session },
+            getParameterNames: { new Vector().elements() },
+            getHeaderNames: { new Vector().elements() }
+        ] as HttpServletRequest
     }
 
     /**
@@ -58,41 +56,39 @@ class ServletBindingTest extends GroovyTestCase {
         def request = makeDefaultRequest()
         def binding = makeDefaultBinding(request)
 
-        assert request == binding.getVariable("request")
-        assert response == binding.getVariable("response")
-        assert context == binding.getVariable("context")
-        assert context == binding.getVariable("application")
-        assert session == binding.getVariable("session")
-        assertTrue binding.getVariable("params").isEmpty()
-        assertTrue binding.getVariable("headers").isEmpty()
+        assert request == binding.getVariable('request')
+        assert response == binding.getVariable('response')
+        assert context == binding.getVariable('context')
+        assert context == binding.getVariable('application')
+        assert session == binding.getVariable('session')
+        assert binding.getVariable('params').isEmpty()
+        assert binding.getVariable('headers').isEmpty()
     }
 
     /**
      * Tests that the constructor binds request parameter names correctly.
      */
     void testConstructor_ParameterNameBindings() {
-
         def parmNames = new Vector()
-        parmNames.add("name1")
-        parmNames.add("name2")
+        parmNames.add('name1')
+        parmNames.add('name2')
 
         def request = [
-                getSession: {session},
-                getHeaderNames: {new Vector().elements()},
-                getParameterNames: {parmNames.elements()},
+                getSession: { session },
+                getHeaderNames: { new Vector().elements() },
+                getParameterNames: { parmNames.elements() },
                 getParameterValues: {
-                    //prepend string parm to known value to simulate attribute map
-                    String[] arr = new String[1];
-                    arr[0] = "value_for_" + it
-                    return arr
-                }] as HttpServletRequest
+                    // prepend string parm to known value to simulate attribute map
+                    ['value_for_' + it] as String[]
+                }
+        ] as HttpServletRequest
 
         def binding = makeDefaultBinding(request)
 
-        def variables = binding.getVariable("params")
+        def variables = binding.getVariable('params')
         assert 2 == variables.size()
-        assert "value_for_name1" == variables.get("name1")
-        assert "value_for_name2" == variables.get("name2")
+        assert 'value_for_name1' == variables.get('name1')
+        assert 'value_for_name2' == variables.get('name2')
     }
 
     /**
@@ -100,48 +96,48 @@ class ServletBindingTest extends GroovyTestCase {
      */
     void testConstructor_HeaderBindings() {
         def headerNames = new Vector()
-        headerNames.add("name1")
-        headerNames.add("name2")
+        headerNames.add('name1')
+        headerNames.add('name2')
 
         def request = [
                 getSession: {session},
                 getParameterNames: {new Vector().elements()},
                 getHeaderNames: {headerNames.elements()},
                 getHeader: {
-                    //prepend string parm to known value to simulate attribute map
-                    "value_for_" + it
-                }] as HttpServletRequest
+                    // prepend string parm to known value to simulate header map
+                    'value_for_' + it
+                }
+        ] as HttpServletRequest
 
         def binding = makeDefaultBinding(request)
 
-        def variables = binding.getVariable("headers")
+        def variables = binding.getVariable('headers')
         assert 2 == variables.size()
-        assert "value_for_name1" == variables.get("name1")
-        assert "value_for_name2" == variables.get("name2")
+        assert 'value_for_name1' == variables.get('name1')
+        assert 'value_for_name2' == variables.get('name2')
     }
 
     /**
      * Tests the argument contract on getVariable.
      */
     void testGetVariable_Contract() {
-
         def request = makeDefaultRequest()
         def binding = makeDefaultBinding(request)
 
         shouldFail(IllegalArgumentException) { binding.getVariable(null) }
-        shouldFail(IllegalArgumentException) { binding.getVariable("") }
+        shouldFail(IllegalArgumentException) { binding.getVariable('') }
     }
 
     /**
      * Tests that getVariables truely returns all variables
      */
     void testGetVariables_Contract() {
-
-        def expectedVariables = ["request", "response", "context", "application",
-                "session", "params", "headers", "out", "sout", "html", "json"]
+        def expectedVariables = ['request', 'response', 'context', 'application',
+                'session', 'params', 'headers', 'out', 'sout', 'html', 'json']
         def request = makeDefaultRequest()
         def binding = makeDefaultBinding(request)
         def keys = binding.variables.keySet()
+
         expectedVariables.each {
             assert keys.contains(it)
         }
@@ -151,13 +147,13 @@ class ServletBindingTest extends GroovyTestCase {
      * Tests that getVariable works for the special key names.
      */
     void testGetVariable_ImplicitKeyNames() {
-
         def writer = new PrintWriter(new StringWriter())
         def outputStream = new OutputStreamStub()
 
         def response = [
-                getWriter: {writer},
-                getOutputStream: {outputStream}] as HttpServletResponse
+                getWriter: { writer },
+                getOutputStream: { outputStream }
+        ] as HttpServletResponse
 
         def request = makeDefaultRequest()
 
@@ -167,20 +163,20 @@ class ServletBindingTest extends GroovyTestCase {
                 context as ServletContext
         )
 
-        assert binding.getVariable("out") instanceof PrintWriter
-        assert binding.getVariable("html") instanceof MarkupBuilder
-        assert binding.getVariable("sout") instanceof ServletOutputStream
-        assert binding.getVariable("json") instanceof groovy.json.StreamingJsonBuilder
+        assert binding.getVariable('out') instanceof PrintWriter
+        assert binding.getVariable('html') instanceof MarkupBuilder
+        assert binding.getVariable('sout') instanceof ServletOutputStream
+        assert binding.getVariable('json') instanceof groovy.json.StreamingJsonBuilder
     }
-    
-    void testOutSoutWriteException() {
 
+    void testOutSoutWriteException() {
         def writer = new PrintWriter(new StringWriter())
         def outputStream = new OutputStreamStub()
 
         def response = [
-                getWriter: {writer},
-                getOutputStream: {outputStream}] as HttpServletResponse
+                getWriter: { writer },
+                getOutputStream: { outputStream }
+        ] as HttpServletResponse
 
         def request = makeDefaultRequest()
 
@@ -190,22 +186,23 @@ class ServletBindingTest extends GroovyTestCase {
                 context as ServletContext
         )
 
-        binding.out.print("foo")
+        binding.out.print('foo')
         binding.html.foo()
-		binding.out.print(binding.json.foo())
+        binding.out.print(binding.json.foo())
+
         shouldFail(IllegalStateException) {
-            binding.sout.print("foo")
+            binding.sout.print('foo')
         }
     }
-    
-    void testSoutOutWriteException() {
 
+    void testSoutOutWriteException() {
         def writer = new PrintWriter(new StringWriter())
         def outputStream = new OutputStreamStub()
 
         def response = [
-                getWriter: {writer},
-                getOutputStream: {outputStream}] as HttpServletResponse
+                getWriter: { writer },
+                getOutputStream: { outputStream }
+        ] as HttpServletResponse
 
         def request = makeDefaultRequest()
 
@@ -215,9 +212,9 @@ class ServletBindingTest extends GroovyTestCase {
                 context as ServletContext
         )
 
-        binding.sout.print("foo")
+        binding.sout.print('foo')
         shouldFail(IllegalStateException) {
-            binding.out.print("foo")
+            binding.out.print('foo')
         }
         shouldFail(IllegalStateException) {
             binding.html.foo()
@@ -228,16 +225,15 @@ class ServletBindingTest extends GroovyTestCase {
      * Tests the contract on setVarible().
      */
     void testSetVariable_Contract() {
-
         def request = makeDefaultRequest()
         def binding = makeDefaultBinding(request)
 
         shouldFail(IllegalArgumentException) { binding.setVariable(null, null) }
-        shouldFail(IllegalArgumentException) { binding.setVariable("", null) }
-        shouldFail(IllegalArgumentException) { binding.setVariable("out", null) }
-        shouldFail(IllegalArgumentException) { binding.setVariable("sout", null) }
-        shouldFail(IllegalArgumentException) { binding.setVariable("html", null) }
-		shouldFail(IllegalArgumentException) { binding.setVariable("json", null) }
+        shouldFail(IllegalArgumentException) { binding.setVariable('', null) }
+        shouldFail(IllegalArgumentException) { binding.setVariable('out', null) }
+        shouldFail(IllegalArgumentException) { binding.setVariable('sout', null) }
+        shouldFail(IllegalArgumentException) { binding.setVariable('html', null) }
+        shouldFail(IllegalArgumentException) { binding.setVariable('json', null) }
     }
 
     /**
@@ -247,9 +243,10 @@ class ServletBindingTest extends GroovyTestCase {
         def request = makeDefaultRequest()
         def binding = makeDefaultBinding(request)
 
-        binding.setVariable("var_name", "var_value")
+        binding.setVariable('var_name', 'var_value')
         def variables = binding.getVariables()
-        assert "var_value" == variables.get("var_name")
+
+        assert 'var_value' == variables.get('var_name')
     }
 }
 
diff --git a/subprojects/groovy-servlet/src/test/java/groovy/servlet/GroovyServletTest.java b/subprojects/groovy-servlet/src/test/java/groovy/servlet/GroovyServletTest.java
index 487acfc..0ecd30c 100644
--- a/subprojects/groovy-servlet/src/test/java/groovy/servlet/GroovyServletTest.java
+++ b/subprojects/groovy-servlet/src/test/java/groovy/servlet/GroovyServletTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.servlet;
 
 import javax.servlet.http.HttpServletRequest;
diff --git a/subprojects/groovy-sql/src/main/java/groovy/sql/DataSet.java b/subprojects/groovy-sql/src/main/java/groovy/sql/DataSet.java
index 6795019..b8875fa 100644
--- a/subprojects/groovy-sql/src/main/java/groovy/sql/DataSet.java
+++ b/subprojects/groovy-sql/src/main/java/groovy/sql/DataSet.java
@@ -67,6 +67,8 @@ import java.util.Set;
  */
 public class DataSet extends Sql {
 
+    private static final int[] EMPTY_INT_ARRAY = new int[0];
+
     private Closure where;
     private Closure sort;
     private boolean reversed = false;
@@ -207,7 +209,7 @@ public class DataSet extends Sql {
         closure.call(this);
         withinDataSetBatch = false;
         if (batchData.size() == 0) {
-            return new int[0];
+            return EMPTY_INT_ARRAY;
         }
         Closure transformedClosure = new Closure(null) {
             public void doCall(BatchingPreparedStatementWrapper stmt) throws SQLException {
diff --git a/subprojects/groovy-sql/src/main/java/groovy/sql/ResultSetMetaDataWrapper.java b/subprojects/groovy-sql/src/main/java/groovy/sql/ResultSetMetaDataWrapper.java
index 2dea757..14ca794 100644
--- a/subprojects/groovy-sql/src/main/java/groovy/sql/ResultSetMetaDataWrapper.java
+++ b/subprojects/groovy-sql/src/main/java/groovy/sql/ResultSetMetaDataWrapper.java
@@ -41,6 +41,7 @@ import org.codehaus.groovy.runtime.InvokerHelper;
  */
 public class ResultSetMetaDataWrapper extends GroovyObjectSupport {
 
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
     private ResultSetMetaData target;
     private int index;
 
@@ -73,7 +74,7 @@ public class ResultSetMetaDataWrapper extends GroovyObjectSupport {
 
     @Override
     public Object getProperty(String property) {
-        return invokeMethod(getPropertyGetterName(property), new Object[0]);
+        return invokeMethod(getPropertyGetterName(property), EMPTY_OBJECT_ARRAY);
     }
 
     @Override
diff --git a/subprojects/groovy-sql/src/main/java/groovy/sql/Sql.java b/subprojects/groovy-sql/src/main/java/groovy/sql/Sql.java
index 0c59175..84769e0 100644
--- a/subprojects/groovy-sql/src/main/java/groovy/sql/Sql.java
+++ b/subprojects/groovy-sql/src/main/java/groovy/sql/Sql.java
@@ -2709,6 +2709,7 @@ public class Sql {
      *                       inserted row or rows (some drivers may be case sensitive, e.g. may require uppercase names)
      * @return A list of the auto-generated row results for each inserted row (typically auto-generated keys)
      * @throws SQLException if a database access error occurs
+     * @since 2.3.2
      */
     public List<GroovyRowResult> executeInsert(String sql, String[] keyColumnNames) throws SQLException {
         Connection connection = createConnection();
@@ -2743,6 +2744,7 @@ public class Sql {
      *                       into the SQL statement's parameter slots
      * @return A list of the auto-generated row results for each inserted row (typically auto-generated keys)
      * @throws SQLException if a database access error occurs
+     * @since 2.3.2
      */
     public List<GroovyRowResult> executeInsert(String sql, String[] keyColumnNames, Object[] params) throws SQLException {
         return executeInsert(sql, Arrays.asList(params), Arrays.asList(keyColumnNames));
diff --git a/subprojects/groovy-sql/src/main/java/groovy/sql/package.html b/subprojects/groovy-sql/src/main/java/groovy/sql/package.html
index 1fd3885..dba27dd 100644
--- a/subprojects/groovy-sql/src/main/java/groovy/sql/package.html
+++ b/subprojects/groovy-sql/src/main/java/groovy/sql/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.sql.*</title>
diff --git a/subprojects/groovy-swing/build.gradle b/subprojects/groovy-swing/build.gradle
index 1b0d0b5..8111323 100644
--- a/subprojects/groovy-swing/build.gradle
+++ b/subprojects/groovy-swing/build.gradle
@@ -6,4 +6,6 @@ dependencies {
 task moduleDescriptor(type: org.codehaus.groovy.gradle.WriteExtensionDescriptorTask) {
     extensionClasses = 'org.codehaus.groovy.runtime.SwingGroovyMethods'
 }
-compileJava.dependsOn moduleDescriptor
\ No newline at end of file
+compileJava.dependsOn moduleDescriptor
+
+apply from: "${rootProject.projectDir}/gradle/jacoco/jacocofix.gradle"
\ No newline at end of file
diff --git a/subprojects/groovy-swing/src/main/groovy/groovy/swing/binding/package.html b/subprojects/groovy-swing/src/main/groovy/groovy/swing/binding/package.html
index c172696..33ae605 100644
--- a/subprojects/groovy-swing/src/main/groovy/groovy/swing/binding/package.html
+++ b/subprojects/groovy-swing/src/main/groovy/groovy/swing/binding/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.swing.binding.*</title>
diff --git a/subprojects/groovy-swing/src/main/groovy/groovy/swing/factory/package.html b/subprojects/groovy-swing/src/main/groovy/groovy/swing/factory/package.html
index c7106e1..a27a750 100644
--- a/subprojects/groovy-swing/src/main/groovy/groovy/swing/factory/package.html
+++ b/subprojects/groovy-swing/src/main/groovy/groovy/swing/factory/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.swing.factory.*</title>
diff --git a/subprojects/groovy-swing/src/main/groovy/groovy/swing/impl/package.html b/subprojects/groovy-swing/src/main/groovy/groovy/swing/impl/package.html
index 897df7f..665a8d0 100644
--- a/subprojects/groovy-swing/src/main/groovy/groovy/swing/impl/package.html
+++ b/subprojects/groovy-swing/src/main/groovy/groovy/swing/impl/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.swing.impl.*</title>
diff --git a/subprojects/groovy-swing/src/main/groovy/groovy/swing/package.html b/subprojects/groovy-swing/src/main/groovy/groovy/swing/package.html
index 451766f..0cb1ac7 100644
--- a/subprojects/groovy-swing/src/main/groovy/groovy/swing/package.html
+++ b/subprojects/groovy-swing/src/main/groovy/groovy/swing/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.swing.*</title>
diff --git a/subprojects/groovy-swing/src/main/java/groovy/model/package.html b/subprojects/groovy-swing/src/main/java/groovy/model/package.html
index 718cdfb..3a11806 100644
--- a/subprojects/groovy-swing/src/main/java/groovy/model/package.html
+++ b/subprojects/groovy-swing/src/main/java/groovy/model/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.model.*</title>
diff --git a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/ClosureSourceBinding.java b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/ClosureSourceBinding.java
index 61aad1f..f7de388 100644
--- a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/ClosureSourceBinding.java
+++ b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/ClosureSourceBinding.java
@@ -24,11 +24,13 @@ import groovy.lang.Closure;
  */
 public class ClosureSourceBinding implements SourceBinding {
 
+    private static final Object[] EMPTY_OBJECT_ARRAY = new Object[0];
+
     Closure closure;
     Object[] arguments;
 
     public ClosureSourceBinding(Closure closure) {
-        this(closure, new Object[0]);
+        this(closure, EMPTY_OBJECT_ARRAY);
     }
 
     public ClosureSourceBinding(Closure closure, Object[] arguments) { //TODO in Groovy 2.0 use varargs?
diff --git a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/package.html b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/package.html
index e7145de..6b47cd1 100644
--- a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/package.html
+++ b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/binding/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package org.codehaus.groovy.binding.*</title>
diff --git a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/runtime/SwingGroovyMethods.java b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/runtime/SwingGroovyMethods.java
index ee8313c..f0d7f10 100644
--- a/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/runtime/SwingGroovyMethods.java
+++ b/subprojects/groovy-swing/src/main/java/org/codehaus/groovy/runtime/SwingGroovyMethods.java
@@ -16,6 +16,7 @@
 package org.codehaus.groovy.runtime;
 
 import groovy.lang.GString;
+import org.codehaus.groovy.runtime.typehandling.ShortTypeHandling;
 
 import javax.swing.*;
 import javax.swing.table.DefaultTableModel;
@@ -673,7 +674,7 @@ public class SwingGroovyMethods {
      */
     @SuppressWarnings("unchecked")
     public static Iterator<TreeNode> iterator(TreeNode self) {
-        return DefaultGroovyMethods.iterator(self.children());
+        return (Iterator<TreeNode>) DefaultGroovyMethods.iterator(self.children());
     }
 
     /**
@@ -1046,4 +1047,15 @@ public class SwingGroovyMethods {
     public static Component getAt(JToolBar self, int index) {
         return self.getComponentAtIndex(index);
     }
+
+    /**
+     * Allows the usage of a one-element string for a mnemonic
+     * @param button a AbstractButton
+     * @param mnemonic the String
+     * @since 2.3.7
+     */
+    public static void setMnemonic(AbstractButton button, String mnemonic) {
+        char c = ShortTypeHandling.castToChar(mnemonic);
+        button.setMnemonic(c);
+    }
 }
diff --git a/subprojects/groovy-swing/src/spec/assets/img/SwingBuilder001.gif b/subprojects/groovy-swing/src/spec/assets/img/SwingBuilder001.gif
new file mode 100644
index 0000000..393316d
Binary files /dev/null and b/subprojects/groovy-swing/src/spec/assets/img/SwingBuilder001.gif differ
diff --git a/subprojects/groovy-swing/src/spec/doc/swing-builder.adoc b/subprojects/groovy-swing/src/spec/doc/swing-builder.adoc
new file mode 100644
index 0000000..02d9cf0
--- /dev/null
+++ b/subprojects/groovy-swing/src/spec/doc/swing-builder.adoc
@@ -0,0 +1,38 @@
+[[swingbuilder]]
+= SwingBuilder
+
+`SwingBuilder` allows you to create full-fledged Swing GUIs in a declarative and concise fashion. It accomplishes this by employing a common idiom in Groovy, builders.
+Builders handle the busywork of creating complex objects for you, such as instantiating children, calling Swing methods, and attaching these children to their parents.
+As a consequence, your code is much more readable and maintainable, while still allowing you access to the full range of Swing components.
+
+Here's a simple example of using `SwingBuilder`:
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy[tags=simple_example,indent=0]
+----
+
+Here is what it will look like:
+
+image::assets/img/SwingBuilder001.gif[]
+
+This hierarchy of components would normally be created through a series of repetitive instantiations, setters, and finally attaching this child to its respective parent.
+Using `SwingBuilder`, however, allows you to define this hierarchy in its native form, which makes the interface design understandable simply by reading the code.
+
+The flexibility shown here is made possible by leveraging the many programming features built-in to Groovy, such as closures, implicit constructor calling, import aliasing, and string interpolation. 
+Of course, these do not have to be fully understood in order to use `SwingBuilder`; as you can see from the code above, their uses are intuitive.
+
+Here is a slightly more involved example, with an example of `SwingBuilder` code re-use via a closure.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy[tags=more_involved_example,indent=0]
+----
+
+Here's another variation that relies on observable beans and binding:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy[tags=observable_binding_example,indent=0]
+----
+
+<<core-metaprogramming.adoc#xform-Bindable, at Bindable>> is one of the core AST Transformations. It generates all the required boilerplate code to turn a simple bean into an observable one. The `bind()` node creates appropriate `PropertyChangeListeners` that will update the interested parties whenever a `PropertyChangeEvent` is fired.
\ No newline at end of file
diff --git a/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy b/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy
new file mode 100644
index 0000000..46a1fd2
--- /dev/null
+++ b/subprojects/groovy-swing/src/spec/test/SwingBuilderTest.groovy
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+ 
+import gls.CompilableTestSupport
+
+class DesignPatternsTest extends CompilableTestSupport {
+
+    void testSimpleExample() {
+        shouldCompile '''
+        // tag::simple_example[]
+        import groovy.swing.SwingBuilder
+        import java.awt.BorderLayout as BL
+        
+        count = 0
+        new SwingBuilder().edt {
+          frame(title: 'Frame', size: [300, 300], show: true) {
+            borderLayout()
+            textlabel = label(text: 'Click the button!', constraints: BL.NORTH)
+            button(text:'Click Me',
+                 actionPerformed: {count++; textlabel.text = "Clicked ${count} time(s)."; println "clicked"}, constraints:BL.SOUTH)
+          }
+        }
+        // end::simple_example[]
+        '''
+    }
+
+    void testMoreInvolvedExample() {
+        shouldCompile '''
+        // tag::more_involved_example[]
+        import groovy.swing.SwingBuilder
+        import javax.swing.*
+        import java.awt.*
+
+        def swing = new SwingBuilder()
+
+        def sharedPanel = {
+             swing.panel() {
+                label("Shared Panel")
+            }
+        }
+
+        count = 0
+        swing.edt {
+            frame(title: 'Frame', defaultCloseOperation: JFrame.EXIT_ON_CLOSE, pack: true, show: true) {
+                vbox {
+                    textlabel = label('Click the button!')
+                    button(
+                        text: 'Click Me',
+                        actionPerformed: {
+                            count++
+                            textlabel.text = "Clicked ${count} time(s)."
+                            println "Clicked!"
+                        }
+                    )
+                    widget(sharedPanel())
+                    widget(sharedPanel())
+                }
+            }
+        }
+        // end::more_involved_example[]
+        '''
+    }
+    
+    void testObservableBindingExample() {
+        shouldCompile '''
+        // tag::observable_binding_example[]
+        import groovy.swing.SwingBuilder
+        import groovy.beans.Bindable
+
+        class MyModel {
+           @Bindable int count = 0
+        }
+
+        def model = new MyModel()
+        new SwingBuilder().edt {
+          frame(title: 'Java Frame', size: [100, 100], locationRelativeTo: null, show: true) {
+            gridLayout(cols: 1, rows: 2)
+            label(text: bind(source: model, sourceProperty: 'count', converter: { v ->  v? "Clicked $v times": ''}))
+            button('Click me!', actionPerformed: { model.count++ })
+          }
+        }
+        // end::observable_binding_example[]
+        '''
+    }
+}
diff --git a/subprojects/groovy-swing/src/test/groovy/groovy/model/TableModelTest.groovy b/subprojects/groovy-swing/src/test/groovy/groovy/model/TableModelTest.groovy
index 1c4ef67..8f2ea89 100644
--- a/subprojects/groovy-swing/src/test/groovy/groovy/model/TableModelTest.groovy
+++ b/subprojects/groovy-swing/src/test/groovy/groovy/model/TableModelTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.model
 
 class TableModelTest extends GroovyTestCase {
diff --git a/subprojects/groovy-templates/build.gradle b/subprojects/groovy-templates/build.gradle
index e39ab2b..a821a27 100644
--- a/subprojects/groovy-templates/build.gradle
+++ b/subprojects/groovy-templates/build.gradle
@@ -1,7 +1,11 @@
 dependencies {
     compile rootProject
     compile project(':groovy-xml')
+    testCompile rootProject.sourceSets.test.runtimeClasspath
     testCompile project(':groovy-test')
+    testCompile("org.spockframework:spock-core:0.7-groovy-2.0") {
+        exclude module: 'groovy-all'
+    }
 }
 
 task backportJar(type:Jar) {
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/GStringTemplateEngine.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/GStringTemplateEngine.java
index d6d6e0a..cb7bea1 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/GStringTemplateEngine.java
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/GStringTemplateEngine.java
@@ -90,6 +90,7 @@ import org.codehaus.groovy.control.CompilationFailedException;
 public class GStringTemplateEngine extends TemplateEngine {
     private final ClassLoader parentLoader;
     private static AtomicInteger counter = new AtomicInteger();
+    private static final boolean reuseClassLoader = Boolean.getBoolean("groovy.GStringTemplateEngine.reuseClassLoader");
 
     public GStringTemplateEngine() {
         this(GStringTemplate.class.getClassLoader());
@@ -178,7 +179,8 @@ public class GStringTemplateEngine extends TemplateEngine {
 
             templateExpressions.append("}}");
 
-            final GroovyClassLoader loader = parentLoader instanceof GroovyClassLoader?(GroovyClassLoader)parentLoader:(
+            // Use a new class loader by default for each class so each class can be independently garbage collected
+            final GroovyClassLoader loader = reuseClassLoader && parentLoader instanceof GroovyClassLoader?(GroovyClassLoader)parentLoader:(
                     (GroovyClassLoader) AccessController.doPrivileged(new PrivilegedAction() {
                         public Object run() {
                             return new GroovyClassLoader(parentLoader);
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/StreamingTemplateEngine.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/StreamingTemplateEngine.java
new file mode 100644
index 0000000..fd2d260
--- /dev/null
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/StreamingTemplateEngine.java
@@ -0,0 +1,970 @@
+/*
+ * Copyright 2003-2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.text;
+
+import groovy.lang.*;
+
+import org.codehaus.groovy.control.CompilationFailedException;
+import org.codehaus.groovy.control.ErrorCollector;
+import org.codehaus.groovy.control.MultipleCompilationErrorsException;
+import org.codehaus.groovy.control.messages.Message;
+import org.codehaus.groovy.control.messages.SyntaxErrorMessage;
+import org.codehaus.groovy.runtime.StackTraceUtils;
+import org.codehaus.groovy.syntax.SyntaxException;
+
+import java.io.IOException;
+import java.io.LineNumberReader;
+import java.io.Reader;
+import java.io.StringReader;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+/**
+ * Processes template source files substituting variables and expressions into
+ * placeholders in a template source text to produce the desired output using a
+ * closure based approach. This engine has equivalent functionality to the
+ * {@link groovy.text.SimpleTemplateEngine} but creates the template using
+ * writable closures making it more scalable for large templates.
+ * <p>
+ * Specifically this template engine can handle strings larger than 64k which
+ * still causes problems for the other groovy template engines.
+ * </p>
+ * <p>
+ * The template engine uses JSP style <% %> script and <%= %>
+ * expression syntax or GString style expressions. The variable
+ * '<code>out</code>' is bound to the writer that the template is being written
+ * to.
+ * </p>
+ * Frequently, the template source will be in a file but here is a simple
+ * example providing the template as a string:
+ * <pre>
+ *
+ * def binding = [
+ *   firstname : "Grace",
+ *   lastname  : "Hopper",
+ *   accepted  : true,
+ *   title     : 'Groovy for COBOL programmers'
+ * ]
+ * def text = '''\
+ * Dear <% out.print firstname %> ${lastname},
+ *
+ * We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> \
+ * to inform you that your paper entitled
+ * '$title' was ${ accepted ? 'accepted' : 'rejected' }.
+ *
+ * The conference committee.
+ * '''
+ *
+ * def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)
+ *
+ * print template.make(binding)
+ * </pre>
+ *
+ * This example uses a mix of the JSP style and GString style
+ * placeholders but you can typically use just one style if you wish. Running
+ * this example will produce this output:
+ *
+ * <pre>
+ *
+ * Dear Grace Hopper,
+ *
+ * We are pleased to inform you that your paper entitled
+ * 'Groovy for COBOL programmers' was accepted.
+ *
+ * The conference committee.
+ * </pre>
+ * <br />
+ * <h3>StreamingTemplateEngine as a servlet engine</h3>
+ * The template engine can also be used as the engine for
+ * {@link groovy.servlet.TemplateServlet} by placing the following in your
+ * <code>web.xml</code> file (plus a corresponding servlet-mapping element):
+ * <pre>
+ *
+ * <servlet>
+ *   <servlet-name>StreamingTemplate</servlet-name>
+ *   <servlet-class>groovy.servlet.TemplateServlet</servlet-class>
+ *   <init-param>
+ *     <param-name>template.engine</param-name>
+ *     <param-value>groovy.text.StreamingTemplateEngine</param-value>
+ *   </init-param>
+ * </servlet>
+ * </pre> In this case, your template source file should be HTML with the
+ * appropriate embedded placeholders.
+ *
+ * <h3>Debugging Template Code</h3>
+ * <p>The template engine makes an effort to throw descriptive exceptions with
+ * context lines, ie:
+ * <pre>
+ *  groovy.text.TemplateExecutionException: Template parse error at line 4:
+ *           3: We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+ *       --> 4: '$txitle' was ${ accepted ? 'accepted' : 'rejected' }.
+ *           5:
+ * at test.run(test.groovy:18)
+ *
+ * Caused by: groovy.lang.MissingPropertyException: No such property: txitle for class: groovy.tmp.templates.StreamingTemplateScript1
+ * ... 1 more
+ * </pre>
+ * and sanitize the exceptions to make things readable.
+ * </p>
+ * <p>When the exceptions are not enough, it might sometimes be useful to view the actual script source
+ * generated by the template engine. This would conceptually be equivalent to viewing the
+ * .java file generated for a jsp page. The source is not currently very readable and
+ * until we get a built in groovy code pretty printer, we will probably continue to opt for compactness
+ * rather than readability.</p>
+ *
+ * <p>With that being said, viewing the source might still have some value. For this reason the script
+ * source is accessible via the template.scriptSource property, i.e.:
+ * <pre>
+ *     println template.scriptSource
+ * </pre>
+ * In the above example.
+ * </p>
+ *
+ * @author mbjarland at gmail.com
+ * @author Matias Bjarland
+ */
+public class StreamingTemplateEngine extends TemplateEngine {
+    private static final String TEMPLATE_SCRIPT_PREFIX = "StreamingTemplateScript";
+
+    private final ClassLoader parentLoader;
+    private static int counter = 1;
+
+    /**
+     * Create a streaming template engine instance using the default class loader
+     */
+    public StreamingTemplateEngine() {
+        this(StreamingTemplate.class.getClassLoader());
+    }
+
+    /**
+     * Create a streaming template engine instance using a custom class loader
+     *
+     * <p>The custom loader is used when parsing the template code</p>
+     *
+     * @param parentLoader The class loader to use when parsing the template code.
+     */
+    public StreamingTemplateEngine(ClassLoader parentLoader) {
+        this.parentLoader = parentLoader;
+    }
+
+    /**
+     * <p>Creates a template instance using the template source from the provided Reader.</p>
+     *
+     * <p>The template can be applied repeatedly on different bindings to produce custom
+     * output.</p>
+     *
+     *
+     * <strong>Technical detail</strong><br />
+     * Under the hood the returned template is represented as a four argument
+     * closure where the three first arguments are {@link groovy.lang.Closure#curry curried} in
+     * while generating the template. <br />
+     * <br />
+     * In essence we start with a closure on the form:
+     *
+     * <pre>
+     *   { parentClass, stringSectionList, binding, out ->
+     *      //code generated by parsing the template data
+     *   }                                                                             *
+     * </pre>
+     *
+     * , we then curry in the parentClass and stringSectionList arguments so that the StreamingTemplate
+     * instance returned from 'createTemplate' internally contains a template closure on the form:
+     *
+     * <pre>
+     *   { binding, out ->
+     *      //code generated by parsing the template data
+     *   }                                                                             *
+     * </pre>
+     *
+     * Calling template.make(binding), curries in the 'binding' argument:
+     *
+     * <pre>
+     *   public Writable make(final Map map) {
+     *     final Closure template = this.template.curry(new Object[]{map});
+     *     return (Writable) template;
+     *   }
+     * </pre>
+     *
+     * which only leaves the 'out' argument unbound. The only method on the {@link groovy.lang.Writable writable} interface is
+     * {@link groovy.lang.Writable#writeTo writeTo(Writer out)} so groovy rules about casting a closure to a one-method-interface
+     * apply and the above works. I.e. we return the now one argument closure as the Writable
+     * which can be serialized to System.out, a file, etc according to the Writable interface contract.
+     * </p>
+     * @see groovy.text.TemplateEngine#createTemplate(java.io.Reader)
+     */
+    @Override
+    public Template createTemplate(final Reader reader) throws CompilationFailedException, ClassNotFoundException, IOException {
+        return new StreamingTemplate(reader, parentLoader);
+    }
+
+    /**
+     * The class used to implement the Template interface for the StreamingTemplateEngine
+     *
+     */
+    private static class StreamingTemplate implements Template {
+        /**
+         * The 'header' we use for the resulting groovy script source.
+         */
+        private static final String SCRIPT_HEAD
+                = "package groovy.tmp.templates;"
+                + "def getTemplate() { "
+                    //the below params are:
+                    //  _p - parent class, for handling exceptions
+                    //  _s - sections, string sections list
+                    //  _b - binding map
+                    //  out - out stream
+                    //the three first parameters will be curried in as we move along
+                +   "return { _p, _s, _b, out -> "
+                +     "int _i = 0;"
+                +     "try {"
+                +       "delegate = new Binding(_b);";
+
+        /**
+         * The 'footer' we use for the resulting groovy script source
+         */
+        private static final String SCRIPT_TAIL
+                =     "} catch (Throwable e) { "
+                +       "_p.error(_i, _s, e);"
+                +     "}"
+                +   "}.asWritable()"
+                + "}";
+
+        private StringBuilder templateSource;
+
+        // we use a hard index instead of incrementing the _i variable due to previous
+        // bug where the increment was not executed when hitting non-executed if branch
+        private int index = 0;
+        final Closure template;
+
+        String scriptSource;
+
+        private static class FinishedReadingException extends Exception {}
+
+        //WE USE THIS AS REUSABLE        
+        //CHECKSTYLE.OFF: ConstantNameCheck - special case with a reusable exception
+        private static final FinishedReadingException finishedReadingException;
+        //CHECKSTYLE.ON: ConstantNameCheck
+
+        public static final StackTraceElement[] EMPTY_STACKTRACE = new StackTraceElement[0];
+
+        static {
+            finishedReadingException = new FinishedReadingException();
+            finishedReadingException.setStackTrace(EMPTY_STACKTRACE);
+        }
+
+        private static final class Position {
+            //CHECKSTYLE.OFF: VisibilityModifierCheck - special case, direct access for performance
+            public int row;
+            public int column;
+            //CHECKSTYLE.ON: VisibilityModifierCheck
+
+            private Position(int row, int column) {
+                this.row = row;
+                this.column = column;
+            }
+
+            private Position(Position p) {
+                set(p);
+            }
+
+            private void set(Position p) {
+                this.row = p.row;
+                this.column = p.column;
+            }
+
+            public String toString() {
+                return row + ":" + column;
+            }
+        }
+
+        /**
+         * A StringSection represent a section in the template source
+         * with only string data (i.e. no branching, GString references, etc).
+         * As an example, the following template string:
+         *
+         * <pre>
+         * Alice why is a $bird like a writing desk
+         * </pre>
+         *
+         * Would produce a string section "Alice why is a " followed by
+         * a dollar identifier expression followed by another string
+         * section " like a writing desk".
+         */
+        private static final class StringSection {
+            StringBuilder data;
+            Position firstSourcePosition;
+            Position lastSourcePosition;
+            Position lastTargetPosition;
+
+            private StringSection(Position firstSourcePosition) {
+                this.data = new StringBuilder();
+                this.firstSourcePosition = new Position(firstSourcePosition);
+            }
+
+            @Override
+            public String toString() {
+                return data.toString();
+            }
+        }
+
+        /**
+         * Called to handle the ending of a string section.
+         *
+         * @param sections The list of string sections. The current section gets added to this section.
+         * @param currentSection The current string section.
+         * @param templateExpressions Template expressions
+         * @param lastSourcePosition The last read position in the source template stream.
+         * @param targetPosition The last written to position in the target script stream.
+         */
+        private void finishStringSection(List<StringSection> sections, StringSection currentSection,
+                                         StringBuilder templateExpressions,
+                                         Position lastSourcePosition, Position targetPosition) {
+            //when we get exceptions from the parseXXX methods in the main loop, we might try to
+            //re-finish a section
+            if (currentSection.lastSourcePosition != null) {
+                return;
+            }
+            currentSection.lastSourcePosition = new Position(lastSourcePosition);
+            sections.add(currentSection);
+            append(templateExpressions, targetPosition, "out<<_s[_i=" + index++ + "];");
+            currentSection.lastTargetPosition = new Position(targetPosition.row, targetPosition.column);
+        }
+
+        public void error(int index, List<StringSection> sections, Throwable e) throws Throwable {
+            int i = Math.max(0, index);
+            StringSection precedingSection = sections.get(i);
+            int traceLine = -1;
+            for (StackTraceElement element : e.getStackTrace()) {
+                if (element.getClassName().contains(TEMPLATE_SCRIPT_PREFIX)) {
+                    traceLine = element.getLineNumber();
+                    break;
+                }
+            }
+
+            if (traceLine != -1) {
+                int actualLine = precedingSection.lastSourcePosition.row + traceLine - 1;
+                String message = "Template execution error at line " + actualLine + ":\n" + getErrorContext(actualLine);
+                TemplateExecutionException unsanitized = new TemplateExecutionException(actualLine, message, StackTraceUtils.sanitize(e));
+                throw StackTraceUtils.sanitize(unsanitized);
+            } else {
+                throw e;
+            }
+        }
+
+        private int getLinesInSource() throws IOException {
+            int result = 0;
+
+            LineNumberReader reader = null;
+            try {
+                reader = new LineNumberReader(new StringReader(templateSource.toString()));
+                reader.skip(Long.MAX_VALUE);
+                result = reader.getLineNumber();
+            } finally {
+                if (reader != null) {
+                    reader.close();
+                }
+            }
+
+            return result;
+        }
+
+        private String getErrorContext(int actualLine) throws IOException {
+            int minLine = Math.max(0, actualLine -1);
+            int maxLine = Math.min(getLinesInSource(), actualLine + 1);
+
+            LineNumberReader r = new LineNumberReader(new StringReader(templateSource.toString()));
+            int lineNr;
+            StringBuilder result = new StringBuilder();
+            while ((lineNr = r.getLineNumber()+1) <= maxLine) {
+                String line = r.readLine();
+                if (lineNr < minLine) continue;
+
+                String nr = Integer.toString(lineNr);
+                if (lineNr == actualLine) {
+                    nr = " --> " + nr;
+                }
+
+                result.append(padLeft(nr, 10));
+                result.append(": ");
+                result.append(line);
+                result.append('\n');
+            }
+
+            return result.toString();
+        }
+
+        private String padLeft(String s, int len) {
+            StringBuilder b = new StringBuilder(s);
+            while (b.length() < len) b.insert(0, " ");
+            return b.toString();
+        }
+
+        /**
+         * Turn the template into a writable Closure. When executed the closure
+         * evaluates all the code embedded in the template and then writes a
+         * GString containing the fixed and variable items to the writer passed
+         * as a parameter
+         * <p/>
+         * For example:
+         * <pre>
+         * '<%= "test" %> of expr and <% test = 1 %>${test} script.'
+         * </pre>
+         * would compile into:
+         * <pre>
+         * { out -> out << "${"test"} of expr and "; test = 1 ; out << "${test} script."}.asWritable()
+         * </pre>
+         * @param source A reader into the template source data
+         * @param parentLoader A class loader we use
+         * @throws CompilationFailedException
+         * @throws ClassNotFoundException
+         * @throws IOException
+         */
+        StreamingTemplate(final Reader source, final ClassLoader parentLoader) throws CompilationFailedException, ClassNotFoundException, IOException {
+            final StringBuilder target = new StringBuilder();
+            List<StringSection> sections = new ArrayList<StringSection>();
+            Position sourcePosition = new Position(1, 1);
+            Position targetPosition = new Position(1, 1);
+            Position lastSourcePosition = new Position(1, 1);
+            StringSection currentSection = new StringSection(sourcePosition);
+            templateSource = new StringBuilder();
+
+            //we use the lookAhead to make sure that a template file ending in say "abcdef\\"
+            //will give a result of "abcdef\\" even though we have special handling for \\
+            StringBuilder lookAhead = new StringBuilder(10);
+
+            append(target, targetPosition, SCRIPT_HEAD);
+            try {
+                int skipRead = -1;
+                //noinspection InfiniteLoopStatement
+                while (true) {
+                    lastSourcePosition.set(sourcePosition);
+
+                    int c = (skipRead != -1) ? skipRead : read(source, sourcePosition, lookAhead);
+                    skipRead = -1;
+
+                    if (c == '\\') {
+                        handleEscaping(source, sourcePosition, currentSection, lookAhead);
+                        continue;
+                    } else if (c == '<') {
+                        c = read(source, sourcePosition, lookAhead);
+                        if (c == '%') {
+                            c = read(source, sourcePosition);
+                            clear(lookAhead);
+                            if (c == '=') {
+                                finishStringSection(sections, currentSection, target, lastSourcePosition, targetPosition);
+                                parseExpression(source, target, sourcePosition, targetPosition);
+                                currentSection = new StringSection(sourcePosition);
+                                continue;
+                            } else {
+                                finishStringSection(sections, currentSection, target, lastSourcePosition, targetPosition);
+                                parseSection(c, source, target, sourcePosition, targetPosition);
+                                currentSection = new StringSection(sourcePosition);
+                                continue;
+                            }
+                        } else {
+                            currentSection.data.append('<');
+                        }
+                    } else if (c == '$') {
+                        c = read(source, sourcePosition);
+                        clear(lookAhead);
+                        if (c == '{') {
+                            finishStringSection(sections, currentSection, target, lastSourcePosition, targetPosition);
+                            parseDollarCurlyIdentifier(source, target, sourcePosition, targetPosition);
+                            currentSection = new StringSection(sourcePosition);
+                            continue;
+                        } else if (Character.isJavaIdentifierStart(c)) {
+                            finishStringSection(sections, currentSection, target, lastSourcePosition, targetPosition);
+                            skipRead = parseDollarIdentifier(c, source, target, sourcePosition, targetPosition);
+                            currentSection = new StringSection(sourcePosition);
+                            continue;
+                        } else {
+                            currentSection.data.append('$');
+                        }
+                    }
+                    currentSection.data.append((char) c);
+                    clear(lookAhead);
+                }
+            } catch (FinishedReadingException e) {
+                if (lookAhead.length() > 0) {
+                    currentSection.data.append(lookAhead);
+                }
+                //Ignored here, just used for exiting the read loop. Yeah I know we don't like
+                //empty catch blocks or expected behavior trowing exceptions, but this just cleaned out the code
+                //_so_ much that I thought it worth it...this once -Matias Bjarland 20100126
+            }
+
+            finishStringSection(sections, currentSection, target, sourcePosition, targetPosition);
+            append(target, targetPosition, SCRIPT_TAIL);
+
+            scriptSource = target.toString();
+
+            this.template = createTemplateClosure(sections, parentLoader, target);
+        }
+
+        private static void clear(StringBuilder lookAhead) {
+            lookAhead.delete(0, lookAhead.length());
+        }
+
+        private void handleEscaping(final Reader source,
+                                    final Position sourcePosition,
+                                    final StringSection currentSection,
+                                    final StringBuilder lookAhead) throws IOException, FinishedReadingException {
+            //if we get here, we just read in a back-slash from the source, now figure out what to do with it
+            int c = read(source, sourcePosition, lookAhead);
+
+            /*
+             The _only_ special escaping this template engine allows is to escape the sequences:
+             ${ and <% and potential slashes in front of these. Escaping in any other sections of the
+             source string is ignored. The following is a source -> result mapping of a few values, assume a
+             binding of [alice: 'rabbit'].
+
+             Note: we don't do java escaping of slashes in the below
+             example, i.e. the source string is what you would see in a text editor when looking at your template
+             file: 
+             source string     result
+             'bob'            -> 'bob'
+             '\bob'           -> '\bob'
+             '\\bob'          -> '\\bob'
+             '${alice}'       -> 'rabbit'
+             '\${alice}'      -> '${alice}'
+             '\\${alice}'     -> '\rabbit'
+             '\\$bob'         -> '\\$bob'
+             '\\'             -> '\\'
+             '\\\'             -> '\\\'
+             '%<= alice %>'   -> 'rabbit'
+             '\%<= alice %>'  -> '%<= alice %>'
+             */
+            if (c == '\\') {
+                //this means we have received a double backslash sequence
+                //if this is followed by ${ or <% we output one backslash
+                //and interpret the following sequences with groovy, if followed by anything
+                //else we output the two backslashes and continue as usual 
+                source.mark(3);
+                int d = read(source, sourcePosition, lookAhead);
+                c = read(source, sourcePosition, lookAhead);
+                clear(lookAhead);
+                if ((d == '$' && c == '{') ||
+                    (d == '<' && c == '%')) {
+                    source.reset();
+                    currentSection.data.append('\\');
+                    return;
+                } else {
+                    currentSection.data.append('\\');
+                    currentSection.data.append('\\');
+                    currentSection.data.append((char) d);
+                }
+            } else if (c == '$') {
+                c = read(source, sourcePosition, lookAhead);
+                if (c == '{') {
+                    currentSection.data.append('$');
+                } else {
+                    currentSection.data.append('\\');
+                    currentSection.data.append('$');
+                }
+            } else if (c == '<') {
+                c = read(source, sourcePosition, lookAhead);
+                if (c == '%') {
+                    currentSection.data.append('<');
+                } else {
+                    currentSection.data.append('\\');
+                    currentSection.data.append('<');
+                }
+            } else {
+                currentSection.data.append('\\');
+            }
+
+            currentSection.data.append((char) c);
+            clear(lookAhead);
+        }
+
+        private Closure createTemplateClosure(List<StringSection> sections, final ClassLoader parentLoader, StringBuilder target) throws ClassNotFoundException {
+            final GroovyClassLoader loader = AccessController.doPrivileged(new PrivilegedAction<GroovyClassLoader>() {
+                public GroovyClassLoader run() {
+                    return new GroovyClassLoader(parentLoader);
+                }
+            });
+            final Class groovyClass;
+            try {
+                groovyClass = loader.parseClass(new GroovyCodeSource(target.toString(), TEMPLATE_SCRIPT_PREFIX + counter++ + ".groovy", "x"));
+            } catch (MultipleCompilationErrorsException e) {
+                throw mangleMultipleCompilationErrorsException(e, sections);
+
+            } catch (Exception e) {
+                throw new GroovyRuntimeException("Failed to parse template script (your template may contain an error or be trying to use expressions not currently supported): " + e.getMessage());
+            }
+
+            Closure result;
+            try {
+                final GroovyObject object = (GroovyObject) groovyClass.newInstance();
+                Closure chicken = (Closure) object.invokeMethod("getTemplate", null);
+                //bind the two first parameters of the generated closure to this class and the sections list
+                result = chicken.curry(this, sections);
+            } catch (InstantiationException e) {
+                throw new ClassNotFoundException(e.getMessage());
+            } catch (IllegalAccessException e) {
+                throw new ClassNotFoundException(e.getMessage());
+            }
+
+            return result;
+        }
+
+        /**
+         * Parses a non curly dollar preceded identifier of the type
+         * '$bird' in the following template example:
+         *
+         * <pre>
+         * Alice why is a $bird like a writing desk
+         * </pre>
+         *
+         * which would produce the following template data:
+         *
+         * <pre>
+         * out << "Alice why is a ";
+         * out << bird;
+         * out << " like a writing desk";
+         * </pre>
+         *
+         * This method is given the 'b' in 'bird' in argument c, checks if it is a valid
+         * java identifier start (we assume groovy did not mangle the java
+         * identifier rules). If so it proceeds to parse characters from the input
+         * until it encounters a non-java-identifier character. At that point
+         *
+         * @param c The first letter of the potential identifier, 'b' in the above example
+         * @param reader The reader reading from the template source
+         * @param target The target groovy script source we write to
+         * @param sourcePosition The reader position in the source stream
+         * @param targetPosition The writer position in the target stream
+         * @return true if a valid dollar preceded identifier was found, false otherwise. More
+         *         specifically, returns true if the first character after the dollar sign is
+         *         a valid java identifier. Note that the dollar curly syntax is handled by
+         *         another method.
+         *
+         * @throws IOException
+         * @throws FinishedReadingException If we encountered the end of the source stream.
+         */
+        private int parseDollarIdentifier(int c ,
+                                          final Reader reader,
+                                          final StringBuilder target,
+                                          final Position sourcePosition,
+                                          final Position targetPosition) throws IOException, FinishedReadingException {
+            append(target, targetPosition, "out<<");
+            append(target, targetPosition, (char) c);
+
+            while (true) {
+                c = read(reader, sourcePosition);
+                if (!Character.isJavaIdentifierPart(c) || c == '$') {
+                    break;
+                }
+                append(target, targetPosition, (char) c);
+            }
+
+            append(target, targetPosition, ";");
+
+            return c;
+        }
+
+        /**
+         * Parses a dollar curly preceded identifier of the type
+         * '${bird}' in the following template example:
+         *
+         * <pre>
+         * Alice why is a ${bird} like a writing desk
+         * </pre>
+         *
+         * which would produce the following template data:
+         *
+         * <pre>
+         * out << "Alice why is a ";
+         * out << """${bird}""";
+         * out << " like a writing desk";
+         * </pre>
+         *
+         * This method is given the 'b' in 'bird' in argument c, checks if it is a valid
+         * java identifier start (we assume groovy did not mangle the java
+         * identifier rules). If so it proceeds to parse characters from the input
+         * until it encounters a non-java-identifier character. At that point
+         *
+         * @param reader The reader reading from the template source
+         * @param target The target groovy script source we write to
+         * @param sourcePosition The reader position in the source stream
+         * @param targetPosition The writer position in the target stream
+         * @throws IOException
+         * @throws FinishedReadingException
+         */
+        private void parseDollarCurlyIdentifier(final Reader reader,
+                                                final StringBuilder target,
+                                                final Position sourcePosition,
+                                                final Position targetPosition) throws IOException, FinishedReadingException {
+            append(target, targetPosition, "out<<\"\"\"${");
+
+            while (true) {
+                int c = read(reader, sourcePosition);
+                append(target, targetPosition, (char) c);
+                if (c == '}') break;
+            }
+
+            append(target, targetPosition, "\"\"\";");
+        }
+
+        /**
+         * Parse a <% .... %> section if we are writing a GString close and
+         * append ';' then write the section as a statement
+         */
+        private void parseSection(final int pendingC,
+                final Reader reader,
+                final StringBuilder target,
+                final Position sourcePosition,
+                final Position targetPosition) throws IOException, FinishedReadingException {
+            //the below is a quirk, we do this so that every non-string-section is prefixed by
+            //the same number of characters (the others have "out<<\"\"\"${"), this allows us to
+            //figure out the exception row and column later on
+            append(target, targetPosition, "          ");
+            append(target, targetPosition, (char) pendingC);
+
+            while (true) {
+                int c = read(reader, sourcePosition);
+                if (c == '%') {
+                    c = read(reader, sourcePosition);
+                    if (c == '>') break;
+                    append(target, targetPosition, '%');
+                }
+                append(target, targetPosition, (char) c);
+            }
+
+            append(target, targetPosition, ';');
+        }
+
+        /**
+         * Parse a <%= .... %> expression
+         */
+        private void parseExpression(final Reader reader,
+                final StringBuilder target,
+                final Position sourcePosition,
+                final Position targetPosition) throws IOException, FinishedReadingException {
+            append(target, targetPosition, "out<<\"\"\"${");
+
+            while (true) {
+                int c = read(reader, sourcePosition);
+                if (c == '%') {
+                    c = read(reader, sourcePosition);
+                    if (c == '>') break;
+                    append(target, targetPosition, '%');
+                }
+                append(target, targetPosition, (char) c);
+            }
+
+            append(target, targetPosition, "}\"\"\";");
+        }
+
+        @Override
+        public Writable make() {
+            return make(null);
+        }
+
+        @Override
+        public Writable make(final Map map) {
+            //we don't need a template.clone here as curry calls clone under the hood
+            final Closure template = this.template.curry(new Object[]{map});
+            return (Writable) template;
+        }
+
+        /*
+         * Create groovy assertion style error message for template error. Example:
+         *
+         * Error parsing expression on line 71 column 15, message: no such property jboss for for class DUMMY
+         * templatedata${jboss}templateddatatemplateddata
+         *             ^------^
+         *                 |
+         *           syntax error
+         */
+        private RuntimeException mangleMultipleCompilationErrorsException(MultipleCompilationErrorsException e, List<StringSection> sections) {
+            RuntimeException result = e;
+
+            ErrorCollector collector = e.getErrorCollector();
+            @SuppressWarnings({"unchecked"})
+            List<Message> errors = (List<Message>) collector.getErrors();
+            if (errors.size() > 0) {
+                Message firstMessage = errors.get(0);
+                if (firstMessage instanceof SyntaxErrorMessage) {
+                    @SuppressWarnings({"ThrowableResultOfMethodCallIgnored"})
+                    SyntaxException syntaxException = ((SyntaxErrorMessage) firstMessage).getCause();
+                    Position errorPosition = new Position(syntaxException.getLine(), syntaxException.getStartColumn());
+
+                    //find the string section which precedes the row/col of the thrown exception
+                    StringSection precedingSection = findPrecedingSection(errorPosition, sections);
+
+                    //and now use the string section to mangle the line numbers so that they refer to the
+                    //appropriate line in the source template data
+                    if (precedingSection != null) {
+                        //if the error was thrown on the same row as where the last string section
+                        //ended, fix column value
+                        offsetPositionFromSection(errorPosition, precedingSection);
+                        //the below being true indicates that we had an unterminated ${ or <% sequence and
+                        //the column is thus meaningless, we reset it to where the %{ or <% starts to at
+                        //least give the user a sporting chance
+                        if (sections.get(sections.size() - 1) == precedingSection) {
+                            errorPosition.column = precedingSection.lastSourcePosition.column;
+                        }
+
+                        String message = mangleExceptionMessage(e.getMessage(), errorPosition);
+                        result = new TemplateParseException(message, e, errorPosition.row, errorPosition.column);
+                    }
+                }
+            }
+
+            return result;
+        }
+
+        private String mangleExceptionMessage(String original, Position p) {
+            String result = original;
+            int index = result.indexOf("@ line ");
+            if (index != -1) {
+                result = result.substring(0, index);
+            }
+
+            int count = 0;
+            index = 0;
+            for (char c : result.toCharArray()) {
+                if (c == ':') {
+                    count++;
+                    if (count == 3) {
+                        result = result.substring(index + 2);
+                        break;
+                    }
+                }
+                index++;
+            }
+
+            String msg = "Template parse error '" + result + "' at line " + p.row + ", column " + p.column;
+            try {
+                msg += "\n" + getErrorContext(p.row);
+            } catch (IOException e) {
+                //we opt for not doing anthing here...we just do not get context if
+                //this happens
+            }
+
+            return msg;
+        }
+
+        private void offsetPositionFromSection(Position p, StringSection s) {
+            if (p.row == s.lastTargetPosition.row) {
+                //The number 8 below represents the number of characters in the header of a non-string-section such as
+                //<% ... %>. A section like this is represented in the target script as:
+                //out<<"""......."""
+                //12345678
+                p.column -= s.lastTargetPosition.column + 8;
+                p.column += s.lastSourcePosition.column;
+            }
+
+            p.row += s.lastSourcePosition.row - 1;
+        }
+
+        private StringSection findPrecedingSection(Position p, List<StringSection> sections) {
+            StringSection result = null;
+            for (StringSection s : sections) {
+                if (s.lastTargetPosition.row > p.row
+                        || (s.lastTargetPosition.row == p.row && s.lastTargetPosition.column > p.column)) {
+                    break;
+                }
+                result = s;
+            }
+
+            return result;
+        }
+
+        private void append(final StringBuilder target, Position targetPosition, char c) {
+            if (c == '\n') {
+                targetPosition.row++;
+                targetPosition.column = 1;
+            } else {
+                targetPosition.column++;
+            }
+
+            target.append(c);
+        }
+
+        private void append(final StringBuilder target, Position targetPosition, String s) {
+            int len = s.length();
+            for (int i = 0; i < len; i++) {
+                append(target, targetPosition, s.charAt(i));
+            }
+        }
+
+        private int read(final Reader reader, Position position, StringBuilder lookAhead) throws IOException, FinishedReadingException {
+            int c = read(reader, position);
+            lookAhead.append((char) c);
+            return c;
+        }
+
+        // SEE BELOW
+        boolean useLastRead = false;
+        private int lastRead = -1;
+
+        /* All \r\n sequences are treated as a single \n. By doing this we
+         * produce the same output as the GStringTemplateEngine. Otherwise, some
+         * of our output is on a newline when it should not be.
+         *
+         * Instead of using a pushback reader, we just keep a private instance
+         * variable 'lastRead'.
+         */
+        private int read(final Reader reader, Position position) throws IOException, FinishedReadingException {
+            int c;
+
+            if (useLastRead) {
+                // use last one if we stored a character
+                c = lastRead;
+                // reset last
+                useLastRead = false;
+                lastRead = -1;
+            } else {
+                c = read(reader);
+                if (c == '\r') {
+                    // IF CRLF JUST KEEP LF
+                    c = read(reader);
+                    if (c != '\n') {
+                        // ELSE keep original char
+                        // and pushback the one we just read
+                        lastRead = c;
+                        useLastRead = true;
+                        c = '\r';
+                    }
+                }
+            }
+
+            if (c == -1) {
+                throw finishedReadingException;
+            }
+
+            if (c == '\n') {
+                position.row++;
+                position.column = 1;
+            } else {
+                position.column++;
+            }
+
+            return c;
+        }
+
+        private int read(final Reader reader) throws IOException {
+            int c = reader.read();
+            templateSource.append((char) c);
+            return c;
+        }
+    }
+}
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateExecutionException.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateExecutionException.java
new file mode 100644
index 0000000..c062cda
--- /dev/null
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateExecutionException.java
@@ -0,0 +1,52 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.text;
+
+/**
+ * A custom exception class to flag template execution errors
+ */
+public class TemplateExecutionException extends Exception  {
+    private int lineNumber;
+
+    public TemplateExecutionException(int lineNumber) {
+        super();
+        this.lineNumber = lineNumber;
+    }
+
+    public TemplateExecutionException(int lineNumber, String message) {
+        super(message);
+        this.lineNumber = lineNumber;
+    }
+
+    public TemplateExecutionException(int lineNumber, String message, Throwable cause) {
+        super(message, cause);
+        this.lineNumber = lineNumber;
+    }
+
+    public TemplateExecutionException(int lineNumber, Throwable cause) {
+        super(cause);
+        this.lineNumber = lineNumber;
+    }
+
+    /**
+     * Returns the line number in the template source where the error occurred
+     *
+     * @return the one-based line number of the template parsing error.
+     */
+    public int getLineNumber() {
+        return lineNumber;
+    }
+}
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateParseException.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateParseException.java
new file mode 100644
index 0000000..0a5c537
--- /dev/null
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/TemplateParseException.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2003-2013 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.text;
+
+/**
+ * A custom exception class to flag template parsing errors
+ */
+public class TemplateParseException extends RuntimeException {
+    private int lineNumber;
+    private int column;
+
+    public TemplateParseException(int lineNumber, int column) {
+        super();
+        this.lineNumber = lineNumber;
+        this.column = column;
+    }
+
+    public TemplateParseException(String message, int lineNumber, int column) {
+        super(message);
+        this.lineNumber = lineNumber;
+        this.column = column;
+    }
+
+    public TemplateParseException(String message, Throwable cause, int lineNumber, int column) {
+        super(message, cause);
+        this.lineNumber = lineNumber;
+        this.column = column;
+    }
+
+    public TemplateParseException(Throwable t, int lineNumber, int column) {
+        super(t);
+        this.lineNumber = lineNumber;
+        this.column = column;
+    }
+
+    public int getLineNumber() {
+        return lineNumber;
+    }
+
+    public int getColumn() {
+        return column;
+    }
+}
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateEngine.java b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateEngine.java
index 5983120..43da682 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateEngine.java
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/MarkupTemplateEngine.java
@@ -31,6 +31,7 @@ import org.codehaus.groovy.control.SourceUnit;
 import org.codehaus.groovy.control.customizers.ASTTransformationCustomizer;
 import org.codehaus.groovy.control.customizers.CompilationCustomizer;
 import org.codehaus.groovy.runtime.DefaultGroovyMethods;
+import org.codehaus.groovy.classgen.asm.BytecodeDumper;
 
 import java.io.File;
 import java.io.IOException;
@@ -59,7 +60,9 @@ public class MarkupTemplateEngine extends TemplateEngine {
     static final ClassNode MARKUPTEMPLATEENGINE_CLASSNODE = ClassHelper.make(MarkupTemplateEngine.class);
     static final String MODELTYPES_ASTKEY = "MTE.modelTypes";
 
-    private static final Pattern LOCALIZED_RESOURCE_PATTERN = Pattern.compile("(.+?)(?:_([a-z]{2}(?:_[A-Z]{2,3})))?\\.(\\p{Alnum}+)");
+    private static final Pattern LOCALIZED_RESOURCE_PATTERN = Pattern.compile("(.+?)(?:_([a-z]{2}(?:_[A-Z]{2,3})))?\\.([\\p{Alnum}.]+)$");
+
+    private static final boolean DEBUG_BYTECODE = Boolean.valueOf(System.getProperty("markuptemplateengine.compiler.debug","false"));
 
     private static final AtomicLong counter = new AtomicLong();
 
@@ -69,6 +72,10 @@ public class MarkupTemplateEngine extends TemplateEngine {
     private final Map<String, GroovyCodeSource> codeSourceCache = new LinkedHashMap<String, GroovyCodeSource>();
     private final TemplateResolver templateResolver;
 
+    public MarkupTemplateEngine() {
+        this(new TemplateConfiguration());
+    }
+
     public MarkupTemplateEngine(final TemplateConfiguration tplConfig) {
         this(MarkupTemplateEngine.class.getClassLoader(), tplConfig);
     }
@@ -98,6 +105,9 @@ public class MarkupTemplateEngine extends TemplateEngine {
                 return new TemplateGroovyClassLoader(parentLoader, compilerConfiguration);
             }
         });
+        if (DEBUG_BYTECODE) {
+            compilerConfiguration.setBytecodePostprocessor(BytecodeDumper.STANDARD_ERR);
+        }
         templateResolver = resolver == null ? new DefaultTemplateResolver() : resolver;
         templateResolver.configure(groovyClassLoader, templateConfiguration);
     }
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/package.html b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/package.html
index 8e1f206..51ea7b7 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/package.html
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/markup/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.text.markup.*</title>
diff --git a/subprojects/groovy-templates/src/main/groovy/groovy/text/package.html b/subprojects/groovy-templates/src/main/groovy/groovy/text/package.html
index d3f8669..f032fbb 100644
--- a/subprojects/groovy-templates/src/main/groovy/groovy/text/package.html
+++ b/subprojects/groovy-templates/src/main/groovy/groovy/text/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.text.*</title>
diff --git a/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc b/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc
index ec7078a..e6510de 100644
--- a/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc
+++ b/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc
@@ -6,21 +6,21 @@ builder syntax. Here is a sample template:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_template,indent=0]
 ----
 
 If you feed it with the following model:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_model,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_model,indent=0]
 ----
 
 It would be rendered as:
 
 [source,xml]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_expected,indent=0]
 ----
 
 The key features of this template engine are:
@@ -36,11 +36,11 @@ The key features of this template engine are:
 == The template format
 === Basics
 
-Templates consist of Groovy code. Let's explore the first example more throughfully:
+Templates consist of Groovy code. Let's explore the first example more thoroughly:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_template_with_bullets,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example1_template_with_bullets,indent=0]
 ----
 <1> renders the XML declaration string.
 <2> opens a `cars` tag
@@ -55,7 +55,7 @@ In a similar fashion, rendering HTML code is as simple as this:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example2_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example2_template,indent=0]
 ----
 <1> renders the HTML doctype special tag
 <2> opens the `html` tag with an attribute
@@ -72,7 +72,7 @@ The output is straightforward:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example2_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=example2_expected,indent=0]
 ----
 
 NOTE: With some <<markuptemplate-config,configuration>>, you can have the output pretty printed, with newlines and indent automatically added.
@@ -89,90 +89,90 @@ The template engine provides several support methods that will help you render c
 |Renders contents, but escapes it before rendering
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yield,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yield,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yield_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yield_expected,indent=0]
 ```
 |yieldUnescaped
 |Renders raw contents. The argument is rendered as is, without escaping.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yieldUnescaped,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yieldUnescaped,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yieldUnescaped_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=yieldUnescaped_expected,indent=0]
 ```
 
 |xmlDeclaration
 |Renders an XML declaration String. If the encoding is specified in the configuration, it is written in the declaration.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_expected,indent=0]
 ```
 
 If `TemplateConfiguration#getDeclarationEncoding` is not null:
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_encoding_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_encoding_expected,indent=0]
 ```
 
 |comment
 |Renders raw contents inside an XML comment
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=comment,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=comment,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=comment_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=comment_expected,indent=0]
 ```
 
 |newLine
 |Renders a new line. See also `TemplateConfiguration#setAutoNewLine` and `TemplateConfiguration#setNewLineString`.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newline,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newline,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newline_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newline_expected,indent=0]
 ```
 
 |pi
 |Renders an XML processing instruction.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=pi,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=pi,indent=0]
 ```
 
 *Output*:
 ```xml
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=pi_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=pi_expected,indent=0]
 ```
 
 |tryEscape
 |Returns an escaped string for an object, if it is a `String` (or any type derived from `CharSequence`). Otherwise returns the object itself.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=tryEscape,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=tryEscape,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=tryEscape_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=tryEscape_expected,indent=0]
 ```
 
 |=======================================================================
@@ -189,21 +189,21 @@ Including another template can be done using:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_template,indent=0]
 ----
 
 Including a file as raw contents, without escaping it, can be done like this:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_raw,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_raw,indent=0]
 ----
 
 Eventually, inclusion of text that should be escaped before rendering can be done using:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_escaped,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=include_escaped,indent=0]
 ----
 
 Alternatively, you can use the following helper methods instead:
@@ -226,7 +226,7 @@ a string, the inner template, and a model, used to render this template. Conside
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=fragment_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=fragment_template,indent=0]
 ----
 
 The `fragment` element creates a nested template, and renders it with a model which is specific to this template. Here,
@@ -235,7 +235,7 @@ we will generate a single `li` element for each page in our model:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=fragment_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=fragment_expected,indent=0]
 ----
 
 Fragments are interesting to factorize template elements. They come at the price of the compilation of a fragment per template, and they cannot
@@ -250,7 +250,7 @@ with a _layout_. First of all, you need to create a layout template:
 [source,groovy]
 .layout-main.tpl
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test-resources/layout-main.tpl[indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test-resources/layout-main.tpl[indent=0]
 ----
 <1> the `title` variable (inside the title tag) is a layout variable
 <2> the `bodyContents` call will render the body
@@ -260,7 +260,7 @@ Then what you need is a template that includes the layout:
 [[example-layout-simple]]
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template,indent=0]
 ----
 <1> use the `main-layout.tpl` layout file
 <2> set the `title` variable
@@ -271,7 +271,7 @@ a result, the template will be rendered as this:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected,indent=0]
 ----
 
 The call to the `contents` method is used to tell the template engine that the block of code is in fact a specification of a
@@ -286,14 +286,14 @@ to make them inherit from the parent model. Imagine that the model is defined li
 
 [source,java]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit_model,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit_model,indent=0]
 ----
 
 and the following template:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit,indent=0]
 ----
 <1> note the use of `true` to enable model inheritance
 
@@ -301,14 +301,14 @@ then it is not necessary to pass the `title` value to the layout as in the <<exa
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected_2,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected_2,indent=0]
 ----
 
 But it is also possible to override a value from the parent model:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit_override,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_template_inherit_override,indent=0]
 ----
 <1> `true` means inherit from the parent model
 <2> but `title` is overriden
@@ -317,7 +317,7 @@ then the output will be:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected_3,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=layout_expected_3,indent=0]
 ----
 
 == Rendering contents
@@ -327,7 +327,7 @@ On the server side, rendering templates require an instance of `groovy.text.mark
 
 [source,java]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=rendering_setup,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=rendering_setup,indent=0]
 ----
 <1> creates a template configuration
 <2> creates a template engine with this configuration
@@ -347,7 +347,7 @@ The last version should in general be preferred:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=rendering_by_name,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=rendering_by_name,indent=0]
 ----
 
 [[markuptemplate-config]]
@@ -363,19 +363,19 @@ The behavior of the engine can be tweaked with several configuration options acc
 |Determines the value of the encoding to be written when `xmlDeclaration` is called. It does *not* influence the writer you are using as output.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_expected,indent=0]
 ```
 
 If `TemplateConfiguration#getDeclarationEncoding` is not null:
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_encoding_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=xmlDeclaration_encoding_expected,indent=0]
 ```
 
 |expandEmptyElements
@@ -383,19 +383,19 @@ include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngi
 |If true, empty tags are rendered in their expanded form.
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements_false,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements_false,indent=0]
 ```
 
 If `expandEmptyElements` is true:
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements_true,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=expandEmptyElements_true,indent=0]
 ```
 
 |useDoubleQuotes
@@ -403,19 +403,19 @@ include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngi
 |If true, use double quotes for attributes instead of simple quotes
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes,indent=0]
 ```
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes_false,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes_false,indent=0]
 ```
 
 If `useDoubleQuotes` is true:
 
 *Output*:
 ```xml
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes_true,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=useDoubleQuotes_true,indent=0]
 ```
 
 |newLineString
@@ -423,14 +423,14 @@ include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngi
 |Allows to choose what string is used when a new line is rendered
 |*Template*:
 ```groovy
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newLineString,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newLineString,indent=0]
 ```
 
 If `newLineString='BAR'`:
 
 *Output*:
 ```html
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newLineString_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=newLineString_expected,indent=0]
 ```
 
 |autoEscape
@@ -475,39 +475,39 @@ By default, the template engine will render output without any specific formatti
 * `autoIndent` is responsible for auto-indenting after a new line is inserted
 * `autoNewLine` is responsible for automatically inserting new lines based on the original formatting of the template source
 
-In general, it is recommanded to set both `autoIndent` and `autoNewLine` to true if you want human-readable, pretty printed, output:
+In general, it is recommended to set both `autoIndent` and `autoNewLine` to true if you want human-readable, pretty printed, output:
 
 [source,java]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_setup,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_setup,indent=0]
 ----
 
 Using the following template:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template,indent=0]
 ----
 
 The output will now be:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template_expected,indent=0]
 ----
 
 We can slightly change the template so that the `title` intruction is found on the same line as the `head` one:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template2,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template2,indent=0]
 ----
 
 And the output will reflect that:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template2_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template2_expected,indent=0]
 ----
 
 New lines are *only* inserted where curly braces for tags are found, and the insertion corresponds to where the nested content is found. This means that
@@ -515,7 +515,7 @@ tags in the body of another tag will *not* trigger new lines unless they use cur
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template3,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template3,indent=0]
 ----
 <1> a new line is inserted because `meta` is not on the same line as `head`
 <2> no new line is inserted, because we're on the same depth as the previous tag
@@ -526,7 +526,7 @@ This time, the output will be:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template3_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoformat_template3_expected,indent=0]
 ----
 
 By default, the renderer uses four(4) spaces as indent, but you can change it by setting the `TemplateConfiguration#autoIndentString` property.
@@ -542,35 +542,35 @@ Let's imagine the following setup:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_setup,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_setup,indent=0]
 ----
 
 and the following template:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template,indent=0]
 ----
 
 Then you wouldn't want the HTML from `unsafeContents` to be rendered as is, because of potential security issues:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_expected,indent=0]
 ----
 
 Automatic escaping will fix this:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_setup_fixed,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_setup_fixed,indent=0]
 ----
 
 And now the output is properly escaped:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_fixed_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_fixed_expected,indent=0]
 ----
 
 Note that using automatic escaping doesn't prevent you from including unescaped contents from the model. To do this, your template should then explicitly
@@ -579,7 +579,7 @@ mention that a model variable should not be escaped by prefixing it with `unesca
 [source,html]
 .Explicit bypass of automatic escaping
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_unescaped,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=autoescape_template_unescaped,indent=0]
 ----
 
 [[markuptemplate-gotchas]]
@@ -590,28 +590,28 @@ Say that you want to generate a `<p>` tag which contains a string containing mar
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_longversion,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_longversion,indent=0]
 ----
 
 and generates:
 
 [source,html]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_longversion_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_longversion_expected,indent=0]
 ----
 
 Can't this be written shorter? A naive alternative would be:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_naive_fail,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_naive_fail,indent=0]
 ----
 
 but the result will not look as expected:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_naive_fail_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_naive_fail_expected,indent=0]
 ----
 
 The reason is that the markup template engine is a _streaming_ engine. In the original version, the first `yield` call
@@ -627,7 +627,7 @@ call. This can be done this way:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_stringof,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_stringof,indent=0]
 ----
 
 Note the `stringOf` call, which basically tells the markup template engine that the underlying markup needs to be rendered
@@ -636,7 +636,7 @@ notation that starts with a _dollar_ sign:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_stringof_dollar,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=gotcha_strings_stringof_dollar,indent=0]
 ----
 
 TIP: It is worth noting that using `stringOf` or the special `$tag` notation triggers the creation of a distinct string writer
@@ -665,7 +665,7 @@ For example, imagine the default locale is set to `Locale.ENGLISH` and that the
 [source,groovy]
 .Use an explicit locale in include
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_explicit_import,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_explicit_import,indent=0]
 ----
 
 then the template is rendered using the specific template:
@@ -673,7 +673,7 @@ then the template is rendered using the specific template:
 [source,html]
 .Bypass the template configuration
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_explicit_import_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_explicit_import_expected,indent=0]
 ----
 
 Using an include without specifying a locale will make the template engine look for a template with the configured locale, and if not, fallback to the default, like here:
@@ -681,13 +681,13 @@ Using an include without specifying a locale will make the template engine look
 [source,groovy]
 .Don't use a locale in include
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import,indent=0]
 ----
 
 [source,html]
 .Fallback to the default template
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import_expected,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import_expected,indent=0]
 ----
 
 However, changing the default locale of the template engine to `Locale.FRANCE` will change the output, because the template engine will now look for a file
@@ -696,7 +696,7 @@ with the `fr_FR` locale:
 [source,html]
 .Don't fallback to the default template because a locale specific template was found
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import_expected2,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=locale_implicit_import_expected2,indent=0]
 ----
 
 This strategy lets you translate your templates one by one, by relying on default templates, for which no locale is set in the file name.
@@ -712,21 +712,21 @@ The template engine provides this ability by setting an alternative `baseTemplat
 
 [source,java]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=custombase_config,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=custombase_config,indent=0]
 ----
 
 The custom base class has to extend `BaseClass` like in this example:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy[tags=basetemplate_class,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy[tags=basetemplate_class,indent=0]
 ----
 
 This example shows a class which provides an additional method named `hasModule`, which can then be used directly in the template:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=custombase_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=custombase_template,indent=0]
 ----
 
 == Type checked templates
@@ -742,21 +742,21 @@ template creation time, which is the types of the variables found in the model.
 [source,groovy]
 .Page.groovy
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=page_class,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=page_class,indent=0]
 ----
 
 Then a list of pages can be exposed in the model, like this:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_setup_no_stc,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_setup_no_stc,indent=0]
 ----
 
 A template can use it easily:
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_template,indent=0]
 ----
 <1> iterate on pages from the model
 <2> `page.title` is valid
@@ -774,7 +774,7 @@ In some situations, this can be complicated to sort out or even notice. By decla
 
 [source,groovy]
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_setup_fixed,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_setup_fixed,indent=0]
 ----
 <1> create a map which will hold the model types
 <2> declare the type of the `pages` variables (note the use of a string for the type)
@@ -797,7 +797,7 @@ directly in the template. In this case, even if you call `createTemplate`, it wi
 [source,groovy]
 .Inline declaration of types
 ----
-include::{rootdir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_inlined_template,indent=0]
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy[tags=typechecked_inlined_template,indent=0]
 ----
 <1> types need to be declared in the `modelTypes` header
 <2> declare one variable per object in the model
diff --git a/subprojects/groovy-templates/src/spec/doc/template-engines.adoc b/subprojects/groovy-templates/src/spec/doc/template-engines.adoc
new file mode 100644
index 0000000..93b2032
--- /dev/null
+++ b/subprojects/groovy-templates/src/spec/doc/template-engines.adoc
@@ -0,0 +1,159 @@
+= Template engines
+
+== Introduction
+
+Groovy supports multiple ways to generate text dynamically including `GStrings`, `printf` and <<_markupbuilder, MarkupBuilder>> just to name a few. In addition to these, there is a dedicated template framework which is well-suited to applications where the text to be generated follows the form of a static template.
+
+== Template framework
+
+The template framework in Groovy consists of a `TemplateEngine` abstract base class that engines must implement and a `Template` interface that the resulting templates they generate must implement.
+
+Included with Groovy are several template engines:
+
+- `SimpleTemplateEngine` - for basic templates
+- `StreamingTemplateEngine` - functionally equivalent to `SimpleTemplateEngine`, but can handle strings larger than 64k
+- `GStringTemplateEngine` - stores the template as writeable closures (useful for streaming scenarios)
+- `XmlTemplateEngine` - works well when the template and output are valid XML
+- `MarkupTemplateEngine` - a very complete, optimized, template engine
+
+== SimpleTemplateEngine
+
+Shown here is the `SimpleTemplateEngine` that allows you to use JSP-like scriptlets (see example below), script, and EL expressions in your template in order to generate parametrized text. Here is an example of using the system:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine1,indent=0]
+----
+
+While it is generally not deemed good practice to mix processing logic in your template (or view), sometimes very simple logic can be useful. E.g. in the example above, we could change this:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine2,indent=0]
+----
+
+to this (assuming we have set up a static import for capitalize **inside** the template):
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine3,indent=0]
+----
+
+or this:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine4,indent=0]
+----
+
+to this:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine5,indent=0]
+----
+
+=== Advanced Usage Note
+
+If you happen to be embedding your template directly in your script (as we did above) you have to be careful about backslash escaping. Because the template string itself will be parsed by Groovy before it is passed to the the templating framework, you have to escape any backslashes inside GString expressions or scriptlet 'code' that are entered as part of a Groovy program. E.g. if we wanted quotes around __The Big Apple__ above, we would use:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine6,indent=0]
+----
+
+Similarly, if we wanted a newline, we would use:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine7,indent=0]
+----
+
+in any GString expression or scriptlet $$'code'$$ that appears inside a Groovy script. A normal "`\n`" is fine within the static template text itself or if the entire template itself is in an external template file. Similarly, to represent an actual backslash in your text you would need
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
+----
+
+in an external file or
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=simple_template_engine8,indent=0]
+----
+
+in any GString expression or scriptlet $$'code'$$. (Note: the necessity to have this extra slash may go away in a future version of Groovy if we can find an easy way to support such a change.)
+
+== StreamingTemplateEngine
+
+The `StreamingTemplateEngine` engine is functionally equivalent to the `SimpleTemplateEngine`, but creates the template using writeable closures making it more scalable for large templates. Specifically this template engine can handle strings larger than 64k.
+
+It uses JSP style <% %> script and <%= %> expression syntax or GString style expressions. The variable 'out' is bound to the writer that the template is being written to.
+
+Frequently, the template source will be a file but here we show a simple example providing the template as a string:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=streaming_template_engine,indent=0]
+----
+
+== GStringTemplateEngine
+
+As an example of using the `GStringTemplateEngine`, here is the example above done again (with a few changes to show some other options). First we will store the template in a file this time:
+
+[source,groovy]
+.test.template
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine1,indent=0]
+----
+
+Note that we used `out` instead of `print` to support the streaming nature of `GStringTemplateEngine`. Because we have the template in a separate file, there is no need to escape the backslashes. Here is how we call it:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=gstring_template_engine2,indent=0]
+----
+
+and here is the output:
+
+----
+Dear "Sam Pullara",
+So nice to meet you in "The Big Apple".
+See you in December,
+Groovy-Dev
+----
+
+== XmlTemplateEngine
+
+`XmlTemplateEngine` for use in templating scenarios where both the template source and the expected output are intended to be XML. Templates may use the normal `${expression}` and `$variable` notations to insert an arbitrary expression into the template. In addition, support is also provided for special tags: `<gsp:scriptlet>` (for inserting code fragments) and `<gsp:expression>` (for code fragments which produce output).
+
+Comments and processing instructions will be removed as part of processing and special XML characters such as `<`, `>`, `"` and `'` will be escaped using the respective XML notation. The output will also be indented using standard XML pretty printing.
+
+The xmlns namespace definition for gsp: tags will be removed but other namespace definitions will be preserved (but may change to an equivalent position within the XML tree).
+
+Normally, the template source will be in a file but here is a simple example providing the XML template as a string:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy[tags=xml_template_engine,indent=0]
+----
+
+This example will produce this output:
+
+[source,xml]
+----
+<document type='letter'>
+  Dearest
+  <foo:to xmlns:foo='baz'>
+    Jochen "blackdrag" Theodorou
+  </foo:to>
+  How are you today?
+</document>
+----
+
+include::{rootProjectDir}/subprojects/groovy-templates/src/spec/doc/markup-template-engine.adoc[leveloffset=+1]
+
+== Other solutions
+
+Also, there are other templating solutions that can be used along with Groovy, such as http://freemarker.org[FreeMarker], http://velocity.apache.org[Velocity], http://stringtemplate.org[StringTemplate] and others.
\ No newline at end of file
diff --git a/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy b/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy
index 8919a9e..4370e61 100644
--- a/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy
+++ b/subprojects/groovy-templates/src/spec/test/MarkupTemplateEngineSpecTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.text.Template
 import groovy.text.markup.MarkupTemplateEngine
 import groovy.text.markup.TemplateConfiguration
diff --git a/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy b/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy
index 19f7449..6387c66 100644
--- a/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy
+++ b/subprojects/groovy-templates/src/spec/test/MyTemplate.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.text.markup.BaseTemplate
 import groovy.text.markup.MarkupTemplateEngine
 import groovy.text.markup.TemplateConfiguration
diff --git a/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy b/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy
new file mode 100644
index 0000000..8822fba
--- /dev/null
+++ b/subprojects/groovy-templates/src/spec/test/TemplateEnginesTest.groovy
@@ -0,0 +1,192 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+import gls.CompilableTestSupport
+
+class TemplateEnginesTest extends CompilableTestSupport {
+
+    void testSimpleTemplateEngine1() {
+        // tag::simple_template_engine1[]
+        def text = 'Dear "$firstname $lastname",\nSo nice to meet you in <% print city %>.\nSee you in ${month},\n${signed}'
+
+        def binding = ["firstname":"Sam", "lastname":"Pullara", "city":"San Francisco", "month":"December", "signed":"Groovy-Dev"]
+
+        def engine = new groovy.text.SimpleTemplateEngine()
+        def template = engine.createTemplate(text).make(binding)
+
+        def result = 'Dear "Sam Pullara",\nSo nice to meet you in San Francisco.\nSee you in December,\nGroovy-Dev'
+
+        assert result == template.toString()
+        // end::simple_template_engine1[]
+    }
+
+    void testSimpleTemplateEngineOther() {
+        def binding = [firstname: 'andrey']
+        def engine = new groovy.text.SimpleTemplateEngine()
+        def text = '''\
+            // tag::simple_template_engine2[]
+            $firstname
+            // end::simple_template_engine2[]
+        '''
+        def template = engine.createTemplate(text).make(binding)
+        def result = template.toString()
+        assert result.readLines()[1].trim() == 'andrey'
+
+        text = '''\
+            // tag::simple_template_engine3[]
+            ${firstname.capitalize()}
+            // end::simple_template_engine3[]
+        '''
+        template = engine.createTemplate(text).make(binding)
+        result = template.toString()
+        assert result.readLines()[1].trim() == 'Andrey'
+
+        binding = [city: 'Moscow']
+        text = '''\
+            // tag::simple_template_engine4[]
+            <% print city %>
+            // end::simple_template_engine4[]
+        '''
+        template = engine.createTemplate(text).make(binding)
+        result = template.toString()
+        assert result.readLines()[1].trim() == 'Moscow'
+
+        binding = [city: 'New York']
+        text = '''\
+            // tag::simple_template_engine5[]
+            <% print city == "New York" ? "The Big Apple" : city %>
+            // end::simple_template_engine5[]
+        '''
+        template = engine.createTemplate(text).make(binding)
+        result = template.toString()
+        assert result.readLines()[1].trim() == 'The Big Apple'
+
+        text = '''\
+            // tag::simple_template_engine6[]
+            <% print city == "New York" ? "\\"The Big Apple\\"" : city %>
+            // end::simple_template_engine6[]
+        '''
+        template = engine.createTemplate(text).make(binding)
+        result = template.toString()
+        assert result.readLines()[1].trim() == '"The Big Apple"'
+
+        text = '''\
+            // tag::simple_template_engine7[]
+            \\n
+            // end::simple_template_engine7[]
+        '''
+        template = engine.createTemplate(text).make()
+        result = template.toString()
+        assert result.readLines().size() == 5
+
+        text = '''\
+            // tag::simple_template_engine8[]
+            \\\\
+            // end::simple_template_engine8[]
+        '''
+        template = engine.createTemplate(text).make()
+        result = template.toString()
+        assert result.readLines()[1].trim() == '\\'
+    }
+    
+        void testStreamingTemplateEngine() {
+// tag::streaming_template_engine[]
+def text = '''\
+Dear <% out.print firstname %> ${lastname},
+
+We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> \
+to inform you that your paper entitled
+'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+
+The conference committee.'''
+
+def template = new groovy.text.StreamingTemplateEngine().createTemplate(text)
+
+def binding = [
+    firstname : "Grace",
+    lastname  : "Hopper",
+    accepted  : true,
+    title     : 'Groovy for COBOL programmers'
+]
+
+String response = template.make(binding)
+
+assert response == '''Dear Grace Hopper,
+
+We are pleased to inform you that your paper entitled
+'Groovy for COBOL programmers' was accepted.
+
+The conference committee.'''
+// end::streaming_template_engine[]
+    }
+
+    void testGStringTemplateEngine() {
+        def binding = [firstname: 'Sam', lastname: 'Pullara', city: 'New York', month: 'December', signed: 'Groovy-Dev']
+        def engine = new groovy.text.GStringTemplateEngine()
+        def text = '''\
+            // tag::gstring_template_engine1[]
+            Dear "$firstname $lastname",
+            So nice to meet you in <% out << (city == "New York" ? "\\"The Big Apple\\"" : city) %>.
+            See you in ${month},
+            ${signed}
+            // end::gstring_template_engine1[]
+        '''
+        def template = engine.createTemplate(text).make(binding)
+        List result = template.toString().readLines()
+        result.remove(0); result.remove(result.size() - 2)
+        assert result.join('\n') == '''\
+            Dear "Sam Pullara",
+            So nice to meet you in "The Big Apple".
+            See you in December,
+            Groovy-Dev
+        '''
+
+        shouldCompile '''
+            // tag::gstring_template_engine2[]
+            def f = new File('test.template')
+            def engine = new groovy.text.GStringTemplateEngine()
+            def template = engine.createTemplate(f).make(binding)
+            println template.toString()
+            // end::gstring_template_engine2[]
+        '''
+    }
+
+    void testXmlTemplateEngine() {
+        // tag::xml_template_engine[]
+        def binding = [firstname: 'Jochen', lastname: 'Theodorou', nickname: 'blackdrag', salutation: 'Dear']
+        def engine = new groovy.text.XmlTemplateEngine()
+        def text = '''\
+            <document xmlns:gsp='http://groovy.codehaus.org/2005/gsp' xmlns:foo='baz' type='letter'>
+                <gsp:scriptlet>def greeting = "${salutation}est"</gsp:scriptlet>
+                <gsp:expression>greeting</gsp:expression>
+                <foo:to>$firstname "$nickname" $lastname</foo:to>
+                How are you today?
+            </document>
+        '''
+        def template = engine.createTemplate(text).make(binding)
+        println template.toString()
+        // end::xml_template_engine[]
+        
+        assert template.toString() == '''\
+<document type='letter'>
+  Dearest
+  <foo:to xmlns:foo='baz'>
+    Jochen "blackdrag" Theodorou
+  </foo:to>
+  How are you today?
+</document>
+'''
+    }
+}
\ No newline at end of file
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/SimpleGStringTemplateEngineTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/SimpleGStringTemplateEngineTest.groovy
index cf6443f..f638fe4 100644
--- a/subprojects/groovy-templates/src/test/groovy/groovy/SimpleGStringTemplateEngineTest.groovy
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/SimpleGStringTemplateEngineTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy;
 
 import groovy.text.Template;
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/SimpleTemplateTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/SimpleTemplateTest.groovy
index ad2dca5..f2b82af 100644
--- a/subprojects/groovy-templates/src/test/groovy/groovy/text/SimpleTemplateTest.groovy
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/SimpleTemplateTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.text
 
 class SimpleTemplateTest extends GroovyTestCase {
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineSpecification.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineSpecification.groovy
new file mode 100644
index 0000000..93be52d
--- /dev/null
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineSpecification.groovy
@@ -0,0 +1,418 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package groovy.text
+
+import spock.lang.*
+
+import static StreamingTemplateEngineSpecification.EngineType.*
+
+/**
+ * Author: Matias Bjarland
+ */
+class StreamingTemplateEngineSpecification extends Specification {
+
+  enum EngineType {
+    STREAMING('StreamingTemplateEngine'),
+    SIMPLE('SimpleTemplateEngine'),
+    GSTRING('GStringTemplateEngine')
+    String displayString
+
+    EngineType(displayString) {
+      this.displayString = displayString
+    }
+
+    String toString() {
+      displayString
+    }
+  }
+
+  @Shared Map defaultBinding = [alice: 'Alice', rabbit: 'Rabbit', queen: 'Queen', desk: 'writing desk']
+
+  private String template(EngineType type, String data, Map binding=null) {
+    TemplateEngine engine
+    switch (type) {
+      case STREAMING:
+        engine = new StreamingTemplateEngine()
+        break
+      case SIMPLE:
+        engine = new SimpleTemplateEngine()
+        break
+      case GSTRING:
+        engine = new GStringTemplateEngine()
+        break
+    }
+    Template template = engine.createTemplate(data)
+
+    Writable writable = (binding ? template.make(binding) : template.make())
+    StringWriter sw = new StringWriter()
+    writable.writeTo(sw)
+
+    sw
+  }
+
+  //TODO: Handle dollarExpressionSlashAtStart case better below
+  @Unroll
+  def "#testName - #engineType should evaluate '#data' to '#expectedResult' using binding '#binding'"() {
+    expect:
+      template(engineType, data, binding) == expectedResult
+
+    where:
+      data                     | expectedResult      | engineType     | binding        | testName
+      ''                       | ''                  | STREAMING      | null           | 'emptyStringNoBinding'
+      ''                       | ''                  | STREAMING      | defaultBinding | 'emptyStringWithBinding'
+      'bob'                    | 'bob'               | STREAMING      | null           | 'noExpressionsNoBinding'
+      'bob'                    | 'bob'               | STREAMING      | defaultBinding | 'noExpressionsWithBinding'
+
+      '\\Hello World'          | '\\Hello World'     | STREAMING      | null           | 'noExpressionsNoBindingEscapingAtStart'
+      '\\Hello World'          | '\\Hello World'     | STREAMING      | defaultBinding | 'noExpressionsWithBindingEscapingAtStart'
+      '\\\\Hello World'        | '\\\\Hello World'   | STREAMING      | null           | 'noExpressionsNoBindingDoubleEscapingAtStart'
+      '\\\\Hello World'        | '\\\\Hello World'   | STREAMING      | defaultBinding | 'noExpressionsWithBindingDoubleEscapingAtStart'
+      '\\\\\\Hello World'      | '\\\\\\Hello World' | STREAMING      | null           | 'noExpressionsNoBindingTripleEscapingAtStart'
+      '\\\\\\Hello World'      | '\\\\\\Hello World' | STREAMING      | defaultBinding | 'noExpressionsWithBindingTripleEscapingAtStart'
+
+      'Hello World\\'          | 'Hello World\\'     | STREAMING      | null           | 'noExpressionsNoBindingEscapingAtEnd'
+      'Hello World\\'          | 'Hello World\\'     | STREAMING      | defaultBinding | 'noExpressionsWithBindingEscapingAtEnd'
+      'Hello World\\\\'        | 'Hello World\\\\'   | STREAMING      | null           | 'noExpressionsNoBindingDoubleEscapingAtEnd'
+      'Hello World\\\\'        | 'Hello World\\\\'   | STREAMING      | defaultBinding | 'noExpressionsWithBindingDoubleEscapingAtEnd'
+      'Hello World\\\\\\'      | 'Hello World\\\\\\' | STREAMING      | null           | 'noExpressionsNoBindingTripleEscapingAtEnd'
+      'Hello World\\\\\\'      | 'Hello World\\\\\\' | STREAMING      | defaultBinding | 'noExpressionsWithBindingTripleEscapingAtEnd'
+
+      'Hello $alice'           | 'Hello Alice'       | STREAMING      | defaultBinding | 'dollarExpressionAtEnd'
+      '$alice Hello'           | 'Alice Hello'       | STREAMING      | defaultBinding | 'dollarExpressionAtBeginning'
+      '$alice'                 | 'Alice'             | STREAMING      | defaultBinding | 'dollarExpressionByItself'
+      'a $alice b'             | 'a Alice b'         | STREAMING      | defaultBinding | 'dollarExpressionInBetweenStrings'
+
+      '$rabbit$alice'          | 'RabbitAlice'       | STREAMING      | defaultBinding | 'dollarExpressionTwoAdjacentButDifferent'
+      '$alice$alice'           | 'AliceAlice'        | STREAMING      | defaultBinding | 'dollarExpressionTwoAdjacentAndIdentical'
+      '$rabbit $alice'         | 'Rabbit Alice'      | STREAMING      | defaultBinding | 'dollarExpressionTwoAdjacentButDifferentWithSpace'
+      '$alice $alice'          | 'Alice Alice'       | STREAMING      | defaultBinding | 'dollarExpressionTwoAdjacentAndIdenticalWithSpace'
+      '$'                      | '$'                 | STREAMING      | defaultBinding | 'literalDollarSignByItself'
+      '\\$'                    | '\\$'               | STREAMING      | defaultBinding | 'literalDollarSignEscapingAtStart'
+      '$\\'                    | '$\\'               | STREAMING      | defaultBinding | 'literalDollarSignEscapingAtEnd'
+      '\\$alice'               | '\\$alice'          | STREAMING      | defaultBinding | 'dollarExpressionSlashAtStart'
+      '\$alice'                | 'Alice'             | STREAMING      | defaultBinding | 'dollarExpressionEscapingAtStart'
+
+      '${rabbit}${alice}'      | 'RabbitAlice'       | STREAMING      | defaultBinding | 'curlyExpressionTwoAdjacentButDifferent'
+      '${alice}${alice}'       | 'AliceAlice'        | STREAMING      | defaultBinding | 'curlyExpressionTwoAdjacentAndIdentical'
+      '${rabbit} ${alice}'     | 'Rabbit Alice'      | STREAMING      | defaultBinding | 'curlyExpressionTwoAdjacentButDifferentWithSpace'
+      '${alice} ${alice}'      | 'Alice Alice'       | STREAMING      | defaultBinding | 'curlyExpressionTwoAdjacentAndIdenticalWithSpace'
+      '${}'                    | 'null'              | STREAMING      | defaultBinding | 'curlyExpressionEmptyEvaluatesToNull'
+
+      "<% out.print alice %>"    | 'Alice'           | STREAMING      | defaultBinding | 'scriptletOutPrintBinding'
+      "a<% out.print alice %>b"  | 'aAliceb'         | STREAMING      | defaultBinding | 'scriptletOutPrintBindingBetween'
+      "<% out.print 'bob' %>"    | 'bob'             | STREAMING      | defaultBinding | 'scriptletOutPrintConstant'
+      "a<% out.print 'bob' %>b"  | 'abobb'           | STREAMING      | defaultBinding | 'scriptletOutPrintConstantBetween'
+
+      "<%= alice %>"             | 'Alice'           | STREAMING      | defaultBinding | 'outExprPrintBinding'
+      "a<%= alice %>b"           | 'aAliceb'         | STREAMING      | defaultBinding | 'outExprPrintBindingBetween'
+      "<%= 'bob' %>"             | 'bob'             | STREAMING      | defaultBinding | 'outExprPrintConstant'
+      "a<%= 'bob' %>b"           | 'abobb'           | STREAMING      | defaultBinding | 'outExprPrintConstantBetween'
+  }
+
+  /**
+   * Validate fix of handling of \r\n line endings as reported by Wilfried Middleton 2014.02.12
+   * https://github.com/mbjarland/groovy-streaming-template-engine/issues/1
+   * Note: This was before the template engine got merged into groovy-core
+   */
+  def "should handle \\r\\n line feeds correctly"() {
+    setup:
+      String basic = '<%\r\n' +
+                     'def var1 = "cookie"\r\n' +
+                     'out << "This is var1: ${var1}"\r\n' +
+                     '%>\r\n' +
+                     'Style 1:\r\n' +
+                     '<%= "Again, this is var1:${var1}" %>\r\n' +
+                     '\r\n' +
+                     'Style 2:\r\n' +
+                     '${"var1:" + var1}'
+
+    when:
+      String gStringTemplate = new GStringTemplateEngine().createTemplate(basic).make().toString()
+      String streamingTemplate = new StreamingTemplateEngine().createTemplate(basic).make().toString()
+
+    then:
+      gStringTemplate == streamingTemplate
+  }
+
+  /**
+   * Validate fix of handling of if statements as reported by Wilfried Middleton 2014.02.12
+   * https://github.com/mbjarland/groovy-streaming-template-engine/issues/2
+   * Note: This was before the template engine got merged into groovy-core
+   */
+  def "should handle simple embedded if statements"() {
+    setup:
+      String templateText = 'before "<% if (false) { %>should not be included<% } else { %>should be included<% } %>" after'
+
+    when:
+      Template template = new StreamingTemplateEngine().createTemplate(templateText)
+      String result  = template.make().toString()
+
+    then:
+      result == 'before "should be included" after'
+  }
+
+  /**
+   * Validate fix of handling of if statements as reported by Wilfried Middleton 2014.02.12
+   * https://github.com/mbjarland/groovy-streaming-template-engine/issues/2
+   * Note: This was before the template engine got merged into groovy-core
+   */
+  def "should handle complex embedded if statements same as GStringTemplateEngine"() {
+    setup:
+      String templateText = 'first line text\n' +
+                            '<%\n' +
+                            'def var1 = "test"\n' +
+                            'if (false) {%>\n' +
+                            '  non executed text\n' +
+                            '  <%\n' +
+                            '  out << "more non-executed text"\n' +
+                            '} else {%>\n' +
+                            '  else stuff\n' +
+                            '<% \n' +
+                            '} %>\n' +
+                            '\n' +
+                            'last line text\n'
+
+    when:
+      Template template1 = new StreamingTemplateEngine().createTemplate(templateText)
+      Template template2 = new GStringTemplateEngine().createTemplate(templateText)
+
+      String streamingResult  = template1.make().toString()
+      String gStringResult    = template2.make().toString()
+
+    then:
+      streamingResult == gStringResult
+  }
+
+  def "should execute the javadoc example with correct output"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+      def text = '''\
+        |Dear <% out.print firstname %> ${lastname},
+        |
+        |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+        |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+        |
+        |The conference committee.
+        '''.stripMargin()
+
+      def expected = '''\
+        |Dear Grace Hopper,
+        |
+        |We regret to inform you that your paper entitled
+        |'Groovy for COBOL programmers' was rejected.
+        |
+        |The conference committee.
+        '''.stripMargin()
+
+    when:
+      String result = template(STREAMING, text, binding)
+
+    then:
+     result == expected
+  }
+
+  def "should execute the javadoc example same as GStringTemplateEngine"() {
+    setup:
+      def binding = [firstname : "Grace",
+                   lastname  : "Hopper",
+                   accepted  : false,
+                   title     : 'Groovy for COBOL programmers']
+    def text = '''\
+        |Dear <% out.print firstname %> ${lastname},
+        |
+        |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+        |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+        |
+        |The conference committee.
+        '''.stripMargin()
+
+    when:
+      String streaming = template(STREAMING, text, binding)
+      String gString   = template(GSTRING, text, binding)
+
+    then:
+      streaming == gString
+  }
+
+  def "should throw exception with correct line number on template execution error in mid template"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+    def text = '''\
+        |Dear <% out.print firstname %> ${lastname},
+        |
+        |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+        |'$txitle' was ${ accepted ? 'accepted' : 'rejected' }.
+        |
+        |The conference committee.
+        '''.stripMargin()
+
+    when:
+      template(STREAMING, text, binding)
+
+    then:
+      def e = thrown(TemplateExecutionException)
+      e.lineNumber == 4
+  }
+
+  def "should throw exception with correct line number on template execution error at start of template"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+      def text = '''\
+          |$txitle Dear <% out.print firstname %> ${lastname},
+          |
+          |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+          |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+          |
+          |The conference committee.
+          '''.stripMargin()
+
+    when:
+      template(STREAMING, text, binding)
+
+    then:
+      def e = thrown(TemplateExecutionException)
+      e.lineNumber == 1
+  }
+
+  def "should throw exception with correct line number on template execution error at end of template"() {
+    setup:
+    def binding = [firstname : "Grace",
+                   lastname  : "Hopper",
+                   accepted  : false,
+                   title     : 'Groovy for COBOL programmers']
+    def text = '''\
+        |Dear <% out.print firstname %> ${lastname},
+        |
+        |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+        |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+        |
+        |The conference committee.
+        |$txitle'''.stripMargin()
+
+    when:
+    template(STREAMING, text, binding)
+
+    then:
+    def e = thrown(TemplateExecutionException)
+    e.lineNumber == 7
+  }
+
+
+  def "should throw exception with correct line number on template parse error in mid template"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+    def text = '''\
+        |Dear <% out.print firstname %> ${lastname},
+        |
+        |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+        |<% -- %> was ${ accepted ? 'accepted' : 'rejected' }.
+        |
+        |The conference committee.
+        '''.stripMargin()
+
+    when:
+      template(STREAMING, text, binding)
+
+    then:
+      def e = thrown(TemplateParseException)
+      e.lineNumber == 4
+  }
+
+  def "should throw exception with correct line number on template parse error at start of template"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+      def text = '''\
+          ||<% -- %> Dear <% out.print firstname %> ${lastname},
+          |
+          |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+          |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+          |
+          |The conference committee.
+          '''.stripMargin()
+
+    when:
+      template(STREAMING, text, binding)
+
+    then:
+      def e = thrown(TemplateParseException)
+      e.lineNumber == 1
+  }
+
+  def "should throw exception with correct line number on template parse error at end of template"() {
+    setup:
+      def binding = [firstname : "Grace",
+                     lastname  : "Hopper",
+                     accepted  : false,
+                     title     : 'Groovy for COBOL programmers']
+      def text = '''\
+          |Dear <% out.print firstname %> ${lastname},
+          |
+          |We <% if (accepted) out.print 'are pleased' else out.print 'regret' %> to inform you that your paper entitled
+          |'$title' was ${ accepted ? 'accepted' : 'rejected' }.
+          |
+          |The conference committee.
+          ||<% -- %>'''.stripMargin()
+
+    when:
+      template(STREAMING, text, binding)
+
+    then:
+      def e = thrown(TemplateParseException)
+      e.lineNumber == 7
+  }
+
+  @Unroll
+  def "should evaluate adjacent expressions '#expression' to '#expected'"() {
+    expect:
+      //noinspection GroovyAssignabilityCheck
+      template(STREAMING, expression, defaultBinding) == expected
+
+    where:
+      //Create all permutations of the different kinds of expressions and validate that they
+      //evaluate to expected results. We have encountered a few too many edge cases with failing
+      //adjacent evaluations...this should cover most of them
+      [expression, expected] << [
+        ['constant'               , 'constant'],
+        ['${alice}'               , 'Alice'],
+        ['$rabbit '               , 'Rabbit '],
+        ['<%= queen %>'           , 'Queen'],
+        ['<% out << desk %>'      , 'writing desk'],
+      ].permutations().collect { p ->
+        p.inject(['','']) { List acc, val ->
+          acc[0] += val[0]
+          acc[1] += val[1]
+          acc
+        }
+      }
+  }
+
+}
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy
new file mode 100644
index 0000000..4c7b698
--- /dev/null
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/StreamingTemplateEngineTest.groovy
@@ -0,0 +1,459 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.text
+
+import org.junit.Test
+import org.junit.Before
+
+class StreamingTemplateEngineTest {
+  TemplateEngine engine
+  Map binding
+  private static final String SIXTY_FOUR_K_OF_A
+  private static final int SIXTY_FOUR_K = 64 * 1024
+
+  static {
+    StringBuilder b = new StringBuilder()
+    def sixtyFourAs = "a" * 64
+    (1..1024).each {
+      b.append(sixtyFourAs)
+    }
+    SIXTY_FOUR_K_OF_A = b.toString()
+  }
+
+  @Before
+  void setUp() {
+    engine = new StreamingTemplateEngine()
+    binding = [alice: 'Alice', rabbit: 'Rabbit', queen: 'Queen', desk: 'writing desk']
+  }
+
+  private String template(String data, Map binding = null) {
+    Template template = engine.createTemplate(data)
+
+    Writable writable = (binding ? template.make(binding) : template.make())
+    StringWriter sw = new StringWriter()
+    writable.writeTo(sw)
+
+    return sw.toString()
+  }
+
+  @Test
+  void testEmptyStringNoBinding() {
+    String data = ''
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void testEmptyStringWithBinding() {
+    String data = ''
+    String result = template(data, binding)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsNoBinding() {
+    String data = 'Hello World!'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsEscapingAtEnd() {
+    String data = 'Hello World\\'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsDoubleEscapingAtEnd() {
+    String data = 'Hello World\\\\'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsTripleEscapingAtEnd() {
+    String data = 'Hello World\\\\\\'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsEscapingAtStart() {
+    String data = '\\Hello World'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsDoubleEscapingAtStart() {
+    String data = '\\\\Hello World'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void noExpressionsTripleEscapingAtStart() {
+    String data = '\\\\\\Hello World'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void incompleteGStringExpressionEscapedAtStart() {
+    String data = '\\$Hello World'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void incompleteGStringExpressionEscapedAtEnd() {
+    String data = 'Hello World\\$'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void incompleteTwoCharGStringExpressionEscapedAtStart() {
+    String data = '\\${Hello World'
+    String result = template(data)
+    assert '${Hello World' == result
+  }
+
+  @Test
+  void incompleteTwoCharGStringExpressionEscapedAtEnd() {
+    String data = 'Hello World\\${'
+    String result = template(data)
+    assert 'Hello World${' == result
+  }
+
+  @Test
+  void escapedSlashesInFrontOfGStringExpressionAtStart() {
+    String data = '\\\\${alice}'
+    String result = template(data, binding)
+    assert '\\Alice' == result
+  }
+
+  @Test
+  void escapedSlashesInFrontOfGStringExpressionAtEnd() {
+    String data = '${alice}\\\\'
+    String result = template(data, binding)
+    assert 'Alice\\\\' == result
+  }
+
+  @Test
+  void incompleteLessThanExpressionEscapedAtStart() {
+    String data = '\\<Hello World'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void incompleteLessThanExpressionEscapedAtEnd() {
+    String data = 'Hello World\\<'
+    String result = template(data)
+    assert data == result
+  }
+
+  @Test
+  void incompleteTwoCharLessThanExpressionEscapedAtStart() {
+    String data = '\\<%Hello World'
+    String result = template(data)
+    assert '<%Hello World' == result
+  }
+
+  @Test
+  void incompleteTwoCharLessThanExpressionEscapedAtEnd() {
+    String data = 'Hello World\\<%'
+    String result = template(data)
+    assert 'Hello World<%' == result
+  }
+
+  @Test
+  void escapedSlashesInFrontOfLessThanExpressionAtStart() {
+    String data = '\\\\<%= alice %>'
+    String result = template(data, binding)
+    assert '\\Alice' == result
+  }
+
+  @Test
+  void escapedSlashesInFrontOfLessThanExpressionAtEnd() {
+    String data = '<%= alice %>\\\\'
+    String result = template(data, binding)
+    assert 'Alice\\\\' == result
+  }
+
+  @Test
+  void testStringOver64kNoBinding() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString())
+
+    assert result.startsWith("aaaaaaaaaaaaa")
+    assert result.endsWith("aaaaaaaaaaa")
+    assert result.length() == SIXTY_FOUR_K
+  }
+
+  @Test
+  void testStringOver64kWithStartingGString() {
+    StringBuilder data = new StringBuilder()
+    String prefix = '${alice}, why is a raven like a ${desk}?'
+    data.append(prefix)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+
+    String expectedStart = 'Alice, why is a raven like a writing desk?'
+    assert result.startsWith(expectedStart)
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == expectedStart.length() + SIXTY_FOUR_K
+  }
+
+  @Test
+  void testStringOver64kWithEndingGString() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String postfix = '${alice}, why is a raven like a ${desk}'
+    data.append(postfix)
+
+    String result = template(data.toString(), binding)
+
+    assert result.startsWith("aaaaaaaaaaaaa")
+    String expectedEnding = 'Alice, why is a raven like a writing desk'
+    assert result.endsWith(expectedEnding)
+    assert result.length() == SIXTY_FOUR_K + expectedEnding.length()
+  }
+
+  @Test
+  void testStringOver64kWithMiddleGString() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String middle = '${alice}, why is a raven like a ${desk}?'
+    data.append(middle)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+    String expectedMiddle = 'Alice, why is a raven like a writing desk?'
+
+    assert result.indexOf(expectedMiddle) == SIXTY_FOUR_K
+    assert result.startsWith("aaaaaaaaaaaaaaaaa")
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == SIXTY_FOUR_K * 2 + expectedMiddle.length()
+  }
+
+  @Test
+  void testStringOver64kWithStartingExpression() {
+    StringBuilder data = new StringBuilder()
+    String prefix = '<%= alice %>, why is a raven like a <%= desk %>?'
+    data.append(prefix)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+
+    String expectedStart = 'Alice, why is a raven like a writing desk?'
+    assert result.startsWith(expectedStart)
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == expectedStart.length() + SIXTY_FOUR_K
+  }
+
+  @Test
+  void testStringOver64kWithEndingExpression() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String postfix = '<%= alice %>, why is a raven like a <%= desk %>'
+    data.append(postfix)
+
+    String result = template(data.toString(), binding)
+
+    assert result.startsWith("aaaaaaaaaaaaa")
+    String expectedEnding = 'Alice, why is a raven like a writing desk'
+    assert result.endsWith(expectedEnding)
+    assert result.length() == SIXTY_FOUR_K + expectedEnding.length()
+  }
+
+  @Test
+  void testStringOver64kWithMiddleExpression() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String middle = '<%= alice %>, why is a raven like a <%= desk %>?'
+    data.append(middle)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+    String expectedMiddle = 'Alice, why is a raven like a writing desk?'
+
+    assert result.indexOf(expectedMiddle) == SIXTY_FOUR_K
+    assert result.startsWith("aaaaaaaaaaaaaaaaa")
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == SIXTY_FOUR_K * 2 + expectedMiddle.length()
+  }
+
+  @Test
+  void testStringOver64kWithStartingSection() {
+    StringBuilder data = new StringBuilder()
+    String prefix = '<% out << alice %>, why is a raven like a <% out << desk %>?'
+    data.append(prefix)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+
+    String expectedStart = 'Alice, why is a raven like a writing desk?'
+    assert result.startsWith(expectedStart)
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == expectedStart.length() + SIXTY_FOUR_K
+  }
+
+  @Test
+  void testStringOver64kWithEndingSection() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String postfix = '<% out << alice %>, why is a raven like a <% out << desk %>'
+    data.append(postfix)
+
+    String result = template(data.toString(), binding)
+
+    assert result.startsWith("aaaaaaaaaaaaa")
+    String expectedEnding = 'Alice, why is a raven like a writing desk'
+    assert result.endsWith(expectedEnding)
+    assert result.length() == SIXTY_FOUR_K + expectedEnding.length()
+  }
+
+  @Test
+  void testStringOver64kWithMiddleSection() {
+    StringBuilder data = new StringBuilder()
+    data.append(SIXTY_FOUR_K_OF_A)
+    String middle = '<% out << alice %>, why is a raven like a <% out << desk %>?'
+    data.append(middle)
+    data.append(SIXTY_FOUR_K_OF_A)
+
+    String result = template(data.toString(), binding)
+    String expectedMiddle = 'Alice, why is a raven like a writing desk?'
+
+    assert result.indexOf(expectedMiddle) == SIXTY_FOUR_K
+    assert result.startsWith("aaaaaaaaaaaaaaaaa")
+    assert result.endsWith("aaaaaaaaaaaaaaa")
+    assert result.length() == SIXTY_FOUR_K * 2 + expectedMiddle.length()
+  }
+
+  @Test
+  void testEscapingGString() {
+    String data = 'This should be \\${left alone}!'
+    String result = template(data, binding)
+    assert 'This should be ${left alone}!' == result
+  }
+
+  @Test
+  void testEscapingNonGString() {
+    String data = 'This should be \\$[left alone]!'
+    String result = template(data, binding)
+    assert 'This should be \\$[left alone]!' == result
+  }
+
+  @Test
+  void testEscapingDollarSign() {
+    String data = 'This should be \\$ left alone'
+    String result = template(data, binding)
+    assert 'This should be \\$ left alone' == result
+  }
+
+  @Test
+  void testEscapingAtEndOfString() {
+    String data = 'This should be \\'
+    String result = template(data, binding)
+    assert 'This should be \\' == result
+  }
+
+  @Test
+  void testEscapingGStringExtraSlashInFront() {
+    String data = 'This should be \\\\${alice}!'
+    String result = template(data, binding)
+    assert 'This should be \\Alice!' == result
+  }
+
+  @Test
+  void mixedGStringExpressionSequenceNoStringSections() {
+    String data = '${alice}<% out << rabbit %><%= queen %>'
+    String result = template(data, binding)
+    assert 'AliceRabbitQueen' == result
+  }
+
+  @Test
+  void mixedGStringExpressionSequenceWithStringSections() {
+    String data = 'Hi ${alice}, have you seen the <% out << rabbit %> and the <%= queen %>?'
+    String result = template(data, binding)
+    assert 'Hi Alice, have you seen the Rabbit and the Queen?' == result
+  }
+
+  @Test
+  void multiLineCodeSectionWithEmbeddedBindings() {
+    String data = '''<%
+      out << "Hi ${alice}, "
+      out << "have you seen the ${rabbit} "
+      out << "and the ${queen}"
+    %>?'''
+    String result = template(data, binding)
+    assert 'Hi Alice, have you seen the Rabbit and the Queen?' == result
+  }
+
+  @Test
+  void multiLineCodeSectionWithErrorsAndBindings() {
+    String data = '''<%
+      out << "Hi ${alice}, "
+      out << "have you seen the ${ :rabbit} "
+      out << "and the ${queen}"
+    %>?'''
+    try {
+      template(data, binding)
+      assert false //we should trow an exception above
+    } catch (Throwable e) {
+      assert e.getMessage().contains("at line 3,")
+    }
+  }
+
+  @Test
+  void nonTerminatedGStringExpression() {
+    String data = '''Hi
+                     ${alice'''
+    try {
+      template(data, binding)
+      assert false //we should trow an exception above
+    } catch (Throwable e) {
+      assert e.getMessage().contains("at line 2,")
+    }
+  }
+
+  @Test
+  void nonTerminatedLessThanExpression() {
+    String data = 'Hi <%=alice'
+    try {
+      template(data, binding)
+      assert false //we should trow an exception above
+    } catch (Throwable e) {
+      assert e.getMessage().contains("at line 1,")
+    }
+  }
+
+  @Test
+  void nonTerminatedLessThanCodeBlock() {
+    String data = 'Hi <% out << alice'
+
+    String result = template(data, binding)
+    //weirdly this is actually ok with the current implementation...
+    assert "Hi Alice" == result
+  }
+
+}
diff --git a/subprojects/groovy-templates/src/test/groovy/groovy/text/markup/TemplateResourceTest.groovy b/subprojects/groovy-templates/src/test/groovy/groovy/text/markup/TemplateResourceTest.groovy
new file mode 100644
index 0000000..9f1ba41
--- /dev/null
+++ b/subprojects/groovy-templates/src/test/groovy/groovy/text/markup/TemplateResourceTest.groovy
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.text.markup
+
+import groovy.text.markup.MarkupTemplateEngine.TemplateResource;
+
+class TemplateResourceTest extends GroovyTestCase {
+	
+	void testSimplePath() {
+		def resource = TemplateResource.parse("simple.foo")
+		assertFalse(resource.hasLocale())
+		assertEquals("simple.foo", resource.toString())
+		assertEquals("simple_fr_FR.foo", resource.withLocale("fr_FR").toString())
+	}
+	
+	void testPathWithLocale() {
+		def resource = TemplateResource.parse("simple_fr_FR.foo")
+		assertTrue(resource.hasLocale())
+		assertEquals("simple_fr_FR.foo", resource.toString())
+		assertEquals("simple.foo", resource.withLocale(null).toString())
+	}
+	
+	void testPathWithMultipleDots() {
+		def resource = TemplateResource.parse("simple.foo.bar")
+		assertFalse(resource.hasLocale())
+		assertEquals("simple.foo.bar", resource.toString())
+		assertEquals("simple_fr_FR.foo.bar", resource.withLocale("fr_FR").toString())
+	}
+	
+	void testPathWithLocaleAndMultipleDots() {
+		def resource = TemplateResource.parse("simple_fr_FR.foo.bar")
+		assertTrue(resource.hasLocale())
+		assertEquals("simple_fr_FR.foo.bar", resource.toString())
+		assertEquals("simple.foo.bar", resource.withLocale(null).toString())
+	}
+
+}
diff --git a/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java b/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
index a1494b3..fe02039 100644
--- a/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
+++ b/subprojects/groovy-templates/src/test/java/groovy/text/XmlTemplateEngineTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.text;
 
 import junit.framework.TestCase;
diff --git a/subprojects/groovy-test/build.gradle b/subprojects/groovy-test/build.gradle
index c794c0d..f478b57 100644
--- a/subprojects/groovy-test/build.gradle
+++ b/subprojects/groovy-test/build.gradle
@@ -1,5 +1,7 @@
 dependencies {
     compile rootProject
-    compile 'junit:junit:4.11'
+    compile 'junit:junit:4.12'
     testRuntime project(':groovy-ant')
 }
+
+apply from: "${rootProject.projectDir}/gradle/jacoco/jacocofix.gradle"
\ No newline at end of file
diff --git a/subprojects/groovy-test/src/main/groovy/groovy/mock/interceptor/package.html b/subprojects/groovy-test/src/main/groovy/groovy/mock/interceptor/package.html
index 4914053..6d259c0 100644
--- a/subprojects/groovy-test/src/main/groovy/groovy/mock/interceptor/package.html
+++ b/subprojects/groovy-test/src/main/groovy/groovy/mock/interceptor/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.mock.interceptor</title>
diff --git a/subprojects/groovy-test/src/main/groovy/groovy/util/StringTestUtil.groovy b/subprojects/groovy-test/src/main/groovy/groovy/util/StringTestUtil.groovy
index 34f7bb1..af11c22 100644
--- a/subprojects/groovy-test/src/main/groovy/groovy/util/StringTestUtil.groovy
+++ b/subprojects/groovy-test/src/main/groovy/groovy/util/StringTestUtil.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 import junit.framework.Assert
diff --git a/subprojects/groovy-test/src/test/groovy/GroovyTestCaseTest.groovy b/subprojects/groovy-test/src/test/groovy/GroovyTestCaseTest.groovy
index 78d3fcd..4c39823 100644
--- a/subprojects/groovy-test/src/test/groovy/GroovyTestCaseTest.groovy
+++ b/subprojects/groovy-test/src/test/groovy/GroovyTestCaseTest.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
 * Copyright 2003-2014 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/subprojects/groovy-test/src/test/groovy/groovy/lang/GroovyLogTestCaseTest.groovy b/subprojects/groovy-test/src/test/groovy/groovy/lang/GroovyLogTestCaseTest.groovy
index e33653a..320a2f6 100644
--- a/subprojects/groovy-test/src/test/groovy/groovy/lang/GroovyLogTestCaseTest.groovy
+++ b/subprojects/groovy-test/src/test/groovy/groovy/lang/GroovyLogTestCaseTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.lang
 
 import java.util.logging.Level
diff --git a/subprojects/groovy-test/src/test/groovy/groovy/util/suite/ATestScriptThatsNoTestCase.groovy b/subprojects/groovy-test/src/test/groovy/groovy/util/suite/ATestScriptThatsNoTestCase.groovy
index 35de296..9246dab 100644
--- a/subprojects/groovy-test/src/test/groovy/groovy/util/suite/ATestScriptThatsNoTestCase.groovy
+++ b/subprojects/groovy-test/src/test/groovy/groovy/util/suite/ATestScriptThatsNoTestCase.groovy
@@ -1,2 +1,17 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // used for testing ScriptTestCaseAdapter usage with AllTestSuite
 assert true
\ No newline at end of file
diff --git a/subprojects/groovy-testng/build.gradle b/subprojects/groovy-testng/build.gradle
index b09d07b..1576717 100644
--- a/subprojects/groovy-testng/build.gradle
+++ b/subprojects/groovy-testng/build.gradle
@@ -1,10 +1,10 @@
 dependencies {
     compile rootProject
-    runtime('org.testng:testng:6.8.8') {
+    runtime('org.testng:testng:6.8.13') {
         // exclude 'optional' beanshell even though testng's pom doesn't say optional
         exclude(group: 'org.beanshell', module: 'bsh')
         // and an older version of jcommander
         exclude(group: 'com.beust', module: 'jcommander')
     }
-    compile('com.beust:jcommander:1.35')
+    compile('com.beust:jcommander:1.47')
 }
diff --git a/subprojects/groovy-xml/src/main/java/groovy/util/slurpersupport/package.html b/subprojects/groovy-xml/src/main/java/groovy/util/slurpersupport/package.html
index ca52df9..e6e32e3 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/util/slurpersupport/package.html
+++ b/subprojects/groovy-xml/src/main/java/groovy/util/slurpersupport/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.util.slurpersupport.*</title>
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/MarkupBuilder.java b/subprojects/groovy-xml/src/main/java/groovy/xml/MarkupBuilder.java
index a3c3d9c..4038e3e 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/MarkupBuilder.java
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/MarkupBuilder.java
@@ -49,7 +49,7 @@ import java.util.Iterator;
  * away from the normal building mode of the builder and get access
  * to helper markup methods such as 'yield' and 'yieldUnescaped'.
  * See the javadoc for {@link #getMkp()} for further details.</li>
- *     <li>Note that tab, newline and carriage return characters are escaped within attributes, i.e. will become 	, 
 and 
 respectively</li>
+ *     <li>Note that tab, newline and carriage return characters are escaped within attributes, i.e. will become &#09;, &#10; and &#13; respectively</li>
  * </ul>
  * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
  * @author Stefan Matthias Aust
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/NamespaceBuilderSupport.java b/subprojects/groovy-xml/src/main/java/groovy/xml/NamespaceBuilderSupport.java
index 55d2fcd..00f2570 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/NamespaceBuilderSupport.java
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/NamespaceBuilderSupport.java
@@ -17,9 +17,13 @@ package groovy.xml;
 
 import groovy.util.BuilderSupport;
 import groovy.util.NodeBuilder;
+
 import org.codehaus.groovy.runtime.InvokerHelper;
 
+import java.util.Collections;
 import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
 import java.util.Map;
 
 /**
@@ -28,6 +32,7 @@ import java.util.Map;
  * @author <a href="mailto:james at coredevelopers.net">James Strachan</a>
  * @author Paul King
  * @author Denver Dino
+ * @author Marc Guillemot
  */
 public class NamespaceBuilderSupport extends BuilderSupport {
     private boolean autoPrefix;
@@ -106,12 +111,42 @@ public class NamespaceBuilderSupport extends BuilderSupport {
         }
         String namespaceURI = nsMap.get(prefix);
         if (namespaceURI == null) {
-            namespaceURI = "";
-            prefix = "";
+        	return methodName;
         }
         return new QName(namespaceURI, localPart, prefix);
     }
 
+    /**
+     * Allow automatic detection of namespace declared in the attributes
+     */
+    @Override
+    public Object invokeMethod(String methodName, Object args) {
+        // detect namespace declared on the added node like xmlns:foo="http:/foo"
+    	Map attributes = findAttributes(args);
+    	for (Iterator<Map.Entry> iter = attributes.entrySet().iterator(); iter.hasNext();) {
+    		Map.Entry entry = iter.next();
+    		String key = String.valueOf(entry.getKey());
+            if (key.startsWith("xmlns:")) {
+                String prefix = key.substring(6);
+                String uri = String.valueOf(entry.getValue());
+                namespace(uri, prefix);
+                iter.remove();
+            }
+        }
+
+        return super.invokeMethod(methodName, args);
+    }
+    
+    private Map findAttributes(Object args) {
+        List list = InvokerHelper.asList(args);
+        for (Object o : list) {
+        	if (o instanceof Map) {
+        		return (Map) o;
+        	}
+        }
+        return Collections.EMPTY_MAP;
+    }
+
     @Override
     protected Object createNode(Object name) {
         return name;
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/dom/package.html b/subprojects/groovy-xml/src/main/java/groovy/xml/dom/package.html
index 3b04de9..7ec0683 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/dom/package.html
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/dom/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.xml.dom.*</title>
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/package.html b/subprojects/groovy-xml/src/main/java/groovy/xml/package.html
index 9a636eb..21b87c1 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/package.html
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.xml.*</title>
diff --git a/subprojects/groovy-xml/src/main/java/groovy/xml/streamingmarkupsupport/package.html b/subprojects/groovy-xml/src/main/java/groovy/xml/streamingmarkupsupport/package.html
index df61ea8..8bcd750 100644
--- a/subprojects/groovy-xml/src/main/java/groovy/xml/streamingmarkupsupport/package.html
+++ b/subprojects/groovy-xml/src/main/java/groovy/xml/streamingmarkupsupport/package.html
@@ -1,3 +1,20 @@
+<!--
+
+    Copyright 2003-2015 the original author or authors.
+
+    Licensed under the Apache License, Version 2.0 (the "License");
+    you may not use this file except in compliance with the License.
+    You may obtain a copy of the License at
+
+        http://www.apache.org/licenses/LICENSE-2.0
+
+    Unless required by applicable law or agreed to in writing, software
+    distributed under the License is distributed on an "AS IS" BASIS,
+    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+    See the License for the specific language governing permissions and
+    limitations under the License.
+
+-->
 <html>
   <head>
     <title>package groovy.xml.streamingmarkupsupport.*</title>
diff --git a/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc b/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc
new file mode 100644
index 0000000..49ce386
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/doc/xml-userguide.adoc
@@ -0,0 +1,558 @@
+= Processing XML
+
+== Parsing XML
+
+=== XmlParser and XmlSlurper
+
+The most commonly used approach for parsing XML with Groovy is to use
+one of:
+
+* `groovy.util.XmlParser`
+* `groovy.util.XmlSlurper`
+
+Both have the same approach to parse an xml. Both come with a bunch of
+overloaded parse methods plus some special methods such as `parseText`,
+parseFile and others. For the next example we will use the `parseText`
+method. It parses a XML `String` and recursively converts it to a list
+or map of objects.
+
+[source,groovy]
+.XmlSlurper
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testParseText,indent=0]
+----
+
+<1> Parsing the XML an returning the root node as a GPathResult
+<2> Checking we're using a GPathResult
+<3> Traversing the tree in a GPath style
+
+[source,groovy]
+.XmlParser
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=testParseText,indent=0]
+----
+
+<1> Parsing the XML an returning the root node as a Node
+<2> Checking we're using a Node
+<3> Traversing the tree in a GPath style
+
+Let's see the *similarities* between `XMLParser` and `XMLSlurper` first:
+
+* Both are based on `SAX` so they both are low memory footprint
+* Both can update/transform the XML
+
+But they have key *differences*:
+
+* `XmlSlurper` evaluates the structure lazily. So if you update the xml
+you'll have to evaluate the whole tree again.
+* `XmlSlurper` returns `GPathResult` instances when parsing XML
+* `XmlParser` returns `Node` objects when parsing XML
+
+When to use one or the another?
+
+NOTE: There is a discussion at
+http://stackoverflow.com/questions/7558019/groovy-xmlslurper-vs-xmlparser[StackOverflow]. The
+conclusions written here are based partially in this entry.
+
+* *If you want to transform an existing document to another* then
+`XmlSlurper` will be the choice
+* *If you want to update and read at the same time* then `XmlParser` is
+the choice.
+
+The rationale behind this is that every time you create a node with
+`XmlSlurper` it won't be available until you parse the document again
+with another `XmlSlurper` instance.  Need to read just a few nodes
+XmlSlurper is for you ".
+
+* *If you just have to read a few nodes* `XmlSlurper` should be your
+choice, since it will not have to create a complete structure in
+memory"
+
+In general both classes perform similar way. Even the way of using
+GPath expressions with them are the same (both use `breadthFirst()` and
+`depthFirst()` expressions). So I guess it depends on the write/read
+frequency.
+
+=== DOMCategory
+
+There is another way of parsing XML documents with Groovy with the
+used of `groovy.xml.dom.DOMCategory` which is a category class which
+adds GPath style operations to Java's DOM classes.
+
+NOTE: Java has in-built support for DOM processing of XML using classes
+representing the various parts of XML documents, e.g. `Document`,
+`Element`, `NodeList`, `Attr` etc. For more information about these classes,
+refer to the respective JavaDocs.
+
+Having a XML like the following:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideDOMCategory.groovy[tags=testXML,indent=0]
+----
+
+You can parse it using 'groovy.xml.DOMBuilder` and
+`groovy.xml.dom.DOMCategory`.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideDOMCategory.groovy[tags=testExample1,indent=0]
+----
+
+<1> Parsing the XML
+<2> Creating `DOMCategory` scope to be able to use helper method calls
+
+== GPath
+
+The most common way of querying XML in Groovy is using `GPath`:
+
+__GPath is a path expression language integrated into Groovy which
+allows parts of nested structured data to be identified. In this
+sense, it has similar aims and scope as XPath does for XML. The two
+main places where you use GPath expressions is when dealing with
+nested POJOs or when dealing with XML__
+
+It is similar to http://en.wikipedia.org/wiki/XPath[XPath]
+expressions and you can use it not only with XML but also with POJO
+classes. As an example, you can specify a path to an object or element
+of interest:
+
+* `a.b.c` -> for XML, yields all the `<c>` elements inside `<b>` inside `<a>`
+* `a.b.c` -> all POJOs, yields the `<c>` properties for all the `<b>`
+  properties of `<a>` (sort of like a.getB().getC() in JavaBeans)
+
+For XML, you can also specify attributes, e.g.:
+
+* `a["@href"]` -> the href attribute of all the a elements
+* `a.'@href'` -> an alternative way of expressing this
+* `a. at href` -> an alternative way of expressing this when using XmlSlurper
+
+Let's illustrate this with an example:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=books,indent=0]
+----
+
+=== Simply traversing the tree
+
+First thing we could do is to get a value using POJO's notation. Let's
+get the first book's author's name
+
+[source,groovy]
+.Getting node value
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testGettingANodeText,indent=0]
+----
+
+First we parse the document with `XmlSlurper` and the we have to
+consider the returning value as the root of the XML document, so in
+this case is "response".
+
+That's why we start traversing the document from response and then
+`value.books.book[0].author`. Note that in `XPath` the node arrays starts
+in [1] instead of [0], but because `GPath` is Java-based it begins at
+index 0.
+
+In the end we'll have the instance of the `author` node and because we
+wanted the text inside that node we should be calling the `text()`
+method.  The `author` node is an instance of `GPathResult` type and
+`text()` a method giving us the content of that node as a String.
+
+When using `GPath` with an xml parsed with `XmlSlurper` we'll have as a
+result a `GPathResult` object. `GPathResult` has many other convenient
+methods to convert the text inside a node to any other type such as:
+
+* `toInteger()`
+* `toFloat()`
+* `toBigInteger()`
+* ...
+
+All these methods try to convert a `String` to the appropriate type.
+
+If we were using a XML parsed with `XmlParser` we could be dealing with
+instances of type `Node`. But still all the actions applied to
+`GPathResult` in these examples could be applied to a Node as
+well. Creators of both parsers took into account `GPath` compatibility.
+
+Next step is to get the some values from a given node's attribute. In the following sample
+we want to get the first book's author's id. We'll be using two different approaches. Let's see the code first:
+
+[source,groovy]
+.Getting an attribute's value
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testGettingAnAttributeText,indent=0]
+----
+
+<1> Getting the first book node
+<2> Getting the book's id attribute `@id`
+<3> Getting the book's id attribute with `map notation` `['@id']`
+<4> Getting the value as a String
+<5> Getting the value of the attribute as an `Integer`
+
+As you can see there are to types of notations to get attributes,
+the
+
+* _direct notation_ with `@nameoftheattribute`
+* _map notation_ using `['@nameoftheattribute']`
+
+Both of them are equally valid.
+
+=== Speed things up with breadthFirst and depthfirst
+
+If you ever have used XPath you may have used expressions like
+
+* `//` : Look everywhere
+* `/following-sibling::othernode` : Look for a node "othernode" in the same level
+
+More or less we have their counterparts in `Gpath` with the methods
+`breadthFirst()` and `depthfirst()`.
+
+The first example shows a simple use of `breadthFirst()`. The creators of
+this methods created a shorter syntax for it using the symbol `*`.
+
+[source,groovy]
+.breadthFirst()
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testBreadFirst1,indent=0]
+----
+
+This test searches for any node at the same level of the "books" node
+first, and *only if* it couldn't find the node we were looking for,
+then it will look deeper in the tree, always taking into account the
+given the expression inside the closure.
+
+The expression says *_Look for any node with a tag name
+equals 'book' having an id with a value of '2'_*.
+
+But what if we would like to look for a given value
+without having to know exactly where it is. Let's say that the
+only thing we know is the id of the author "Lewis Carroll" . How are
+we going to be able to find that book? `depthFirst()` is the solution:
+
+[source,groovy]
+.depthFirst()
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testDepthFirst1,indent=0]
+----
+
+`depthfirst()` is the same as looking something *everywhere in the
+tree from this point down*. In this case we've used the method
+`find(Closure cl)` to find just the first occurrence.
+
+What if we want to collect all book's titles?
+
+[source,groovy]
+.depthFirst()
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testDepthFirst2,indent=0]
+----
+
+It is worth mentioning again that there are some useful methods
+converting a node's value to an integer,float...etc. Those methods
+could be convenient when doing comparisons like this:
+
+[source,groovy]
+.helpers
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testHelpers,indent=0]
+----
+
+In this case the number 2 has been hardcoded but imagine that value
+could have come from any other source (database...etc).
+
+== Creating XML
+
+The most commonly used approach for creating XML with Groovy is to use
+a builder, i.e. one of:
+
+* `groovy.xml.MarkupBuilder`
+* `groovy.xml.StreamingMarkupBuilder`
+
+=== MarkupBuilder
+
+Here is an example of using Groovy's MarkupBuilder to create a new XML file:
+
+[source,groovy]
+.Creating Xml with MarkupBuilder
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=createCarsTest,indent=0]
+----
+
+<1> Create an instance of `MarkupBuilder`
+<2> Start creating the XML tree
+<3> Create an instance of `XmlSlurper` to traverse and test the
+generated XML
+
+Let's take a look a little bit closer:
+
+[source,groovy]
+.Creating XML elements
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testCreateSimpleXml1,indent=0]
+----
+
+<1> We're creating a reference string to compare against
+<2> The `xmlWriter` instance is used by `MarkupBuilder` to convert the
+xml representation to a String instance eventually
+<3> The `xmlMarkup.movie(...)` call will create a XML node with a tag
+called `movie` and with content `the godfather`.
+
+[source,groovy]
+.Creating XML elements with attributes
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testCreateSimpleXml2,indent=0]
+----
+
+<1> This time in order to create both attributes and node content you
+can create as many map entries as you like and finally add a value
+to set the node's content
+
+NOTE: The value could be any `Object`, the value will be serialized to its
+`String` representation.
+
+[source,groovy]
+.Creating XML nested elements
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testCreateSimpleXml3,indent=0]
+----
+
+<1> A closure represents the children elements of a given node. Notice
+this time instead of using a String for the attribute we're using a
+number.
+
+Sometimes you may want to use a specific namespace in your xml documents:
+
+[source,groovy]
+.Namespace aware
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testNamespaceAware,indent=0]
+----
+
+<1> Creating a node with a given namespace `xmlns:x`
+<2> Creating a `XmlSlurper` registering the namespace to be able to
+test the XML we just created
+
+What about having some more meaningful example. We may want to
+generate more elements, to have some logic when creating our XML:
+
+[source,groovy]
+.Mix code
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testComplexUse1,indent=0]
+----
+
+<1> Generating elements from a range
+<2> Using a conditional for creating a given element
+
+Of course the instance of a builder can be passed as a parameter to
+refactor/modularize your code:
+
+[source,groovy]
+.Mix code
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testComplexUse2,indent=0]
+----
+
+<1> In this case we've created a Closure to handle the creation of a list of movies
+<2> Just using the `buildMovieList` function when necessary
+
+=== StreamingMarkupBuilder
+
+The class `groovy.xml.StreamingMarkupBuilder` is a builder class for
+creating XML markup. This implementation uses a
+`groovy.xml.streamingmarkupsupport.StreamingMarkupWriter` to handle
+output.
+
+[source,groovy]
+.Using StreamingMarkupBuilder
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideStreamingMarkupBuilderTest.groovy[tags=testSimpleExample,indent=0]
+----
+
+<1> Note that `StreamingMarkupBuilder.bind` returns a `Writable`
+instance that may be used to stream the markup to a Writer
+<2> We're capturing the output in a String to parse it again an check
+the structure of the generated XML with `XmlSlurper`.
+
+=== MarkupBuilderHelper
+
+The `groovy.xml.MarkupBuilderHelper` is, as its name reflects, a
+helper for `groovy.xml.MarkupBuilder`.
+
+This helper normally can be accessed from within an instance of class
+`groovy.xml.MarkupBuilder` or an instance of
+`groovy.xml.StreamingMarkupBuilder`.
+
+This helper could be handy in situations when you may want to:
+
+* Produce a comment in the output
+* Produce an XML processing instruction in the output
+* Produce an XML declaration in the output
+* Print data in the body of the current tag, escaping XML entities
+* Print data in the body of the current tag
+
+In both `MarkupBuilder` and `StreamingMarkupBuilder` this helper is
+accessed by the property `mkp`:
+
+[source,groovy]
+.Using MarkupBuilder's 'mkp'
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testMkp1,indent=0]
+----
+
+<1> Using `mkp` to create a comment in the XML
+<2> Using `mkp` to generate an escaped value
+<3> Checking both assumptions were true
+
+Here is another example to show the use of `mkp` property accessible
+from within the `bind` method scope when using
+`StreamingMarkupBuilder`:
+
+[source,groovy]
+.Using StreamingMarkupBuilder's 'mkp'
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideStreamingMarkupBuilderTest.groovy[tags=testMkp,indent=0]
+----
+
+<1> If we want to generate a escaped value for the name attribute with
+`mkp.yield`
+<2> Checking the values later on with `XmlSlurper`
+
+=== DOMToGroovy
+
+Suppose we have an existing XML document and we want to automate
+generation of the markup without having to type it all in? We just
+need to use `org.codehaus.groovy.tools.xml.DOMToGroovy` as shown in
+the following example:
+
+[source,groovy]
+.Building MarkupBuilder from DOMToGroovy
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy[tags=testDOMToGroovy,indent=0]
+----
+
+<1> Creating `DOMToGroovy` instance 
+<2> Converts the XML to `MarkupBuilder` calls which are available in the output `StringWriter`
+<3> Using `output` variable to create the whole MarkupBuilder 
+<4> Back to XML string
+
+== Manipulating XML
+
+In this chapter you'll see the different ways of adding / modifying /
+removing nodes using `XmlSlurper` or `XmlParser`. The xml we are going
+to be handling is the following:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=responseBookXml,indent=0]
+----
+
+=== Adding nodes
+
+The main difference between `XmlSlurper` and `XmlParser` is that when
+former creates the nodes they won't be available until the document's
+been evaluated again, so you should parse the transformed document
+again in order to be able to see the new nodes. So keep that in mind
+when choosing any of both approaches.
+
+If you needed to see a node right after creating it then `XmlParser`
+should be your choice, but if you're planning to do many changes to
+the XML and send the result to another process maybe `XmlSlurper` would
+be more efficient.
+
+You can't create a new node directly using the `XmlSlurper` instance,
+but you can with `XmlParser`. The way of creating a new node from
+XmlParser is through its method `createNode(..)`
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=testAddingNodes1,indent=0]
+----
+
+The `createNode()` method receives the following parameters:
+
+* parent node (could be null)
+* The qualified name for the tag (In this case we only use the local
+  part without any namespace). We're using an instance of
+  `groovy.xml.QName`
+* A map with the tag's attributes (None in this particular case)
+
+Anyway you won't normally be creating a node from the parser instance
+but from the parsed XML instance. That is from a `Node` or a
+`GPathResult` instance.
+
+Take a look at the next example. We are parsing the xml with `XmlParser`
+and then creating a new node from the parsed document's instance
+(Notice the method here is slightly different in the way it receives
+the parameters):
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=testAddingNodes2,indent=0]
+----
+
+When using `XmlSlurper`, `GPathResult` instances don't have `createNode()`
+method.
+
+=== Modifying / Removing nodes
+
+We know how to parse the document, add new nodes, now I want to change
+a given node's content. Let's start using `XmlParser` and `Node`. This
+example changes the first book information to actually another book.
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=testModifyingNodes1,indent=0]
+----
+
+When using `replaceNode()` the closure we pass as parameter should
+follow the same rules as if we were using `groovy.xml.MarkupBuilder`:
+
+Here's the same example using `XmlSlurper`:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testModifyingNodes1,indent=0]
+----
+
+Notice how using `XmlSlurper` we have to parse the transformed document
+again in order to find the created nodes. In this particular example
+could be a little bit annoying isn't it?
+
+Finally both parsers also use the same approach for adding a new
+attribute to a given attribute. This time again the difference is
+whether you want the new nodes to be available right away or
+not. First `XmlParser`:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy[tags=testSettingAttributes1,indent=0]
+----
+
+And `XmlSlurper`:
+
+[source,groovy]
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy[tags=testSettingAttributes1,indent=0]
+----
+
+When using `XmlSlurper`, adding a new attribute does *not* require you to perform a new evaluation.
+
+=== Printing XML
+
+==== XmlUtil
+
+Sometimes is useful to get not only the value of a given node but the
+node itself (for instance to add this node to another XML).
+
+For that you can use `groovy.xml.XmlUtil` class. It has several static
+methods to serialize the xml fragment from several type of sources
+(Node,GPathResult,String...)
+
+[source,groovy]
+.Getting a node as a string
+----
+include::{rootProjectDir}/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy[tags=testGettingANode,indent=0]
+----
+
diff --git a/subprojects/groovy-xml/src/spec/test/DomBuilderTest.groovy b/subprojects/groovy-xml/src/spec/test/DomBuilderTest.groovy
new file mode 100644
index 0000000..0919280
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/DomBuilderTest.groovy
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+import groovy.util.GroovyTestCase
+import org.junit.Test
+import groovy.xml.DOMBuilder
+
+/**
+* Tests for DomBuilder. The tests directly in this file are specific
+* to DomBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class DomBuilderTest  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::dombuilder_nullobject1[]
+    DOMBuilder dombuilder;
+    
+    // dombuilder should be null when not initialized
+    assert dombuilder == null;
+// end::dombuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::dombuilder_nullobject2[]
+    DOMBuilder dombuilder = null;
+    
+    // dombuilder should be null when initialized to null
+    assert dombuilder == null;
+// end::dombuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::dombuilder_object_does_not_exists1[]
+    shouldFail
+    {
+        // Could not find which method <init>() to invoke from this list as Document or DocumentBuilder
+        // required in constructor - empty parm not allowed 
+        DOMBuilder dombuilder = new DOMBuilder();
+    }
+// end::dombuilder_object_does_not__exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::dombuilder_object_exists2[]
+     // Could not find which method <init>() to invoke from this list:
+     // public groovy.xml.DOMBuilder#<init>(javax.xml.parsers.DocumentBuilder)
+     // public groovy.xml.DOMBuilder#<init>(org.w3c.dom.Document)
+    shouldFail
+    {
+        DOMBuilder dombuilder = new DOMBuilder();
+    }
+// end::dombuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::dombuilder_object_exists3[]
+    // dombuilder does not throw an exception when null parm used in constructor instead of Document
+    DOMBuilder dombuilder = new DOMBuilder(null);
+// end::dombuilder_object_exists3[]
+    } // end of method
+
+} // end of DomBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-xml/src/spec/test/MarkupBuilderTest2.groovy b/subprojects/groovy-xml/src/spec/test/MarkupBuilderTest2.groovy
new file mode 100644
index 0000000..6023d64
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/MarkupBuilderTest2.groovy
@@ -0,0 +1,195 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+import groovy.util.GroovyTestCase
+import org.junit.Test
+import groovy.xml.MarkupBuilder
+
+/**
+ * Tests for MarkupBuilder. The tests directly in this file are specific
+ * to MarkupBuilder. Functionality in common with other Builders
+ * is tested in the parent class.
+ *
+ * @author Groovy Documentation Community
+ *
+ * Additional Tests for MarkupBuilder. 
+ *
+ * This test set contain several of the original tests from groovy-core/subprojects/groovy-xml/src/test/groovy/groovy/xml/MarkupBuilderTest.groovy
+ *
+ * Some additional test senarios are added here to increase code coverage and implementation robustness.
+ *  
+ * The tests directly in this file are specific to MarkupBuilder. Other builders may extend this builder.     
+ * Tests for other implemenattions would reside in their respective directories.
+ *
+ */
+class MarkupBuilderTest2 extends GroovyTestCase {
+    private StringWriter writer
+    private MarkupBuilder xml
+
+    protected void setUp() {
+        writer = new StringWriter()
+        xml = new MarkupBuilder(writer)
+    }
+
+    private assertExpectedXmlDefault(expectedXml) {
+        checkXml expectedXml, writer
+    }
+
+    // assert both strings are the same using the GroovyTestCase junit method
+    private checkXml(String expectedXml, Object writer) {
+        assertEquals(expectedXml, writer.toString())
+    }
+
+
+    /**
+     * Main test method. Checks that well-formed XML is generated
+     * and that the appropriate characters are escaped with the
+     * correct entities.
+     */
+    void testBuilder() {
+        String expectedXml = '''\
+<chars>
+  <ampersand a='&'>&</ampersand>
+  <quote attr='"'>"</quote>
+  <apostrophe attr='''>'</apostrophe>
+  <lessthan attr='value'>chars: & < > '</lessthan>
+  <element attr='value 1 & 2'>chars: & < > " in middle</element>
+  <greaterthan>></greaterthan>
+  <emptyElement />
+  <null />
+  <nullAttribute t1='' />
+  <emptyWithAttributes attr1='set' />
+  <emptyAttribute t1='' />
+  <parent key='value'>
+    <label for='usernameId'>Username: </label>
+    <input name='test' id='1' />
+  </parent>
+</chars>'''
+
+        // Generate the markup.
+        xml.chars {
+            ampersand(a: "&", "&")
+            quote(attr: "\"", "\"")
+            apostrophe(attr: "'", "'")
+            lessthan(attr: "value", "chars: & < > '")
+            element(attr: "value 1 & 2", "chars: & < > \" in middle")
+            greaterthan(">")
+            emptyElement()
+            'null'(null)
+            nullAttribute(t1:null)
+            emptyWithAttributes(attr1:'set')
+            emptyAttribute(t1:'')
+            parent(key:'value'){
+                label(for:'usernameId', 'Username: ')
+                input(name:'test', id:1)
+            }
+        }
+
+        assertEquals expectedXml, fixEOLs(writer.toString())
+    }
+
+    void testOmitAttributeSettingsKeepBothDefaultCase() {
+        xml.element(att1:null, att2:'')
+        assertExpectedXmlDefault "<element att1='' att2='' />"
+    }
+
+    void testOmitAttributeSettingsOmitNullKeepEmpty() {
+        xml.omitNullAttributes = true
+        xml.element(att1:null, att2:'')
+        assertExpectedXmlDefault "<element att2='' />"
+    }
+
+    void testDelegateOnlyToSkipInternalClosureMethods() {
+        def items = {
+          pizza(price: 8.5)
+          curry(price: 8)
+          burger(price: 7.5)
+        }
+        items.resolveStrategy = Closure.DELEGATE_ONLY
+        xml.menu(items)
+
+        assertExpectedXmlDefault '''<menu>
+  <pizza price='8.5' />
+  <curry price='8' />
+  <burger price='7.5' />
+</menu>'''
+    }
+
+
+    protected assertExpectedXml(Closure markup, String expectedXml) {
+        assertExpectedXml markup, null, expectedXml
+    }
+
+    protected assertExpectedXml(Closure markup, Closure configureBuilder, String expectedXml) {
+        def writer = new StringWriter()
+        def builder = new MarkupBuilder(writer)
+        if (configureBuilder) configureBuilder(builder)
+        markup.delegate = builder
+        markup()
+        checkXml(expectedXml, writer)
+    }
+    
+    void testObjectNotDefined() {
+// tag::markupbuilder_nullobject1[]
+    MarkupBuilder markupbuilder;
+    
+    // markupbuilder should be null when not initialized
+    assert markupbuilder == null;
+// end::markupbuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::markupbuilder_nullobject2[]
+    MarkupBuilder markupbuilder = null;
+    
+    // markupbuilder should be null when initialized to null
+    assert markupbuilder == null;
+// end::markupbuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::markupbuilder_object_exists1[]
+    MarkupBuilder markupbuilder = new MarkupBuilder();
+    
+    // markupbuilder should not be null after construction
+    assert markupbuilder != null;
+// end::markupbuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::markupbuilder_object_exists2[]
+    MarkupBuilder markupbuilder = new MarkupBuilder();
+    
+    // markupbuilder should be an instance of correct MarkupBuilder class
+    assert markupbuilder instanceof MarkupBuilder, 'default MarkupBuilder constructor did not build a version of MarkupBuilder'
+// end::markupbuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::markupbuilder_object_exists3[]
+    shouldFail 
+    {
+        // markupbuilder should throw an exception when null parm used in constructor
+        MarkupBuilder markupbuilder = new MarkupBuilder(null);
+    }
+// end::markupbuilder_object_exists3[]
+    } // end of method
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/SaxBuilderTest.groovy b/subprojects/groovy-xml/src/spec/test/SaxBuilderTest.groovy
new file mode 100644
index 0000000..668c476
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/SaxBuilderTest.groovy
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+import groovy.util.GroovyTestCase
+import org.junit.Test
+import groovy.xml.SAXBuilder
+
+/**
+* Tests for SaxBuilder. The tests directly in this file are specific
+* to SaxBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class SaxBuilderTest  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::saxbuilder_nullobject1[]
+    SAXBuilder saxBuilder;
+    
+    // SAXBuilder should be null when not initialized
+    assert saxBuilder == null;
+// end::SAXBuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::SAXBuilder_nullobject2[]
+    SAXBuilder saxBuilder = null;
+    
+    // SAXBuilder should be null when initialized to null
+    assert saxBuilder == null;
+// end::SAXBuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::SAXBuilder_object_exists1[]
+    SAXBuilder saxBuilder = new SAXBuilder();
+    
+    // SAXBuilder should not be null after construction
+    assert saxBuilder != null;
+// end::SAXBuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::SAXBuilder_object_exists2[]
+    SAXBuilder saxBuilder = new SAXBuilder();
+    
+    // SAXBuilder should be an instance of correct SAXBuilder class
+    assert saxBuilder instanceof SAXBuilder, 'default SAXBuilder constructor did not build a version of SAXBuilder'
+// end::SAXBuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::SAXBuilder_object_exists3[]
+        SAXBuilder saxBuilder = new SAXBuilder(null);
+        // SAXBuilder should not be null after construction
+        assert saxBuilder != null;
+    
+// end::SAXBuilder_object_exists3[]
+    } // end of method
+
+} // end of SAXBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-xml/src/spec/test/StreamingMarkupBuilderTest2.groovy b/subprojects/groovy-xml/src/spec/test/StreamingMarkupBuilderTest2.groovy
new file mode 100644
index 0000000..d61ad94
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/StreamingMarkupBuilderTest2.groovy
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+import groovy.util.GroovyTestCase
+import org.junit.Test
+import groovy.xml.StreamingMarkupBuilder
+
+/**
+* Tests for StreamingMarkupBuilder. The tests directly in this file are specific
+* to StreamingMarkupBuilder. Functionality in common with other Builders
+* is tested in the parent class.
+*
+* @author Groovy Documentation Community
+*/
+class StreamingMarkupBuilderTest2  extends GroovyTestCase {
+
+    void testObjectNotDefined() {
+// tag::streamingmarkupbuilder_nullobject1[]
+    StreamingMarkupBuilder streamingmarkupbuilder;
+    
+    // streamingmarkupbuilder should be null when not initialized
+    assert streamingmarkupbuilder == null;
+// end::streamingmarkupbuilder_nullobject1[]
+    } // end of method
+
+
+    void testObjectDefinedNull() {
+// tag::streamingmarkupbuilder_nullobject2[]
+    StreamingMarkupBuilder streamingmarkupbuilder = null;
+    
+    // streamingmarkupbuilder should be null when initialized to null
+    assert streamingmarkupbuilder == null;
+// end::streamingmarkupbuilder_nullobject2[]
+    } // end of method
+
+
+    void testObjectDefinedDefaultConstructor() {
+// tag::streamingmarkupbuilder_object_exists1[]
+    StreamingMarkupBuilder streamingmarkupbuilder = new StreamingMarkupBuilder();
+    
+    // streamingmarkupbuilder should not be null after construction
+    assert streamingmarkupbuilder != null;
+// end::streamingmarkupbuilder_object_exists1[]
+    } // end of method
+
+
+    void testObjectDefinedAsInstanceOf() {
+// tag::streamingmarkupbuilder_object_exists2[]
+    StreamingMarkupBuilder streamingmarkupbuilder = new StreamingMarkupBuilder();
+    
+    // streamingmarkupbuilder should be an instance of correct StreamingMarkupBuilder class
+    assert streamingmarkupbuilder instanceof StreamingMarkupBuilder, 'default StreamingMarkupBuilder constructor did not build a version of StreamingMarkupBuilder'
+// end::streamingmarkupbuilder_object_exists2[]
+    } // end of method
+
+
+    void testObjectDefinedConstructorNullParm() {
+// tag::streamingmarkupbuilder_object_exists3[]
+    shouldFail 
+    {
+        // streamingmarkupbuilder should throw an exception when null parm used in constructor
+        StreamingMarkupBuilder streamingmarkupbuilder = new StreamingMarkupBuilder(null);
+    }    
+// end::streamingmarkupbuilder_object_exists3[]
+    } // end of method
+
+} // end of StreamingMarkupBuilder class
\ No newline at end of file
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideDOMCategory.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideDOMCategory.groovy
new file mode 100644
index 0000000..3c9b50c
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideDOMCategory.groovy
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.xml.DOMBuilder
+import groovy.xml.dom.DOMCategory
+
+/**
+* Tests for the Groovy Xml user guide related to DOMCategory.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideDOMCategoryTest  extends GroovyTestCase {
+
+    // tag::testXML[]
+    static def CAR_RECORDS = '''
+    <records>
+      <car name='HSV Maloo' make='Holden' year='2006'>
+        <country>Australia</country>
+        <record type='speed'>Production Pickup Truck with speed of 271kph</record>
+      </car>
+      <car name='P50' make='Peel' year='1962'>
+        <country>Isle of Man</country>
+        <record type='size'>Smallest Street-Legal Car at 99cm wide and 59 kg in weight</record>
+      </car>
+      <car name='Royale' make='Bugatti' year='1931'>
+        <country>France</country>
+        <record type='price'>Most Valuable Car at $15 million</record>
+      </car>
+    </records>
+  '''
+  // end::testXML[]
+
+  void testExample1() {
+      // tag::testExample1[]
+      def reader = new StringReader(CAR_RECORDS)
+      def doc = DOMBuilder.parse(reader) //<1>
+      def records = doc.documentElement
+
+      use(DOMCategory) { // <2>
+          assert records.car.size() == 3
+      }
+      // end::testExample1[]
+  }
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy
new file mode 100644
index 0000000..e6e2aea
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideMarkupBuilderTest.groovy
@@ -0,0 +1,220 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.xml.MarkupBuilder
+import org.codehaus.groovy.tools.xml.DomToGroovy
+
+/**
+* Tests for the Groovy Xml user guide related to MarkupBuilderTest.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideMarkupBuilderTest  extends GroovyTestCase {
+
+    void createCarsTest() {
+        // tag::createCarsTest[]
+        def writer = new StringWriter()
+        def xml = new MarkupBuilder(writer) // <1>
+
+        xml.records() { // <2>
+            car(name:'HSV Maloo', make:'Holden', year:2006) {
+                country('Australia')
+                record(type:'speed', 'Production Pickup Truck with speed of 271kph')
+            }
+            car(name:'Royale', make:'Bugatti', year:1931) {
+                country('France')
+                record(type:'price', 'Most Valuable Car at $15 million')
+            }
+        }
+
+        def records = new XmlSlurper().parseText(writer.toString()) // <3>
+
+        assert records.car.first().name.text() == 'HSV Maloo'
+        assert records.car.last().name.text() == 'Royale'
+        // end::createCarsTest[]
+    }
+
+    void testCreateSimpleXml1() {
+        // tag::testCreateSimpleXml1[]
+        def xmlString = "<movie>the godfather</movie>" // <1>
+
+        def xmlWriter = new StringWriter() // <2>
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        xmlMarkup.movie("the godfather") // <3>
+
+        assert xmlString == xmlWriter.toString() // <4>
+        // end::testCreateSimpleXml1[]
+    }
+
+
+    void testCreateSimpleXml2() {
+        // tag::testCreateSimpleXml2[]
+        def xmlString = "<movie id='2'>the godfather</movie>"
+
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        xmlMarkup.movie(id: "2", "the godfather") // <1>
+
+        assert xmlString == xmlWriter.toString()
+        // end::testCreateSimpleXml2[]
+    }
+
+    void testCreateSimpleXml3() {
+        // tag::testCreateSimpleXml3[]
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        xmlMarkup.movie(id: 2) { // <1>
+            name("the godfather")
+        }
+
+        def movie = new XmlSlurper().parseText(xmlWriter.toString())
+
+        assert movie. at id == 2
+        assert movie.name.text() == 'the godfather'
+        // end::testCreateSimpleXml3[]
+    }
+
+    void testNamespaceAware() {
+        // tag::testNamespaceAware[]
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        xmlMarkup
+            .'x:movies'('xmlns:x':'http://www.groovy-lang.org') { // <1>
+                'x:movie'(id: 1, 'the godfather')
+                'x:movie'(id: 2, 'ronin')
+            }
+
+        def movies =
+            new XmlSlurper() // <2>
+                .parseText(xmlWriter.toString())
+                .declareNamespace(x:'http://www.groovy-lang.org')
+
+        assert movies.'x:movie'.last(). at id == 2
+        assert movies.'x:movie'.last().text() == 'ronin'
+        // end::testNamespaceAware[]
+    }
+
+    void testComplexUse1() {
+        // tag::testComplexUse1[]
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        xmlMarkup
+            .'x:movies'('xmlns:x':'http://www.groovy-lang.org') {
+                (1..3).each { n -> // <1>
+                    'x:movie'(id: n, "the godfather $n")
+                    if (n % 2 == 0) { // <2>
+                        'x:movie'(id: n, "the godfather $n (Extended)")
+                    }
+                }
+            }
+
+        def movies =
+            new XmlSlurper()
+                .parseText(xmlWriter.toString())
+                .declareNamespace(x:'http://www.groovy-lang.org')
+
+        assert movies.'x:movie'.size() == 4
+        assert movies.'x:movie'*.text().every { name -> name.startsWith('the')}
+        // end::testComplexUse1[]
+    }
+
+    void testComplexUse2() {
+        // tag::testComplexUse2[]
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter)
+
+        // <1>
+        Closure<MarkupBuilder> buildMovieList = { MarkupBuilder builder ->
+            (1..3).each { n ->
+                builder.'x:movie'(id: n, "the godfather $n")
+                if (n % 2 == 0) {
+                    builder.'x:movie'(id: n, "the godfather $n (Extended)")
+                }
+            }
+
+            return builder
+        }
+
+        xmlMarkup.'x:movies'('xmlns:x':'http://www.groovy-lang.org') {
+            buildMovieList(xmlMarkup) // <2>
+        }
+
+        def movies =
+            new XmlSlurper()
+                .parseText(xmlWriter.toString())
+                .declareNamespace(x:'http://www.groovy-lang.org')
+
+        assert movies.'x:movie'.size() == 4
+        assert movies.'x:movie'*.text().every { name -> name.startsWith('the')}
+        // end::testComplexUse2[]
+    }
+
+    void testDOMToGroovy() {
+        // tag::testDOMToGroovy[]
+        def songs  = """
+            <songs>
+              <song>
+                <title>Here I go</title>
+                <band>Whitesnake</band>
+              </song>
+            </songs>
+        """
+
+        def builder     =
+            javax.xml.parsers.DocumentBuilderFactory.newInstance().newDocumentBuilder()
+
+            def inputStream = new ByteArrayInputStream(songs.bytes)
+            def document    = builder.parse(inputStream)
+            def output      = new StringWriter()
+            def converter   = new DomToGroovy(new PrintWriter(output)) // <1>
+
+            converter.print(document) // <2>
+
+            String xmlRecovered  =
+                new GroovyShell()
+                .evaluate("""
+                   def writer = new StringWriter()
+                   def builder = new groovy.xml.MarkupBuilder(writer)
+                   builder.${output}
+
+                   return writer.toString()
+                """) // <3>
+
+            assert new XmlSlurper().parseText(xmlRecovered).song.title.text() == 'Here I go' // <4>
+        // end::testDOMToGroovy[]
+    }
+
+    void testMkp1() {
+        // tag::testMkp1[]
+        def xmlWriter = new StringWriter()
+        def xmlMarkup = new MarkupBuilder(xmlWriter).rules {
+            mkp.comment('THIS IS THE MAIN RULE') // <1>
+            rule(sentence: mkp.yield('3 > n')) // <2>
+        }
+
+        // <3>
+        assert xmlWriter.toString().contains('3 > n')
+        assert xmlWriter.toString().contains('<!-- THIS IS THE MAIN RULE -->')
+        // end::testMkp1[]
+    }
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideStreamingMarkupBuilderTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideStreamingMarkupBuilderTest.groovy
new file mode 100644
index 0000000..91d4c96
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideStreamingMarkupBuilderTest.groovy
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.xml.StreamingMarkupBuilder
+
+/**
+* Tests for the Groovy Xml user guide related to StreamingMarkupBuilderTest.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideStreamingMarkupBuilderTest  extends GroovyTestCase {
+
+    void testSimpleExample() {
+        // tag::testSimpleExample[]
+        def xml = new StreamingMarkupBuilder().bind { // <1>
+            records {
+                car(name:'HSV Maloo', make:'Holden', year:2006) { // <2>
+                    country('Australia')
+                    record(type:'speed', 'Production Pickup Truck with speed of 271kph')
+                }
+                car(name:'P50', make:'Peel', year:1962) {
+                    country('Isle of Man')
+                    record(type:'size', 'Smallest Street-Legal Car at 99cm wide and 59 kg in weight')
+                }
+                car(name:'Royale', make:'Bugatti', year:1931) {
+                    country('France')
+                    record(type:'price', 'Most Valuable Car at $15 million')
+                }
+            }
+        }
+
+        def records = new XmlSlurper().parseText(xml.toString()) // <3>
+
+        assert records.car.size() == 3
+        assert records.car.find { it. at name == 'P50' }.country.text() == 'Isle of Man'
+        // end::testSimpleExample[]
+    }
+
+    void testMkp() {
+        // tag::testMkp[]
+        def xml = new StreamingMarkupBuilder().bind {
+            records {
+                car(name: mkp.yield('3 < 5')) // <1>
+                car(name: mkp.yieldUnescaped('1 < 3')) // <2>
+            }
+        }
+
+        assert xml.toString().contains('3 < 5')
+        assert xml.toString().contains('1 < 3')
+        // end::testMkp[]
+    }
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy
new file mode 100644
index 0000000..3ff538c
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideXmlParserTest.groovy
@@ -0,0 +1,122 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.util.GroovyTestCase
+
+/**
+* Tests for the Groovy Xml user guide related to XmlParser.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideXmlParserTest  extends GroovyTestCase {
+
+    // tag::responseBookXml[]
+    def xml = """
+    <response version-api="2.0">
+        <value>
+            <books>
+                <book id="2">
+                    <title>Don Xijote</title>
+                    <author id="1">Manuel De Cervantes</author>
+                </book>
+            </books>
+        </value>
+    </response>
+    """
+    // end::responseBookXml[]
+
+    void testParseText() {
+        // tag::testParseText[]
+        def text = '''
+            <list>
+                <technology>
+                    <name>Groovy</name>
+                </technology>
+            </list>
+        '''
+
+        def list = new XmlParser().parseText(text) // <1>
+
+        assert list instanceof groovy.util.Node // <2>
+        assert list.technology.name.text() == 'Groovy' // <3>
+        // end::testParseText[]
+    }
+
+    void testAddingNodes1() {
+        // tag::testAddingNodes1[]
+        def parser = new XmlParser()
+        def response = parser.parseText(xml)
+        def numberOfResults = parser.createNode(
+            response,
+            new QName("numberOfResults"),
+            [:]
+        )
+
+        numberOfResults.value = "1"
+        assert response.numberOfResults.text() == "1"
+        // end::testAddingNodes1[]
+    }
+
+    void testAddingNodes2() {
+        // tag::testAddingNodes2[]
+        def parser = new XmlParser()
+        def response = parser.parseText(xml)
+
+        response.appendNode(
+            new QName("numberOfResults"),
+            [:],
+            "1"
+        )
+
+        response.numberOfResults.text() == "1"
+        // end::testAddingNodes2[]
+    }
+
+    void testModifyingNodes1() {
+        // tag::testModifyingNodes1[]
+         def response = new XmlParser().parseText(xml)
+
+      /* Use the same syntax as groovy.xml.MarkupBuilder */
+         response.value.books.book[0].replaceNode{ // <1>
+             book(id:"3"){
+                 title("To Kill a Mockingbird")
+                 author(id:"3","Harper Lee")
+             }
+         }
+
+         def newNode = response.value.books.book[0]
+
+         assert newNode.name() == "book"
+         assert newNode. at id == "3"
+         assert newNode.title.text() == "To Kill a Mockingbird"
+         assert newNode.author.text() == "Harper Lee"
+         assert newNode.author. at id.first() == "3"
+        // end::testModifyingNodes1[]
+    }
+
+    void testSettingAttributes1() {
+        // tag::testSettingAttributes1[]
+         def parser = new XmlParser()
+         def response = parser.parseText(xml)
+
+         response. at numberOfResults = "1"
+
+         assert response. at numberOfResults == "1"
+        // end::testSettingAttributes1[]
+    }
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy
new file mode 100644
index 0000000..be8b1a0
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideXmlSlurperTest.groovy
@@ -0,0 +1,176 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.util.GroovyTestCase
+
+/**
+* Tests for the Groovy Xml user guide related to XmlSlurper.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideXmlSlurperTest  extends GroovyTestCase {
+
+    // tag::books[]
+    static final String books = '''
+        <response version-api="2.0">
+            <value>
+                <books>
+                    <book available="20" id="1">
+                        <title>Don Xijote</title>
+                        <author id="1">Manuel De Cervantes</author>
+                    </book>
+                    <book available="14" id="2">
+                        <title>Catcher in the Rye</title>
+                       <author id="2">JD Salinger</author>
+                   </book>
+                   <book available="13" id="3">
+                       <title>Alice in Wonderland</title>
+                       <author id="3">Lewis Carroll</author>
+                   </book>
+                   <book available="5" id="4">
+                       <title>Don Xijote</title>
+                       <author id="4">Manuel De Cervantes</author>
+                   </book>
+               </books>
+           </value>
+        </response>
+    '''
+    // end::books[]
+
+    void testParseText() {
+        // tag::testParseText[]
+        def text = '''
+            <list>
+                <technology>
+                    <name>Groovy</name>
+                </technology>
+            </list>
+        '''
+
+        def list = new XmlSlurper().parseText(text) // <1>
+
+        assert list instanceof groovy.util.slurpersupport.GPathResult // <2>
+        assert list.technology.name == 'Groovy' // <3>
+        // end::testParseText[]
+    }
+
+    void testGettingANodeText() {
+        // tag::testGettingANodeText[]
+        def response = new XmlSlurper().parseText(books)
+        def authorResult = response.value.books.book[0].author
+
+        assert authorResult.text() == 'Manuel De Cervantes'
+        // end::testGettingANodeText[]
+    }
+
+    void testGettingAnAttributeText() {
+        // tag::testGettingAnAttributeText[]
+        def response = new XmlSlurper().parseText(books)
+
+        def book = response.value.books.book[0] // <1>
+        def bookAuthorId1 = book. at id // <2>
+        def bookAuthorId2 = book['@id'] // <3>
+
+        assert bookAuthorId1 == '1' // <4>
+        assert bookAuthorId1.toInteger() == 1 // <5>
+        assert bookAuthorId1 == bookAuthorId2
+        // end::testGettingAnAttributeText[]
+    }
+
+    void testBreadFirst1() {
+        // tag::testBreadFirst1[]
+        def response = new XmlSlurper().parseText(books)
+
+        def catcherInTheRye = response.value.books.'*'.find { node->
+         /* node. at id == 2 could be expressed as node['@id'] == 2 */
+            node.name() == 'book' && node. at id == '2'
+        }
+
+        assert catcherInTheRye.title.text() == 'Catcher in the Rye'
+        // end::testBreadFirst1[]
+    }
+
+    void testDepthFirst1() {
+        // tag::testDepthFirst1[]
+        def response = new XmlSlurper().parseText(books)
+
+        def bookId = response.'**'.find { book->
+            book.author.text() == 'Lewis Carroll'
+        }. at id
+
+        assert bookId == 3
+        // end::testDepthFirst1[]
+    }
+
+    void testDepthFirst2() {
+        // tag::testDepthFirst2[]
+        def response = new XmlSlurper().parseText(books)
+
+        def titles = response.'**'.findAll{ node-> node.name() == 'title' }*.text()
+
+        assert titles.size() == 4
+        // end::testDepthFirst2[]
+    }
+
+    void testHelpers() {
+        // tag::testHelpers[]
+        def response = new XmlSlurper().parseText(books)
+
+        def titles = response.value.books.book.findAll{book->
+         /* You can use toInteger() over the GPathResult object */
+            book. at id.toInteger() > 2
+        }*.title
+
+        assert titles.size() == 2
+        // end::testHelpers[]
+    }
+
+    void testModifyingNodes1() {
+        // tag::testModifyingNodes1[]
+        def response = new XmlSlurper().parseText(books)
+
+        /* Use the same syntax as groovy.xml.MarkupBuilder */
+        response.value.books.book[0].replaceNode{
+            book(id:"3"){
+                title("To Kill a Mockingbird")
+                author(id:"3","Harper Lee")
+            }
+        }
+
+        assert response.value.books.book[0].title.text() == "Don Xijote"
+
+        /* That mkp is a special namespace used to escape away from the normal building mode
+           of the builder and get access to helper markup methods
+           'yield', 'pi', 'comment', 'out', 'namespaces', 'xmlDeclaration' and
+           'yieldUnescaped' */
+        def result = new StreamingMarkupBuilder().bind { mkp.yield response }.toString()
+        def changedResponse = new XmlSlurper().parseText(result)
+
+        assert changedResponse.value.books.book[0].title.text() == "To Kill a Mockingbird"
+        // end::testModifyingNodes1[]
+    }
+
+    void testSettingAttributes1() {
+        // tag::testSettingAttributes1[]
+        def response = new XmlSlurper().parseText(books)
+        response. at numberOfResults = "2"
+
+        assert response. at numberOfResults == "2"
+        // end::testSettingAttributes1[]
+    }
+
+}
diff --git a/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy b/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy
new file mode 100644
index 0000000..2cf07a4
--- /dev/null
+++ b/subprojects/groovy-xml/src/spec/test/UserGuideXmlUtilTest.groovy
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2014 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package groovy.xml
+
+import groovy.util.GroovyTestCase
+
+/**
+* Tests for the Groovy Xml user guide related to XmlUtil.
+*
+* @author Groovy Documentation Community
+*/
+class UserGuideXmlUtilTest  extends GroovyTestCase {
+
+    // tag::responseBookXml[]
+    def xml = """
+    <response version-api="2.0">
+        <value>
+            <books>
+                <book id="2">
+                    <title>Don Xijote</title>
+                    <author id="1">Manuel De Cervantes</author>
+                </book>
+            </books>
+        </value>
+    </response>
+    """
+    // end::responseBookXml[]
+
+    void testGettingANode() {
+        // tag::testGettingANode[]
+        def response = new XmlParser().parseText(xml)
+        def nodeToSerialize = response.'**'.find {it.name() == 'author'}
+        def nodeAsText = XmlUtil.serialize(nodeToSerialize)
+
+        assert nodeAsText ==
+            XmlUtil.serialize('<?xml version="1.0" encoding="UTF-8"?><author id="1">Manuel De Cervantes</author>')
+        // end::testGettingANode[]
+    }
+
+}
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/bugs/StaticMarkupBug.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/bugs/StaticMarkupBug.groovy
index 5c7f1bf..00c212d 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/bugs/StaticMarkupBug.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/bugs/StaticMarkupBug.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.bugs
 
 import groovy.xml.MarkupBuilder
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomNode.java b/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomNode.java
index 3d40bb5..99c6a93 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomNode.java
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomNode.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 import java.util.Map;
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomXmlParser.java b/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomXmlParser.java
index cdc57dc..8888712 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomXmlParser.java
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/util/CustomXmlParser.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util;
 
 import org.xml.sax.SAXException;
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlNodePrinterTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlNodePrinterTest.groovy
index 1b9e60e..0b132c5 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlNodePrinterTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlNodePrinterTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.util
 
 class XmlNodePrinterTest extends GroovyTestCase {
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlSlurperTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlSlurperTest.groovy
index 82d84ec..0bd03a4 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlSlurperTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/util/XmlSlurperTest.groovy
@@ -1,5 +1,5 @@
 /*
- * Copyright 2003-2013 the original author or authors.
+ * Copyright 2003-2014 the original author or authors.
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -33,17 +33,17 @@ class XmlSlurperTest extends GroovyTestCase {
                          xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
                          xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/"
                          xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
-                         xmlns="http://schemas.xmlsoap.org/wsdl/">                                              
-                <message name="SomeRequest">                                                          
-                    <part name="parameters" element="ns1:SomeReq" />                                  
-                </message>                                                                            
-                <message name="SomeResponse">                                                         
-                    <part name="result" element="ns1:SomeRsp" />                                      
-                </message>                                                                            
-            </definitions>                                                                            
-            '''
+                         xmlns="http://schemas.xmlsoap.org/wsdl/">
+                <message name="SomeRequest">
+                    <part name="parameters" element="ns1:SomeReq" />
+                </message>
+                <message name="SomeResponse">
+                    <part name="result" element="ns1:SomeRsp" />
+                </message>
+            </definitions>
+        '''
         def xml = new XmlSlurper().parseText(wsdl)
-        assert xml.message.part. at element.findAll {it =~ /.Req$/}.size() == 1
+        assert xml.message.part. at element*.text().findAll {it =~ /.Req$/}.size() == 1
         assert xml.message.part.findAll { true }.size() == 2
         assert xml.message.part.find { it.name() == 'part' }.name() == 'part'
         assert xml.message.findAll { true }.size() == 2
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/DOMTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/DOMTest.groovy
index 09749d2..c82e609 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/DOMTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/DOMTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 /**
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/FactorySupportTest.java b/subprojects/groovy-xml/src/test/groovy/groovy/xml/FactorySupportTest.java
index 0909126..0b72ade 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/FactorySupportTest.java
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/FactorySupportTest.java
@@ -1,3 +1,18 @@
+/**
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml;
 
 import junit.framework.TestCase;
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/MixedMarkupTestSupport.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/MixedMarkupTestSupport.groovy
index 4539219..d1d2eef 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/MixedMarkupTestSupport.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/MixedMarkupTestSupport.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 class MixedMarkupTestSupport {
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeGPathTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeGPathTest.groovy
index 400d918..3184e91 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeGPathTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeGPathTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 /**
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeTest.groovy
index 94d9e2f..e9d7b90 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/NamespaceNodeTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 /**
@@ -63,4 +78,43 @@ class NamespaceNodeTest extends TestXmlSupport {
         def attrNode = root[xsd.complexType][xsd.attribute]
         assert attrNode[0]. at name == 'orderDate'
     }
+
+    void testNodeBuilderWithImplicitNamespace() {
+        def n = new Namespace('http://foo/bar')
+        def builder = NamespaceBuilder.newInstance(new NodeBuilder(), n.uri)
+
+        def result = builder.outer(id: "3") {
+            'ns1:innerWithNewNamespace'('xmlns:ns1': "http://foo/other", someAttr: 'someValue') {
+                'ns1:nested'("foo")
+            }
+            innerWithoutNewNamespace("bar")
+        }
+        
+        def expected = """<?xml version="1.0" encoding="UTF-8"?>\
+<outer xmlns="http://foo/bar" id="3">
+  <ns1:innerWithNewNamespace xmlns:ns1="http://foo/other" someAttr="someValue">
+    <ns1:nested>foo</ns1:nested>
+  </ns1:innerWithNewNamespace>
+  <innerWithoutNewNamespace>bar</innerWithoutNewNamespace>
+</outer>
+""".replaceAll('[\r\n]','')
+        def actual = XmlUtil.serialize(result).replaceAll("[\r\n]", "")
+        assert actual == expected
+    }
+
+    void testNamespaceBuilderWithoutNamespace() {
+        def builder = NamespaceBuilder.newInstance(new NodeBuilder())
+        def result = builder.outer(id: "3") {
+            inner(name: "foo")
+            inner("bar")
+        }
+        def expected = """<?xml version="1.0" encoding="UTF-8"?>\
+<outer id="3">
+  <inner name="foo"/>
+  <inner>bar</inner>
+</outer>
+""".replaceAll('[\r\n]','')
+        def actual = XmlUtil.serialize(result).replaceAll("[\r\n]", "")
+        assert actual == expected
+    }
 }
\ No newline at end of file
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/SAXTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/SAXTest.groovy
index 3bb642a..2ec1218 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/SAXTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/SAXTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 /**
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/TraversalTestSupport.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/TraversalTestSupport.groovy
index 6f3add5..43c2bc0 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/TraversalTestSupport.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/TraversalTestSupport.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package groovy.xml
 
 class TraversalTestSupport {
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/UseMarkupWithWriterScript.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/UseMarkupWithWriterScript.groovy
index 5d01a94..eda4a57 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/UseMarkupWithWriterScript.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/UseMarkupWithWriterScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 // used by MarkupWithWriterTest.testWriterUseInScriptFile
 
 writer = new java.io.StringWriter()
diff --git a/subprojects/groovy-xml/src/test/groovy/groovy/xml/XmlUtilTest.groovy b/subprojects/groovy-xml/src/test/groovy/groovy/xml/XmlUtilTest.groovy
index 6112128..185a250 100644
--- a/subprojects/groovy-xml/src/test/groovy/groovy/xml/XmlUtilTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/groovy/xml/XmlUtilTest.groovy
@@ -1,4 +1,19 @@
 /*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+/*
 * Copyright 2003-2013 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
diff --git a/subprojects/groovy-xml/src/test/groovy/org/codehaus/groovy/benchmarks/BuilderPerfTest.groovy b/subprojects/groovy-xml/src/test/groovy/org/codehaus/groovy/benchmarks/BuilderPerfTest.groovy
index 4ddf678..e3f2b2a 100644
--- a/subprojects/groovy-xml/src/test/groovy/org/codehaus/groovy/benchmarks/BuilderPerfTest.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/org/codehaus/groovy/benchmarks/BuilderPerfTest.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 import groovy.xml.MarkupBuilder
 
 class BuilderPerfTest extends GroovyTestCase {
diff --git a/subprojects/groovy-xml/src/test/groovy/script/AtomTestScript.groovy b/subprojects/groovy-xml/src/test/groovy/script/AtomTestScript.groovy
index 5fcce27..c43bc30 100644
--- a/subprojects/groovy-xml/src/test/groovy/script/AtomTestScript.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/script/AtomTestScript.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package script
 
 import groovy.xml.MarkupBuilder;
diff --git a/subprojects/groovy-xml/src/test/groovy/util/NavToWiki.groovy b/subprojects/groovy-xml/src/test/groovy/util/NavToWiki.groovy
index 5a8dfce..b109483 100644
--- a/subprojects/groovy-xml/src/test/groovy/util/NavToWiki.groovy
+++ b/subprojects/groovy-xml/src/test/groovy/util/NavToWiki.groovy
@@ -1,3 +1,18 @@
+/*
+ * Copyright 2003-2015 the original author or authors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
 package util
 
 if (args.size() < 1) {

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-java/groovy2.git



More information about the pkg-java-commits mailing list