You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@groovy.apache.org by ch...@apache.org on 2023/01/27 21:07:25 UTC

[groovy-website] 01/01: Migrating blog posts from Roller

This is an automated email from the ASF dual-hosted git repository.

christ pushed a commit to branch christ/blog_migration
in repository https://gitbox.apache.org/repos/asf/groovy-website.git

commit 63378adf31152f407c2b5fd5aca80a2960a6fdde
Author: Chris Thistlethwaite <ch...@apache.org>
AuthorDate: Fri Jan 27 16:07:13 2023 -0500

    Migrating blog posts from Roller
---
 site/src/site/blog/adventures-with-groovyfx.md     |  37 ++
 .../site/blog/announce-announcing-codenarc-1-2.md  |  28 ++
 site/src/site/blog/apache-groovy-2022-year-in.md   |  29 ++
 .../blog/apache-groovy-committer-graeme-rocher.md  |  10 +
 .../calculating-fibonacci-with-groovy-revisited.md |  25 ++
 .../blog/classifying-iris-flowers-with-deep.md     | 176 ++++++++
 .../site/blog/comparators-and-sorting-in-groovy.md |  85 ++++
 site/src/site/blog/deck-of-cards-with-groovy.md    |  17 +
 .../blog/deep-learning-and-eclipse-collections.md  |  57 +++
 .../site/blog/detecting-objects-with-groovy-the.md |  43 ++
 .../blog/encryption-and-decryption-with-groovy.md  |  51 +++
 site/src/site/blog/fruity-eclipse-collections.md   |  48 +++
 site/src/site/blog/fun-with-obfuscated-groovy.md   |  31 ++
 site/src/site/blog/gmavenplus-1-6-2-released.md    |  11 +
 site/src/site/blog/gpars-meets-virtual-threads.md  |  44 ++
 site/src/site/blog/groovy-2-4-16-released.md       |   9 +
 site/src/site/blog/groovy-2-4-16-windows.md        |   7 +
 site/src/site/blog/groovy-2-4-17-released.md       |   7 +
 site/src/site/blog/groovy-2-5-1-released.md        |  60 +++
 site/src/site/blog/groovy-2-5-2-released.md        |  51 +++
 site/src/site/blog/groovy-2-5-2-windows.md         |   7 +
 site/src/site/blog/groovy-2-5-3-released.md        |  48 +++
 site/src/site/blog/groovy-2-5-3-windows.md         |   7 +
 site/src/site/blog/groovy-2-5-4-released.md        |  17 +
 site/src/site/blog/groovy-2-5-4-windows.md         |  10 +
 site/src/site/blog/groovy-2-5-5-released.md        |   8 +
 site/src/site/blog/groovy-2-5-5-windows.md         |   7 +
 site/src/site/blog/groovy-2-5-6-released.md        |   7 +
 site/src/site/blog/groovy-2-5-7-and.md             |  17 +
 site/src/site/blog/groovy-2-5-7-released.md        |   7 +
 site/src/site/blog/groovy-3-0-0-alpha.md           |   7 +
 site/src/site/blog/groovy-3-0-0-alpha1.md          |   9 +
 site/src/site/blog/groovy-3-0-0-beta.md            |   7 +
 site/src/site/blog/groovy-3-0-0-beta1.md           |  43 ++
 site/src/site/blog/groovy-3-0-0-beta2.md           |  14 +
 site/src/site/blog/groovy-3-highlights.md          | 235 +++++++++++
 site/src/site/blog/groovy-4-0-3-released.md        |   7 +
 site/src/site/blog/groovy-dates-and-times-cheat.md | 402 ++++++++++++++++++
 .../blog/groovy-list-processing-cheat-sheet.md     |  55 +++
 site/src/site/blog/groovy-release-train-4-0.md     |  10 +
 site/src/site/blog/jvm-hello-world-with-groovy.md  |  88 ++++
 site/src/site/blog/life-on-mars-units-of.md        |  66 +++
 .../blog/matrix-calculations-with-groovy-apache.md | 119 ++++++
 .../natural-language-processing-with-groovy.md     | 449 +++++++++++++++++++++
 site/src/site/blog/parsing-json-with-groovy.md     |  70 ++++
 .../src/site/blog/reading-and-writing-csv-files.md |  26 ++
 .../solving-cryptarithmetic-puzzles-with-groovy.md | 138 +++++++
 .../src/site/blog/testing-your-java-with-groovy.md |  99 +++++
 .../site/blog/using-groovy-with-apache-wayang.md   |  34 ++
 .../blog/whiskey-clustering-with-groovy-and.md     |  63 +++
 .../site/blog/working-with-sql-databases-with.md   |  87 ++++
 .../site/blog/zipping-collections-with-groovy.md   |  59 +++
 52 files changed, 3048 insertions(+)

diff --git a/site/src/site/blog/adventures-with-groovyfx.md b/site/src/site/blog/adventures-with-groovyfx.md
new file mode 100644
index 0000000..27ad144
--- /dev/null
+++ b/site/src/site/blog/adventures-with-groovyfx.md
@@ -0,0 +1,37 @@
+---
+layout: post
+title: Adventures with GroovyFX
+date: '2022-12-12T14:22:57+00:00'
+permalink: adventures-with-groovyfx
+---
+<p>This blog looks at a <a href="http://groovyfx.org/" target="_blank">GroovyFX</a> version of a <a href="https://donraab.medium.com/my-weird-and-wonderful-first-adventures-with-javafx-6efe3b1923c8" target="_blank">ToDo application originally written in JavaFX</a>. First we start with a <code>ToDoCategory</code> enum of our ToDo categories:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/453d4f49-c4f0-4f77-977e-863d2f8c47d2" alt="TodoEnum.png"></p>
+
+
+<p>We will have a <code>ToDoItem</code> class containing the todo task, the previously mentioned category and the due date.</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:11pt;"><span style="color:#bbb529;">@Canonical<br></span><span style="color:#bbb529;">@JsonIncludeProperties</span>([<span style="color:#6a8759;">'task'</span>, <span style="color:#6a8759;">'category'</span>, <span style="color:#6a8759;">'date'</span>])<br><span st [...]
+
+<p>It's annotated with <code>@JsonIncludeProperties</code> to allow easy serialization to/from JSON format, to provide easy persistence, and <code>@FXBindable</code>&nbsp;which eliminates the boilerplate required to define JavaFX properties.</p>
+<p>Next, we'll define some helper variables:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:11pt;"><span style="color:#cc7832;">var </span>file = <span style="color:#6a8759;">'todolist.json' </span><span style="color:#cc7832;">as </span>File<br><span style="color:#cc7832;">var </span>mapper = <span style="color:#cc7832;">new </span>ObjectMapper().registerModule(<span style="color:#cc7832;">new </span>JavaTimeModule())<br><span style="color:#cc7832;">var </span>open = <span style= [...]
+
+<p>Here, <code>mapper</code> serializes and deserializes our top-level domain object (the ToDo list) into JSON using the <a href="https://github.com/FasterXML/jackson" target="_blank">Jackson library</a>. The&nbsp;<code>open</code> and <code>close</code>&nbsp;Closures do the reading and writing respectively.
+</p>
+<p>For a bit of fun and only slightly more complexity, we have included some slightly nicer images in our application. JavaFX's default emoji font rendering is a little sketchy on some platforms and it's not much work to have nice multi-colored images. This is achieved using the icons from&nbsp;<span style="background-color: rgb(245, 245, 245); color: rgb(51, 51, 51); font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; font-size: 13px;"><a href="https://github.com/p [...]
+<p>Our application will have a combo box for selecting a ToDo item's category. We'll create a factory for the combo box so that each selection will be a label with both graphic and text components.</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:11pt;"><span style="color:#cc7832;">def </span>graphicLabelFactory = <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">new </span>ListCell&lt;ToDoCategory&gt;() {<br>        <span style="color:#cc7832;">void </span>updateItem(ToDoCategory cat, <span style="color:#cc7832;">boolean </span>empty) {<br>            <span style="c [...]
+
+<p>When displaying our ToDo list, we'll use a table view. So, let's create a factory for table cells that will use the pretty images as a centered graphic.</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:11pt;"><span style="color:#cc7832;">def </span>graphicCellFactory = <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">new </span>TableCell&lt;ToDoItem, ToDoItem&gt;() {<br>        <span style="color:#cc7832;">void </span>updateItem(ToDoItem item, <span style="color:#cc7832;">boolean </span>empty) {<br>            <span style [...]
+
+<p>Finally, with these definitions out of the way, we can define our GroovyFX application for manipulating our ToDo list:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:11pt;"><span style="color:#9876aa;font-style:italic;">start </span><span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>stage(<span style="color:#6a8759;">title</span>: <span style="color:#6a8759;">'GroovyFX ToDo Demo'</span>, <span  [...]
+                        <span style="color:#cc7832;">if </span>(task.text &amp;&amp; category.value &amp;&amp; date.value 
+                                &amp;&amp; !table.selectionModel.empty) {
+                            <span style="color:#cc7832;">var </span>item = items[table.selectionModel.selectedIndex.value]<br>                            item.task = task.text<br>                            item.category = category.value<br>                            item.date = date.value<br>                        }<br>                    <span style="font-weight:bold;">}</span>)<br>                    button(<span style="color:#6a8759;">'Remove'</span>, <span style="color:#6a8759;">o [...]
+
+<p>We could have somewhat separated the concerns of application logic and display logic by placing the GUI part of this app in an&nbsp;<code>fxml</code> file. For our purposes however, we'll keep the whole application in one source file and use Groovy's declarative builder style.</p>
+<p>Here is the application in use:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/62c91bfb-6594-4858-8368-e17e518b7c26" alt="TodoScreenshot.png"><br></p>
+
+<h3>Further information</h3>
+
+<p>The code for this application can be found here:&nbsp;<a href="https://github.com/paulk-asert/groovyfx-todo" target="_blank">https://github.com/paulk-asert/groovyfx-todo</a>.</p><p>It's a Groovy 3 and JDK 8 application but see this <a href="https://blogs.apache.org/groovy/entry/reading-and-writing-csv-files" target="_blank">blog</a> if you want to see Jackson deserialization of classes and records (and Groovy's emulated records) from CSV files using the most recent Groovy and JDK vers [...]
diff --git a/site/src/site/blog/announce-announcing-codenarc-1-2.md b/site/src/site/blog/announce-announcing-codenarc-1-2.md
new file mode 100644
index 0000000..2572d3d
--- /dev/null
+++ b/site/src/site/blog/announce-announcing-codenarc-1-2.md
@@ -0,0 +1,28 @@
+---
+layout: post
+title: "[ANNOUNCE] Announcing CodeNarc 1.2"
+date: '2018-07-10T10:16:39+00:00'
+permalink: announce-announcing-codenarc-1-2
+---
+
+<a href="http://groovy-lang.org/index.html"><img src="https://blogs.apache.org/groovy/mediaresource/58a149c0-e332-40dd-b450-59ffe0c96b74?t=true" alt="groovy-logo.png"></img></a>
+
+<p>
+The CodeNarc Team is proud to announce the release of version 1.2.
+</p><p>
+<a href="http://codenarc.org/">CodeNarc</a> is a static analysis tool for Groovy source code. 
+ </p><p>
+Version 1.2 includes 5 new rules and several enhancements and bug fixes. See the full details in the <a href="https://github.com/CodeNarc/CodeNarc/blob/master/CHANGELOG.md">release notes</a>. 
+ </p>
+<h3>New Rules</h3>
+<b></b>
+<li><b>StaticFieldsBeforeInstanceFields</b> rule (convention) - Enforce that all static fields are above all instance fields within a class.
+<li><b>StaticMethodsBeforeInstanceMethods</b> rule (convention) - Enforce that all static methods within each visibility level (public, protected, private) are above all instance methods within that same visibility level.
+<li><b>PublicMethodsBeforeNonPublicMethods</b> rule (convention) - Enforce that all public methods are above protected and private methods.
+<li><b>GrailsDomainStringPropertyMaxSize</b> rule (grails) - String properties in Grails domain classes have to define maximum size otherwise the property is mapped to VARCHAR(255) causing runtime exceptions to occur.
+<li><b>NoJavaUtilDate</b> rule (convention) - Do not use java.util.Date. Prefer the classes in the java.time.* packages. Checks for construction of new java.util.Date objects.
+</p><p>
+Check out the <a href="https://github.com/CodeNarc/CodeNarc">project on GitHub</a>!
+ </p><p>
+The <a href="http://grails.org/plugin/codenarc">Grails CodeNarc Plugin</a> has been updated to version 1.2 as well.
+</p>
diff --git a/site/src/site/blog/apache-groovy-2022-year-in.md b/site/src/site/blog/apache-groovy-2022-year-in.md
new file mode 100644
index 0000000..9fb2e36
--- /dev/null
+++ b/site/src/site/blog/apache-groovy-2022-year-in.md
@@ -0,0 +1,29 @@
+---
+layout: post
+title: Apache Groovy 2022 Year In Review
+date: '2022-12-29T14:28:20+00:00'
+permalink: apache-groovy-2022-year-in
+---
+<p><span></span>The year 2022 has been a reasonably good one for the Groovy Programming Language. Here are just a few of the highlights.</p>
+
+<h2>Releases &amp; Contributions</h2>
+
+<p>In 2022, Groovy had 18 releases starting with Groovy 4 in January:</p>
+<p><img style="width:75%" src="https://blogs.apache.org/groovy/mediaresource/96d5fd2c-d134-49fe-afda-da540363205b" alt="Tweet for Groovy 4 release"></p>
+<p>The latest release of Groovy 4 is 4.0.7 which includes over 300 improvements and bug fixes since 4.0.0. For more details about Groovy 4, you can read the&nbsp;<a href="https://groovy-lang.org/releasenotes/groovy-4.0.html" target="_blank" style="background-color: rgb(255, 255, 255);">release notes</a>. There have also been bug fix releases for earlier Groovy versions.</p><p>For our main branch of our main source code repo, there were 820 commits from 28 contributors. This is the branch [...]
+
+<h2>Downloads</h2>
+
+<p>In early 2021, Groovy surpassed the 1 billion artifacts downloaded mark. This is downloads of artifacts from repositories like Maven Central and (at least until recently) Bintray. We now only collect stats from Maven Central. We don't collect stats on downloads of the zip releases nor attempt to account for the many downloads where Groovy is bundled within other products, so the stats are no doubt much higher. Well, the good news is that the rate of downloads is still increasing, so i [...]
+
+<h2>Blogs</h2>
+
+<p>We also started increasing the number of posts in the official ASF blog platform: <a href="https://blogs.apache.org/groovy/" target="_blank">blogs.apache.org/groovy</a>. There were nearly 30 posts for you to peruse from this year. We try to show off Groovy features and also have some fun.</p><p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/15c5a15d-84fd-416e-83c1-071ff9c8dcd3" alt="blog_collage.jpg"></p>
+<p>You might also like to check out the <a href="https://www.javaadvent.com/2022/12/groovy-and-data-science.html">Groovy and Data Science blog post</a> from the <a href="https://www.javaadvent.com/" target="_blank">JVM Advent</a> folks. It summaries a handful of the above mentioned blog posts.</p>
+
+<h2>ApacheCon</h2>
+
+<p>Several folks from the project and many friends of Groovy participated in the sold out ApacheCon conference in New Orleans in October. We thank the conference organisers, speakers and attendees for the wonderful conference.</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/470e0399-3b04-435c-ac59-df53cdfa63c4" alt="apachecon_collage.jpg"></p>
+<p>We have plenty more in store for 2023. We invite you to come on the journey with us!</p>
+<p>Social media: <a href="https://twitter.com/ApacheGroovy" target="_blank">@ApacheGroovy</a> <a href="https://fosstodon.org/@ApacheGroovy" target="_blank">@ApacheGroovy@fosstodon.org</a></p>
diff --git a/site/src/site/blog/apache-groovy-committer-graeme-rocher.md b/site/src/site/blog/apache-groovy-committer-graeme-rocher.md
new file mode 100644
index 0000000..8345673
--- /dev/null
+++ b/site/src/site/blog/apache-groovy-committer-graeme-rocher.md
@@ -0,0 +1,10 @@
+---
+layout: post
+title: Apache Groovy committer Graeme Rocher receives Oracle Groundbreaker award
+date: '2018-10-24T23:33:37+00:00'
+permalink: apache-groovy-committer-graeme-rocher
+---
+<p>
+The <a href="http://groovy.apache.org/">Apache Groovy</a> team congratulates long-time Groovy committer Graeme Rocher on receiving his Groundbreaker award at Oracle Code One.
+Graeme has made numerous significant contributions to Apache Groovy and has also founded two of the most important frameworks using Groovy: <a href="https://grails.org/">Grails</a> and <a href="http://micronaut.io/">Micronaut</a>. </p> <img height="600" width="800" src="https://pbs.twimg.com/media/DqPOTAPU0AAK_5d.jpg" /> 
+  <p>&quot;<em>Grails pioneered truly rapid web application development on the JVM, helping to drive the adoption of the Groovy language which today has such an inclusive community and phenomemal ecosystem</em>&quot;.&nbsp;</p>
diff --git a/site/src/site/blog/calculating-fibonacci-with-groovy-revisited.md b/site/src/site/blog/calculating-fibonacci-with-groovy-revisited.md
new file mode 100644
index 0000000..b111f26
--- /dev/null
+++ b/site/src/site/blog/calculating-fibonacci-with-groovy-revisited.md
@@ -0,0 +1,25 @@
+---
+layout: post
+title: Calculating Fibonacci with Groovy revisited
+date: '2022-09-08T10:59:56+00:00'
+permalink: calculating-fibonacci-with-groovy-revisited
+---
+<p>In a <a href="https://blogs.apache.org/roller-ui/authoring/entryEdit.rol?weblog=groovy&amp;bean.id=7e7c1b79-5567-452b-ac11-0d55f765fd90" target="_blank">recent post</a>, we looked at using <a href="https://blogs.apache.org/roller-ui/authoring/entryEdit.rol?weblog=groovy&amp;bean.id=7e7c1b79-5567-452b-ac11-0d55f765fd90" target="_blank">Matrices with Groovy</a> including using matrices to calculate Fibonacci terms. But do you need that complexity to calculate Fibonacci? Not, not at all. [...]
+
+<h3>Iterative style</h3>
+
+<p>Unless you learned a functional programming language as your first language, you may have written an iterative Factorial or Fibonacci as one of your first programming learning exercises. Such an algorithm for Fibonacci could look something like this:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>fib(n) {<br>    <span style="color:#cc7832;">if </span>(n &lt;= <span style="color:#689 [...]
+
+<h3>Recursive</h3>
+
+<p>Once you mastered iterative programming, your next programming learning exercise may have been the recursive version of Factorial or Fibonacci. For Fibonacci, you may have coded something like this:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>fib(n) {<br>    <span style="color:#cc7832;">if </span>(n &lt;= <span style="color:#6897bb;">1</span>) <span style="color:#cc7832;">return </span>n<br>    fib(n - <span style="color:#6897bb;">1</span>) + fib(n - <span style="color:#6897bb;">2</span>)<br>}<br><br><span style="color:#cc7832;">assert </span>fib(<span style="color:#6897bb;">10</s [...]
+<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Call_Tree_for_Fibonacci_Number_F6.svg/750px-Call_Tree_for_Fibonacci_Number_F6.svg.png" style="width:40%"></p>
+<p>There are several ways to avoid that repetition. One option is to use the <code>@Memoized</code> annotation. Adding this annotation on a method causes the compiler to inject appropriate code for caching results into the method. This is ideal for pure functions like Fibonacci since they always return the same output for a given input. There are annotation attributes to adjust how big such a cache might be, but that sophistication isn't needed here.</p><pre style="background-color:#2b2b [...]
+<p>This now runs just as quickly as the iterative method. If you happened to use a <code>Closure</code> instead of a method, you can call one of the <code>memoize</code> methods on <code>Closure</code>.</p><p>A problem with this approach (in fact recursion in general) is that you hit a stack overflow exception for larger values of <code>n</code>, e.g. <code>fib(500G)</code>. Groovy supports tail call elimination with the inclusion of the <code>TailRecursive</code> annotation. In this cas [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#bbb529;">@TailRecursive<br></span><span style="color:#cc7832;">static </span>fib(n, a, b) {<br>    <span style="color:#cc7832;">if </span>(n == <span style="color:#6897bb;">0</span>) <span style="color:#cc7832;">return </span>a<br>    <span style="color:#cc7832;">if </span>(n == <span style="color:#6897bb;">1</span>) <span style="color:#cc7832;">return </span>b< [...]
+<p>We saw the Stream based "one-liner" solution at the start of this blog post. Let's adopt the duck-typing idioms we have used so far and define a fib method. It could look like this:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>fib(n) {<br>    <span style="color:#cc7832;">def </span>zero = n.valueOf(<span style="color:#6897bb;">0</span>)<br>    <span style="color:#cc7832;">def </span>one = n.valueOf(<span style="color:#6897bb;">1</span>)<br>    Stream.<span style="color:#9876aa;font-style:italic;">iterate</span>([zero, one], t -&gt; [t[<span style="color:#6897bb;">1 [...]
+<h3>Bytecode and AST transforms</h3>
+<p>Finally, just so you know all your options, here is a version using the <a href="https://github.com/melix/groovy-bytecode-ast" target="_blank">@Bytecode AST transform</a> which lets you write JVM bytecode directly in your Groovy! Note this falls into the category of "don't ever ever do this" but just so you know you can, it is included here:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#bbb529;">@Bytecode<br></span><span style="color:#cc7832;">int </span>fib(<span style="color:#cc7832;">int </span>i) {<br>    l0<br>    iload <span style="color:#6897bb;">1<br></span><span style="color:#6897bb;">    </span>iconst_2<br>    if_icmpgt l1<br>    iconst_1<br>    _goto l2<br>    l1<br>    frame SAME<br>    aload <span style="color:#6897bb;">0<br></span [...]
diff --git a/site/src/site/blog/classifying-iris-flowers-with-deep.md b/site/src/site/blog/classifying-iris-flowers-with-deep.md
new file mode 100644
index 0000000..5cf89e6
--- /dev/null
+++ b/site/src/site/blog/classifying-iris-flowers-with-deep.md
@@ -0,0 +1,176 @@
+---
+layout: post
+title: Classifying Iris Flowers with Deep Learning, Groovy and GraalVM
+date: '2022-06-25T10:52:59+00:00'
+permalink: classifying-iris-flowers-with-deep
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/80b1adc8-7234-4046-a279-e272b0a0edd4" alt="iris_description.png" style="width: 25%;" align="right">A classic data science <a href="https://en.wikipedia.org/wiki/Iris_flower_data_set" target="_blank">dataset</a> captures flower characteristics of Iris flowers. It captures the <i>width </i>and <i>length </i>of the <i>sepals </i>and <i>petals </i>for three <i>species </i>(<a href="https://en.wikipedia.org/wiki/Iris_setosa" target="_ [...]
+<p></p><table style="margin-top: 0px; margin-bottom: 16px; display: block; width: max-content; max-width: 70%; overflow: auto; color: rgb(36, 41, 47); font-family: -apple-system, BlinkMacSystemFont, &quot;Segoe UI&quot;, Helvetica, Arial, sans-serif, &quot;Apple Color Emoji&quot;, &quot;Segoe UI Emoji&quot;; font-size: 16px; background-color: rgb(255, 255, 255);"><thead><tr style="background-color: var(--color-canvas-default); border-top: 1px solid var(--color-border-muted);"><th style=" [...]
+<p>Feel free to browse these other examples and the Jupyter/BeakerX notebook if you are interested in any of these additional techniques.</p>
+<p><a href="https://blogs.apache.org/groovy/mediaresource/f389f220-38f0-473b-ab52-72032694d435"><img style="width: 50%;" src="https://blogs.apache.org/groovy/mediaresource/f389f220-38f0-473b-ab52-72032694d435" alt="iris_jupyter.png"></a></p>
+<p>For this blog, let's just look at the Deep Learning examples. We'll look at solutions using Encog, Eclipse DeepLearning4J and Deep Netts (with standard Java and as a native image using GraalVM) but first a brief introduction.</p>
+
+<h3>Deep Learning</h3>
+
+<p>Deep learning falls under the branches of <a href="https://en.wikipedia.org/wiki/Machine_learning" target="_blank">machine learning</a> and <a href="https://en.wikipedia.org/wiki/Artificial_intelligence" target="_blank">artificial intelligence</a>. It involves multiple layers (hence the "deep") of an <a href="https://en.wikipedia.org/wiki/Artificial_neural_network" target="_blank">artificial neural network</a>. There are lots of ways to configure such networks and the details are beyo [...]
+<p><a href="https://blogs.apache.org/groovy/mediaresource/2206eccb-0c50-4091-a030-e3057517d810"><img src="https://blogs.apache.org/groovy/mediaresource/2206eccb-0c50-4091-a030-e3057517d810" style="width: 50%;" alt="deep_network.png"></a></p>
+<p>Each node in this network mimics to some degree a neuron in the human brain. Again, we'll simplify the details. Each node has multiple inputs, which are given a particular weight, as well as an activation function which will determine whether our node "fires". Training the model is a process which works out what the best weights should be.</p>
+<p><a href="https://blogs.apache.org/groovy/mediaresource/b5d32431-a273-481d-b0b5-169b0665b385"><img src="https://blogs.apache.org/groovy/mediaresource/b5d32431-a273-481d-b0b5-169b0665b385" style="width: 50%;" alt="deep_node.png"></a></p>
+<p>The math involved for converting inputs to output for any node isn't too hard. We could write it ourselves (as shown <a href="https://github.com/paulk-asert/groovy-data-science/blob/master/subprojects/Mnist/src/main/groovy/MnistTrainer.groovy" target="_blank">here</a> using matrices and <a href="https://commons.apache.org/proper/commons-math/" target="_blank">Apache Commons Math</a> for a digit recognition example) but luckily we don't have to. The libraries we are going to use do muc [...]
+
+<h3>Encog</h3>
+
+<p><a href="https://www.heatonresearch.com/encog/" target="_blank">Encog</a> is a pure Java machine learning framework that was created in 2008. There is also a C# port for .Net users. Encog is a simple framework that supports a number of advanced algorithms not found elsewhere but isn't as widely used as other more recent frameworks.</p><p>The complete source code for our Iris classification example using Encog is <a href="https://github.com/paulk-asert/groovy-data-science/blob/master/s [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;">def model = <span style="color:#cc7832;">new </span>EncogModel(data).tap <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>selectMethod(data, <span style="color:#9876aa;font-style:italic;">TYPE_FEEDFORWARD</span>)<br>    <span style="color:#9876aa;">report </span>= <span style="color:#cc7832;">new </span>ConsoleStatusReportable()<br>    data.nor [...]
+println <span style="color:#6a8759;">"Validation error: " </span>+ pretty(<span style="font-size: 9.8pt; color: rgb(152, 118, 170); font-style: italic;">calculateRegressionError</span><span style="font-size: 9.8pt;">(bestMethod, model.</span><span style="font-size: 9.8pt; color: rgb(152, 118, 170);">validationDataset</span><span style="font-size: 9.8pt;">))</span></pre>
+<p>When we run the example, we see:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color: rgb(78, 154, 6); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.8pt;"><b>paulk@pop-os</b></span><font color="#a9b7c6" face="JetBrains Mono, monospace"><span style="font-size: 9.8pt;">:</span></font><span style="color: rgb(52, 101, 164); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.8pt;"><b>/extra/projects/iris_encog</b></spa [...]
+1/5 : Fold #1
+1/5 : Fold #1/5: Iteration #1, Training Error: 1.43550735, Validation Error: 0.73302237
+1/5 : Fold #1/5: Iteration #2, Training Error: 0.78845427, Validation Error: 0.73302237
+...
+5/5 : Fold #5/5: Iteration #163, Training Error: 0.00086231, Validation Error: 0.00427126
+5/5 : Cross-validated score:0.10345818553910753
+</span><span style="font-size: 13.0667px;">Training error:  0.0009
+Validation error:  0.0991
+Prediction errors:
+predicted: Iris-virginica, actual: Iris-versicolor, normalized input: -0.0556, -0.4167,  0.3898,  0.2500
+Confusion matrix:            Iris-setosa     Iris-versicolor      Iris-virginica
+         Iris-setosa                  19                   0                   0
+     Iris-versicolor                   0                  15                   1
+      Iris-virginica                   0                   0                  10
+</span><span style="font-size: 9.8pt;">
+real	0m3.073s
+user	0m9.973s
+sys	0m0.367s</span></font></pre>
+<p>We won't explain all of the stats, but it basically says we have a pretty good model with low errors in prediction. If you see the <span style="color: rgb(57, 123, 33); font-weight: bold;">green</span> and <span style="color: rgb(49, 24, 115); font-weight: bold;">purple</span> points in the notebook image earlier in this blog, you'll see there are some points which are going to be hard to predict correctly all the time. The confusion matrix shows that the model predicted one flower in [...]
+
+<h3>Eclipse DeepLearning4j</h3>
+<p><a href="https://deeplearning4j.konduit.ai/" target="_blank">Eclipse DeepLearning4j</a> is&nbsp;a suite of tools for running deep learning on the JVM. It has support for scaling up to <a href="https://spark.apache.org/" target="_blank">Apache Spark</a> as well as some integration with python at a number of levels. It also provides integration to GPUs and C/++ libraries for native integration.</p><p>The complete source code for our Iris classification example using DeepLearning4J is <a [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;">MultiLayerConfiguration conf = <span style="color:#cc7832;">new </span>NeuralNetConfiguration.Builder()<br>    .seed(seed)<br>    .activation(Activation.<span style="color:#9876aa;font-style:italic;">TANH</span>) <span style="color:#808080;">// global activation<br></span><span style="color:#808080;">    </span>.weightInit(WeightInit.<span style="color:#9876aa;font-style:italic;">X [...]
+
+<p>When we run this example, we see:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/iris_dl4j</b></span>$ time groovy -cp "build/lib/*" IrisDl4j.groovy 
+[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
+[main] INFO org.nd4j.nativeblas.NativeOpsHolder - Number of threads used for linear algebra: 4
+[main] INFO org.nd4j.nativeblas.Nd4jBlas - Number of threads used for OpenMP BLAS: 4
+[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Backend used: [CPU]; OS: [Linux]
+...
+[main] INFO org.deeplearning4j.optimize.listeners.ScoreIterationListener - Score at iteration 0 is 0.9707752535968273
+[main] INFO org.deeplearning4j.optimize.listeners.ScoreIterationListener - Score at iteration 100 is 0.3494968712782093
+...
+[main] INFO org.deeplearning4j.optimize.listeners.ScoreIterationListener - Score at iteration 900 is 0.03135504326480282
+
+========================Evaluation Metrics========================
+ # of classes:    3
+ Accuracy:        0.9778
+ Precision:       0.9778
+ Recall:          0.9744
+ F1 Score:        0.9752
+Precision, recall &amp; F1: macro-averaged (equally weighted avg. of 3 classes)
+
+
+=========================Confusion Matrix=========================
+  0  1  2
+----------
+ 18  0  0 | 0 = 0
+  0 14  0 | 1 = 1
+  0  1 12 | 2 = 2
+
+Confusion matrix format: Actual (rowClass) predicted as (columnClass) N times
+==================================================================
+
+real	0m5.856s
+user	0m25.638s
+sys	0m1.752s
+</pre>
+
+<p>Again the stats tell us that the model is good. One error in the confusion matrix for our testing dataset.<br>DeepLearning4J does have an impressive range of technologies that can be used to enhance performance in certain scenarios.
+For this example, I enabled&nbsp;AVX (Advanced Vector Extensions) support but didn't try using the CUDA/GPU support nor make use of any Apache Spark integration. The GPU option might have sped up the application but given the size of the dataset and the amount of calculations needed to train our network, it probably wouldn't have sped up much. For this little example, the overheads of putting the plumbing in place to access native C++ implementations and so forth, outweighed the gains. T [...]
+<p>The other increase in complexity is the number of jar files needed in the classpath. I went with the easy option of using the <span style="color: rgb(66, 66, 66);font-family:'JetBrains Mono',monospace;">nd4j-native-platform</span> dependency plus added the <span style="color: rgb(66, 66, 66);font-family:'JetBrains Mono',monospace;">org.nd4j:nd4j-native:1.0.0-M2:linux-x86_64-avx2</span> dependency for AVX support. This made my life easy but brought in over 170 jars including many for u [...]
+<h3>Deep Netts</h3>
+<p><a href="https://www.deepnetts.com/" target="_blank">Deep Netts</a> is a company offering a range of products and services related to deep learning. Here we are using the&nbsp;free open-source <a href="https://www.deepnetts.com/blog/deep-netts-community-edition" target="_blank">Deep Netts community edition</a> pure java deep learning library. It provides support for the&nbsp;Java Visual Recognition API (<a href="https://jcp.org/en/jsr/detail?id=381" target="_blank" style="">JSR381</a> [...]
+<p>The complete source code for our Iris classification example using Deep Netts is <a href="https://github.com/paulk-asert/groovy-data-science/blob/master/subprojects/Iris/src/main/groovy/NNFF_DeepNetts.groovy" target="_blank">here</a> and the important part is below:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#cc7832;">var </span>splits = dataSet.split(<span style="color:#6897bb;">0.7d</span>, <span style="color:#6897bb;">0.3d</span>)  <span style="color:#808080;">// 70/30% split<br></span><span style="color:#cc7832;">var </span>train = splits[<span style="color:#6897bb;">0</span>]<br><span style="color:#cc7832;">var </span>test = splits[<span style="color:#6897bb;">1 [...]
+<p>When we run this command we see:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/iris_graalvm</b></span>$ time groovy -cp "build/lib/*" Iris.groovy 
+16:49:27.089 [main] INFO deepnetts.core.DeepNetts - ------------------------------------------------------------------------
+16:49:27.091 [main] INFO deepnetts.core.DeepNetts - TRAINING NEURAL NETWORK
+16:49:27.091 [main] INFO deepnetts.core.DeepNetts - ------------------------------------------------------------------------
+16:49:27.100 [main] INFO deepnetts.core.DeepNetts - Epoch:1, Time:6ms, TrainError:0.8584314, TrainErrorChange:0.8584314, TrainAccuracy: 0.5252525
+16:49:27.103 [main] INFO deepnetts.core.DeepNetts - Epoch:2, Time:3ms, TrainError:0.52278274, TrainErrorChange:-0.33564866, TrainAccuracy: 0.52820516
+...
+16:49:27.911 [main] INFO deepnetts.core.DeepNetts - Epoch:3031, Time:0ms, TrainError:0.029988592, TrainErrorChange:-0.015680967, TrainAccuracy: 1.0
+TRAINING COMPLETED
+16:49:27.911 [main] INFO deepnetts.core.DeepNetts - Total Training Time: 820ms
+16:49:27.911 [main] INFO deepnetts.core.DeepNetts - ------------------------------------------------------------------------
+CLASSIFIER EVALUATION METRICS
+Accuracy: 0.95681506 (How often is classifier correct in total)
+Precision: 0.974359 (How often is classifier correct when it gives positive prediction)
+F1Score: 0.974359 (Harmonic average (balance) of precision and recall)
+Recall: 0.974359 (When it is actually positive class, how often does it give positive prediction)
+
+CONFUSION MATRIX
+                          none    Iris-setosaIris-versicolor Iris-virginica
+           none              0              0              0              0
+    Iris-setosa              0             14              0              0
+Iris-versicolor              0              0             18              1
+ Iris-virginica              0              0              0             12
+
+
+real	0m3.160s
+user	0m10.156s
+sys	0m0.483s
+</pre>
+
+<p>This is faster than DeepLearning4j and similar to Encog. This is to be expected given our small data set and isn't indicative of performance for larger problems.</p>
+<p>
+Another plus is the dependency list. It isn't quite the single jar situation as we saw with Encog but not far off.
+There is the Encog jar, the JSR381 VisRec API which is in a separate jar, and a handful of logging jars.
+</p>
+
+<h3>Deep Netts with GraalVM</h3>
+
+<p>Another technology we might want to consider if performance is important to us is <a href="https://www.graalvm.org/" target="_blank">GraalVM</a>. GraalVM is&nbsp;a high-performance JDK distribution designed to speed up the execution of applications written in Java and other JVM languages. We'll look at creating a native version of our Iris Deep Netts application. We used&nbsp;GraalVM 22.1.0 Java 17 CE and Groovy 4.0.3. We'll cover just the basic steps but there are other places for ad [...]
+<p>Groovy has two natures. It's dynamic nature supports adding methods at runtime through metaprogramming and interacting with method dispatch processing through missing method interception and other tricks. Some of these tricks make heavy use of reflection and dynamic class loading and cause problems for GraalVM which is trying to determine as much information as it can at compile time. Groovy's static nature has a more limited set of metaprogramming capabilities but allows bytecode muc [...]
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><br><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/iris_graalvm</b></span>$ groovyc -cp "build/lib/*" --compile-static Iris.groovy
+<br></pre>
+<p>Next we build our native application:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><br><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/iris_graalvm</b></span>$ native-image  --report-unsupported-elements-at-runtime \
+   --initialize-at-run-time=groovy.grape.GrapeIvy,deepnetts.net.weights.RandomWeights \
+   --initialize-at-build-time --no-fallback  -H:ConfigurationFileDirectories=conf/  -cp ".:build/lib/*" Iris
+<br></pre>
+<p>We told GraalVM to initialize <span style="color: rgb(66, 66, 66);font-family:'JetBrains Mono',monospace;">GrapeIvy</span>
+at runtime (to avoid needing Ivy jars in the classpath since Groovy will lazily load those classes only if
+we use&nbsp;<span style="color: rgb(66, 66, 66);font-family:'JetBrains Mono',monospace;">@Grab</span> statements).
+We also did the same for the <span style="color: rgb(66, 66, 66);font-family:'JetBrains Mono',monospace;">RandomWeights</span> class to avoid it being locked into a random seed fixed at compile time.</p>
+<p>Now we are ready to run our application:</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><br><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/iris_graalvm</b></span>$ time ./iris
+...
+CLASSIFIER EVALUATION METRICS
+Accuracy: 0.93460923 (How often is classifier correct in total)
+Precision: 0.96491224 (How often is classifier correct when it gives positive prediction)
+F1Score: 0.96491224 (Harmonic average (balance) of precision and recall)
+Recall: 0.96491224 (When it is actually positive class, how often does it give positive prediction)
+
+CONFUSION MATRIX
+                          none    Iris-setosaIris-versicolor Iris-virginica
+           none              0              0              0              0
+    Iris-setosa              0             21              0              0
+Iris-versicolor              0              0             20              2
+ Iris-virginica              0              0              0             17
+
+
+real    0m0.131s
+user    0m0.096s
+sys     0m0.029s
+<br></pre>
+
+<p>We can see here that the speed has dramatically increased. This is great, but we should note, that using GraalVM often involves some tricky investigation especially for Groovy which by default has its dynamic nature. There are a few features of Groovy which won't be available when using Groovy's static nature and some libraries might be problematical. As an example, Deep Netts has log4j2 as one of its dependencies. At the time of writing, there are still issues using log4j2 with Graal [...]
+<h3>Conclusion</h3>
+
+<p>We have seen a few different libraries for performing deep learning classification using Groovy.
+Each has its own strengths and weaknesses.
+There are certainly options to cater for folks wanting blinding fast startup speeds through to options which scale to massive computing farms in the cloud.</p>
diff --git a/site/src/site/blog/comparators-and-sorting-in-groovy.md b/site/src/site/blog/comparators-and-sorting-in-groovy.md
new file mode 100644
index 0000000..e442bb4
--- /dev/null
+++ b/site/src/site/blog/comparators-and-sorting-in-groovy.md
@@ -0,0 +1,85 @@
+---
+layout: post
+title: Comparators and Sorting in Groovy
+date: '2022-07-21T15:51:31+00:00'
+permalink: comparators-and-sorting-in-groovy
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/2eb621f3-0419-437e-950b-0c9e5e15804e" align="right" style="width:15%;" alt="2022-07-22 01_05_29-s-l300.webp (300×291).png">This blog post is inspired by the Comparator examples in the excellent <i>Collections Refuelled</i> <a href="https://www.youtube.com/watch?v=q6zF3vf114M&amp;t=13s" target="_blank">talk</a> and <a href="https://blogs.oracle.com/java/post/collections-refueled" target="_blank">blog</a> by Stuart Marks. That blog [...]
+</p>
+<p>Rather than have a <code>Student</code> class as per the original blog example, we'll have a <code>Celebrity</code> class (and later record) which has the same <code>first</code> and <code>last</code> name fields and an additional <code>age</code> field. We'll compare initially by <code>last</code> name with nulls before non-nulls and then by <code>first</code> name and lastly by <code>age</code>.</p>
+
+<p>As with the original blog, we'll cater for nulls, e.g. a celebrity known by a single name.</p>
+<h3>The Java comparator story recap</h3>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/97dd3c82-aae5-481a-a158-701c8244d5c1" style="width:10%;" align="right" alt="JavaTransparent.png">Our <code>Celebrity</code> class if we wrote it in Java would look something like:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">public class </span><span style="color:#000000;">Celebrity </span>{                    <span style="color:#777777 [...]
+<pre>Celebrities:
+Celebrity{firstName='Cher', age=76}
+Celebrity{firstName='Alex', lastName='Lloyd', age=37}
+Celebrity{firstName='Alex', lastName='Lloyd', age=47}
+Celebrity{firstName='Cher', lastName='Lloyd', age=28}
+Celebrity{firstName='Cher', lastName='Wang', age=63}
+</pre>
+<p>As pointed out in the original blog, this code is rather tedious and error-prone and can be improved greatly with comparator improvements in JDK8:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">import </span><span style="color:#000000;">java.util.Arrays</span>;             // Java<br><span style="color:#0033b3;">import </span><span style="color:#000000;">java.util.List</span>;<br><br><span sty [...]
+<h3>The Groovy comparator story</h3>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/c5ba5e59-737e-4ebf-91c9-08fa67dc8f70" align="right" style="width:15%;" alt="groovy.png">At about the same time that Java was evolving its comparator story Groovy added some complementary features to tackle many of the same problems. We'll look at some of those features and also how the JDK improvements we saw above features can be used instead if preferred.</p><p>First off, let's create a Groovy <code>Celebrity</code> record:</p> [...]
+<p>And create our list of celebrities:</p>
+<pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">var </span><span style="color:#000000;">celebrities </span>= [<br>    <span style="color:#0033b3;">new </span><span style="color:#000000;">Celebrity</span>(<span style="color:#067d17;">"Cher"</span>, <span style="color:#067d17;">"Wang"</span>, <span style="color:#1750eb;">63</span>),<br>    <span style="color:#0033b3;">new </span><span style="color:#000 [...]
+<pre>Celebrities:
+Celebrity(first:Cher, age:76)
+Celebrity(first:Alex, last:Lloyd, age:37)
+Celebrity(first:Alex, last:Lloyd, age:47)
+Celebrity(first:Cher, last:Lloyd, age:28)
+Celebrity(first:Cher, last:Wang, age:63)</pre>
+<p>We'd have a tiny bit more work to do if we wanted nulls last but the defaults work well for the example at hand.</p><p>We can alternatively, make use of the "new in JDK8" methods mentioned earlier:</p>
+<pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#000000;">celebrities</span>.sort(<span style="font-style:italic;">comparing</span>(<span style="color:#000000;">Celebrity</span>::last, <span style="font-style:italic;">nullsFirst</span>(<span style="font-style:italic;">naturalOrder</span>())).<br>        thenComparing(c -&gt; c.first).thenComparing(c -&gt; c.age))<br></pre><p>But this is where we should come ba [...]
+<pre>Celebrities:
+Celebrity(first:Cher, last:Lloyd, age:28)
+Celebrity(first:Alex, last:Lloyd, age:37)
+Celebrity(first:Alex, last:Lloyd, age:47)
+Celebrity(first:Cher, last:Wang, age:63)
+Celebrity(first:Cher, age:76)</pre>
+<p>In addition to the <code>sort</code> method, Groovy provides a <code>toSorted</code> method which sorts a copy of the list, leaving the original unchanged. So, to create a list sorted by first name we can use this code:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">var </span><span style="color:#000000;">celebritiesByFirst </span>= <span style="color:#000000;">celebrities</span>.toSorted(<spa [...]
+<pre>Celebrities:
+Celebrity(first:Alex, last:Lloyd, age:37)
+Celebrity(first:Alex, last:Lloyd, age:47)
+Celebrity(first:Cher, last:Lloyd, age:28)
+Celebrity(first:Cher, last:Wang, age:63)
+Celebrity(first:Cher, age:76)</pre>
+<p>If you are a fan of functional style programming, you might consider using <code>List.of</code> to define the original list and then only <code>toSorted</code> method calls in further processing.</p>
+<h3>Mixing in some language integrated queries</h3><p>Groovy also has a GQuery (aka GINQ) capability which provides a SQL inspired DSL for working with collections. We can use GQueries to examine and order our collection. Here is an example:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="font-style:italic;">GQ </span><span style="font-weight:bold;">{<br></span>    from c <span style="color: rgb(0, 51, 17 [...]
+<p>Which has this output:</p>
+<pre>+-------+-------+-----+
+| first | last&nbsp; | age |
++-------+-------+-----+
+| Cher&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;| 76&nbsp; |
+| Alex&nbsp; | Lloyd | 37&nbsp; |
+| Alex&nbsp; | Lloyd | 47&nbsp; |
+| Cher&nbsp; | Lloyd | 28&nbsp; |
+| Cher&nbsp; | Wang&nbsp; | 63&nbsp; |
++-------+-------+-----+</pre>
+<p>In this case, it's using the natural ordering which <code>@Sortable</code> gives us.</p><p>Or we can sort by age:</p>
+<pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="font-style:italic;">GQ </span><span style="font-weight:bold;">{<br></span>    from c <span style="color: rgb(0, 51, 179);">in </span><span style="color: rgb(0, 0, 0);">celebrities<br></span><span style="color: rgb(0, 0, 0);">    </span>orderby c.age<br>    select c.first, c.last, c.age<br><span style="font-weight:bold;">}<br></span></pre>
+<p>Which has this output:</p>
+<pre>+-------+-------+-----+
+| first | last&nbsp; | age |
++-------+-------+-----+
+| Cher&nbsp; | Lloyd | 28&nbsp; |
+| Alex&nbsp; | Lloyd | 37&nbsp; |
+| Alex&nbsp; | Lloyd | 47&nbsp; |
+| Cher&nbsp; | Wang&nbsp; | 63&nbsp; |
+| Cher&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;| 76&nbsp; |
++-------+-------+-----+
+</pre>
+<p>Or we can sort by last name descending and then age:</p>
+<pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="font-style:italic;">GQ </span><span style="font-weight:bold;">{<br></span>    from c <span style="color: rgb(0, 51, 179);">in </span><span style="color: rgb(0, 0, 0);">celebrities<br></span><span style="color: rgb(0, 0, 0);">    </span>orderby c.last <span style="color: rgb(0, 51, 179);">in </span>desc, c.age<br>    select c.first, c.last, c.age<br><span style= [...]
+<p>Which has this output:</p>
+<pre>+-------+-------+-----+
+| first | last&nbsp; | age |
++-------+-------+-----+
+| Cher&nbsp; | Wang&nbsp; | 63&nbsp; |
+| Cher&nbsp; | Lloyd | 28&nbsp; |
+| Alex&nbsp; | Lloyd | 37&nbsp; |
+| Alex&nbsp; | Lloyd | 47&nbsp; |
+| Cher&nbsp; |&nbsp; &nbsp; &nbsp; &nbsp;| 76&nbsp; |
++-------+-------+-----+</pre>
+<h3>Conclusion</h3>
+<p>We have seen a little example of using comparators in Groovy. All the great JDK capabilities are available as well as the spaceship operator, the <code>sort</code> and <code>toSorted</code> methods, and the <code>@Sortable</code> AST transformation.</p>
diff --git a/site/src/site/blog/deck-of-cards-with-groovy.md b/site/src/site/blog/deck-of-cards-with-groovy.md
new file mode 100644
index 0000000..b52aa22
--- /dev/null
+++ b/site/src/site/blog/deck-of-cards-with-groovy.md
@@ -0,0 +1,17 @@
+---
+layout: post
+title: Deck of cards with Groovy, JDK collections and Eclipse Collections
+date: '2022-09-23T10:18:36+00:00'
+permalink: deck-of-cards-with-groovy
+---
+<p>Once again, <a href="https://twitter.com/TheDonRaab" target="_blank">Donald Raab</a> has produced an interesting <a href="https://donraab.medium.com/how-to-create-a-deck-of-cards-using-eclipse-collections-d9838ac430b7" target="_blank">blog post</a> on <a href="https://github.com/eclipse/eclipse-collections" target="_blank">Eclipse Collections</a>;&nbsp;this one shows some code for modelling and manipulating cards with Java 17 and Eclipse Collections. His related katas are highly recom [...]
+<pre>[Card[rank=FOUR, suit=SPADES], Card[rank=FOUR, suit=DIAMONDS], Card[rank=SIX, suit=HEARTS], Card[rank=NINE, suit=CLUBS], Card[rank=JACK, suit=CLUBS]]
+[Card[rank=FIVE, suit=DIAMONDS], Card[rank=TWO, suit=HEARTS], Card[rank=FIVE, suit=HEARTS], Card[rank=TEN, suit=CLUBS], Card[rank=QUEEN, suit=CLUBS]]
+[Card[rank=FIVE, suit=SPADES], Card[rank=NINE, suit=SPADES], Card[rank=QUEEN, suit=SPADES], Card[rank=THREE, suit=DIAMONDS], Card[rank=TWO, suit=CLUBS]]
+[Card[rank=EIGHT, suit=SPADES], Card[rank=TWO, suit=DIAMONDS], Card[rank=EIGHT, suit=DIAMONDS], Card[rank=KING, suit=HEARTS], Card[rank=FIVE, suit=CLUBS]]
+[Card[rank=SIX, suit=SPADES], Card[rank=KING, suit=DIAMONDS], Card[rank=THREE, suit=HEARTS], Card[rank=TEN, suit=HEARTS], Card[rank=QUEEN, suit=HEARTS]]
+</pre>
+<p>We can do a similar example with the built-in JDK collections and make some additional tweaks for nicer output:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">enum </span>Rank {<br>    <span style="color:#9876aa;font-style:italic;">ACE</span>, <span style="color:#9876aa;font-style:italic;">TWO</span>, <span style="color:#9876aa;font-style:italic;">THREE</span>, <span style="color:#9876aa;font- [...]
+<p>Which has this output:</p>
+<p><img style="width:50%" src="https://blogs.apache.org/groovy/mediaresource/f519b2c3-c303-429e-b34e-97e6eac94253" alt="Cards3.png"><br></p>
+<p>Both these Groovy examples run on JDK versions from 8 to 19<br>(emulated records are used in JDK versions 8 to 15).</p><p><b>Updated 25/Sep/2022</b>: Use same ordering for the JDK collections version.</p>
diff --git a/site/src/site/blog/deep-learning-and-eclipse-collections.md b/site/src/site/blog/deep-learning-and-eclipse-collections.md
new file mode 100644
index 0000000..1fbbcf8
--- /dev/null
+++ b/site/src/site/blog/deep-learning-and-eclipse-collections.md
@@ -0,0 +1,57 @@
+---
+layout: post
+title: Deep Learning and Eclipse Collections
+date: '2022-10-11T10:41:58+00:00'
+permalink: deep-learning-and-eclipse-collections
+---
+<h2>DeepLearning4J and Eclipse Collections revisited</h2>
+
+<p>In previous blogs, we have covered <a href="https://blogs.apache.org/groovy/entry/deck-of-cards-with-groovy" target="_blank">Eclipse Collections</a> and <a href="https://blogs.apache.org/groovy/entry/detecting-objects-with-groovy-the" target="_blank">Deep Learning</a>. Recently, a couple of the highly recommended katas for Eclipse Collections have been revamped to include "pet" and "fruit" emojis for a little bit of extra fun. What could be better than <i>Learning</i> Eclipse Collecti [...]
+<pre><span style="color:#dd4444">
+[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
+...
+[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Blas vendor: [OPENBLAS]
+...
+============================================================================================================================================
+VertexName (VertexType)                 nIn,nOut       TotalParams    ParamsShape                    Vertex Inputs
+============================================================================================================================================
+input_1 (InputVertex)                   -,-            -              -                              -
+block1_conv1 (Frozen ConvolutionLayer)  3,64           1792           b:{1,64}, W:{64,3,3,3}         [input_1]
+block1_conv2 (Frozen ConvolutionLayer)  64,64          36928          b:{1,64}, W:{64,64,3,3}        [block1_conv1]
+block1_pool (Frozen SubsamplingLayer)   -,-            0              -                              [block1_conv2]
+block2_conv1 (Frozen ConvolutionLayer)  64,128         73856          b:{1,128}, W:{128,64,3,3}      [block1_pool]
+block2_conv2 (Frozen ConvolutionLayer)  128,128        147584         b:{1,128}, W:{128,128,3,3}     [block2_conv1]
+block2_pool (Frozen SubsamplingLayer)   -,-            0              -                              [block2_conv2]
+block3_conv1 (Frozen ConvolutionLayer)  128,256        295168         b:{1,256}, W:{256,128,3,3}     [block2_pool]
+block3_conv2 (Frozen ConvolutionLayer)  256,256        590080         b:{1,256}, W:{256,256,3,3}     [block3_conv1]
+block3_conv3 (Frozen ConvolutionLayer)  256,256        590080         b:{1,256}, W:{256,256,3,3}     [block3_conv2]
+block3_pool (Frozen SubsamplingLayer)   -,-            0              -                              [block3_conv3]
+block4_conv1 (Frozen ConvolutionLayer)  256,512        1180160        b:{1,512}, W:{512,256,3,3}     [block3_pool]
+block4_conv2 (Frozen ConvolutionLayer)  512,512        2359808        b:{1,512}, W:{512,512,3,3}     [block4_conv1]
+block4_conv3 (Frozen ConvolutionLayer)  512,512        2359808        b:{1,512}, W:{512,512,3,3}     [block4_conv2]
+block4_pool (Frozen SubsamplingLayer)   -,-            0              -                              [block4_conv3]
+block5_conv1 (Frozen ConvolutionLayer)  512,512        2359808        b:{1,512}, W:{512,512,3,3}     [block4_pool]
+block5_conv2 (Frozen ConvolutionLayer)  512,512        2359808        b:{1,512}, W:{512,512,3,3}     [block5_conv1]
+block5_conv3 (Frozen ConvolutionLayer)  512,512        2359808        b:{1,512}, W:{512,512,3,3}     [block5_conv2]
+block5_pool (Frozen SubsamplingLayer)   -,-            0              -                              [block5_conv3]
+flatten (PreprocessorVertex)            -,-            -              -                              [block5_pool]
+fc1 (Frozen DenseLayer)                 25088,4096     102764544      b:{1,4096}, W:{25088,4096}     [flatten]
+fc2 (Frozen DenseLayer)                 4096,4096      16781312       b:{1,4096}, W:{4096,4096}      [fc1]
+predictions (OutputLayer)               4096,2         8194           b:{1,2}, W:{4096,2}            [fc2]
+--------------------------------------------------------------------------------------------------------------------------------------------
+            Total Parameters:  134268738
+        Trainable Parameters:  8194
+           Frozen Parameters:  134260544
+============================================================================================================================================
+...</span>
+Tabby is a cat
+Dolly is a cat
+Spot is a dog
+Spike is a dog
+Serpy is a cat
+Tweety is unknown
+Speedy is a dog
+Fuzzy is unknown
+Wuzzy is unknown
+</pre>
+<p>As we can see, it correctly predicted the cats (Tabby and Dolly) and dogs (Spot and Spike) but incorrectly thought a snake (Serpy) was a cat and a turtle (Speedy) was a dog. Given the lack of detail in the emoji images compared to the training images, this lack of accuracy isn't unexpected. We could certainly use better images or train our model differently if we wanted better results but it is fun to see our model not doing too badly even with emojis!</p>
diff --git a/site/src/site/blog/detecting-objects-with-groovy-the.md b/site/src/site/blog/detecting-objects-with-groovy-the.md
new file mode 100644
index 0000000..0d9c6a9
--- /dev/null
+++ b/site/src/site/blog/detecting-objects-with-groovy-the.md
@@ -0,0 +1,43 @@
+---
+layout: post
+title: Detecting objects with Groovy, the Deep Java Library (DJL), and Apache MXNet
+date: '2022-08-01T11:52:26+00:00'
+permalink: detecting-objects-with-groovy-the
+---
+<p>This blog posts looks at using <a href="https://groovy-lang.org/" target="_blank">Apache Groovy</a> with the <a href="https://djl.ai/" target="_blank">Deep Java Library (DJL)</a> and backed by the <a href="https://mxnet.incubator.apache.org/" target="_blank">Apache MXNet</a> engine to detect objects within an image. (Apache MXNet is an <a href="https://incubator.apache.org/" target="_blank">incubating project</a> at <a href="https://www.apache.org/" target="_blank">the ASF</a>.)</p>
+
+<h3>Deep Learning</h3>
+
+<p>Deep learning falls under the branches of <a href="https://en.wikipedia.org/wiki/Machine_learning" target="_blank">machine learning</a> and <a href="https://en.wikipedia.org/wiki/Artificial_intelligence" target="_blank">artificial intelligence</a>. It involves multiple layers (hence the "deep") of an <a href="https://en.wikipedia.org/wiki/Artificial_neural_network" target="_blank">artificial neural network</a>. There are lots of ways to configure such networks and the details are beyo [...]
+<p><a href="https://blogs.apache.org/groovy/mediaresource/2206eccb-0c50-4091-a030-e3057517d810"><img src="https://blogs.apache.org/groovy/mediaresource/2206eccb-0c50-4091-a030-e3057517d810" style="width: 50%;" alt="deep_network.png"></a></p>
+<p>Each node in this network mimics to some degree a neuron in the human brain. Again, we'll simplify the details. Each node has multiple inputs, which are given a particular weight, as well as an activation function which will determine whether our node "fires". Training the model is a process which works out what the best weights should be.</p>
+<p><a href="https://blogs.apache.org/groovy/mediaresource/b5d32431-a273-481d-b0b5-169b0665b385"><img src="https://blogs.apache.org/groovy/mediaresource/b5d32431-a273-481d-b0b5-169b0665b385" style="width: 50%;" alt="deep_node.png"></a></p>
+
+<h3>Deep Java Library (DJL) &amp; Apache MXNet</h3>
+
+<p>Rather than writing your own neural networks, libraries such as <a href="https://djl.ai/" target="_blank">DJL</a> provide high-level abstractions which automate to some degree the creation of the necessary neural network layers. DJL is engine agnostic, so it's capable of supporting different backends including Apache MXNet, PyTorch, TensorFlow and ONNX Runtime. We'll use the default engine which for our application (at the time of writing) is Apache MXNet.</p><p><a href="https://mxnet [...]
+<h3>Using DJL with Groovy</h3>
+<p>Groovy uses the Java binding. Consider looking at the DJL beginner tutorials for Java - they will work almost unchanged for Groovy.</p><p>For our example, the first thing we need to do is download the image we want to run the object detection model on:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">Path tempDir = Files.<span style="color:#9876aa;font-style:italic;">createTempDirectory</span>(<span style="color:#6a8759;">" [...]
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>detection = criteria.loadModel().withCloseable <span style="font-weight:bold;">{ </span>model <span style="font-weight:bold;">-&gt;<br></span><span style="font-weight:bold;">    </span>model.newPredictor().predict(img)<br><span style="font-weight:bold;">}<br></span>detection.items().each <span style="font-weight:bold;">{ </span>println it <sp [...]
+
+<p>Our code is stored on a source file called <code>ObjectDetect.groovy</code>.</p><p>We used <a href="https://gradle.org/" target="_blank">Gradle</a> for our build file:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">apply <span style="color:#6a8759;">plugin</span>: <span style="color:#6a8759;">'groovy'<br></span>apply <span style="color:#6a8759;">plugin</span>: <span style="color:#6a8759;">'application'<br></span><span sty [...]
+
+<p>We run the application with the gradle run task:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;"><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/groovy-data-science</b></span>$ ./gradlew DLMXNet:run
+<b>&gt; Task :DeepLearningMxnet:run</b>
+Downloading: 100% |████████████████████████████████████████| dog-ssd.jpg
+Loading:     100% |████████████████████████████████████████|
+...
+class: "car", probability: 0.99991, bounds: [x=0.611, y=0.137, width=0.293, height=0.160]
+class: "bicycle", probability: 0.95385, bounds: [x=0.162, y=0.207, width=0.594, height=0.588]
+class: "dog", probability: 0.93752, bounds: [x=0.168, y=0.350, width=0.274, height=0.593]
+</pre>
+
+<p>The displayed image looks like this:<br><img src="https://blogs.apache.org/groovy/mediaresource/b92cafbe-1866-4335-9c91-c3371253887e" style="width:50%;" alt="2022-08-01 21_28_33-3 detected objects.png"><br></p>
+
+<h3>Further Information</h3><p>The full source code can be found in the following repo:<br><a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/DeepLearningMxnet" target="_blank">https://github.com/paulk-asert/groovy-data-science/subprojects/DeepLearningMxnet</a><a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/DeepLearningMxnet" target="_blank"></a><br></p>
+
+<h3>Conclusion</h3>
+
+<p>We have examined using Apache Groovy, DLJ and Apache MXNet to detect objects within an image. We've used a model based on a rich deep learning model but we didn't need to get into the details of the model or its neural network layers. DLJ and Apache MXNet did the hard lifting for us. Groovy provided a simple coding experience for building our application.</p>
diff --git a/site/src/site/blog/encryption-and-decryption-with-groovy.md b/site/src/site/blog/encryption-and-decryption-with-groovy.md
new file mode 100644
index 0000000..13ec168
--- /dev/null
+++ b/site/src/site/blog/encryption-and-decryption-with-groovy.md
@@ -0,0 +1,51 @@
+---
+layout: post
+title: Encryption and decryption with Groovy
+date: '2022-09-19T14:34:39+00:00'
+permalink: encryption-and-decryption-with-groovy
+---
+<p>Inspired by this <a href="https://asyncq.com/how-to-encrypt-and-decrypt-data-in-java" target="_blank">recent blog entry</a>, here is an example showing how to encrypt and decrypt with Groovy.</p>
+
+<h3>Using the JDK crypto classes</h3>
+
+<p>First, we need some text to encrypt. We'll use an excerpt of the one from the aforementioned blog post:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>text = <span style="color:#6a8759;">'Contrary to popular belief, Lorem Ipsum is not simply random text.</span><span style="color:#cc7832;">\<br></span><span style="color:#6a8759;"> It has roots in a piece of classical Latin literature [...]
+<p>Which has this output:</p>
+<pre>Encrypted bytes : [-117, 36, 18, 69, -101, -8, 35, 93, -102, -49, -12, ..., -19, -100]
+Encrypted text : ‹$E›ø#]šÏôæ”Á˜çp^µ³=L(Ö^_ŒC&gt;CIË„ö,1É8ÆŸ.Š?vßG,Èw‰å¼zÜf&gt;?µ›D¹éÆk€	°˜2êÔ}í©àhl$&gt;?¹¡Kå3ÔO?±&amp;…êî¶Ê–¾°®q®à—0ú‘ÔhO&lt;H¦ç®Ç”ÈhAëjó QPyƒy6Ĥ*´un¼ï¯m¨´ÙjeJtëº\ó6ƪKªœíœ
+Decrypted bytes : [67, 111, 110, 116, 114, 97, 114, 121, 32, 116, 111, 32, ..., 100, 46]
+Decrypted text : Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.
+</pre>
+<p>We can see that everything worked as expected, since the final output matches our original input text.</p>
+
+<h3>Using the Bouncy Castle library</h3>
+
+<p>We can alternatively, swap algorithms. There are numerous <a href="https://docs.oracle.com/en/java/javase/11/docs/api/java.base/javax/crypto/Cipher.html" target="_blank">algorithms and modes supported</a> by the JDK and others supported by third-party libraries. A nice summary can be found <a href="https://en.wikipedia.org/wiki/Comparison_of_cryptography_libraries" target="_blank">here</a>.</p>
+<p>We'll swap to use the CAST5 (<a href="https://en.wikipedia.org/wiki/CAST-128" target="_blank">CAST-128</a>) algorithm which supports up to a 128-bit key. We'll use <a href="https://en.wikipedia.org/w/index.php?title=HMAC-SHA1" target="_blank">HMAC-SHA1</a> to generate our key.</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">import </span>org.bouncycastle.jce.provider.BouncyCastleProvider<br><sp [...]
+<p>Which has this output:</p>
+<pre>Encrypted text : Mªá?r?v9£÷~4µT'›ÙÝÁl¿Þg¾0ñŽ¡?Ü=³9Q¬»3«ÖÁ¡µ ¾@4÷`FñÙŠfø7¥#›v¤Í–‰¼Ü¢ƒE6ôŽTÙlæÏz&gt;o?àL›¡¢z1nÖo9]šOÔ¼SÔOÍ#Ý7LœÀî}ó5m%q•»l%/AWT´¢zH#t솱l¶£—Œ«©wˆÃ®&gt;®Ü6ër-E
+Decrypted text : Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old.
+</pre>
+
+<h3>Other useful functionality</h3>
+<p>Passing around binary data like our secret key or the encrypted data, has its own problems. Groovy provides extension methods to encode such data (and corresponding decode methods). For example, we can encode our secret key in various ways:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>keyBytes = key.<span style="color:#9876aa;">encoded<br></span>println keyBytes.encodeHex()<br>pri [...]
+
+<pre>85a0d3f0ce0cbe6402dc9579fbffcf1d
+haDT8M4MvmQC3JV5+//PHQ==
+haDT8M4MvmQC3JV5-__PHQ
+</pre>
+
+<p>Groovy also provides extension methods for various checksums (but you might want to look at stronger checksum algorithms in security sensitive scenarios):</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="color:#6a8759;">"SHA256 : </span>$<span style="font-weight:bold;">{</span>text.sha256()<span style="font-weight:bold;">}</span><span style="color:#6a8759;">"<br></span>println <span style="color:#6a8759 [...]
+
+<pre>SHA256 : ccb184e35e4c32bafc730d84ec924ea2980035ea5fadb012e3b2b31abf4323c9
+MD5 : 46c61a174c2dc99204521ca89f09f63c
+</pre>
+<p>If you are encrypting and decrypting entire files, the JDK has <a href="https://www.baeldung.com/java-cipher-input-output-stream" target="_blank">special classes for that too</a> which are also easy to use from Groovy. That's all for now.</p>
+
+<h3>References</h3>
+
+<ul><li><a href="https://en.wikipedia.org/wiki/Comparison_of_cryptography_libraries" target="_blank">Comparison of cryptography libraries</a>&nbsp;(Wikipedia)</li><li><a href="https://asyncq.com/how-to-encrypt-and-decrypt-data-in-java" target="_blank">How to encrypt and decrypt data in java</a>&nbsp;(also on <a href="https://i-sammy.medium.com/how-to-encrypt-and-decrypt-data-in-java-de41be237422" target="_blank">medium.com</a>)</li><li><a href="https://mvnrepository.com/artifact/org.boun [...]
+
+
+<h3>Conclusion</h3>
+
+<p>We have taken a brief look at encrypting and decrypting with Apache Groovy.</p>
diff --git a/site/src/site/blog/fruity-eclipse-collections.md b/site/src/site/blog/fruity-eclipse-collections.md
new file mode 100644
index 0000000..2c2c24b
--- /dev/null
+++ b/site/src/site/blog/fruity-eclipse-collections.md
@@ -0,0 +1,48 @@
+---
+layout: post
+title: Fruity Eclipse Collections
+date: '2022-10-13T11:05:54+00:00'
+permalink: fruity-eclipse-collections
+---
+<p>This blog post continues on to some degree from the <a href="https://blogs.apache.org/roller-ui/authoring/entryEdit.rol?weblog=groovy&amp;bean.id=f948dba2-e4a8-40b1-80b7-3de48b36520a" target="_blank">previous post</a>, but instead of deep learning, we'll look at clustering using k-means after first exploring some top methods of <a href="https://www.eclipse.org/collections/" target="_blank">Eclipse Collections</a> with fruit emoji examples.</p>
+
+<h2>Eclipse Collections Fruit Salad</h2>
+
+<p>First, we'll define a Fruit enum (it adds one additional fruit compared to the related <a href="https://github.com/eclipse/eclipse-collections-kata/tree/master/top-methods-kata-solutions" target="_blank">Eclipse Collections kata</a>):</p><p><img src="https://blogs.apache.org/groovy/mediaresource/8d0d5468-f58a-445a-8e79-854c7815d861" style="width:100%" alt="code for fruit enum"></p><p>We can use this enum in the following examples:</p><p><img src="https://blogs.apache.org/groovy/mediar [...]
+
+<h2>Exploring emoji colors</h2>
+
+<p>For some fun, let's look at whether the nominated color of each fruit matches the color of the related emoji. As in the previous blog, we'll use the slightly nicer&nbsp;<a href="https://fonts.google.com/noto/specimen/Noto+Color+Emoji?preview.text=%F0%9F%8D%8E%F0%9F%8D%91%F0%9F%8D%8C%F0%9F%8D%92%F0%9F%8D%8A%F0%9F%8D%87&amp;preview.text_type=custom">Noto Color Emoji</a><span style="color: rgb(51, 51, 51); font-size: 15.4px;"> fonts for our fruit as shown here:</span></p><p><img src="htt [...]
+
+<h3>Most Common Color</h3>
+
+<p>Ignoring the background white color, the most common color for our PEACH emoji is a shade of orange. The graph below shows the count of each color:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/b9f82465-62e2-45c0-926f-634568381be8" style="width:75%" alt="2022-10-17 15_57_40-Color histogram for PEACH.png"></p>
+
+<h3>Most Common Range</h3>
+
+<p>If instead of counting each color, we group colors into their range and count the numbers in each range, we get the following graph for PEACH:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/4ce2ac0e-87ac-4509-9fa8-10928419f4a0" style="width:75%" alt="2022-10-17 15_56_58-Range histogram for PEACH.png"></p><p><br></p>
+
+<h3>K-Means</h3>
+
+<p>K-Means is an algorithm for finding cluster centroids. For k=3, we would start by picking
+3 random points as our starting centroids.</p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/6192d3b7-a3c7-4ce5-b0c0-a3286619dd12" style="width:70%" alt="kmeans_step1.png"></p>
+<p>We allocate all points to their closest centroid:</p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/751eaac0-5ba2-448d-8f67-6ebf53613ac9" style="width:70%" alt="kmeans_step2.png"></p>
+<p>Given this allocation, we re-calculate each centroid from all of its points:</p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/daa9530e-fc5d-458d-8029-a1fd8a62d521" style="width:70%" alt="kmeans_step3.png"></p>
+<p>We repeat this process until either a stable centroid selection is found, or we have reached a certain number of iterations.</p>
+<p>We used the K-Means algorithm from <a href="https://commons.apache.org/proper/commons-math/userguide/ml.html#clustering" target="_blank">Apache Commons Math</a>.</p><p>Here is the kind of result we would expect if run on the complete set of points for the PEACH emoji. The black dots are the centroids. It has found one green, one orange and one red centroid. The centroid with the most points allocated to it should be the most predominant color. (This is another interactive 3D scatterpl [...]
+<p></p>
+
+<h3>K-Means with subimages</h3><p>The approach we will take for our third option enhances K-Means. Instead of finding centroids for the whole image as the graphs just shown do, we divide the image into subimages and perform the K-Means on each subimage. Our overall pre-dominant color is determined to be the most common color predicated across all of our subimages.</p><h3>Putting it all together</h3>
+
+<p><span style="color: rgb(51, 51, 51); font-size: 15.4px;">Here is the final code covering all three approaches (including printing some pretty images highlighting the third approach and the Plotly 3D scatter plots):</span></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>results = Fruit.<span style="color:#9876aa;font-style:italic;">ALL</span>.collect { fruit -&gt;<br>    <span style=" [...]
+<p>Here are the resulting images:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/442d7100-5023-43ce-a525-0db682fc7b60" alt="2022-10-13 20_37_25-Original.png"></p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/1fc50ff2-7881-4bd3-a8c7-a6283222d91d" alt="2022-10-13 20_37_08-Original.png"></p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/6b35338d-be4b-40a4-81dc-e317a68fbb1e" alt="2022-10-13 20_36_49-Original.png"></p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/d3ff8625-d429-4c7c-bfcd-531df53a8256" alt="2022-10-13 20_36_27-Original.png"></p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/1f1b755a-7dcf-4c53-b930-07c3ef8f0a2f" alt="2022-10-13 20_36_07-Original.png"></p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/d166e557-2ba2-4058-9bde-fb8b682d4c4b" alt="2022-10-13 20_35_21-Original.png"></p>
+<p>And, here are the final results:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/78b1f289-2200-4750-a923-69ac01dc12d2" style="width:70%" alt="final results"></p><p>In our case, all three approaches yielded the same results. Results for other emojis may vary.</p><h3>Further information</h3><ul><li>Repo with example code:&nbsp;<a href="https://github.com/paulk-asert/fruity-eclipse-collections" target="_blank">https://github.com/paulk-asert/fruity-eclipse-collections</a><a  [...]
diff --git a/site/src/site/blog/fun-with-obfuscated-groovy.md b/site/src/site/blog/fun-with-obfuscated-groovy.md
new file mode 100644
index 0000000..21f6166
--- /dev/null
+++ b/site/src/site/blog/fun-with-obfuscated-groovy.md
@@ -0,0 +1,31 @@
+---
+layout: post
+title: Fun with obfuscated Groovy
+date: '2022-12-08T00:40:23+00:00'
+permalink: fun-with-obfuscated-groovy
+---
+<p>An interesting tweet appeared in my feed this morning:</p><p><img style="width:80%" src="https://blogs.apache.org/groovy/mediaresource/e3a9547d-2715-4f93-96eb-f5a7ad75fb85" alt="ObfuscatedJava@joshbloch.png"></p><p><br></p><p>And of course it prints the same thing in Groovy:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">char </span>p(<span style="color:#cc7832;">int </span>i) {<br>    (<span style="color:#cc7832;">char</span>) (<span style="color:#6897bb;">72.5<br></span><span style="color:#6897bb;">    </span>+ i * (<span style="color:#6897bb;">17488.589319014318<br></span><span style="color:#6897bb;">    </span>+ i * (-<span style="color:#6897bb;">54923.96120078333<b [...]
+<p><b style="color: rgb(255, 0, 0);"><br></b></p><p><b style="color: rgb(255, 0, 0);">STOP</b> reading now and try it out for yourself ... or browse the <a href="https://community.oracle.com/tech/developers/discussion/1239419/java-code-obfuscation-contest" target="_blank">possible origin</a>.</p><p><br></p><p><span style="color: rgb(255, 0, 0); font-weight: bold;">SPOILER ALERT</span>&nbsp;okay, if you didn't stop, I guess it's still okay to scroll down to see what it prints out and how  [...]
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↓</p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↓</p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;↓</p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p><br></p>
+<p>Let's Groovify the <a href="https://twitter.com/nikialeksey/status/1600598026678149120" target="_blank">reply</a> from <a href="https://twitter.com/nikialeksey" target="_blank">Alexey Nikitin</a>&nbsp;which uses&nbsp;<a href="https://commons.apache.org/proper/commons-math/" target="_blank" style="background-color: rgb(255, 255, 255);">Apache Commons Math</a>&nbsp;to replicate the problem:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#bbb529;">@Grab</span>(<span style="color:#6a8759;">'org.apache.commons:commons-math3:3.6.1'</span>)<br><span style="color:#cc7832;">import </span>org.apache.commons.math3.analysis.interpolation.NevilleInterpolator<br><br><span style="color:#cc7832;">var </span>text = <span style="color:#6a8759;">'Hello, world!</span><span style="color:#cc7832;">\n</span><span st [...]
+<p>This generates the script, prints it out, and then runs it to make sure it produces what we intended. It only differs from above in that instead of printing out each character, it builds up and returns a String so that we can assert our expectations. It was simpler than capturing stdout by other means.</p><p>Enjoy!</p>
diff --git a/site/src/site/blog/gmavenplus-1-6-2-released.md b/site/src/site/blog/gmavenplus-1-6-2-released.md
new file mode 100644
index 0000000..3d6374a
--- /dev/null
+++ b/site/src/site/blog/gmavenplus-1-6-2-released.md
@@ -0,0 +1,11 @@
+---
+layout: post
+title: GMavenPlus 1.6.2 Released (Community Artifact)
+date: '2018-10-14T22:00:45+00:00'
+permalink: gmavenplus-1-6-2-released
+---
+GMavenPlus 1.6.2 has been released.
+
+GMavenPlus Plugin is a rewrite of <a href="https://github.com/groovy/gmaven">GMaven</a>, a <a href="http://maven.apache.org/">Maven</a> plugin that allows you to integrate <a href="http://groovy-lang.org/">Groovy</a> into your Maven projects.
+Basic usage can be found on the <a href="https://github.com/groovy/GMavenPlus/wiki/Usage">usage</a> page, with additional usages on the <a href="https://github.com/groovy/GMavenPlus/wiki/Examples">examples</a> page. For more information, consult the <a href="https://github.com/groovy/GMavenPlus/wiki">wiki</a>.
+
diff --git a/site/src/site/blog/gpars-meets-virtual-threads.md b/site/src/site/blog/gpars-meets-virtual-threads.md
new file mode 100644
index 0000000..fdc7047
--- /dev/null
+++ b/site/src/site/blog/gpars-meets-virtual-threads.md
@@ -0,0 +1,44 @@
+---
+layout: post
+title: GPars meets Virtual Threads
+date: '2022-06-15T11:28:56+00:00'
+permalink: gpars-meets-virtual-threads
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/52d821d8-f108-48e6-805d-f8fdd514f9ca" style="width: 20%;" align="right" alt="gpars-rgb.png">An exciting preview feature coming in JDK19 is Virtual Threads (<a href="https://openjdk.java.net/jeps/425" target="_blank">JEP 425</a>). In my experiments so far, virtual threads work well with my favourite Groovy parallel and concurrency library <a href="http://gpars.org/" target="_blank">GPars</a>. GPars has been around a while (since J [...]
+
+<h3>Parallel Collections</h3>
+
+<p>First a refresher, to use the GPars parallel collections feature with normal threads, use the
+<span style="background-color: #FFFFFF; color: rgb(8, 8, 8); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 14px;> GParsPool.<span style=" font-style="italic;&quot;">withPool</span> method as follows:
+</p>
+
+<pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="font-style:italic;">withPool </span><span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#0033b3;">assert </span>[<span style="color:#1750eb;">1</span>, <span style="color:#1750eb;">2</span>, <span style="color:#1750eb;">3</span>].collectParallel<span style="font-weight:bold;">{ </span>it ** <span style="color:#1750eb;">2 </span><span style= [...]
+}</pre>
+
+<p>For any Java readers, don't get confused with the <span style="font-family:'JetBrains Mono',monospace;font-size: 14px; color: rgb(8, 8, 8);">collectParallel</span> method name. Groovy's <span style="font-family:'JetBrains Mono',monospace;font-size: 14px; color: rgb(8, 8, 8);">collect</span> method (naming inspired by Smalltalk) is the equivalent of Java's <span style="font-family:'JetBrains Mono',monospace;font-size: 14px; color: rgb(8, 8, 8);">map</span> method. So, the equivalent Gr [...]
+
+</p><pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">assert </span>[<span style="color:#1750eb;">1</span>, <span style="color:#1750eb;">2</span>, <span style="color:#1750eb;">3</span>].parallelStream().map(n -&gt; n ** <span style="color:#1750eb;">2</span>).collect(<span style="color:#000000;">Collectors</span>.<span style="font-style:italic;">toList</span>()) == [<span style="color:#1750eb;">1</span>, <span style="color:#175 [...]
+
+<p>Now, let's bring virtual threads into the picture. Luckily, GPars parallel collection facilities provide a hook for using an <i>existing </i>custom executor service. This makes using virtual threads for such code easy:</p><pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="font-style:italic;">withExistingPool</span>(<span style="color:#000000;">Executors</span>.newVirtualThreadPerTaskExecutor()) <span style="font-weight:bold;">{<br></span><s [...]
+<p>Nice! But let's move onto some areas examples which might be less familiar to Java developers.</p><p>GPars has additional features for providing custom thread pools and the remaining examples rely on those features. The current version of GPars doesn't have a&nbsp;<span style="font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt;">DefaultPool&nbsp;</span>constructor that takes a vanilla executor service, so, we'll write our own class:</p><pre style="color:#080808;font- [...]
+
+<h3>Agents</h3>
+<p>Agents provide a thread-safe non-blocking wrapper around an otherwise potentially mutable shared state object. They are inspired by agents in Clojure.</p><p>In our case we'll use an agent to "protect" a plain&nbsp;<span style="font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt;">ArrayList</span>. For this simple case, we could have used some synchronized list, but in general, agents eliminate the need to find thread-safe implementation classes or indeed care at all a [...]
+<pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">def </span><span style="color:#000000;">mutableState </span>= []     <span style="color:#8c8c8c;font-style:italic;">// a non-synchronized mutable list<br></span><span style="color:#0033b3;">def </span><span style="color:#000000;">agent </span>= <span style="color:#0033b3;">new </span><span style="color:#000000;">Agent</span>(<span style="color:#000000;">mutableState</span>)<br> [...]
+
+<h3>Actors</h3>
+<p>Actors allow for a message passing-based concurrency model. The actor model ensures that at most one thread processes the actor's body at any time. The GPars API and DSLs for actors are quite rich supporting many features. We'll look at a simple example here.</p><p>GPars manages actor thread pools in groups. Let's create one backed by virtual threads:</p>
+<pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">def </span><span style="color:#000000;">vgroup </span>= <span style="color:#0033b3;">new </span><span style="color:#000000;">DefaultPGroup</span>(<span style="color:#0033b3;">new </span><span style="color:#000000;">VirtualPool</span>())
+</pre>
+<p>Now we can write an encrypting and decrypting actor pair as follows:</p>
+<pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">def </span><span style="color:#000000;">decryptor </span>= <span style="color:#000000;">vgroup</span>.actor <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>loop <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">        </span>react <span style="font-weight:bold;">{ </span><span style="color:#000000;">String </span [...]
+<h3>Dataflow</h3>
+<p style="">Dataflow&nbsp;offers an inherently safe and robust declarative concurrency model. Dataflows are also managed via thread groups, so we'll use&nbsp;<span style="font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 14px;">vgroup</span>&nbsp;which we created earlier.</p><p style="">We have three logical tasks which can run in parallel and perform their work. The tasks need to exchange data and they do so using <i>dataflow variables</i>. Think of dataflow variables as on [...]
+<pre style="color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">def </span><span style="color:#000000;">df </span>= <span style="color:#0033b3;">new </span><span style="color:#000000;">Dataflows</span>()<br><br><span style="color:#000000;">vgroup</span>.task <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#000000;">df</span>.z = <span style="color:#000000;">df</span>.x + <span style= [...]
+<p>The dataflow framework works out how to schedule the individual tasks and ensures that
+a task's input variables are ready when needed.</p>
+<h3>Conclusion</h3>
+<p>We have had a quick glimpse at using virtual threads with Groovy and GPars.
+It is very early days, so expect much more to emerge in this space once virtual
+threads are released in preview in production versions of JDK19 and eventually beyond a preview feature.
+</p>
diff --git a/site/src/site/blog/groovy-2-4-16-released.md b/site/src/site/blog/groovy-2-4-16-released.md
new file mode 100644
index 0000000..b7bd98d
--- /dev/null
+++ b/site/src/site/blog/groovy-2-4-16-released.md
@@ -0,0 +1,9 @@
+---
+layout: post
+title: Groovy 2.4.16 Released
+date: '2018-12-18T22:04:41+00:00'
+permalink: groovy-2-4-16-released
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 2.4.16 of Apache Groovy.</span><br style="color: #22 [...]
+  <div class="yj6qo" style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"></div> 
+  <div><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></span></div>
diff --git a/site/src/site/blog/groovy-2-4-16-windows.md b/site/src/site/blog/groovy-2-4-16-windows.md
new file mode 100644
index 0000000..1ad86c5
--- /dev/null
+++ b/site/src/site/blog/groovy-2-4-16-windows.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.4.16 Windows Installer Released (Community Artifact)
+date: '2018-12-18T22:06:49+00:00'
+permalink: groovy-2-4-16-windows
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The&nbsp;</span><span class="m_7668295082065290147gmail-m_8396036641248403423gmail-m_-1956765625531232616gmail-m_7427032002885253719gmail-il" style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Windows</span><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"> </span><span class="m_7668295082065290147gmail-m_8396036641248403423 [...]
diff --git a/site/src/site/blog/groovy-2-4-17-released.md b/site/src/site/blog/groovy-2-4-17-released.md
new file mode 100644
index 0000000..a614dcf
--- /dev/null
+++ b/site/src/site/blog/groovy-2-4-17-released.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.4.17 Released
+date: '2019-05-12T22:32:57+00:00'
+permalink: groovy-2-4-17-released
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 2.4.17 of Apache Groovy.</span><br style="color: #22 [...]
diff --git a/site/src/site/blog/groovy-2-5-1-released.md b/site/src/site/blog/groovy-2-5-1-released.md
new file mode 100644
index 0000000..8cf02b6
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-1-released.md
@@ -0,0 +1,60 @@
+---
+layout: post
+title: Groovy 2.5.1 released
+date: '2018-07-14T02:18:31+00:00'
+permalink: groovy-2-5-1-released
+---
+<a href="http://groovy-lang.org/index.html"><img src="https://blogs.apache.org/groovy/mediaresource/58a149c0-e332-40dd-b450-59ffe0c96b74?t=true" alt="groovy-logo.png"></img></a>
+
+<p>
+Dear community,
+</p><p>
+
+The Apache Groovy team is pleased to announce version 2.5.1 of Apache Groovy.
+Apache Groovy is a multi-faceted programming language for the JVM.
+Further details can be found at the <a href="http://groovy.apache.org/">http://groovy.apache.org</a> website.
+</p><p>
+
+For this release we focused on fixing up some of the usability/packaging issues
+that the 2.5.0 release introduced as part of supporting Groovy across
+JDKs 7 through (soon) 11. Maven/Gradle users not needing JAXB should
+now have a much improved experience building with the new version.
+(SUREFIRE users should read the release notes about some caveats).
+In 2.5.2, we should have additional changes to improve the build
+experience even further
+for JAXB users and users of the Groovy command-line tools. Please read
+the release
+notes for further information:
+<a href="http://groovy-lang.org/releasenotes/groovy-2.5.html#Groovy2.5releasenotes-Addendum251">http://groovy-lang.org/releasenotes/groovy-2.5.html#Groovy2.5releasenotes-Addendum251</a>
+</p><p>
+
+This release is a maintenance release of the GROOVY_2_5_X branch.
+It is strongly encouraged that all users using prior
+versions on this branch upgrade to this version.
+</p><p>
+
+This release includes 44 bug fixes/improvements as outlined in the changelog:
+<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343365">https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343365</a>
+</p><p>
+
+Sources, convenience binaries, downloadable documentation and an SDK
+bundle can be found at: <a href="http://www.groovy-lang.org/download.html">http://www.groovy-lang.org/download.html</a>
+We recommend you verify your installation using the information on that page.
+</p><p>
+
+Jars are also available within the major binary repositories.
+</p><p>
+
+We welcome your help and feedback and in particular want
+to thank everyone who contributed to this release.
+</p><p>
+
+For more information on how to report problems, and to get involved,
+visit the project website at <a href="https://groovy.apache.org/">https://groovy.apache.org/</a>
+</p><p>
+
+Best regards,
+</p><p>
+
+The Apache Groovy team.
+</p>
diff --git a/site/src/site/blog/groovy-2-5-2-released.md b/site/src/site/blog/groovy-2-5-2-released.md
new file mode 100644
index 0000000..642a986
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-2-released.md
@@ -0,0 +1,51 @@
+---
+layout: post
+title: Groovy 2.5.2 released
+date: '2018-08-16T02:52:30+00:00'
+permalink: groovy-2-5-2-released
+---
+<a href="http://groovy-lang.org/index.html"><img src="https://blogs.apache.org/groovy/mediaresource/58a149c0-e332-40dd-b450-59ffe0c96b74?t=true" alt="groovy-logo.png"></img></a>
+
+<p>
+Dear community,
+</p><p>
+
+
+The Apache Groovy team is pleased to announce version 2.5.2 of Apache Groovy.
+Apache Groovy is a multi-facet programming language for the JVM.
+Further details can be found at the <a href="http://groovy.apache.org/">http://groovy.apache.org</a> website.
+</p><p>
+
+This release is a maintenance release of the GROOVY_2_5_X branch.
+It is strongly encouraged that all users using prior
+versions on this branch upgrade to this version.
+</p><p>
+
+This release includes 20 bug fixes/improvements as outlined in the changelog:
+<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343651">https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343651</a>
+Of particular note are numerous small fixes for trait edge cases and
+some important changes for running the Groovy tools on JDK10
+(particularly on macOS). Let us know if you spot any further problems.
+</p><p>
+
+Sources, convenience binaries, downloadable documentation and an SDK
+bundle can be found at: <a href="http://www.groovy-lang.org/download.html">http://www.groovy-lang.org/download.html</a>
+We recommend you verify your installation using the information on that page.
+</p><p>
+
+Jars are also available within the major binary repositories.
+</p><p>
+
+We welcome your help and feedback and in particular want
+to thank everyone who contributed to this release.
+</p><p>
+
+For more information on how to report problems, and to get involved,
+visit the project website at <a href="https://groovy.apache.org/">https://groovy.apache.org/</a>
+</p><p>
+
+Best regards,
+</p><p>
+
+The Apache Groovy team.
+</p>
diff --git a/site/src/site/blog/groovy-2-5-2-windows.md b/site/src/site/blog/groovy-2-5-2-windows.md
new file mode 100644
index 0000000..85cfd06
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-2-windows.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.5.2 Windows Installer Released (Community Artifact)
+date: '2018-08-19T09:50:27+00:00'
+permalink: groovy-2-5-2-windows
+---
+The Windows installer for Groovy 2.5.2 (community artifact) is available from: <a href="https://dl.bintray.com/groovy/Distributions/groovy-2.5.2-installer.exe">https://dl.bintray.com/groovy/Distributions/groovy-2.5.2-installer.exe</a>.
diff --git a/site/src/site/blog/groovy-2-5-3-released.md b/site/src/site/blog/groovy-2-5-3-released.md
new file mode 100644
index 0000000..53a2095
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-3-released.md
@@ -0,0 +1,48 @@
+---
+layout: post
+title: Groovy 2.5.3 Released
+date: '2018-10-14T21:43:43+00:00'
+permalink: groovy-2-5-3-released
+---
+<a href="http://groovy-lang.org/index.html"><img src="https://blogs.apache.org/groovy/mediaresource/58a149c0-e332-40dd-b450-59ffe0c96b74?t=true" alt="groovy-logo.png"></img></a>
+
+<p>
+Dear community,
+</p><p>
+
+
+The Apache Groovy team is pleased to announce version 2.5.3 of Apache Groovy.
+Apache Groovy is a multi-facet programming language for the JVM.
+Further details can be found at the <a href="http://groovy.apache.org/">http://groovy.apache.org</a> website.
+</p><p>
+
+This release is a maintenance release of the GROOVY_2_5_X branch.
+It is strongly encouraged that all users using prior
+versions on this branch upgrade to this version.
+</p><p>
+
+This release includes 50 bug fixes/improvements as outlined in the changelog:
+<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343876"> https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12343876 </a>
+</p><p>
+
+Sources, convenience binaries, downloadable documentation and an SDK
+bundle can be found at: <a href="http://www.groovy-lang.org/download.html">http://www.groovy-lang.org/download.html</a>
+We recommend you verify your installation using the information on that page.
+</p><p>
+
+Jars are also available within the major binary repositories.
+</p><p>
+
+We welcome your help and feedback and in particular want
+to thank everyone who contributed to this release.
+</p><p>
+
+For more information on how to report problems, and to get involved,
+visit the project website at <a href="https://groovy.apache.org/">https://groovy.apache.org/</a>
+</p><p>
+
+Best regards,
+</p><p>
+
+The Apache Groovy team.
+</p>
diff --git a/site/src/site/blog/groovy-2-5-3-windows.md b/site/src/site/blog/groovy-2-5-3-windows.md
new file mode 100644
index 0000000..009adb4
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-3-windows.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.5.3 Windows Installer Released (Community Artifact)
+date: '2018-10-14T21:47:48+00:00'
+permalink: groovy-2-5-3-windows
+---
+The Windows installer for Groovy 2.5.3 (community artifact) is available from: <a href="https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.3-installer">https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.3-installer</a>.
diff --git a/site/src/site/blog/groovy-2-5-4-released.md b/site/src/site/blog/groovy-2-5-4-released.md
new file mode 100644
index 0000000..f752ca6
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-4-released.md
@@ -0,0 +1,17 @@
+---
+layout: post
+title: Groovy 2.5.4 Released
+date: '2018-11-12T11:42:45+00:00'
+permalink: groovy-2-5-4-released
+---
+<a href="http://groovy-lang.org/index.html"><img src="https://blogs.apache.org/groovy/mediaresource/58a149c0-e332-40dd-b450-59ffe0c96b74?t=true" alt="groovy-logo.png" /></a> 
+  <p>Dear community,</p> 
+  <p>The Apache Groovy team is pleased to announce version 2.5.4 of Apache Groovy. Apache Groovy is a multi-facet programming language for the JVM. Further details can be found at the <a href="http://groovy.apache.org/">http://groovy.apache.org</a> website.</p> 
+  <p>This release is a maintenance release of the GROOVY_2_5_X branch. It is strongly encouraged that all users using prior versions on this branch upgrade to this version.</p> 
+  <p>This release includes 15 bug fixes/improvements as outlined in the changelog:&nbsp;<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&amp;version=12344270" rel="noreferrer" target="_blank" data-saferedirecturl="https://www.google.com/url?q=https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId%3D12318123%26version%3D12344270&amp;source=gmail&amp;ust=1542109084206000&amp;usg=AFQjCNGquYBktDLDuDpYYWrAD9vImHOUFw" style="font-size: small; color:  [...]
+  <p>Sources, convenience binaries, downloadable documentation and an SDK bundle can be found at: <a href="http://www.groovy-lang.org/download.html">http://www.groovy-lang.org/download.html</a>We recommend you verify your installation using the information on that page.</p> 
+  <p>Jars are also available within the major binary repositories.</p> 
+  <p>We welcome your help and feedback and in particular want to thank everyone who contributed to this release.</p> 
+  <p>For more information on how to report problems, and to get involved, visit the project website at <a href="https://groovy.apache.org/">https://groovy.apache.org/</a></p> 
+  <p>Best regards,</p> 
+  <p>The Apache Groovy team.</p>
diff --git a/site/src/site/blog/groovy-2-5-4-windows.md b/site/src/site/blog/groovy-2-5-4-windows.md
new file mode 100644
index 0000000..a959357
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-4-windows.md
@@ -0,0 +1,10 @@
+---
+layout: post
+title: Groovy 2.5.4 Windows Installer Released (Community Artifact)
+date: '2018-11-12T11:43:00+00:00'
+permalink: groovy-2-5-4-windows
+---
+<p> </p> 
+  <p>&nbsp;The Windows installer for Groovy 2.5.4 (community artifact) is available from: <a href="https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.4-installer" title="https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.4-installer">https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.4-installer</a>.</p> 
+  <p><br /></p> 
+  <p> </p>
diff --git a/site/src/site/blog/groovy-2-5-5-released.md b/site/src/site/blog/groovy-2-5-5-released.md
new file mode 100644
index 0000000..2322020
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-5-released.md
@@ -0,0 +1,8 @@
+---
+layout: post
+title: Groovy 2.5.5 released
+date: '2018-12-24T11:53:41+00:00'
+permalink: groovy-2-5-5-released
+---
+<p><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 2.5.5 of Apache Groovy.</span><br style="color: # [...]
+  <p><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Jars are also available within the major binary repositories.</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">We welcome your help and feedback and in particular wan [...]
diff --git a/site/src/site/blog/groovy-2-5-5-windows.md b/site/src/site/blog/groovy-2-5-5-windows.md
new file mode 100644
index 0000000..7f144bc
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-5-windows.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.5.5 Windows Installer Released (Community Artifact)
+date: '2018-12-24T22:02:33+00:00'
+permalink: groovy-2-5-5-windows
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Windows installer for Groovy 2.5.5 (community artifact) is available at:&nbsp;</span><a href="https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.5-installer" target="_blank" data-saferedirecturl="https://www.google.com/url?q=https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2.5.5-installer&amp;source=gmail&amp;ust=1545775073631000&amp;usg=AFQjCNFpY0kyRs3qyemjX [...]
diff --git a/site/src/site/blog/groovy-2-5-6-released.md b/site/src/site/blog/groovy-2-5-6-released.md
new file mode 100644
index 0000000..963dc6b
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-6-released.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.5.6 Released
+date: '2019-02-04T22:19:07+00:00'
+permalink: groovy-2-5-6-released
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 2.5.6 of Apache Groovy.</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Apache Groovy is a multi-faceted programming language for the JVM.</span><br style="color: #222222; font-family: Arial, Helvetica, sans [...]
diff --git a/site/src/site/blog/groovy-2-5-7-and.md b/site/src/site/blog/groovy-2-5-7-and.md
new file mode 100644
index 0000000..d9b8887
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-7-and.md
@@ -0,0 +1,17 @@
+---
+layout: post
+title: Groovy 2.5.7 and 3.0.0-beta-1 Windows Installers Released (Community Artifacts)
+date: '2019-05-12T22:49:16+00:00'
+permalink: groovy-2-5-7-and
+---
+<div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The&nbsp;<span class="m_3561116796173860354gmail-il">Windows</span> <span class="m_3561116796173860354gmail-m_5094819221954259979gmail-il">installer</span>&nbsp;for&nbsp;<span class="m_3561116796173860354gmail-m_5094819221954259979gmail-il">Groovy</span> <wbr />2.5.7 (Community Artifact) is now available from Bintray:&nbsp;<a href="https://bintray.com/groovy/Distributions/Windows-Installer/groovy-2. [...]
+  <div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div> 
+  <div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"> 
+    <div>The <span class="m_3561116796173860354gmail-il">Windows</span> <span class="m_3561116796173860354gmail-m_5094819221954259979gmail-il">installer</span>&nbsp;for&nbsp;<span class="m_3561116796173860354gmail-m_5094819221954259979gmail-il">Groovy</span> <wbr />3.0.0-beta-1 (Community Artifact)&nbsp;is now available from Bintray: <a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-1-installer.exe" target="_blank" data-saferedirecturl="https://w [...]
+    <div><br /></div> 
+    <div>These are also the first releases where a preview of the Windows Installers is created with the WiX Toolset.&nbsp; You are invited to try them out and provide any feedback you might have.&nbsp; The intention is to eventually replace the current NSIS-based installer with this installer.&nbsp; It is believed to be reasonably stable.&nbsp; The maintainer of these installer has personally been using these instead of the NSIS based installer for a while now.&nbsp; Here are the links  [...]
+    <div>3.0.0-beta-1: <a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-1+%28preview+installer%29.msi" target="_blank" data-saferedirecturl="https://www.google.com/url?q=https://bintray.com/groovy/Distributions/download_file?file_path%3Dgroovy-3.0.0-beta-1%2B%2528preview%2Binstaller%2529.msi&amp;source=gmail&amp;ust=1557704432712000&amp;usg=AFQjCNGZ9l55suLVqz2cgcAX2iiX5NHBLw" style="color: #1155cc;">https://bintray.com/groovy/<wbr />Distribution [...]
+    <div>2.5.7: <a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-2.5.7+%28preview+installer%29.msi" target="_blank" data-saferedirecturl="https://www.google.com/url?q=https://bintray.com/groovy/Distributions/download_file?file_path%3Dgroovy-2.5.7%2B%2528preview%2Binstaller%2529.msi&amp;source=gmail&amp;ust=1557704432712000&amp;usg=AFQjCNEhTwP4Rn2tcUyBL3EO7Mxqsn6ykg" style="color: #1155cc;">https://bintray.com/groovy/<wbr />Distributions/download_file?<wbr  [...]
+    <div><br /></div> 
+    <div>Be aware that you need to fully uninstall the NSIS based Groovy installation before installing with an MSI installer.</div> 
+  </div>
diff --git a/site/src/site/blog/groovy-2-5-7-released.md b/site/src/site/blog/groovy-2-5-7-released.md
new file mode 100644
index 0000000..bf5cc05
--- /dev/null
+++ b/site/src/site/blog/groovy-2-5-7-released.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 2.5.7 Released
+date: '2019-05-12T22:39:42+00:00'
+permalink: groovy-2-5-7-released
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 2.5.7 of Apache Groovy.</span><br style="color: #222 [...]
diff --git a/site/src/site/blog/groovy-3-0-0-alpha.md b/site/src/site/blog/groovy-3-0-0-alpha.md
new file mode 100644
index 0000000..36f2102
--- /dev/null
+++ b/site/src/site/blog/groovy-3-0-0-alpha.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 3.0.0-alpha-4 Released
+date: '2019-01-01T09:24:28+00:00'
+permalink: groovy-3-0-0-alpha
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 3.0.0-alpha-4 of</span><br style="color: #222222; fo [...]
diff --git a/site/src/site/blog/groovy-3-0-0-alpha1.md b/site/src/site/blog/groovy-3-0-0-alpha1.md
new file mode 100644
index 0000000..d4f6df9
--- /dev/null
+++ b/site/src/site/blog/groovy-3-0-0-alpha1.md
@@ -0,0 +1,9 @@
+---
+layout: post
+title: Groovy 3.0.0-alpha-4 Windows Installer Released (Community Artifact)
+date: '2019-01-01T09:28:58+00:00'
+permalink: groovy-3-0-0-alpha1
+---
+<div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Windows&nbsp;<span class="m_-7737421595273415518gmail-il">installer</span> for Groovy 3.0.0-alpha-4&nbsp;(Community Artifact) is available from the usual place: <a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-alpha-4-installer.exe" target="_blank" data-saferedirecturl="https://www.google.com/url?q=https://bintray.com/groovy/Distributions/download_file?file_ [...]
+  <div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;"><br /></div>
+  <div style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Note this installer doesn't include Spock since there isn't a Spock release compatible with Groovy 3.0.</div>
diff --git a/site/src/site/blog/groovy-3-0-0-beta.md b/site/src/site/blog/groovy-3-0-0-beta.md
new file mode 100644
index 0000000..e09dd10
--- /dev/null
+++ b/site/src/site/blog/groovy-3-0-0-beta.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 3.0.0-beta-1 Released
+date: '2019-05-12T22:41:09+00:00'
+permalink: groovy-3-0-0-beta
+---
+<span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><br style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;" /><span style="color: #222222; font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 3.0.0-beta-1 of&nbsp;</span><span style="color: #222 [...]
diff --git a/site/src/site/blog/groovy-3-0-0-beta1.md b/site/src/site/blog/groovy-3-0-0-beta1.md
new file mode 100644
index 0000000..37f648c
--- /dev/null
+++ b/site/src/site/blog/groovy-3-0-0-beta1.md
@@ -0,0 +1,43 @@
+---
+layout: post
+title: Groovy 3.0.0-beta-2 Released
+date: '2019-07-15T10:25:28+00:00'
+permalink: groovy-3-0-0-beta1
+---
+The Apache Groovy team is pleased to announce version 3.0.0-beta-2 of Apache Groovy.
+Apache Groovy is a multi-faceted programming language for the JVM.
+Further details can be found at the <a href="https://groovy.apache.org">https://groovy.apache.org</a> website.
+
+<p>
+This is a pre-release of a new version of Groovy.
+We greatly appreciate any feedback you can give us when using this version.
+
+<p>
+This release includes 40 bug fixes/improvements as outlined in the changelog:
+<a href="https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12345498">https://issues.apache.org/jira/secure/ReleaseNote.jspa?projectId=12318123&version=12345498</a>
+
+<p>
+Sources, convenience binaries, downloadable documentation and an SDK
+bundle can be found at: <a href="https://groovy.apache.org/download.html">https://groovy.apache.org/download.html</a>
+We recommend you verify your installation using the information on that page.
+
+<p>
+Jars are also available within the major binary repositories.
+
+<p>
+We welcome your help and feedback and in particular want
+to thank everyone who contributed to this release.
+
+<p>
+For more information on how to report problems, and to get involved,
+visit the project website at <a href="https://groovy.apache.org/">https://groovy.apache.org/</a>
+
+<p>
+Note: Apache Groovy 3.0.0-beta-2 was compiled with JDK8, so the illegal access warnings will come back if you use JDK9+. But don't worry, we will do another release in a week or two. Please verify the issues you reported first and give us feedback, which will help us improve the quality of next release.
+
+
+<p>
+Best regards,
+
+<p>
+The Apache Groovy team.
diff --git a/site/src/site/blog/groovy-3-0-0-beta2.md b/site/src/site/blog/groovy-3-0-0-beta2.md
new file mode 100644
index 0000000..12e74f5
--- /dev/null
+++ b/site/src/site/blog/groovy-3-0-0-beta2.md
@@ -0,0 +1,14 @@
+---
+layout: post
+title: Groovy 3.0.0-beta-2 Windows Installer Released (Community Release)
+date: '2019-07-15T10:30:34+00:00'
+permalink: groovy-3-0-0-beta2
+---
+The Windows installer for Groovy 3.0.0-beta-2 is now available from Bintray: <a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-2-installer.exe">https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-2-installer.exe</a>.
+
+<p>
+I've again included a preview of an msi built with WiX, which I'm seeking feedback on: 
+<a href="https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-2+%28preview+installer%29.msi">https://bintray.com/groovy/Distributions/download_file?file_path=groovy-3.0.0-beta-2+%28preview+installer%29.msi</a>
+
+<p>
+Be aware that you need to fully uninstall the NSIS based Groovy installation before installing with an MSI installer.
diff --git a/site/src/site/blog/groovy-3-highlights.md b/site/src/site/blog/groovy-3-highlights.md
new file mode 100644
index 0000000..b8a67c5
--- /dev/null
+++ b/site/src/site/blog/groovy-3-highlights.md
@@ -0,0 +1,235 @@
+---
+layout: post
+title: Groovy 3 Highlights
+date: '2020-02-13T02:28:07+00:00'
+permalink: groovy-3-highlights
+---
+<h1>Groovy 3 Highlights&nbsp;</h1> 
+  <h2>General Improvements</h2> 
+  <p>Groovy has both a dynamic nature (supporting code styles similar to Ruby and Python) as well as a static nature (supporting styles similar to Java, Kotlin and Scala). Groovy continues to improve both those natures - filling in any feature gaps. As just one example, Groovy has numerous facilities for better managing null values. You can use Groovy's null-safe navigation operator, piggy back on Java's <font face="courier new, courier, monospace">Optional</font> or provide a null-check [...]
+  <p>In general,&nbsp;the language design borrows heavily from Java, so careful attention is paid to changes in Java and acted on accordingly if appropriate. A lot of work has been done getting Groovy ready for Java modules and for making it work well with JDK versions 9-15. Other work has dramatically improved the performance of bytecode generation which makes use of the JVMs invoke dynamic capabilities. Additional changes are already underway for further improvements in these areas in  [...]
+  <p>There are also many other performance improvements under the covers. More efficient type resolution occurs during compilation and more efficient byecode is generated for numerous scenarios. The addition of a Maven BOM allows more flexible usage of Groovy from other projects.</p> 
+  <p>Groovy also has particular strengths for scripting, testing, writing Domain Specific Languages (DSLs) and in domains like financial calculations and data science. On-going work has been made to ensure those strengths are maintained. The accuracy used for high-precision numbers has been improved and is configurable. Much of the tooling such as Groovy Console and groovysh have also been improved.</p> 
+  <p>Other key strengths of Groovy such as its runtime and compile-time meta-programming capabilities have also seen many minor enhancements. All in all, this release represents the culmination of several years of activity. Over 500 new features, improvements and bug fixes have been added since Groovy 2.5. Just a few highlights are discussed below.</p> 
+  <h2>Parrot parser</h2> 
+  <p>Groovy has a new parser. While mostly an internal change within Groovy, the good news for users is that the new parser is more flexible and will allow the language to more rapidly change should the need arise.</p> 
+  <h3>New syntax</h3> 
+  <p>The new parser gave us the opportunity to add some new syntax features:</p> 
+  <ul> 
+    <li>!in and !instanceof operators</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin-top: 0px; margin-bottom: 0px; margin-left: 40px; border: medium none; padding: 0px;">assert 45 !instanceof Date
+assert 4 !in [1, 3, 5, 7]</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Elvis assignment operator</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin-top: 0px; margin-bottom: 0px; margin-left: 40px; border: medium none; padding: 0px;">def first = 'Jane'
+def last = null
+first ?= 'John'
+last ?= 'Doe'
+assert [first, last] == ['Jane', 'Doe']</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Identity comparison operators</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin-top: 0px; margin-bottom: 0px; margin-left: 40px; border: medium none; padding: 0px;">assert cat === copyCat&nbsp; // operator shorthand for <font face="courier new, courier, monospace">is</font> method
+assert cat !== lion&nbsp; &nbsp; &nbsp;// negated operator shorthand</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Safe indexing (for maps, lists and arrays)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: none; padding: 0px;">println map?['someKey'] // return null if map is null instead of throwing NPE</pre> 
+  </blockquote> 
+  <h3>Java compatibility</h3> 
+  <p>The Groovy syntax can be thought of as a superset of Java syntax. It's considered good style to use the enhancements that Groovy provides when appropriate, but Groovy's aim is to still support as much of the Java syntax as possible to allow easy migration from Java or easy switching for folks working with both Java and Groovy.</p> 
+  <p>The flexibility provided by the new parser allowed several syntax compatibility holes to be closed including:</p> 
+  <p> </p> 
+  <ul> 
+    <li>do/while loop</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;">def count = 5
+def factorial = 1
+do {
+&nbsp; &nbsp; factorial *= count--
+} while(count &gt; 1)
+assert factorial == 120</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Enhanced classic Java-style for loop (see multi-assignment for-loop example; note the comma in the last clause of the for statement)</li> 
+    <li>Multi-assignment in combination with for loop</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;">def count = 3
+println 'The next three months are:'
+for (def (era, yr, mo) = new Date(); count--; yr = mo == 11 ? yr + 1 : yr, mo = mo == 11 ? 0 : mo + 1) {
+&nbsp; &nbsp; println "$yr/$mo"
+}</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Java-style array initialization (but you might prefer Groovy's literal list notation)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;">def primes = new int[] {2, 3, 5, 7, 11}</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Lambda expressions (but you might often prefer Groovy's Closures which support trampoline/tail recursion, partial application/currying, memoization/auto caching)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>(1..10).forEach(e -&gt; { println e })</pre> 
+    </blockquote> 
+  </blockquote> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>assert (1..10).stream()
+              .filter(e -&gt; e % 2 == 0)
+              .map(e -&gt; e * 2)
+              .toList() == [4, 8, 12, 16, 20]</pre> 
+    </blockquote> 
+  </blockquote> 
+  <ul> </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>def add = (int x, int y) -&gt; { def z = y; return x + z }
+assert add(3, 4) == 7</pre> 
+    </blockquote> 
+  </blockquote> 
+  <ul></ul> 
+  <ul> 
+    <li>Method references (but you might often prefer Groovy's Method pointers which are Closures with the previously mentioned benefits)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>assert ['1', '2', '3'] == Stream.of(1, 2, 3)
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;                 .map(String::valueOf)
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;                 .toList()</pre> 
+    </blockquote> 
+  </blockquote> 
+  <ul></ul> 
+  <ul></ul> 
+  <ul></ul> 
+  <ul> 
+    <li>&quot;var&quot; reserved type (allows Java 10/11 features even when using JDK 8)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;">var two = 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Java 10
+IntFunction&lt;Integer&gt; twice = (final var x) -&gt; x * two&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; // Java 11
+assert [1, 2, 3].collect{ twice.apply(it) } == [2, 4, 6]</pre> 
+  </blockquote> 
+  <ul> 
+    <li>ARM Try with resources (Java 7 and 9 variations work on JDK 8 - but you might prefer Groovy's internal iteration methods for resources)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;">def file = new File('/path/to/file.ext')
+def reader = file.newReader()
+try(reader) {
+&nbsp; &nbsp; String line = null
+&nbsp; &nbsp; while (line = reader.readLine()) {
+&nbsp; &nbsp; &nbsp; &nbsp; println line
+&nbsp; &nbsp; }
+}</pre> 
+  </blockquote> 
+  <ul> 
+    <li>Nested code blocks</li> 
+    <li>Java-style non-static inner class instantiation</li> 
+    <li>Interface default methods (but you might prefer Groovy's traits)</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: none; padding: 0px;"> 
+    <pre style="margin: 0px 0px 0px 40px; border: none; padding: 0px;">interface Greetable {
+&nbsp; &nbsp; String target()
+&nbsp; &nbsp; default String salutation() {
+&nbsp; &nbsp; &nbsp; &nbsp; 'Greetings'
+&nbsp; &nbsp; }
+&nbsp; &nbsp; default String greet() {
+&nbsp; &nbsp; &nbsp; &nbsp; "${salutation()}, ${target()}"
+&nbsp; &nbsp; }
+}</pre> 
+  </blockquote> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> </blockquote> 
+  <ul> </ul> 
+  <h2>Split package changes</h2> 
+  <p>In preparation for Groovy's modular jars to be first class modules, several classes have moved packages. Some examples:</p> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <pre>groovy.util.XmlParser =&gt; groovy.xml.XmlParser
+groovy.util.XmlSlurper =&gt; groovy.xml.XmlSlurper
+groovy.util.GroovyTestCase =&gt;&nbsp;groovy.test.GroovyTestCase</pre> 
+  </blockquote> 
+  <p>In most cases, both the old and new class are available in Groovy 3. But by Groovy 4, the old classes will be removed. See the <a href="http://groovy-lang.org/releasenotes/groovy-3.0.html" title="release notes">release notes</a> for a complete list of these changes.&nbsp;</p> 
+  <h2>DGM improvements</h2> 
+  <p>Groovy adds many extension methods to existing Java classes. In Groovy 3, about 80 new such extension methods were added. We highlight just a few here:</p> 
+  <p> </p> 
+  <ul> 
+    <li>average() on arrays and iterables</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>assert 3 == [1, 2, 6].average()</pre> 
+    </blockquote> 
+  </blockquote> 
+  <p> </p> 
+  <ul> 
+    <li><font face="courier new, courier, monospace">takeBetween()</font> on <font face="courier new, courier, monospace">String</font>, <font face="courier new, courier, monospace">CharSequence</font> and <font face="courier new, courier, monospace">GString</font></li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>assert 'Groovy'.takeBetween( 'r', 'v' ) == 'oo'</pre> 
+    </blockquote> 
+  </blockquote> 
+  <p> </p> 
+  <ul> 
+    <li><font face="courier new, courier, monospace">shuffle()</font> and <font face="courier new, courier, monospace">shuffled()</font> on arrays and iterables</li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>def orig = [1, 3, 5, 7]
+def mixed = orig.shuffled()
+assert mixed.size() == orig.size()
+assert mixed.toString() ==~ /\[(\d, ){3}\d\]/</pre> 
+    </blockquote> 
+  </blockquote> 
+  <p> </p> 
+  <ul> 
+    <li><font face="courier new, courier, monospace">collect{ }</font> on <font face="courier new, courier, monospace">Future</font></li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>Future&lt;String&gt; foobar = executor.submit{ "foobar" }
+Future&lt;Integer&gt; foobarSize = foobar.collect{ it.size() } // async
+assert foobarSize.get() == 6</pre> 
+    </blockquote> 
+  </blockquote> 
+  <p> </p> 
+  <ul> 
+    <li><font face="courier new, courier, monospace">minus()</font> on <font face="courier new, courier, monospace">LocalDate</font></li> 
+  </ul> 
+  <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+    <blockquote style="margin: 0px 0px 0px 40px; border: medium none; padding: 0px;"> 
+      <pre>def xmas = LocalDate.of(2019, Month.DECEMBER, 25)
+def newYear = LocalDate.of(2020, Month.JANUARY, 1)
+assert newYear - xmas == 7 // a week apart
+</pre> 
+    </blockquote> 
+  </blockquote> 
+  <h2>Other Improvements</h2> 
+  <h3>Improved Annotation Support</h3> 
+  <p>Recent version of Java allow annotations in more places (JSR308). Groovy now also supports such use cases. This is important for frameworks like Spock, Micronaut, Grails, Jqwik and others, and also opens up the possibility for additional AST transformations (a key meta-programming feature of Groovy).</p> 
+  <h3>Groovydoc Enhancements</h3> 
+  <p>In addition to Groovydoc supporting the new parser, you can now embed Groovydoc comments in various ways:</p> 
+  <p> </p> 
+  <ul> 
+    <li>They can be made available within the AST for use by AST transformations and other tools.</li> 
+    <li>Groovydoc comments starting with a special <font face="courier new, courier, monospace">/**@</font> opening comment delimiter can also be embedded into the class file. This provides a capability in Groovy inspired by languages like Ruby which can embed documentation into the standard binary jar and is thus always available rather than relying on a separate javadoc jar.</li> 
+  </ul> 
+  <h2>Getting Groovy</h2> 
+  <p>The official source release are on the <a href="https://groovy.apache.org/download.html" title="download page">download page</a>. Convenience binaries, downloadable documentation, an SDK bundle and pointers to various community artifacts can be found on that page along with information to allow you to verify your installation. You can use the zip installation on any platform with Java support, or consider using an installer for your platform or IDE.</p> 
+  <p>The Windows installer for the latest versions of Groovy 3 are available from <a href="https://bintray.com/groovy/Distributions/Windows-Installer" title="groovy msi">bintray</a>. (community artifact)</p> 
+  <p>For Linux users, the latest versions of Groovy 3 are also available in the <a href="https://snapcraft.io/groovy" title="snap store">Snap Store</a>. (community artifact)</p> 
+  <p>For Eclipse users, the latest versions of the Groovy 3 groovy-eclipse-batch plugin are available from&nbsp;<a href="https://bintray.com/groovy/maven/groovy-eclipse-batch/" title="groovy-eclipse-batch">bintray</a>. (community artifact)</p>
+  <p>For Intellij users, the latest community editions of <a href="https://www.jetbrains.com/idea/" title="IDEA">IDEA</a> have Groovy 3 support.&nbsp;</p> 
+  <p> </p>
diff --git a/site/src/site/blog/groovy-4-0-3-released.md b/site/src/site/blog/groovy-4-0-3-released.md
new file mode 100644
index 0000000..4233bd6
--- /dev/null
+++ b/site/src/site/blog/groovy-4-0-3-released.md
@@ -0,0 +1,7 @@
+---
+layout: post
+title: Groovy 4.0.3 Released
+date: '2022-06-15T08:16:53+00:00'
+permalink: groovy-4-0-3-released
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/c5ba5e59-737e-4ebf-91c9-08fa67dc8f70" style="width: 20%;" align="right" alt="groovy.png"><span style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;"><br style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="color: rgb(34, 3 [...]
diff --git a/site/src/site/blog/groovy-dates-and-times-cheat.md b/site/src/site/blog/groovy-dates-and-times-cheat.md
new file mode 100644
index 0000000..58928ef
--- /dev/null
+++ b/site/src/site/blog/groovy-dates-and-times-cheat.md
@@ -0,0 +1,402 @@
+---
+layout: post
+title: Groovy Dates And Times Cheat Sheet
+date: '2022-10-24T07:27:25+00:00'
+permalink: groovy-dates-and-times-cheat
+---
+<p>Java has had a <code>Date</code> class from the very beginning and Groovy supports using it and several related classes like <code>Calendar</code>. Throughout this blog post we refer to those classes as the <i style="background-color: rgb(255, 255, 255);"><b>legacy date classes</b></i>.
+Groovy enhances the experience of using the legacy date classes with simpler mechanisms for formatting, parsing and extracting fields from the related classes.</p>
+
+<p>Since Java 8, the JDK has included the <a href="https://jcp.org/en/jsr/detail?id=310" target="_blank">JSR-310</a> Date Time API. We refer to these classes as the <i style="background-color: rgb(255, 255, 255);"><b>new date classes</b></i>. The new date classes remove many limitations of the legacy date classes and bring some greatly appreciated additional consistency. Groovy provides similar enhancements for the new date classes too.</p><p>Groovy's enhancements for the legacy date cla [...]
+
+<h2>Representing the current date/time</h2>
+
+<p>The legacy date classes have an abstraction which includes date and time. If you are only interested in one of those two aspects, you simply ignore the other aspect. The new date classes allow you to have date-only, time-only and date-time representations.</p><table cellspacing="5px"><tbody><tr></tr></tbody></table>The examples create instances representing the current date and/or time. Various information is extracted from the instances and they are printed in various ways. Some of t [...]
+<tr style="background-color:#ddeedd"><td style="padding:10px"><p><span style="background-color: transparent;">current date and time</span></p></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println LocalDateTime.<span style="color:#9876aa;font-style:italic;">now</span>()      <span style="color:#808080;"><br></span>println Instant.<span style="color:#9876aa;font-style:italic;">now</span>()            <span style="color:#808080;"><br></span></pre>
+<pre>2022-10-24T12:40:02.218130200
+2022-10-24T02:40:02.223131Z
+</pre></td>
+<td style="padding:10px">
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="color:#cc7832;">new </span>Date()               <span style="color:#808080;"><br></span>println Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>.<span style="color:#9876aa;">time   </span><span style="color:#808080;"></span></pre>
+<pre>Mon Oct 24 12:40:02 AEST 2022
+Mon Oct 24 12:40:02 AEST 2022<br></pre></td></tr>
+<tr style="background-color:#ddddee"><td style="padding:10px">day of current year &amp;<br>day of current month</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println LocalDateTime.<span style="color:#9876aa;font-style:italic;">now</span>().<span style="color:#9876aa;">dayOfYear<br></span>println LocalDateTime.<span style="color:#9876aa;font-style:italic;">now</span>().<span style="color:#9876aa;">dayOfMonth<br></span></pre>
+<pre>297
+24</pre>
+</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>[<span style="color:#9876aa;font-style:italic;">DAY_OF_YEAR</span>]<br>println Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>[<span style="color:#9876aa;font-style:italic;">DAY_OF_MONTH</span>]<br></pre><pre>297
+24</pre></td>
+</tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">extract today's<br>year, month &amp; day</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>now = LocalDate.<span style="color:#9876aa;font-style:italic;">now</span>()     <span style="font-size: 9.6pt; color: rgb(128, 128, 128);">// or LocalDateTime</span><br><br>println SV(now.<span style="color:#9876aa;">year</span>, now.<span style="color:#9876aa;">monthValue</span>, now.<span style="color:#9876aa;">dayO [...]
+Today is 2022 10 24</pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>now = Calendar.<span style="color:#9876aa;font-style:italic;">instance<br></span>(_E, Y, M, _WY, _WM, D) = now<br>println <span style="color:#6a8759;">"Today is </span>$Y $<span style="font-weight:bold;">{</span>M+<span style="color:#6897bb;">1</span><span style="font-weight:bold;">} </span>$D<span style="color:#6a875 [...]
+Today is 2022 10 24</pre></td>
+</tr>
+<tr style="background-color:#ddddee"><td style="padding:10px">alternatives to print today</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println now.format(<span style="color:#6a8759;">"'Today is 'YYYY-MM-dd"</span>)<br>printf <span style="color:#6a8759;">'Today is %1$tY-%1$tm-%1$te%n'</span>, now</pre><pre>Today is 2022-10-24
+Today is 2022-10-24</pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println now.format(<span style="color:#6a8759;">"'Today is 'YYYY-MM-dd"</span>)<br>printf <span style="color:#6a8759;">'Today is %1$tY-%1$tm-%1$te%n'</span>, now</pre><pre>Today is 2022-10-24
+Today is 2022-10-24</pre></td>
+</tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px"><p>extract parts of current time</p></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">now = LocalTime.<span style="color:#9876aa;font-style:italic;">now</span>() <span style="color:#808080;">// or LocalDateTime<br></span>println SV(now.<span style="color:#9876aa;">hour</span>, now.<span style="color:#9876aa;">minute</span>, now.<span style="color:#9876aa;">second</span>)<br>(H, M, S) = now[<span style="color:#9876aa;font-style:italic;">HOUR_ [...]
+The time is 12:40:02</pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">(H, M, S) = now[<span style="color:#9876aa;font-style:italic;">HOUR_OF_DAY</span>, <span style="color:#9876aa;font-style:italic;">MINUTE</span>, <span style="color:#9876aa;font-style:italic;">SECOND</span>]
+<br>println SV(H, M, S)
+<br>printf <span style="color:#6a8759;">'The time is %02d:%02d:%02d%n</span><span style="color:#6a8759;">'</span>, H, M, S<br></pre><pre>H=12, M=40, S=2
+The time is 12:40:02</pre></td>
+</tr>
+<tr style="background-color:#ddddee"><td style="padding:10px">alternatives to print time</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println now.format(<span style="color:#6a8759;">"'The time is 'HH:mm:ss"</span>)<br>printf <span style="color:#6a8759;">'The time is %1$tH:%1$tM:%1$tS%n</span><span style="color:#6a8759;">'</span>, now<br></pre><pre>The time is 12:40:02
+The time is 12:40:02<br></pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println now.format(<span style="color:#6a8759;">"'The time is 'HH:mm:ss"</span>)<br>printf <span style="color:#6a8759;">'The time is %1$tH:%1$tM:%1$tS%n</span><span style="color:#6a8759;">'</span>, now<br></pre><pre>The time is 12:40:02
+The time is 12:40:02<br></pre></td>
+</tr>
+</tbody></table>
+
+<h2>Processing times</h2>
+
+<p>The new date classes have a <code>LocalTime</code> class specifically for representing time-only quantities. The legacy date classes don't have such a purpose-built abstraction; you essentially just ignore the day, month, and year parts of a date. The <code>java.sql.Time</code> class could be used as an alterative but rarely is.&nbsp;The Java <a href="https://docs.oracle.com/javase/tutorial/datetime/iso/legacy.html" target="_blank" style="background-color: rgb(255, 255, 255);">documen [...]
+using <code>GregorianCalendar</code> with the date set to the epoch value of <code>1970-01-01</code>
+as an approximation of the <code>LocalTime</code> class. We'll follow that approach here to provide a comparison but we <i>strongly recommend</i> upgrading to the
+new classes if you need to represent time-only values or use the <a href="https://www.joda.org/joda-time/" target="_blank" style="background-color: rgb(255, 255, 255);">Joda-Time</a> library on JDK versions prior to 8.</p><p>
+</p>
+
+The examples look at representing a minute before and after midnight, and some times at which you might eat your meals. For the meals, as well as printing various values, we might be interested in calculating new times in terms of existing times, e.g. lunch and dinner are 7 hours apart.<table cellspacing="5px"><tbody>
+<tr><th style="text-align:center; padding:10px">task</th><th style="text-align:center; padding:10px">java.time</th><th style="text-align:center; padding:10px">legacy</th></tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">one min after midnight</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">LocalTime.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6897bb;">0</span>, <span style="color:#6897bb;">1</span>).with <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>println format(<span style="color:#6a8759;">'HH:mm'</span>)<br>    println format(<span style="color:#6a8759;">'hh:mm a'</ [...]
+12:01 am
+0:01 am</pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>.with <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>clear()<br>    set(<span style="color:#9876aa;font-style:italic;">MINUTE</span>, <span style="color:#6897bb;">1</span>)<br>    println format(<span style="color:#6a8759;">'HH:mm'</span>)<br>    p [...]
+12:01 am
+0:01 am</pre></td>
+</tr>
+<tr style="background-color:#ddddee"><td style="padding:10px">one min before midnight</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">LocalTime.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6897bb;">23</span>, <span style="color:#6897bb;">59</span>).with <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>println format(<span style="color:#6a8759;">'HH:mm'</span>)<br>    println format(<span style="color:#6a8759;">'hh:mm a' [...]
+11:59 pm
+11:59 pm</pre></td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>.with <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>clear()<br>    set(<span style="color:#6a8759;">hourOfDay</span>: <span style="color:#6897bb;">23</span>, <span style="color:#6a8759;">minute</span>: <span style="color:#6897bb;">59</span>)<br>   [...]
+11:59 pm
+11:59 pm</pre></td>
+</tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">meal times</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>breakfast = LocalTime.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6897bb;">7</span>, <span style="color:#6897bb;">30</span>)<br><span style="color:#cc7832;">var </span>lunch = LocalTime.<span style="color:#9876aa;font-style:italic;">parse</span>(<span style="color:#6a8759;">'12:30'</sp [...]
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>breakfast = Date.<span style="color:#9876aa;font-style:italic;">parse</span>(<span style="color:#6a8759;">'hh:mm'</span>, <span style="color:#6a8759;">'07:30'</span>)<br><span style="color:#cc7832;">var </span>lunch = Calendar.<span style="color:#9876aa;font-style:italic;">instance</span>.tap <span style="font-weight: [...]
+</tr>
+</tbody></table>
+
+<h2>Processing dates</h2>
+
+<p>To represent date-only information with the legacy date classes, you set the time aspects to zero, or simply ignore them. Alternatively, you could consider the less commonly used&nbsp;<code>java.sql.Date</code>&nbsp;class. The new date classes have the special <code>LocalDate</code> class for this purpose which we highly recommend.</p><p>The examples create dates for Halloween and Melbourne Cup day (a public holiday in the Australia state of Victoria). We look at various properties of [...]
+
+<table cellspacing="5px"><tbody>
+<tr><th style="text-align:center; padding:10px">task</th><th style="text-align:center; padding:10px">java.time</th><th style="text-align:center; padding:10px">legacy</th></tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">holidays</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>halloween22 = LocalDate.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6897bb;">2022</span>, <span style="color:#6897bb;">10</span>, <span style="color:#6897bb;">31</span>)<br><span style="color:#cc7832;">var </span>halloween23 = LocalDate.<span style="color:#9876aa;font-style:italic;">pa [...]
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>halloween21 = Date.<span style="color:#9876aa;font-style:italic;">parse</span>(<span style="color:#6a8759;">'dd/MM/yyyy'</span>, <span style="color:#6a8759;">'31/10/2021'</span>)<br><span style="color:#cc7832;">var </span>halloween22 = Date.<span style="color:#9876aa;font-style:italic;">parse</span>(<span style="color [...]
+</tr>
+</tbody></table>
+
+<h2>Processing date and time combinations</h2>
+
+<p>
+The new date classes use <code>LocalDateTime</code> to represent a quantity with both date and time aspects. Many of the methods seen earlier will also be applicable here.</p>
+<p>The examples show creating and printing a representation of lunch on Melbourne Cup day.</p><p>
+</p>
+
+<table cellspacing="5px"><tbody>
+<tr><th style="text-align:center; padding:10px">task</th><th style="text-align:center; padding:10px">java.time</th><th style="text-align:center; padding:10px">legacy</th></tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">holidays</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>melbourneCupLunch = LocalDateTime.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6897bb;">2022</span>, <span style="color:#6897bb;">11</span>, <span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">12</span>, <span style="color:#6897bb;">30</span>)<br><span style="color:#cc78 [...]
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>melbourneCupLunch = <span style="color:#cc7832;">new </span>GregorianCalendar(<span style="color:#6897bb;">2022</span>, <span style="color:#6897bb;">10</span>, <span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">12</span>, <span style="color:#6897bb;">30</span>).<span style="color:#9876aa;">time<br></s [...]
+</tr>
+</tbody></table>
+
+<h2>Processing zoned date and times</h2>
+
+<p>
+The legacy date classes have the concept of a <code>TimeZone</code>, predominantly used by the Calendar class. The new date classes has a similar concept but uses the <code>ZoneId</code>, <code>ZoneOffset</code>, and <code>ZonedDateTime</code> classes (among others).</p><p>The examples show various properties of zones and show that during the Melbourne cup breakfast, it would still be the night before (Halloween) in Los Angeles. They also show that those two zones are 18 hours apart at t [...]
+
+<table cellspacing="5px"><tbody>
+<tr><th style="text-align:center; padding:10px">task</th><th style="text-align:center; padding:10px">java.time</th><th style="text-align:center; padding:10px">legacy</th></tr>
+<tr style="background-color:#ddeedd"><td style="padding:10px">holidays</td>
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>aet = ZoneId.<span style="color:#9876aa;font-style:italic;">of</span>(<span style="color:#6a8759;">'Australia/Sydney'</span>)<br><span style="color:#cc7832;">assert </span>aet.<span style="color:#9876aa;">fullName </span>== <span style="color:#6a8759;">'Australian Eastern Time' </span>&amp;&amp; aet.<span style="color [...]
+<td style="padding:10px"><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>aet = TimeZone.<span style="color:#9876aa;font-style:italic;">getTimeZone</span>(<span style="color:#6a8759;">'Australia/Sydney'</span>)<br><span style="color:#cc7832;">assert </span>aet.<span style="color:#9876aa;">displayName </span>== <span style="color:#6a8759;">'Australian Eastern Standard Time'<br></span><span s [...]
+
+<h2>Other useful classes</h2>
+
+<p>The new date classes offer a few more useful classes. Here are some of the common ones:</p>
+
+<ul><li><code>OffsetDateTime</code> - like <code>ZonedDateTime</code> but with just an offset from UTC rather than a full time-zone</li>
+<li><code>Instant</code> - like <code>OffsetDateTime</code> but tied to UTC</li>
+<li><code>YearMonth</code> - like a <code>LocalDate</code> but with no day component</li>
+<li><code>MonthDay</code> - like a <code>LocalDate</code> but with no year component</li>
+<li><code>Period</code> - used to represent periods of time, e.g. <code>Period.ofDays(14)</code>, <code>Period.ofYears(2)</code>; see also the&nbsp;<code>LocalDate</code> example above.</li>
+<li><code>Duration</code> - a time-based amount of time, e.g. <code>Duration.ofSeconds(30)</code>, <code>Duration.ofHours(7)</code>; see also the&nbsp;<code>LocalTime</code> example above.</li></ul>
+
+<h2>Conversions</h2>
+
+<p>It is useful to convert between the new and legacy classes. Some useful conversion methods are shown below with Groovy enhancements shown in <span style="color:blue">blue</span>.</p>
+<table style="width:70%;">
+<tbody style="background-color:#eeeeee;">
+<tr><th>From</th><th>Conversion method/property</th></tr>
+<tr><td>GregorianCalendar&nbsp;</td><td><pre>toInstant()
+toZonedDateTime()
+from(ZonedDateTime)
+</pre></td></tr>
+<tr><td>Calendar</td><td><pre>toInstant()
+<span style="color:blue">toZonedDateTime()
+toOffsetDateTime()
+toLocalDateTime()
+toLocalDate()
+toLocalTime()
+toOffsetTime()
+toDayOfWeek()
+toYear()
+toYearMonth()
+toMonth()
+toMonthDay()
+zoneOffset
+zoneId
+</span></pre></td></tr>
+<tr><td>Date</td>
+<td><pre>toInstant()
+from(Instant)
+<span style="color:blue">toZonedDateTime()
+toOffsetDateTime()
+toLocalDateTime()
+toLocalDate()
+toLocalTime()
+toOffsetTime()
+toDayOfWeek()
+toYear()
+toYearMonth()
+toMonth()
+toMonthDay()
+zoneOffset
+zoneId
+</span></pre></td></tr>
+<tr><td>ZonedDateTime<br>OffsetDateTime<br>LocalDateTime<br>LocalDate<br>LocalTime</td>
+<td><pre><span style="color:blue">toDate()
+toCalendar()
+</span></pre></td></tr>
+</tbody></table>
+
+
+<h2>SimpleDateFormat patterns</h2>
+
+<p>
+We saw several examples above using the <code>format</code> and <code>parse</code> methods. For the legacy date classes, numerous Groovy enhancements delegate to <code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/text/SimpleDateFormat.html" target="_blank">SimpleDateFormat</a></code>.
+This class represents date/time formats using pattern strings. These are special letters to represent some time or date component mixed with escaped literal strings. The special letters are often repeated to represent the minimum size field for number components and whether the full or an abbreviated form is used for other components.
+</p>
+<p>As an example, for the U.S. locale and U.S. Pacific Time time zone, the following pattern:
+</p><pre>yyyy.MM.dd G 'at' HH:mm:ss z</pre>
+would apply to the following text:
+<pre>2001.07.04 AD at 12:08:56 PDT</pre>
+<p></p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Letter&nbsp;</th><th>Description</th></tr>
+<tr><td>G</td><td>Era designator <code>AD</code></td></tr>
+<tr><td>y</td><td>Year <code>1996; 96</code></td></tr>
+<tr><td>Y</td><td>Week year (similar to year but allotted by weeks; the first/last few days of a year might be allotted to finish/start the last/previous week)</td></tr>
+<tr><td>M</td><td>Month in year (context sensitive) <code>July; Jul; 07</code></td></tr>
+<tr><td>L</td><td>Month in year (standalone form) <code>July; Jul; 07</code></td></tr>
+<tr><td>w</td><td>Week in year <code>27</code></td></tr>
+<tr><td>W</td><td>Week in month <code>2</code></td></tr>
+<tr><td>D</td><td>Day in year <code>189</code></td></tr>
+<tr><td>d</td><td>Day in month <code>10</code></td></tr>
+<tr><td>F</td><td>Day of week in month <code>2</code></td></tr>
+<tr><td>E</td><td>Day name in week <code>Tuesday; Tue</code></td></tr>
+<tr><td>u</td><td>Day number of week (1 = Monday, ..., 7 = Sunday)</td></tr>
+<tr><td>a</td><td>Am/pm marker <code>PM</code></td></tr>
+<tr><td>H</td><td>Hour in day (0-23) <code>0</code></td></tr>
+<tr><td>k</td><td>Hour in day (1-24) <code>24</code></td></tr>
+<tr><td>K</td><td>Hour in am/pm (0-11) <code>0</code></td></tr>
+<tr><td>h</td><td>Hour in am/pm (1-12) <code>12</code></td></tr>
+<tr><td>m</td><td>Minute in hour <code>30</code></td></tr>
+<tr><td>s</td><td>Second in minute <code>55</code></td></tr>
+<tr><td>S</td><td>Millisecond <code>978</code></td></tr>
+<tr><td>z</td><td>Time zone <code>Pacific Standard Time; PST; GMT-08:00</code></td></tr>
+<tr><td>Z</td><td>Time zone (RFC 822) <code>-0800</code></td></tr>
+<tr><td>X</td><td>Time zone (ISO 8601) <code>-08; -0800; -08:00</code></td></tr>
+<tr><td>'</td><td>to escape text put a single quote on either side</td></tr>
+<tr><td>''</td><td>two single quotes for a literal single quote <code>'</code></td></tr>
+</tbody></table>
+
+<p><br></p>
+
+<h2>DateTimeFormatter patterns</h2>
+
+<p>Groovy's <code>format</code> and <code>parse</code> enhancements for the new date classes delegate to the <code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/time/format/DateTimeFormatter.html" target="_blank">DateTimeFormatter</a></code> class. It's behavior is similar to what we saw for&nbsp;<code>SimpleDateFormat</code>&nbsp;but with slightly different conversion letters:</p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Conversion suffix&nbsp;</th><th>Description</th></tr>
+<tr><td>G</td><td>era <code>AD</code></td></tr>
+<tr><td>u</td><td>year <code>2004; 04</code></td></tr>
+<tr><td>y</td><td>year-of-era <code>2004; 04</code></td></tr>
+<tr><td>D</td><td>day-of-year <code>189</code></td></tr>
+<tr><td>M/L</td><td>month-of-year <code>7; 07; Jul; July; J</code></td></tr>
+<tr><td>d</td><td>day-of-month <code>10</code></td></tr>
+<tr><td>Q/q</td><td>quarter-of-year <code>3; 03; Q3; 3rd quarter</code></td></tr>
+<tr><td>Y</td><td>week-based-year <code>1996; 96</code></td></tr>
+<tr><td>w</td><td>week-of-week-based-year <code>27</code></td></tr>
+<tr><td>W</td><td>week-of-month <code>4</code></td></tr>
+<tr><td>E</td><td>day-of-week <code>Tue; Tuesday; T</code></td></tr>
+<tr><td>e/c</td><td>localized day-of-week <code>2; 02; Tue; Tuesday; T</code></td></tr>
+<tr><td>F</td><td>week-of-month <code>3</code></td></tr>
+<tr><td>a</td><td>am-pm-of-day <code>PM</code></td></tr>
+<tr><td>h</td><td>clock-hour-of-am-pm (1-12) <code>12</code></td></tr>
+<tr><td>K</td><td>hour-of-am-pm (0-11) <code>0</code></td></tr>
+<tr><td>k</td><td>clock-hour-of-am-pm (1-24) <code>0</code></td></tr>
+<tr><td>H</td><td>hour-of-day (0-23) <code>0</code></td></tr>
+<tr><td>m</td><td>minute-of-hour <code>30</code></td></tr>
+<tr><td>s</td><td>second-of-minute <code>55</code></td></tr>
+<tr><td>S</td><td>fraction-of-second <code>978</code></td></tr>
+<tr><td>A</td><td>milli-of-day <code>1234</code></td></tr>
+<tr><td>n</td><td>nano-of-second <code>987654321</code></td></tr>
+<tr><td>N</td><td>nano-of-day <code>1234000000</code></td></tr>
+<tr><td>V</td><td>time-zone ID <code>America/Los_Angeles; Z; -08:30</code></td></tr>
+<tr><td>z</td><td>time-zone name <code>Pacific Standard Time; PST</code></td></tr>
+<tr><td>O</td><td>localized zone-offset <code>GMT+8; GMT+08:00; UTC-08:00;</code></td></tr>
+<tr><td>X</td><td>zone-offset 'Z' for zero <code>Z; -08; -0830; -08:30; -083015; -08:30:15;</code></td></tr>
+<tr><td>x</td><td>zone-offset <code>+0000; -08; -0830; -08:30; -083015; -08:30:15;</code></td></tr>
+<tr><td>Z</td><td>zone-offset <code>+0000; -0800; -08:00;</code></td></tr>
+<tr><td>p</td><td>pad next</td></tr>
+<tr><td>'</td><td>to escape text put a single quote on either side</td></tr>
+<tr><td>''</td><td>two single quotes for a literal single quote <code>'</code></td></tr>
+</tbody></table>
+
+<h3 id="localizedPatterns">Localized Patterns</h3>
+
+<p>JDK19 adds the <code>ofLocalizedPattern(String requestedTemplate)</code> method. The requested template is one or more regular expression pattern symbols ordered from the largest to the smallest unit, and
+consisting of the following patterns:</p>
+<pre>     "G{0,5}" +        // Era
+     "y*" +            // Year
+     "Q{0,5}" +        // Quarter
+     "M{0,5}" +        // Month
+     "w*" +            // Week of Week Based Year
+     "E{0,5}" +        // Day of Week
+     "d{0,2}" +        // Day of Month
+     "B{0,5}" +        // Period/AmPm of Day
+     "[hHjC]{0,2}" +   // Hour of Day/AmPm (refer to LDML for 'j' and 'C')
+     "m{0,2}" +        // Minute of Hour
+     "s{0,2}" +        // Second of Minute
+     "[vz]{0,4}"       // Zone
+</pre>
+<p>The requested template is mapped to the closest of available localized format as defined by the <a href="https://www.unicode.org/reports/tr35/tr35-dates.html#availableFormats_appendItems" target="_blank">Unicode LDML specification</a>. Here is an example of usage:<br></p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>now = ZonedDateTime.<span style="color:#9876aa;font-style:italic;">now</span>()<br><span style="color:#cc7832;">var </span>columns = <span style="color:#6a8759;">'%7s | %10s | %10s | %10s | %14s%n'<br></span>printf columns, <span style="color:#6a8759;">'locale'</span>, <span style="color:#6a8759;">'GDK'</span>, <span style="color:#6a8759;">'c [...]
+
+<p>Which has this output:<br></p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#808080;">locale |        GDK |     custom |      local |           both<br></span><span style="color:#808080;"> en_US | 2022-12-18 | 2022-12-18 |   12/18/22 |        12/2022<br></span><span style="color:#808080;"> ro_RO | 2022-12-18 | 2022-12-18 | 18.12.2022 |        12.2022<br></span><span style="color:#808080;"> vi_VN | 2022-12-18 | 2022-12-18 | 18/12/2022 | t [...]
+<p>Example credit: <a href="https://twitter.com/nipafx/status/1604152548503461891" target="_blank">this example</a> from <a href="https://twitter.com/nipafx" target="_blank">Nicolai Parlog</a>.</p>
+
+<h2>Formatter formats</h2>
+
+<p>The <code><a href="https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/util/Formatter.html" target="_blank">java.util.Formatter</a></code> class is a base class in Java for various kinds of formatting. It can be used directly, via <code>String.format</code>, <code>parse</code>, <code>printf</code>, or Groovy's <code>sprintf</code>.
+We saw several examples of using <code>printf</code> and <code>parse</code> formatting in the above examples.
+</p>
+<p>
+The <code>Formatter</code> class has methods which take a format string as its first argument and zero or more additional arguments.
+The format string typically has one or more format specifiers (starting with a percent character) which
+indicate that a formatted version of one of the additional arguments should be placed into the string at that point.
+The general form of a format specifier is:
+</p>
+<pre>%[argument_index$][flag][width][.precision]conversion</pre>
+<p>
+Most of the parts are optional. The <code>argument_index</code> part is only used when referencing
+one of the additional arguments more than once (or out of order). The <code>precision</code> part
+is only used for floating point numbers. The <code>flag</code> part is used to indicate always include sign(+),
+zero-padding(0), locale-specific comma delimiters(,), and left justification(-).
+The <code>width</code> indicates the minimum number of characters for the output.
+The <code>conversion</code> indicates how the argument should be processed, e.g. as a numeric field, a date,
+a special character, or some other special processing. Upper and lowercase variants exist for most conversions
+which, for the uppercase variant, will call <code>toUpperCase</code> after the conversion is complete.
+</p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Conversion&nbsp;</th><th>Description</th></tr>
+<tr><td>'b', 'B'</td><td>Treat as a boolean or false if null</td></tr>
+<tr><td>'h', 'H'</td><td>Output the arguments hashcode as a hex string</td></tr>
+<tr><td>'s', 'S'</td><td>Treat as a String</td></tr>
+<tr><td>'c', 'C'</td><td>Treat as a Unicode character</td></tr>
+<tr><td>'d'</td><td>Treat as a decimal integer</td></tr>
+<tr><td>'o'</td><td>Treat as an octal integer</td></tr>
+<tr><td>'x', 'X'</td><td>Treat as a hexadecimal integer</td></tr>
+<tr><td>'e', 'E'</td><td>Treat as a decimal number in scientific notation</td></tr>
+<tr><td>'f'</td><td>Treat as a floating point number</td></tr>
+<tr><td>'g', 'G'</td><td>Treat as a floating point in either decimal or scientific notation</td></tr>
+<tr><td>'a', 'A'</td><td>Treat as a hexadecimal floating-point number</td></tr>
+<tr style="background-color:#a9b7c6"><td>'t', 'T'</td><td>Treat as the <i>prefix </i>for a date/time conversion</td></tr>
+<tr><td>'%'</td><td>A literal percent</td></tr>
+<tr><td>'n'</td><td>A line separator</td></tr>
+</tbody>
+</table>
+<p>When the date/time prefix is used, additional suffixes are applicable.</p>
+
+<p>For formatting times:</p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Conversion suffix&nbsp;</th><th>Description</th></tr>
+<tr><td>'H'</td><td>Hour of the day for the 24-hour clock as two digits <code>00 - 23</code></td></tr>
+<tr><td>'I'</td><td>Hour for the 12-hour clock as two digits <code>01 - 12</code></td></tr>
+<tr><td>'k'</td><td>Hour of the day for the 24-hour clock <code>0 - 23</code></td></tr>
+<tr><td>'l'</td><td>Hour for the 12-hour clock <code>1 - 12</code></td></tr>
+<tr><td>'M'</td><td>Minute within the hour as two digits <code>00 - 59</code></td></tr>
+<tr><td>'S'</td><td>Seconds within the minute as two digits <code>00 - 60</code><br>("60" is used for leap seconds)</td></tr>
+<tr><td>'L'</td><td>Millisecond within the second as three digits <code>000 - 999</code></td></tr>
+<tr><td>'N'</td><td>Nanosecond within the second as nine digits <code>000000000 - 999999999</code></td></tr>
+<tr><td>'p'</td><td>Locale-specific morning or afternoon marker in lower case, <code>am</code> or <code>pm</code><br>(The conversion prefix 'T' forces this output to upper case)</td></tr>
+<tr><td>'z'</td><td>RFC&nbsp;822 style numeric time zone offset from GMT <code>-0800</code><br>(Adjusted as needed for Daylight Saving Time)</td></tr>
+<tr><td>'Z'</td><td>Abbreviated time zone</td></tr>
+<tr><td>'s'</td><td>Seconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC</td></tr>
+<tr><td>'Q'</td><td>Milliseconds since the beginning of the epoch starting at 1 January 1970 00:00:00 UTC</td></tr>
+</tbody></table>
+
+<p><br>For formatting dates:</p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Conversion suffix&nbsp;</th><th>Description</th></tr>
+<tr><td>'B'</td><td>Locale-specific full month name <code>January</code></td></tr>
+<tr><td>'b', 'h'</td><td>Locale-specific abbreviated month name <code>Jan</code></td></tr>
+<tr><td>'A'</td><td>Locale-specific full name of the day of the week <code>Sunday</code></td></tr>
+<tr><td>'a'</td><td>Locale-specific short name of the day of the week <code>Sun</code></td></tr>
+<tr><td>'C'</td><td>First two digits of four-digit year <code>00 - 99</code></td></tr>
+<tr><td>'Y'</td><td>Year as four digits <code>0092</code></td></tr>
+<tr><td>'y'</td><td>Last two digits of the year <code>00 - 99</code></td></tr>
+<tr><td>'j'</td><td>Day of year as three digits <code>001 - 366</code></td></tr>
+<tr><td>'m'</td><td>Month as two digits <code>01 - 13<code></code></code></td></tr>
+<tr><td>'d'</td><td>Day of month as two digits <code>01 - 31</code></td></tr>
+<tr><td>'e'</td><td>Day of month <code>1 - 31</code></td></tr>
+</tbody></table>
+
+<p><br>For formatting date/time compositions:</p>
+
+<table>
+<tbody style="background-color:#eeeeee">
+<tr><th>Conversion suffix&nbsp;</th><th>Description</th></tr>
+<tr><td>'R'</td><td>Time formatted for the 24-hour clock as "%tH:%tM"</td></tr>
+<tr><td>'T'</td><td>Time formatted for the 24-hour clock as "%tH:%tM:%tS"</td></tr>
+<tr><td>'r'</td><td>Time formatted for the 12-hour clock as "%tI:%tM:%tS %Tp"<br>The location of the morning or afternoon marker ('%Tp') may be locale-dependent.</td></tr>
+<tr><td>'D'</td><td>Date formatted as "%tm/%td/%ty"</td></tr>
+<tr><td>'F'</td><td>ISO&nbsp;8601 date formatted as "%tY-%tm-%td"</td></tr>
+<tr><td>'c'</td><td>Date and time formatted as "%ta %tb %td %tT %tZ %tY" <code>Sun Jul 21 15:17:00 EDT 1973</code></td></tr>
+</tbody></table>
+
+<p><br></p>
+
+<h2>Further information</h2>
+
+<ul><li>Java 8 LocalDate, LocalDateTime, Instant <a href="https://www.digitalocean.com/community/tutorials/java-8-date-localdate-localdatetime-instant" target="_blank">tutorial</a></li><li><a href="https://www.baeldung.com/java-8-date-time-intro" target="_blank">Introduction</a> to the Java 8 Date/Time API</li><li>A <a href="https://www.baeldung.com/java-simple-date-format" target="_blank">guide</a> to SimpleDateFormat</li><li>Joda-Time <a href="https://www.joda.org/joda-time/" target="_ [...]
+<li>Source code: <a href="https://github.com/paulk-asert/groovy-cheat-sheets/blob/main/src/main/groovy/DateTimeExamples.groovy" target="_blank">examples for new date classes</a></li>
+<li>Source code: <a href="https://github.com/paulk-asert/groovy-cheat-sheets/blob/main/src/main/groovy/DateUtilExamples.groovy" target="_blank">examples for legacy date classes</a></li></ul>
diff --git a/site/src/site/blog/groovy-list-processing-cheat-sheet.md b/site/src/site/blog/groovy-list-processing-cheat-sheet.md
new file mode 100644
index 0000000..349afd4
--- /dev/null
+++ b/site/src/site/blog/groovy-list-processing-cheat-sheet.md
@@ -0,0 +1,55 @@
+---
+layout: post
+title: Groovy List Processing Cheat Sheet
+date: '2022-08-28T08:46:29+00:00'
+permalink: groovy-list-processing-cheat-sheet
+---
+<h3>Declaring lists</h3>
+
+<p>Several styles are supported for declaring lists:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>pets    = [<span style="color:#6a8759;">'cat'</span>, <span style="color:#6a8759;">'canary'</span>, <span style="color:#6a8759;">'dog'</span>, <span style="color:#6a8759;">'fish'</span>, <span style="color:#6a8759;">'gerbil'</span>]  <span style="color:#808080;">// idiomatic Groovy<br></ [...]
+
+<h3>List elements and properties</h3>
+
+<p>Java methods for accessing list elements and list properties:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">assert </span>!pets.isEmpty()<br><span style="color:#cc7832;">assert </span>pets.size() == <span style="color:#6897bb;">5<br></span><span style="color:#cc7832;">assert </span>pets.get(<span style="color:#6897bb;">0</span>) == <span style="color:#6a8759;">'cat'<br></span><span style="col [...]
+
+<h3>Modifying mutable lists</h3>
+
+<p>Methods from Java for modifying lists:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">pets.remove(<span style="color:#6897bb;">2</span>);                        <span style="color:#cc7832;">assert </span>pets == [<span style="color:#6a8759;">'cat'</span>, <span style="color:#6a8759;">'canary'</span>, <span style="color:#6a8759;">'fish'</span>, <span style="color:#6a8759;">'gerbil'</span>]  <span style="color:#808080;">//  [...]
+
+<h3>Additional list functionality</h3>
+
+<p>Methods and operators which return new lists or values:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">assert </span>[<span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">3</span>] + [<span style="color:#6897bb;">1</span>] == [<span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">3</span> [...]
+
+<h3>GINQ processing</h3><p>Groovy also supports language integrated query support to process lists:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#808080;">// squares of odd numbers between 1 and 5<br></span><span style="color:#cc7832;">assert </span>[<span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">9</span>, <span style="color:#6897bb;">25</span>] == <span style="color:#9876aa;font-sty [...]
+
+<p>Useful stream methods (it is worthwhile comparing some of the examples to earlier non-stream variants):</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">pets = [<span style="color:#6a8759;">'cat'</span>, <span style="color:#6a8759;">'canary'</span>, <span style="color:#6a8759;">'dog'</span>, <span style="color:#6a8759;">'fish'</span>, <span style="color:#6a8759;">'gerbil'</span>]<br><span style="color:#cc7832;">assert </spa [...]
+
+<h3>GPars</h3>
+
+<p>Before looking at <a href="http://gpars.org/" target="_blank">GPars</a>, it is worth looking at parallel stream processing:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#808080;">// calculate squares of odd numbers from input list<br></span><span style="color:#cc7832;">assert </span>(<span style="color:#6897bb;">1</span>..<span style="color:#6897bb;">5</span>).parallelStream().filter<span style="font- [...]
+
+<h3>Other libraries</h3>
+<p>There are numerous list-related libraries on the JVM. We'll look at just a few.</p>
+
+<h4>Eclipse collections</h4>
+<p><a href="https://www.eclipse.org/collections/" target="_blank">Eclipse collections</a> comes with many container types including immutable collections, primitive collections, bimaps, multimaps and bags as well as numerous utility methods. It focuses on reduced memory footprint and efficient containers. It might be particularly of interest if you need primitive collections, immutable collections or some more exotic collection types like bag or bidirectional maps. Here are just a few ex [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>certainties = Lists.<span style="color:#9876aa;font-style:italic;">immutable</span>.of(<span style="color:#6a8759;">'death'</span>, <span style="color:#6a8759;">'taxes'</span>)<br><span style="color:#cc7832;">assert </span>certainties.reduce<span style="font-weight:bold;">{ </span>a, b <span style="font-weight:bold;">-&gt; </span><span style= [...]
+
+<h4>Guava</h4>
+
+<p><a href="https://github.com/google/guava/wiki" target="_blank">Guava</a> provides a number of extensions to the JDK collections ecosystem. In particular, it has immutable collections, new collection types like multisets and bidirectional maps and various powerful extensions and utilities. Here are a few examples:</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>set = TreeMultiset.<span style="color:#9876aa;font-style:italic;">create</span>([<span style="color:#6897bb;">1</span>, <span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">3</span>])<br><span style="color:#cc7832;">assert </span>set == TreeMultiset.<span style="color:#9876aa;font-style:italic;">create</span>([<span style="colo [...]
+
+<h4>Apache Commons Collections</h4>
+<p>The <a href="https://commons.apache.org/proper/commons-collections/" target="_blank">Apache Commons Collections</a> library extends upon the JDK collections framework adding some new types like bidirectional maps and bags as well as providing many comparator and iterator implementations. The library was designed to fill gaps in the JDK offerings and while some of those gaps in the JDK have now been filled by the JDK itself, Commons Collections still contains much useful functionality. [...]
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>six = <span style="color:#e8bf6a;font-weight:bold;">[</span><span style="color:#6a8759;">six</span>: <span style="color:#6897bb;">6</span><span style="color:#e8bf6a;font-weight:bold;">] </span><span style="color:#cc7832;">as </span>TreeBidiMap<br><span style="color:#cc7832;">assert </span>six.inverseBidiMap() == [<span style="color:#6897bb;"> [...]
+
+<h3>Further Information</h3>
+
+<ul><li>GPars (<a href="http://gpars.org/" target="_blank">website</a>)</li><li>Eclipse Collections (<a href="https://www.eclipse.org/collections/" target="_blank">website</a> and <a href="https://github.com/eclipse/eclipse-collections" target="_blank">github site</a>)</li><li>Guava (<a href="https://github.com/google/guava/wiki" target="_blank">user guide</a>)</li><li>Apache Commons Collections (<a href="https://commons.apache.org/proper/commons-collections/" target="_blank">website</a> [...]
+
+<h3>Conclusion</h3>
+
+<p>We have looked at the more common methods for list processing with Groovy and a few other useful libraries.</p><p><br></p>
diff --git a/site/src/site/blog/groovy-release-train-4-0.md b/site/src/site/blog/groovy-release-train-4-0.md
new file mode 100644
index 0000000..a44d950
--- /dev/null
+++ b/site/src/site/blog/groovy-release-train-4-0.md
@@ -0,0 +1,10 @@
+---
+layout: post
+title: 'Groovy release train: 4.0.4, 3.0.12, 2.5.18'
+date: '2022-07-24T12:55:23+00:00'
+permalink: groovy-release-train-4-0
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/c5ba5e59-737e-4ebf-91c9-08fa67dc8f70" align="right" style="width:20%;" alt="groovy.png"><span style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;"><i>It's been a productive time for the Apache Groovy project recently. We recently released versions 4.0.4, 3.0.12 and 2.5.18 with 42, 21 and 15 fixes and improvements respectively. Two quick highlights for the 4.0.4 release before getting into m [...]
+<p><span style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;"><i>Eric Milles has been interacting for many months with the team from the <a href="https://github.com/hephaestus-compiler-project/hephaestu" target="_blank">hephaestus project</a> in particular Stefanos Chaliasos and Thodoris Sotiropoulos. You can think of hephaestus as a fuzzying tool for type checkers and they have been putting Groovy's static compiler through its paces finding plenty [...]
+<p><i style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;">We've also had some great contributions from Sandip Chitale for Groovy's Object Browser. You can access this from a number of ways including the <code>:inspect</code> command in groovysh or in the GroovyConsole via the <code>Script-&gt;Inspect Last</code> or <code>Script-&gt;Inspect Variables</code> menu items. It's also hooked into the AST Browser if you're exploring code produced by the G [...]
+<p></p><hr><p></p><p><span style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;">Dear community,</span><br></p><p><br style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;"><span style="color: rgb(34, 34, 34); font-family: Arial, Helvetica, sans-serif; font-size: small;">The Apache Groovy team is pleased to announce version 4.0.4 of Apache Groovy.</span><br style="color: rgb(34, 34, 34); font-family: Arial, Helv [...]
diff --git a/site/src/site/blog/jvm-hello-world-with-groovy.md b/site/src/site/blog/jvm-hello-world-with-groovy.md
new file mode 100644
index 0000000..0c4beb5
--- /dev/null
+++ b/site/src/site/blog/jvm-hello-world-with-groovy.md
@@ -0,0 +1,88 @@
+---
+layout: post
+title: JVM Hello World with Groovy
+date: '2022-12-22T14:24:07+00:00'
+permalink: jvm-hello-world-with-groovy
+---
+<p>For those that haven't seen it yet, the <a href="https://www.javaadvent.com/" target="_blank">JVM Advent</a> <a href="https://twitter.com/JavaAdvent" target="_blank">folks</a> posted a great <a href="https://www.javaadvent.com/2022/12/groovy-and-data-science.html" target="_blank">Groovy and Data Science blog post</a> several days ago as part of the 2022 JVM Advent series. If you have an interest in Data Science, we recommend you check that out before continuing with this post.</p><p>< [...]
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println <span style="color:#6a8759;">'Hello world'<br></span></pre>
+
+<p>The examples shown in this blog post illustrate how you could create the equivalent class file using libraries which let you manipulate the generated bytecode directly. It's a bit of a deep dive if you want to know more about JVM internals and can also be handy for numerous use cases like building tools or&nbsp;modifying Java classes on the fly. I suggest you read the web sites for those libraries if you want further details or additional motivation.</p>
+
+<h3>ProGuardCORE</h3>
+
+<p>The ProGuardCORE library lets you&nbsp;read, analyze, modify, and write Java class files. Here's how we could use it to write a hello world class file:</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>name = <span style="color:#6a8759;">'HelloProGuardCORE'<br></span><span style="color:#cc7832;">var </span>superclass = <span style="color:#6a8759;">'java/lang/Object'<br></span><span style="color:#cc7832;">var </span>classBuilder = <span style="color:#cc7832;">new </span>ClassBuilder(<span style="color:#9876aa;font-style:italic;">CLASS_VERSIO [...]
+
+<p>This is essentially the "<i>Groovified</i>" version of the example in the JVM Advent blog post. We are using the libraries <code>ClassBuilder</code> class, adding a method, then adding four bytecode statements as the body of the method. If you haven't seen method and type descriptor syntax before, a few parts might seem a little strange but you possibly won't be surprised that it seems to be referencing a <code>System.out.println</code> call and passing it a constant String.</p>
+<p>When we run this script, a <code>HelloProGuardCORE</code> class file is produced. We can invoke that class file in the normal way:</p>
+<pre>$ java HelloProGuardCORE
+Hello from HelloProGuardCORE
+</pre>
+
+<p>We encourage you to read the JVM Advent post or the library documentation if you want more details.</p>
+
+<h3>ASM</h3>
+
+<p><a href="https://asm.ow2.io/" target="_blank">ASM</a> is an all purpose Java bytecode manipulation and analysis framework. In fact, it's the one that Groovy uses in its parser and some of its tools. Here is how to use it to generate more or less the same class as previously:</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>name = <span style="color:#6a8759;">'HelloASM'<br></span><span style="color:#cc7832;">var </span>superclass = <span style="color:#6a8759;">'java/lang/Object'<br></span><span style="color:#cc7832;">var </span>cw = <span style="color:#cc7832;">new </span>ClassWriter(<span style="color:#6897bb;">0</span>)<br>cw.visit(<span style="color:#9876aa;f [...]
+
+<p>After running this script, a <code>HelloASM</code> class file is produced, and here is the output when running that class file:</p>
+<pre>$ java HelloASM
+Hello from HelloASM
+</pre>
+
+<p>Parts of the code should look familiar to the previous example.</p>
+
+<h3>Byte Buddy</h3>
+
+<p><a href="https://bytebuddy.net/" target="_blank">Byte Buddy</a> is a code generation and manipulation library for creating and modifying Java classes. It's strengths lie in its ability to create and modify classes dynamically. So, its power is perhaps not needed for our simple example. A nice aspect of this library however, is that it hides some of the low-level details like type and method descriptors behind its fluent API. Here is our example:<br></p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">var </span>name = <span style="color:#6a8759;">'HelloByteBuddy'<br></span><span style="color:#cc7832;">new </span>ByteBuddy()<br>    .subclass(Object)<br>    .name(name)<br>    .defineMethod(<span style="color:#6a8759;">'main'</span>, Void.<span style="color:#9876aa;font-style:italic;">TYPE</span>, <span style="color:#9876aa;font-style:italic;">PUBLIC < [...]
+
+<p>Like the other scripts, this also produces a class file which we can invoke as shown here:</p>
+<pre>$ java HelloByteBuddy
+Hello from HelloByteBuddy
+</pre>
+
+<p>That wraps up our examples using the three libraries, but we have one more fun
+alternative to cover!</p>
+
+<h3>Using Groovy ASTs</h3>
+
+<p>Groovy is a very extensible language. It provides among other things, a compile-time
+metaprogramming mechanism called AST Transforms (Abstract Syntax Tree Transformations). This mechanism uses annotations to indicate to the compiler that special processing is required during compilation. A now somewhat outdated AST transform, <a href="https://github.com/melix/groovy-bytecode-ast" target="_blank">@Bytecode</a>, experimented with allowing you to write bytecode instructions directly in your Groovy code. Let's look at using that AST transform here:</p>
+
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#bbb529;">@CompileStatic @POJO<br></span><span style="color:#cc7832;">class </span>HelloAST {<br>    <span style="color:#bbb529;">@Bytecode<br></span><span style="color:#bbb529;">    </span><span style="color:#cc7832;">static void </span>main(args) {<br>        getstatic <span style="color:#6a8759;">'java/lang/System.out'</span>, <span style="color:#6a8759;">'Lja [...]
+
+<p>We are writing directly the instructions that the Java or Groovy compiler (with static compilation enabled) would produce. For this example, we don't run the script to produce the class file, we just compile it using the Groovy compiler.</p><p>We definitely don't recommend relying on the <code>@Bytecode</code> AST transform for any production code but it can be fun to play with. We've also used the <code>@CompileStatic</code> and <code>@POJO</code> AST transforms to tell the compiler  [...]
+
+<pre>  public static void main(java.lang.String...);
+    descriptor: ([Ljava/lang/String;)V
+    flags: (0x0089) ACC_PUBLIC, ACC_STATIC, ACC_VARARGS
+    Code:
+      stack=2, locals=1, args_size=1
+         0: getstatic     #21                 // Field java/lang/System.out:Ljava/io/PrintStream;
+         3: ldc           #23                 // String Hello from HelloAST
+         5: invokevirtual #29                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
+         8: return
+      LocalVariableTable:
+        Start  Length  Slot  Name   Signature
+            0       9     0  args   Ljava/lang/Object;
+</pre>
+<p>Because the code is not calling the Groovy runtime, we can invoke it directly without the Groovy jar:</p>
+<pre>$ java HelloAST
+Hello from HelloAST
+</pre>
+
+<p>That wraps up our little tour of bytecode libraries. I hope you have learnt some additional JVM details!</p>
+
+<h3>Further information</h3>
+
+<ul>
+<li><a href="https://github.com/paulk-asert/bytecode-fun" target="_blank">Github repo</a> of the above examples</li><li>A <a href="https://openjdk.org/jeps/8280389" target="_blank">draft JEP</a> for what might become an official API for parsing, generating, and transforming Java class files</li>
+<li>Social media:&nbsp;<a href="https://twitter.com/ApacheGroovy" target="_blank">@ApacheGroovy</a> <a href="https://fosstodon.org/@ApacheGroovy" target="_blank">@ApacheGroovy@fosstodon.org</a></li>
+</ul>
diff --git a/site/src/site/blog/life-on-mars-units-of.md b/site/src/site/blog/life-on-mars-units-of.md
new file mode 100644
index 0000000..3e0603d
--- /dev/null
+++ b/site/src/site/blog/life-on-mars-units-of.md
@@ -0,0 +1,66 @@
+---
+layout: post
+title: 'Life on Mars: Units of Measurement systems, Groovy, and domain specific languages
+  (DSLs)'
+date: '2022-08-13T06:31:47+00:00'
+permalink: life-on-mars-units-of
+---
+<p><img src="https://avatars.githubusercontent.com/u/6383598?s=200&amp;v=4" align="right">The Mars Climate Orbiter was launched in 1998 as part of a multi-faceted Mars exploration program. It was lost due to a trajectory calculation error when nearing Mars. An <a href="http://scholar.google.com/scholar?hl=en&amp;q=Stephenson+A%2C+LaPiana+L%2C+Mulville+D%2C+et+al.+Mars+climate+orbiter+mishap+investigation+board+phase+1+report%3B+1999.+https%3A%2F%2Fllis.nasa.gov.+Accessed+October+14%2C+20 [...]
+<p><img src="https://upload.wikimedia.org/wikipedia/commons/thumb/1/19/Mars_Climate_Orbiter_2.jpg/1280px-Mars_Climate_Orbiter_2.jpg" alt="Mars Climate Orbiter - image credit: wikipedia" style="width:50%"></p><p>If the system in question had been developed using a units of measurement system, perhaps the failure could have been avoided.</p>
+
+<h3>Units of measurement systems</h3>
+
+<p>All programming languages have types for representing numbers. As an example, we may have three integers, one representing a height, one a weight and one a temperature. We can write code to add those three integers together, but the result may have no useful meaning. We could start writing our own class hierarchies for each integer type but it can quickly become cumbersome to use the resulting classes. Units of measurement systems attempt to provide a range of commonplace units, ways  [...]
+
+<h3>JSR 385: Units of Measurement API 2.0</h3>
+
+<p>The first thing we need to do is bring in our dependencies (shown for <a href="https://gradle.org/" target="_blank">Gradle</a> - <a href="https://mvnrepository.com/artifact/tech.units/indriya/2.1.3" target="_blank">other options</a>). The main one is the reference implementation (it brings in the <code>javax.measure</code> API transitively):</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">implementation <span style="color: [...]
+<pre>639000000000000000000000 kg
+6779 km
+</pre>
+<p>If we try to compare or add those two values, we'll see an error. Groovy has both static and dynamic natures. Using dynamic code like this:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println mass<span style="font-family:'Courier New',monospace;">ₘ </span>&gt; diameter<span style="font-family:'Courier New',monospace;">ₘ<br></span></pre>
+<p>We'll see a runtime error like this:</p>
+<pre><span style="color:#D03030;">javax.measure.IncommensurableException: km is not compatible with kg</span></pre>
+<p>Or, with <code>TypeChecked</code> or <code>CompileStatic</code> in play for a statement like this:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println mass<span style="font-family:'Courier New',monospace;">ₘ</span>.add(diameter<span style="font-family:'Courier New',monospace;">ₘ</span>)</pre><p>We'd see a compile-time error like this:</p>
+<pre><span style="color:#d03030">[Static type checking] - Cannot call tech.units.indriya.ComparableQuantity#add(javax.measure.Quantity&lt;javax.measure.quantity.<b>Mass</b>&gt;)
+with arguments [tech.units.indriya.ComparableQuantity&lt;javax.measure.quantity.<b>Length</b>&gt;]</span></pre>
+<p>If for some strange reason we did want to compare or perform calculations between incommensurable types, we can explicitly get the value:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">assert </span>mass<span style="font-family:'Courier New',monospace;">ₘ</span>.<span style="color:#9876aa;">value </span>&gt; diameter<span style="font-family:'Courier New',monospace;">ₘ</span>.<span style="color [...]
+<pre>-128 ℃
+-198.400 ((K*5)/9)+459.67
+70 ((K*5)/9)+459.67
+21.1111111111111111111111111111111 ℃
+min= -128 ℃, max= 70 ((K*5)/9)+459.67</pre>
+<p>In case you're wondering about the strange looking unit display for Fahrenheit temperatures, the definition of that unit that we are using, defines degrees Fahrenheit using a formula calculated from the temperature in degrees Kelvin.</p><p>We'd see the same thing if using the <code>MILE</code> unit:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">println diameter<span style="font-family:'Courier New',monospace;">ₘ</span>.to(<span style="color:#9876aa;font-style:italic;">MILE</span>)<br></pre><p>Which shows us that the diameter of Mars is a little over 4200 miles:</p>
+<pre>4212.275312176886980036586335798934 (m*1609344)/1000</pre>
+
+<h3>Adding some metaprogramming</h3>
+
+<p>Groovy has various features which allow methods to be (apparently) added to classes. We'll use extension methods. This technique involves writing static methods in a helper class using certain conventions. The first parameter in all such methods is the target of the extension. Groovy code referencing instances of the target class have code that can call such a method as if it existed on the target class. In reality, the Groovy compiler or runtime funnels the call through the helper cl [...]
+<h3>A dynamic DSL for controlling a Mars Rover</h3>
+
+<p>Let's now look at how you could write a little Domain-Specific-Language (DSL) to control a Mars rover robot.</p>
+<p><img src="https://upload.wikimedia.org/wikipedia/commons/f/f3/Curiosity_Self-Portrait_at_%27Big_Sky%27_Drilling_Site.jpg" alt="Mars Rover Selfie - image credit: wikipedia" style="width:40%;"></p>
+
+<p>First, we'll write a <code>Direction</code> enum as part of our robot domain model:<br></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">enum </span>Direction {<br>    <span style="color:#9876aa;font-style:italic;">left</span>, <span style="color:#9876aa;font-style:italic;">right</span>, <span style="color:#9876aa;font-style:italic;">forward</span>, <span style="color:#9876aa;font-style:italic;" [...]
+<h3>A type-rich DSL for the Rover</h3>
+<p>Now, instead of using our nested map style we saw previously, we create several richly-typed helper classes and define our <code>move</code> method in terms of those classes:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">class </span>MoveHolder {<br>    Direction <span style="color:#9876aa;">dir<br></span><span style="color:#9876aa;">    </span>ByHolder by(Quantity&lt;Length&gt; dist) {<br>   [...]
+<p>We'll now see a compile-time error:</p>
+<pre><span style="color:#C03030;">[Static type checking] - Cannot call MoveHolder#by(javax.measure.Quantity&lt;javax.measure.quantity.<b>Length</b>&gt;) with arguments [javax.measure.Quantity&lt;javax.measure.quantity.<b>Mass</b>&gt;]
+</span></pre>
+<p>It is great to get this additional earlier feedback on script errors, so you may wonder why we don't write our DSL implementations like this all of the time? Actually, both the dynamic and static flavors of our DSL can be useful at different times. When prototyping our script DSL, deciding on all the nouns and verbs that we should be using to control our robot, the dynamic flavored style can be much quicker to write especially during early iterations which might evolve and change rapi [...]
+
+<h3>Adding custom type checking</h3>
+
+<p>There is one additional language feature of Groovy we haven't mentioned. Groovy's type checking mechanism is extensible, so we'll have a look at using that feature here. The rover's speed is <a href="https://mars.nasa.gov/mars2020/spacecraft/rover/wheels/" target="_blank">rather limited</a>, "<i>In the case of exploring Mars, however, speed isn't the most relevant quality. It's about the journey and the destinations along the way. The slow pace is energy-efficient...</i>". Let's look  [...]
+<pre><span style="color:#C03030;">[Static type checking] - Speed of 6 is too fast!</span></pre>
+
+<h3>Further information</h3>
+
+<ul><li><a href="https://www.jcp.org/en/jsr/detail?id=385" target="_blank">JSR 385: Units of Measurement API 2.0</a></li><li><a href="https://unitsofmeasurement.github.io/2017/taste_of_indriya.html" target="_blank">A Taste of Indriya</a><br></li><li><a href="https://betterprogramming.pub/unit-and-measurement-in-swift-7c6be4a25586" target="_blank">Unit and Measurement in Swift</a></li><li><a href="https://docs.microsoft.com/en-us/archive/blogs/andrewkennedy/" target="_blank">Units of Meas [...]
+
+<h3>Conclusion</h3>
+
+<p>We have looked at using the JSR 385 <code>javax.measure</code> API using Groovy and added some DSL examples to make using the API a little nicer.</p>
diff --git a/site/src/site/blog/matrix-calculations-with-groovy-apache.md b/site/src/site/blog/matrix-calculations-with-groovy-apache.md
new file mode 100644
index 0000000..88b1542
--- /dev/null
+++ b/site/src/site/blog/matrix-calculations-with-groovy-apache.md
@@ -0,0 +1,119 @@
+---
+layout: post
+title: Matrix calculations with Groovy, Apache Commons Math, ojAlgo, Nd4j and EJML
+date: '2022-08-18T13:41:03+00:00'
+permalink: matrix-calculations-with-groovy-apache
+---
+<p>This blogs looks at performing matrix calculations with Groovy using various libraries:&nbsp;<a href="https://commons.apache.org/" target="_blank">Apache Commons</a> <a href="https://commons.apache.org/proper/commons-math/" target="_blank">Math</a>, <a href="https://www.ojalgo.org/" target="_blank">ojAlgo</a>, <a href="https://ejml.org/" target="_blank">EJML</a>, and <a href="https://deeplearning4j.konduit.ai/nd4j/tutorials/quickstart" target="_blank">Nd4j</a>&nbsp;(part of Eclipse <a [...]
+<h3>Fibonacci</h3><p>The Fibonacci sequence has origins in India centuries earlier but is named after the Italian author of the publication, <a href="https://en.wikipedia.org/wiki/Fibonacci_number" target="_blank">The Book of Calculation</a>, published in 1202. In that publication, Fibonacci proposed the sequence as a means&nbsp;to calculate the growth of&nbsp;idealized (biologically unrealistic)&nbsp;<span style="background-image: none; background-position: initial; background-size: ini [...]
+
+<pre>1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233</pre>
+
+<p>We can solve this problem using matrices. If we multiply the matrix <img src="https://blogs.apache.org/groovy/mediaresource/473d4a77-a5ea-4ccb-9d55-4936decf74f0" style="width:5%;" alt="2022-08-18 23_42_31-ASF Blogs_ Edit Entry.png">&nbsp;by itself <i>n</i> times we get&nbsp;<img src="https://blogs.apache.org/groovy/mediaresource/3aa6c41b-4458-400a-9350-b0b2fce0ca99" style="width:10%;" alt="2022-08-18 23_42_48-ASF Blogs_ Edit Entry.png">. This is an operation known as matrix exponentia [...]
+<h4>Apache Commons Math</h4><p>Let's explore solving this problem using Apache Commons Math. Apache Commons Math is a library of lightweight self-contained mathematics and statics components. Matrices are part of the linear algebra part of this library and for that context, matrices of double values are relevant. So, we'll represent our Fibonacci numbers as double values.</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span  [...]
+<pre>Array2DRowRealMatrix{{3.0,2.0},{2.0,1.0}}
+Array2DRowRealMatrix{{13.0,8.0},{8.0,5.0}}
+</pre>
+<p>We could go a little further and print the values from the matrix, but the result is clear enough. We see the values in the Fibonacci sequence appearing in the output.</p>
+<h4>EJML</h4><p>EJML (Efficient Java Matrix Library) is a linear algebra library for manipulating real, complex, dense, and sparse matrices. It is also a 100% Java solution. It has some novel features including import from Matlab and support for semirings (<a href="https://en.wikipedia.org/wiki/GraphBLAS" target="_blank">GraphBLAS</a>) which can be used for graph algorithms where a sparse matrix may be used to represent a graph as an adjacency matrix or incidence matrix.</p><p>We can do  [...]
+<pre>Type = DDRM , rows = 2 , cols = 2
+ 3.0000E+00  2.0000E+00 
+ 2.0000E+00  1.0000E+00 
+
+Type = DDRM , rows = 2 , cols = 2
+ 5.5000E+01  3.4000E+01 
+ 3.4000E+01  2.1000E+01
+</pre>
+<p>The first matrix has the same number as previously, and the second reveals the next numbers in the Fibonacci sequence (21, 34, and 55).</p>
+<h4>Nd4j</h4><p>Nd4j provides functionality available on Python to Java users. It&nbsp;contains a mix of numpy operations and tensorflow/pytorch operations. Nd4l makes use of native backends to allow it to work on different platforms and provide efficient operation when scaling up.</p><p>The code for our Fibonacci solution is very similar to EJML:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">de [...]
+<p>One feature that is different to the previous two libraries is that Nd4j supports <i>integer </i>matrices (as well as doubles and numerous other numerical and related types).</p><p>Running the script gives the following output:</p>
+<pre><span style="color:#d03030">...
+[main] INFO org.nd4j.linalg.factory.Nd4jBackend - Loaded [CpuBackend] backend
+...
+[main] INFO org.nd4j.linalg.cpu.nativecpu.CpuNDArrayFactory - Binary level Generic x86 optimization level AVX/AVX2
+[main] INFO org.nd4j.linalg.api.ops.executioner.DefaultOpExecutioner - Blas vendor: [OPENBLAS]
+...</span>
+[[         3,         2], 
+ [         2,         1]]
+[[       233,       144], 
+ [       144,        89]]
+</pre>
+<p>Again, the first matrix is the same as we have seen previously, the second has been bumped along the Fibonacci sequence by three more elements.</p>
+<h4>ojAlgo</h4><p>The next library we'll look at is ojAlgo (oj! Algorithms). It is an open source all-Java offering for mathematics, linear algebra and optimisation, supporting data science, machine learning and scientific computing. It claims to be the fastest pure-Java linear algebra library available and the project website provide links to numerous benchmarks backing that claim.<br></p><p>Here is the code for our Fibonacci example:</p><pre style="background-color:#2b2b2b;color:#a9b7c [...]
+<pre>org.ojalgo.matrix.Primitive64Matrix &lt; 2 x 2 &gt;
+{ { 3.0,	2.0 },
+{ 2.0,	1.0 } }
+org.ojalgo.matrix.Primitive64Matrix &lt; 2 x 2 &gt;
+{ { 987.0,	610.0 },
+{ 610.0,	377.0 } }
+</pre>
+<p>As expected, the first matrix is as we've seen before, while the second reveals the next three numbers in the sequence.</p><h4>Exploring the Vector API and EJML</h4>
+
+<p>From JDK16, various versions (JEPs&nbsp;<a href="https://openjdk.org/jeps/338" target="_blank" style="background-color: rgb(255, 255, 255);">338</a>,&nbsp;<a href="https://openjdk.org/jeps/414" target="_blank" style="background-color: rgb(255, 255, 255);">414</a>,&nbsp;<a href="https://openjdk.org/jeps/417" target="_blank" style="background-color: rgb(255, 255, 255);">417</a>,&nbsp;<a href="https://openjdk.org/jeps/426" target="_blank" style="background-color: rgb(255, 255, 255);">426 [...]
+<br><span style="color:#cc7832;">long </span>t0 = System.<span style="color:#9876aa;font-style:italic;">nanoTime</span>()<br><span style="color:#6897bb;">1000</span>.times <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>step1 = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">2</span>)<br>    result = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color:#6897b [...]
+<br></span><span style="color:#cc7832;">long </span>t1 = System.<span style="color:#9876aa;font-style:italic;">nanoTime</span>()<br><span style="color:#6897bb;">1000</span>.times <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>step1 = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">2</span>)<br>    result = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color [...]
+<br></span><span style="color:#cc7832;">long </span>t2 = System.<span style="color:#9876aa;font-style:italic;">nanoTime</span>()<br><span style="color:#6897bb;">1000</span>.times <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>step1 = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color:#6897bb;">2</span>, <span style="color:#6897bb;">2</span>)<br>    result = <span style="color:#cc7832;">new </span>SimpleMatrix(<span style="color [...]
+<br></span><span style="color:#cc7832;">long </span>t3 = System.<span style="color:#9876aa;font-style:italic;">nanoTime</span>()<br>printf <span style="color:#6a8759;">"Simple:    %6.2f ms</span><span style="color:#cc7832;">\n</span><span style="color:#6a8759;">"</span>, (t1 - t0)/<span style="color:#6897bb;">1000_000<br></span>printf <span style="color:#6a8759;">"Optimized: %6.2f ms</span><span style="color:#cc7832;">\n</span><span style="color:#6a8759;">"</span>, (t2 - t1)/<span style= [...]
+<pre><span style="color:#d03030">WARNING: Using incubator modules: jdk.incubator.vector</span>
+Simple:    116.34 ms
+Optimized:  34.91 ms
+Vector:     21.94 ms
+</pre>
+<p>We can see here that we have some improvement even for our trivial little calculation. Certainly, for biggest problems, the benefit of using the Vector API could be quite substantial.</p><p>We should give a big disclaimer here. This little microbenchmark using a loop of 1000 will give highly variable results and was just done to give a very simple performance comparison. For a more predictable comparison, consider running the <a href="https://github.com/openjdk/jmh" target="_blank">jm [...]
+
+<h3>Leslie Matrices</h3>
+
+<p>Earlier, we described the Fibonacci sequence as being for <i>unrealistic</i> rabbit populations, where rabbits never died and continued breeding forever. It turns out that Fibonacci matrices are a special case of a more generalised model which can model realistic rabbit populations (among other things). These are <a href="https://en.wikipedia.org/wiki/Leslie_matrix" target="_blank">Leslie matrices</a>. For Leslie matrices, populations are divided into classes, and we keep track of bir [...]
+<pre>Initial populations: {400; 400; 400}
+Population after 1 round: {1,080; 240; 120}
+Population after 2 rounds: {600; 648; 72}
+Population after 10 rounds: [3019, 2558, 365]</pre>
+<p>After the first round, we see many young roos but a worrying drop off in the older age groups. After the second round, only the oldest age group looks worryingly small. However, with the healthy numbers in the young generation, we can see that after 10 generations that indeed, the overall population is not at risk. In fact, overpopulation might become a problem.</p>
+
+<h3>Encryption with matrices</h3>
+
+<p>An early technique to encrypt a message was the <a href="https://en.wikipedia.org/wiki/Caesar_cipher" target="_blank">Caesar cipher</a>. It substitutes letters in the alphabet by the letter shifted a certain amount along in the alphabet, e.g. "IBM" becomes "HAL" if shifting to the previous letter and "VMS" becomes "WNT" if shifting one letter forward in the alphabet. This kind of cipher can be broken by looking at frequency analysis of letters or pattern words.</p><p>The <a href="http [...]
+<p>When run, it has the following output:</p>
+<pre>Original: GROOVY
+Encrypted: ĴŔŚWZc
+Decrypted: GROOVY
+</pre>
+<p>This offers far more security than the Caesar cipher, however, given today's computing availability, Hill ciphers can still eventually be broken with sufficient brute force. For this reason, Hill ciphers are seldom used on their own for encryption but they <i>are</i> often used in combination with other techniques to add diffusion - strengthening the security offered by the other techniques.</p>
+
+<h3>Shape manipulation</h3>
+
+<p>Our final example looks at geometrically transforming shapes. To do this, we represent the points of the shape as vectors and multiply them using transforms represented as matrices. We need only worry about the corners, since we'll use Swing to draw our shape and it has a method for drawing a polygon by giving its corners.</p>
+<p>First we'll use Groovy's SwingBuilder to set up our frame:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">new </span>SwingBuilder().edt <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">def </span>frame = frame(<span style="color:#6a8759;">title</span>: <span style="color:#6a8759;">'Shapes'</span>, <span style="color:#6a8759;">size</span>: [<span style="color:#6897bb;">420</span>, <span style [...]
+<p>We aren't really use much of SwingBuilder's functionality here but if we wanted to add more functionality, SwingBuilder would make that task easier.</p>
+<p>We will actually draw our shapes within a custom component. We'll define a few color constants, a <code>drawPolygon</code> method which given a matrix of points will draw those points as a polygon. We'll also define a <code>vectors</code> method to convert a list of points (the corners) into vectors, and a <code>transform</code> method which is a factory method for creating a transform matrix.</p><p>Here is the code:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'J [...]
+        ...<br></span><br>        <span style="color:#cc7832;">def </span>rectangle = <span style="color:#9876aa;font-style:italic;">vectors</span>([<span style="color:#6897bb;">0</span>, -<span style="color:#6897bb;">110</span>], [<span style="color:#6897bb;">0</span>, -<span style="color:#6897bb;">45</span>], [<span style="color:#6897bb;">95</span>, -<span style="color:#6897bb;">45</span>], [<span style="color:#6897bb;">95</span>, -<span style="color:#6897bb;">110</span>])<br>        g [...]
+        ...<br></span><br>        <span style="color:#cc7832;">def </span>trapezoid = <span style="color:#9876aa;font-style:italic;">vectors</span>([<span style="color:#6897bb;">50</span>, <span style="color:#6897bb;">50</span>], [<span style="color:#6897bb;">70</span>, <span style="color:#6897bb;">100</span>], [<span style="color:#6897bb;">100</span>, <span style="color:#6897bb;">100</span>], [<span style="color:#6897bb;">120</span>, <span style="color:#6897bb;">50</span>])<br>        g [...]
+        ...<br></span><span style="font-weight:bold;">    </span>}<br>}</pre><p>When we run this code we see our three shapes:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/2050e66e-86ef-4307-a1bf-dde13b786bdc" style="width:50%;;border: 1px solid #555;" alt="2022-08-18 00_02_11-Shapes.png"><br></p><p>We can now add our transforms. We'll have one which rotate by 90 degrees anti-clockwise. Another which enlarges a shape by 25% and one that shrinks a shape by 25%. We can com [...]
+
+<h3>Language and tool extensibility</h3>
+
+<p>We saw earlier that some of the examples could make use of Groovy operator shorthand syntax, while others couldn't. Here is a summary of some common methods in the libraries:</p>
+<p></p><table style="border:1px solid gray; margin:5px;"><tbody>
+<tr style="background-color:#ADD8E6"><td style="text-align:center;padding:5px;">Groovy operator</td><td style="text-align:center;padding:5px;">+</td><td style="text-align:center;padding:5px;">-</td><td style="text-align:center;padding:5px;">*</td><td style="text-align:center;padding:5px;">**</td></tr>
+<tr style="background-color:#ADD8E6"><td style="text-align:center;padding:5px;">Groovy method</td><td style="text-align:center;padding:5px;">plus</td><td style="text-align:center;padding:5px;">minus</td><td style="text-align:center;padding:5px;">multiply</td><td style="text-align:center;padding:5px;">power</td></tr>
+<tr><td style="text-align:center;padding:5px;">Commons math</td><td style="text-align:center;padding:5px;">add</td><td style="text-align:center;padding:5px;">subtract</td><td style="text-align:center;padding:5px;">multiply</td><td style="text-align:center;padding:5px;">power</td></tr>
+<tr><td style="text-align:center;padding:5px;">EJML</td><td style="text-align:center;padding:5px;">plus</td><td style="text-align:center;padding:5px;">minus</td><td style="text-align:center;padding:5px;">mult</td><td style="text-align:center;padding:5px;">-</td></tr>
+<tr><td style="text-align:center;padding:5px;">Nd4j</td><td style="text-align:center;padding:5px;">add</td><td style="text-align:center;padding:5px;">sub</td><td style="text-align:center;padding:5px;">mmul</td><td style="text-align:center;padding:5px;">-</td></tr>
+<tr><td style="text-align:center;padding:5px;">ojAlgo</td><td style="text-align:center;padding:5px;">add</td><td style="text-align:center;padding:5px;">subtract</td><td style="text-align:center;padding:5px;">multiply</td><td style="text-align:center;padding:5px;">power</td>
+</tr></tbody></table><p>
+</p><p>Where the library used the same name as Groovy's method, the shorthand could be used.</p><p>Groovy offers numerous extensibility features. We won't go into all of the details but instead refer readers to the <a href="https://dl.acm.org/doi/abs/10.1145/3386326" target="_blank">History of Groovy</a> paper which gives more details.</p><p>In summary, that paper defined the following extensions for Commons Math matrices:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family [...]
+
+<h3>Further information</h3>
+
+<ul>
+<li>Apache Commons Math <a href="https://commons.apache.org/proper/commons-math/userguide/linear.html" target="_blank">User Guide</a>&nbsp;and <a href="https://github.com/apache/commons-math" target="_blank">github mirror</a><br></li>
+<li>ojAlgo <a href="https://www.ojalgo.org/" target="_blank">website</a>&nbsp;and <a href="https://github.com/optimatika/ojAlgo/" target="_blank">github repo</a></li>
+<li>EJML <a href="http://ejml.org/" target="_blank">website</a> and <a href="https://github.com/lessthanoptimal/ejml" target="_blank">github repo</a></li><li>Nd4j <a href="https://deeplearning4j.konduit.ai/nd4j/tutorials/quickstart" target="_blank">documentation</a>&nbsp;and <a href="https://github.com/eclipse/deeplearning4j/tree/master/nd4j" target="_blank">github repo</a></li>
+<li><a href="https://github.com/paulk-asert/MatrixGroovy" target="_blank">Example code repo</a></li><li><a href="https://www.youtube.com/watch?v=I5WM2wdjr1M" target="_blank">Leslie Matrices for population age distribution modelling</a>&nbsp;video</li>
+<li><a href="https://dl.acm.org/doi/abs/10.1145/3386326" target="_blank">A history of the Groovy programming language</a>&nbsp;paper</li>
+<li><a href="https://medium.com/@Styp/java-18-vector-api-do-we-get-free-speed-up-c4510eda50d2" target="_blank">Java 18: Vector API — Do we get free speed-up?</a> blog post<br></li></ul>
+
+<h3>Conclusion</h3>
+
+<p>We have examined a number of simple applications of matrices using the Groovy programming language and the Apache Commons Math, ojAlgo, Nd4j, and JEML libraries. You should be convinced that using matrices on the JVM isn't hard and you have numerous options. We also saw a brief glimpse at the Vector API which looks like an exciting addition to the JVM (hopefully arriving soon in non-preview mode).</p><p><br></p>
diff --git a/site/src/site/blog/natural-language-processing-with-groovy.md b/site/src/site/blog/natural-language-processing-with-groovy.md
new file mode 100644
index 0000000..7155aa8
--- /dev/null
+++ b/site/src/site/blog/natural-language-processing-with-groovy.md
@@ -0,0 +1,449 @@
+---
+layout: post
+title: Natural Language Processing with Groovy, OpenNLP, CoreNLP, Nlp4j, Datumbox,
+  Smile, Spark NLP, DJL and TensorFlow
+date: '2022-08-07T07:34:08+00:00'
+permalink: natural-language-processing-with-groovy
+---
+<p>Natural Language Processing is certainly a large and sometimes complex topic with many aspects. Some of those aspects deserve entire blogs in their own right. For this blog, we will briefly look at a few simple use cases illustrating where you might be able to use NLP technology in your own project.</p>
+
+<h3>Language Detection</h3>
+
+<p>Knowing what language some text represents can be a critical first step to subsequent processing. Let's look at how to predict the language using a pre-built model and <a href="https://opennlp.apache.org/" target="_blank">Apache OpenNLP</a>. Here, <code>ResourceHelper</code> is a utility class used to download and cache the model. The first run may take a little while as it downloads the model. Subsequent runs should be fast. Here we are using a well-known model referenced in the Open [...]
+<p>The <code>LanguageDetectorME</code> class lets us predict the language. In general, the predictor may not be accurate on small samples of text but it was good enough for our example. We've used the language code as the key in our map and we check that against the predicted language.</p><p>A more complex scenario is training your own model. Let's look at how to do that with <a href="https://www.datumbox.com/machine-learning-framework/" target="_blank">Datumbox</a>. Datumbox has a <a hr [...]
+</pre><p>Our test dataset will consist of some hard-coded illustrative phrases. Let's use our model to predict the language for each phrase:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">[   <span style="color:#6a8759;">'Bienvenido a Madrid'</span>, <span style="color:#6a8759;">'Bienvenue à Paris'</span>, <span style="color:#6a8759;">'Welcome to London'</span>,<br>    <span style="color:#6a8759;">'Willkommen in Berlin'</span>, <span style="color:#6a8759;">'Selamat Datang di Jakarta'<br></span>].each <span style="font-weight:bold;">{ </span>txt <span style="font-wei [...]
+<p>When run, it has this output:</p>
+<pre>Classifying: 'Bienvenido a Madrid',&nbsp; Predicted: Spanish,&nbsp; Probability: 0.83
+Classifying: 'Bienvenue à Paris',&nbsp; Predicted: French,&nbsp; Probability: 0.71
+Classifying: 'Welcome to London',&nbsp; Predicted: English,&nbsp; Probability: 1.00
+Classifying: 'Willkommen in Berlin',&nbsp; Predicted: German,&nbsp; Probability: 0.84
+Classifying: 'Selamat Datang di Jakarta',&nbsp; Predicted: Indonesian,&nbsp; Probability: 1.00
+</pre>
+<div>Given these phrases are very short, it is nice to get them all correct, and the probabilities all seem reasonable for this scenario.</div>
+
+<h3>Parts of Speech</h3>
+
+<p>Parts of speech (POS) analysers examine each part of a sentence (the words and potentially punctuation) in terms of the role they play in a sentence. A typical analyser will assign or annotate words with their role like identifying nouns, verbs, adjectives and so forth. This can be a key early step for tools like the voice assistants from Amazon, Apple and Google.</p><p> We'll start by looking at a perhaps lesser known library Nlp4j before looking at some others. In fact, there are mu [...]
+<pre>PRP(I) VBP(eat) NN(sushi) IN(with) NNS(chopsticks) .(.)</pre>
+<p>The annotations, also known as tags or facets, for this example are as follows:</p>
+
+<table style="border:1px solid gray; margin:5px;">
+<tbody><tr style="color:#9876aa;"><td style="padding:5px;">PRP</td><td style="padding:5px;">Personal pronoun</td></tr>
+<tr><td style="padding:5px;">VBP</td><td style="padding:5px;">Present tense verb</td></tr>
+<tr style="color:#9876aa;"><td style="padding:5px;">NN</td><td style="padding:5px;">Noun, singular</td></tr>
+<tr><td style="padding:5px;">IN</td><td style="padding:5px;">Preposition</td></tr>
+<tr style="color:#9876aa;"><td style="padding:5px;">NNS</td><td style="padding:5px;">Noun, plural</td></tr>
+</tbody></table>
+
+<p>The documentation for the libraries we are using give a more complete list of such annotations.</p><p>A nice aspect of this library is support for other languages, in particular, Japanese. The code is very similar but uses a different annotator:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">doc = <span style="color:#cc7832;">new </span>DefaultDocument()<br>doc.putAttribute(<span style="color:#6a8759;">'text'</span>, <spa [...]
+<p>When run, we see the following output:</p>
+<pre>名詞(私) 助詞(は) 名詞(学校) 助詞(に) 動詞(行き) 助動詞(まし) 助動詞(た) 記号(。)</pre>
+<p>Before progressing, we'll highlight the result visualization capabilities of the GroovyConsole. This feature lets us write a small Groovy script which converts results to any swing component. In our case we'll convert lists of annotated strings to a <code>JLabel</code> component containing HTML including colored annotation boxes. The details aren't included here but can be found in the <a href="https://github.com/paulk-asert/groovy-data-science/blob/master/subprojects/LanguageProcessi [...]
+<p><img src="https://blogs.apache.org/groovy/mediaresource/dab9114e-95d6-4dd6-a294-76be3d2e3a47" style="width:80%;" alt="Screenshot from 2022-08-04 21-57-35.png"></p>
+<p>Then we should see the following when running the script:</p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/8ed6c774-f2a5-40d9-94ac-89ecbf56132d" style="width:100%;" alt="Screenshot from 2022-08-04 21-59-47.png"></p>
+<p>The visualization is purely optional but adds a nice touch. If using Groovy in notebook environments like Jupyter/BeakerX, there might be visualization tools in those environments too.</p>
+<p>Let's look at a larger example using the <a href="https://haifengl.github.io/" target="_blank">Smile</a> library.</p>
+<p>First, the sentences that we'll examine:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>sentences = [<br>    <span style="color:#6a8759;">'Paul has two sisters, Maree and Christine.'</span>,<br>    <span style="color:#6a8759;">'No wise fish would go anywhere without a porpoise'</span>,<br>    <span style="color:#6a8759;">'His bark was much worse than his bite'</span>,<br>    <span s [...]
+<p>A couple of those sentences might seem a little strange but they are selected to show off quite a few of the different POS tags.</p><p>Smile has a tokenizer class which splits a sentence into words. It handles numerous cases like contractions and abbreviations ("e.g.", "'tis", "won't"). Smile also has a POS class based on the&nbsp;hidden Markov model and a built-in model is used for that class. Here is our code using those classes:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>tokenizer = <span style="color:#cc7832;">new </span>SimpleTokenizer(<span style="color:#cc7832;">true</span>)<br>sentences.each <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">def </span>tokens = Arrays.<span style="color:#9876aa;font-style:italic;">stream</span>(tokenizer.sp [...]
+
+<p></p><table style="background-color: white; margin: 5px; border: 1px solid gray"><tbody><tr><td style="padding: 5px;">
+  <table><tbody><tr><td style="padding: 5px; text-align: center; "><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Paul</span><br>
+        <span style="color:white;">NNP</span></div></td><td style="padding: 5px; text-align: center;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">has</span><br>
+        <span style="color:white;">VBZ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#DF401C;">
+        <span style="background-color:white; color:#DF401C;">two</span><br>
+        <span style="color:white;">CD</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">sisters</span><br>
+        <span style="color:white;">NNS</span></div></td><td style="text-align: center; padding: 5px;">, </td><td style="padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Maree</span><br>
+        <span style="color:white;">NNP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">and</span><br>
+        <span style="color:white;">CC</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Christine</span><br>
+        <span style="color:white;">NNP</span></div></td><td style="text-align: center; padding: 5px;">.</td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#895C9F;">
+        <span style="background-color:white; color:#895C9F;">No</span><br>
+        <span style="color:white;">DT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">wise</span><br>
+        <span style="color:white;">JJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">fish</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#FC5F00;">
+        <span style="background-color:white; color:#FC5F00;">would</span><br>
+        <span style="color:white;">MD</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">go</span><br>
+        <span style="color:white;">VB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">anywhere</span><br>
+        <span style="color:white;">RB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">without</span><br>
+        <span style="color:white;">IN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#895C9F;">
+        <span style="background-color:white; color:#895C9F;">a</span><br>
+        <span style="color:white;">DT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">porpoise</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#CD853F;">
+        <span style="background-color:white; color:#CD853F;">His</span><br>
+        <span style="color:white;">PRP$</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">bark</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#8B4513;">
+        <span style="background-color:white; color:#8B4513;">was</span><br>
+        <span style="color:white;">VBD</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">much</span><br>
+        <span style="color:white;">RB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#57411B;">
+        <span style="background-color:white; color:#57411B;">worse</span><br>
+        <span style="color:white;">JJR</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">than</span><br>
+        <span style="color:white;">IN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#CD853F;">
+        <span style="background-color:white; color:#CD853F;">his</span><br>
+        <span style="color:white;">PRP$</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">bite</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">Turn</span><br>
+        <span style="color:white;">VB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">on</span><br>
+        <span style="color:white;">IN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#895C9F;">
+        <span style="background-color:white; color:#895C9F;">the</span><br>
+        <span style="color:white;">DT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">lights</span><br>
+        <span style="color:white;">NNS</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">to</span><br>
+        <span style="color:white;">TO</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#895C9F;">
+        <span style="background-color:white; color:#895C9F;">the</span><br>
+        <span style="color:white;">DT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">main</span><br>
+        <span style="color:white;">JJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">bedroom</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Light</span><br>
+        <span style="color:white;">NNP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">'em</span><br>
+        <span style="color:white;">PRP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">all</span><br>
+        <span style="color:white;">RB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">up</span><br>
+        <span style="color:white;">RB</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">Make</span><br>
+        <span style="color:white;">VB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">it</span><br>
+        <span style="color:white;">PRP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">dark</span><br>
+        <span style="color:white;">JJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">downstairs</span><br>
+        <span style="color:white;">NN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+  </td></tr></tbody></table><p></p>
+
+<p>[Note: the scripts in the repo just print to stdout which is perfect when using the command-line or IDEs. The visualization in the GoovyConsole kicks in only for the actual result. So, if you are following along at home and wanting to use the GroovyConsole, you'd change the <code>each</code> to <code>collect</code> and remove the <code>println</code>, and you should be good for visualization.]</p><p>The OpenNLP code is very similar:</p><pre style="background-color:#2b2b2b;color:#a9b7c [...]
+<p></p><table style="background-color: white; margin:5px; border: 1px solid gray;"><tbody><tr><td style="padding: 5px;">
+  <table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Paul</span><br>
+        <span style="color:white;">PROPN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">has</span><br>
+        <span style="color:white;">VERB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#DF401C;">
+        <span style="background-color:white; color:#DF401C;">two</span><br>
+        <span style="color:white;">NUM</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">sisters</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">,</span><br>
+        <span style="color:white;">PUNCT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Maree</span><br>
+        <span style="color:white;">PROPN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#895C9F;">
+        <span style="background-color:white; color:#895C9F;">and</span><br>
+        <span style="color:white;">CCONJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Christine</span><br>
+        <span style="color:white;">PROPN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">.</span><br>
+        <span style="color:white;">PUNCT</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">No</span><br>
+        <span style="color:white;">DET</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">wise</span><br>
+        <span style="color:white;">ADJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">fish</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#FC5F00;">
+        <span style="background-color:white; color:#FC5F00;">would</span><br>
+        <span style="color:white;">AUX</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">go</span><br>
+        <span style="color:white;">VERB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">anywhere</span><br>
+        <span style="color:white;">ADV</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">without</span><br>
+        <span style="color:white;">ADP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">a</span><br>
+        <span style="color:white;">DET</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">porpoise</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">His</span><br>
+        <span style="color:white;">PRON</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">bark</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#FC5F00;">
+        <span style="background-color:white; color:#FC5F00;">was</span><br>
+        <span style="color:white;">AUX</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">much</span><br>
+        <span style="color:white;">ADV</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">worse</span><br>
+        <span style="color:white;">ADJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">than</span><br>
+        <span style="color:white;">ADP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">his</span><br>
+        <span style="color:white;">PRON</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">bite</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">Turn</span><br>
+        <span style="color:white;">VERB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">on</span><br>
+        <span style="color:white;">ADP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">the</span><br>
+        <span style="color:white;">DET</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">lights</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">to</span><br>
+        <span style="color:white;">ADP</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6AA4;">
+        <span style="background-color:white; color:#5B6AA4;">the</span><br>
+        <span style="color:white;">DET</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">main</span><br>
+        <span style="color:white;">ADJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">bedroom</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">Light</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">'</span><br>
+        <span style="color:white;">PUNCT</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">em</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#561B06;">
+        <span style="background-color:white; color:#561B06;">all</span><br>
+        <span style="color:white;">ADV</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#32CD32;">
+        <span style="background-color:white; color:#32CD32;">up</span><br>
+        <span style="color:white;">ADP</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+<table><tbody><tr><td style="padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">Make</span><br>
+        <span style="color:white;">VERB</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0000CD;">
+        <span style="background-color:white; color:#0000CD;">it</span><br>
+        <span style="color:white;">PRON</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#5B6633;">
+        <span style="background-color:white; color:#5B6633;">dark</span><br>
+        <span style="color:white;">ADJ</span></div></td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">downstairs</span><br>
+        <span style="color:white;">NOUN</span></div></td><td style="text-align: center; padding: 5px;"></td></tr></tbody></table>
+  </td></tr></tbody></table>
+
+<p>The observant reader may have noticed some slight differences in the tags used in this library. They are essentially the same but using slightly different names. This is something to be aware of when swapping between POS libraries or models. Make sure you look up the documentation for the library/model you are using to understand the available tag types.</p>
+
+<h3>Entity Detection</h3>
+
+<p>Named entity recognition (NER), seeks to identity and classify named entities in text. Categories of interest might be persons, organizations, locations dates, etc. It is another technology used in many fields of NLP.</p><p>We'll start with our sentences to analyse:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">String[] sentences = [<br>    <span style="color:#6a8759;">"A commit by Daniel Sun on December 6, 2020 improved Groovy 4's language integrated query."</span>,<br>    <span style="color:#6a8759;">"A commit by Daniel on Sun., December 6, 2020 improved Groovy 4's language integrated query."</span>,<br>    <span style="color:#6a8759;">'The Groovy in Action book by Dierk Koenig et. al.  [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>base = <span style="color:#6a8759;">'http://opennlp.sourceforge.net/models-1.5'<br></span><span style="color:#cc7832;">def </span>modelNames = [<span style="color:#6a8759;">'person'</span>, <span style="color:#6a8759;">'money'</span>, <span style="color:#6a8759;">'date'</span>, <span style="color:#6a8759;">'time'</span>, <span style="color:#6 [...]
+
+<p></p><table style="border:1px solid grey; margin:5px; background-color:white"><tbody><tr><td>
+  <table style="margin:5px;"><tbody><tr><td style="padding:5px;">A commit by </td><td style="text-align:center;"><div style="padding:5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Daniel Sun</span><br>
+        <span style="color:white;">person</span></div></td><td style="text-align: center; padding:5px;">on </td><td style="text-align:center;"><div style="padding:5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">December 6, 2020</span><br>
+        <span style="color:white;">date</span></div></td><td style="text-align: center; padding:5px;">improved Groovy 4's language integrated query.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="text-align: center; padding:5px;">A commit by </td><td style="text-align: center;"><div style="padding:5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Daniel</span><br>
+        <span style="color:white;">person</span></div></td><td style="text-align:center; padding:5px;">on Sun., </td><td style="text-align:center;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">December 6, 2020</span><br>
+        <span style="color:white;">date</span></div></td><td style="text-align: center; padding:5px;">improved Groovy 4's language integrated query.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="text-align: center; padding:5px;">The Groovy in Action book by </td><td style="text-align: center;"><div style="padding:5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Dierk Koenig</span><br>
+        <span style="color:white;">person</span></div></td><td style="text-align: center; padding:5px;">et. al. is a bargain at </td><td style="text-align:center;"><div style="padding:5px; background-color:#DF401C;">
+        <span style="background-color:white; color:#DF401C;">$50</span><br>
+        <span style="color:white;">money</span></div></td><td style="text-align: center; padding:5px;">, or indeed any price.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="text-align: center; padding:5px;">The conference wrapped up </td><td style="text-align: center;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">yesterday</span><br>
+        <span style="color:white;">date</span></div></td><td style="text-align: center; padding:5px;">at </td><td style="text-align:center;"><div style="padding:5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">5:30 p.m.</span><br>
+        <span style="color:white;">time</span></div></td><td style="text-align: center; padding:5px;">in </td><td style="text-align: center;"><div style="padding:5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">Copenhagen</span><br>
+        <span style="color:white;">location</span></div></td><td style="padding:5px;">, </td><td style="text-align:center;"><div style="padding: 5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">Denmark</span><br>
+        <span style="color:white;">location</span></div></td><td style="padding:5px;">.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="padding:5px;">I saw Ms. </td><td style="text-align:center;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">May Smith</span><br>
+        <span style="color:white;">person</span></div></td><td style="text-align: center; padding:5px;">waving to </td><td style="text-align:center;"><div style="padding:5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">June Jones</span><br>
+        <span style="color:white;">person</span></div></td><td style="text-align: center; padding:5px;">.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="padding:5px;">The parcel was passed from </td><td style="text-align:center;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">May to June</span><br>
+        <span style="color:white;">date</span></div></td><td style="padding:5px;">.</td></tr></tbody></table>
+<table style="margin:5px;"><tbody><tr><td style="padding:5px;">The Mona Lisa by </td><td style="text-align:center;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Leonardo da Vinci</span><br>
+        <span style="color:white;">person</span></div></td><td style="padding:5px;">has been on display in the Louvre, </td><td style="text-align:center;"><div style="padding:5px; background-color:#C54AA8;">
+        <span style="background-color:white; color:#C54AA8;">Paris</span><br>
+        <span style="color:white;">location</span></div></td><td style="text-align:center; padding:5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">since 1797</span><br>
+        <span style="color:white;">date</span></div></td><td>.</td></tr></tbody></table>
+  </td></tr></tbody></table><p></p>
+<p>We can see here that most examples have been categorized as we might expect. We'd have to improve our model for it to do a better job on the "May to June" example.</p>
+
+<h3>Scaling Entity Detection</h3>
+
+<p>We can also run our named entity detection algorithms on platforms like <a href="http://nlp.johnsnowlabs.com/" target="_blank">Spark NLP</a> which adds NLP functionality to <a href="https://spark.apache.org/" target="_blank">Apache Spark</a>. We'll use <a href="https://nlp.johnsnowlabs.com/2020/01/22/glove_100d.html" target="_blank">glove_100d</a> embeddings and the <a href="https://nlp.johnsnowlabs.com/2020/02/03/onto_100_en.html" target="_blank">onto_100</a> NER model.</p><pre style [...]
+<p>Here we have used a utility <code>SparkCategory</code> class which makes accessing the information in Spark <code>Row</code> instances a little nicer in terms of Groovy shorthand syntax. We can use <code>row.text</code> instead of <code>row.get(row.fieldIndex('text'))</code>. Here is the code for this utility class:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">class </span>SparkCategory {<br [...]
+<p>If doing more than this simple example, the use of <code>SparkCategory</code> could be made implicit through various standard Groovy techniques.</p>
+<p>When we run our script, we see the following output:</p>
+<pre>22/08/07 12:31:39 INFO SparkContext: Running Spark version 3.3.0
+...
+glove_100d download started this may take some time.
+Approximate size to download 145.3 MB
+...
+onto_100 download started this may take some time.
+Approximate size to download 13.5 MB
+...
++--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
+|                text|            document|               token|          embeddings|                 ner|           ner_chunk|
++--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
+|The Mona Lisa is ...|[{document, 0, 98...|[{token, 0, 2, Th...|[{word_embeddings...|[{named_entity, 0...|[{chunk, 0, 12, T...|
++--------------------+--------------------+--------------------+--------------------+--------------------+--------------------+
+PERSON(The Mona Lisa) is a DATE(16th century) oil painting created by PERSON(Leonardo). It's held at the FAC(Louvre) in GPE(Paris).
+</pre>
+<p>The result has the following visualization:</p>
+
+  <p></p><table style="border:1px solid grey; margin:5px; background-color:white;"><tbody><tr><td style="text-align: center; padding: 5px;">
+  <table style="margin:5px;"><tbody><tr><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">The Mona Lisa</span><br>
+        <span style="color:white;">PERSON</span></div></td><td style="text-align: center; padding: 5px;">is a </td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#2B5F19;">
+        <span style="background-color:white; color:#2B5F19;">16th century</span><br>
+        <span style="color:white;">DATE</span></div></td><td style="text-align: center; padding: 5px;">oil painting created by </td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#0088FF;">
+        <span style="background-color:white; color:#0088FF;">Leonardo</span><br>
+        <span style="color:white;">PERSON</span></div></td><td style="text-align: center; padding: 5px;">. It's held at the </td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#DF401C;">
+        <span style="background-color:white; color:#DF401C;">Louvre</span><br>
+        <span style="color:white;">FAC</span></div></td><td style="text-align: center; padding: 5px;">in </td><td style="text-align: center; padding: 5px;"><div style="padding: 5px; background-color:#A4772B;">
+        <span style="background-color:white; color:#A4772B;">Paris</span><br>
+        <span style="color:white;">GPE</span></div></td><td style="text-align: center; padding: 5px;">.</td></tr></tbody></table>
+  </td></tr></tbody></table><p></p>
+
+<p>Here FAC is facility (buildings, airports, highways, bridges, etc.) and GPE is Geo-Political Entity (countries, cities, states, etc.).</p>
+
+<h3>Sentence Detection</h3>
+
+<p>Detecting sentences in text might seem a simple concept at first but there are numerous special cases.</p><p>Consider the following text:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>text = <span style="color:#6a8759;">'''<br></span><span style="color:#6a8759;">The most referenced scientific paper of all time is "Protein measurement with the<br></span><span style="color:#6a8759;"> [...]
+<pre><span style="color:#D02020;">Downloading en-sent</span>
+Found 4 sentences:
+The most referenced scientific paper of all time is "Protein measurement with the
+Folin phenol reagent" by Lowry, O. H., Rosebrough, N. J., Farr, A. L. &amp; Randall,
+R. J. and was published in the J. BioChem. in 1951.
+
+It describes a method for
+measuring the amount of protein (even as small as 0.2 γ, were γ is the specific
+weight) in solutions and has been cited over 300,000 times and can be found here:
+https://www.jbc.org/content/193/1/265.full.pdf.
+
+Dr. Lowry completed
+two doctoral degrees under an M.D.-Ph.D. program from the University of Chicago
+before moving to Harvard under A. Baird Hastings.
+
+He was also the H.O.D of
+Pharmacology at Washington University in St. Louis for 29 years.</pre>
+<p>We can see here, it handled all of the tricky cases in the example.</p>
+
+<h3>Relationship Extraction with Triples</h3>
+
+<p>The next step after detecting named entities and the various parts of speech of certain words is to explore relationships between them. This is often done in the form of <i>subject-predicate-object</i> triplets. In our earlier NER example, for the sentence "<span style="background-color: rgb(245, 245, 245); color: rgb(51, 51, 51); font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; font-size: 13px;">The conference wrapped up yesterday at 5:30 p.m. in Copenhagen,  [...]
+<pre>Input sentence: The conference wrapped up yesterday at 5:30 p.m. in Copenhagen, Denmark.
+=============================
+Extractions:
+        Triple: "conference"    "wrapped up yesterday at"       "5:30 p.m."
+        Factuality: (+,CT)      Attribution: NONE
+        ----------
+        Triple: "conference"    "wrapped up yesterday in"       "Copenhagen"
+        Factuality: (+,CT)      Attribution: NONE
+        ----------
+        Triple: "conference"    "wrapped up"    "yesterday"
+        Factuality: (+,CT)      Attribution: NONE
+</pre>
+<p>We can now piece together the relationships between the earlier entities we detected.</p><p>There was also a problematic case amongst the earlier NER examples, "<span style="background-color: rgb(245, 245, 245); color: rgb(51, 51, 51); font-family: Menlo, Monaco, Consolas, &quot;Courier New&quot;, monospace; font-size: 13px;">The parcel was passed from May to June.</span>". Using the previous model, detected "<span style="background-color: rgb(245, 245, 245); color: rgb(51, 51, 51); f [...]
+<pre>Sentence #7: The parcel was passed from May to June.
+root(ROOT-0, passed-4)
+det(parcel-2, The-1)
+nsubj:pass(passed-4, parcel-2)
+aux:pass(passed-4, was-3)
+case(May-6, from-5)
+obl:from(passed-4, May-6)
+case(June-8, to-7)
+obl:to(passed-4, June-8)
+punct(passed-4, .-9)
+
+Triples:
+1.0	parcel	was	passed
+1.0	parcel	was passed to	June
+1.0	parcel	was	passed from May to June
+1.0	parcel	was passed from	May
+</pre>
+<p>We can see that this has done a better job of piecing together what entities we have and their relationships.</p>
+<h3>Sentiment Analysis</h3>
+
+<p>Sentiment analysis is a NLP technique used to determine whether data is positive, negative, or neutral. Standford CoreNLP has default models it uses for this purpose:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>doc = <span style="color:#cc7832;">new </span>Document(<span style="color:#6a8759;">'''<br></span><span style="color:#6a8759;">StanfordNLP is fantastic!<br></span><span st [...]
+<pre><span style="color:#D02020;">[main] INFO edu.stanford.nlp.parser.common.ParserGrammar - Loading parser from serialized file edu/stanford/nlp/models/lexparser/englishPCFG.ser.gz ... done [0.6 sec].</span>
+<span style="color:#C02020;">[main] INFO edu.stanford.nlp.sentiment.SentimentModel - Loading sentiment model edu/stanford/nlp/models/sentiment/sentiment.ser.gz ... done [0.1 sec].</span>
+StanfordNLP is fantastic!&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; POSITIVE
+Groovy is great fun!&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;VERY_POSITIVE
+Math can be hard!&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; NEUTRAL</pre>
+<p>We can also train our own. Let's start with two datasets:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>datasets = [<br>    <span style="color:#6a8759;">positive</span>: getClass().<span style="color:#9876aa;">classLoader</span>.getResource(<span style="color:#6a8759;">"rt-polarity.pos"</span>).toURI(),<br>    <span style="color:#6a8759;">negative</span>: getClass().<span style="co [...]
+
+<pre><span style="color:#D02020;">[main] INFO com.datumbox.framework.core.common.dataobjects.Dataframe$Builder - Dataset Parsing positive class
+[main] INFO com.datumbox.framework.core.common.dataobjects.Dataframe$Builder - Dataset Parsing negative class
+...</span>
+Classifier Accuracy (using training data): 0.8275959103273615
+</pre>
+
+<p>Now we can test our model against several sentences:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">[<span style="color:#6a8759;">'Datumbox is divine!'</span>, <span style="color:#6a8759;">'Groovy is great fun!'</span>, <span style="color:#6a8759;">'Math can be hard!'</span>].each <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">def </span>r = classifier.p [...]
+<pre><span style="color:#D02020;">...
+[main] INFO com.datumbox.framework.applications.nlp.TextClassifier - predict()
+...</span>
+Classifing: 'Datumbox is divine!',  Predicted: positive,  Probability: 0.83
+Classifing: 'Groovy is great fun!',  Predicted: positive,  Probability: 0.80
+Classifing: 'Math can be hard!',  Predicted: negative,  Probability: 0.95
+</pre>
+<p>We can do the same thing but with OpenNLP. First, we collect our input data. OpenNLP is expecting it in a single dataset with tagged examples:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>trainingCollection = datasets.collect <span style="font-weight:bold;">{ </span>k, v <span style="font-weight:bold;">-&gt;<br></span><span style="font-weight:bold;">    </span><span style="color:# [...]
+<p>Now, we'll train two models. One uses <i>naïve bayes</i>, the other <i>maxent</i>. We train up both variants.</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>variants = [<br>        <span style="color:#6a8759;">Maxent    </span>: <span style="color:#cc7832;">new </span>TrainingParameters(),<br>        <span style="color:#6a8759;">NaiveBayes</span>: <span style="color:#cc7832;">new </ [...]
+<pre>Training using Maxent ...done.
+...
+
+Training using NaiveBayes ...done.
+...
+
+Analyzing using Maxent
+OpenNLP is fantastic! positive (0.64)}
+Groovy is great fun!  positive (0.74)}
+Math can be hard!     negative (0.61)}
+
+Analyzing using NaiveBayes
+OpenNLP is fantastic! positive (0.72)}
+Groovy is great fun!  positive (0.81)}
+Math can be hard!     negative (0.72)}
+</pre>
+<p>The models here appear to have lower probability levels compared to the model we trained for Datumbox. We could try tweaking the training parameters further if this was a problem. We'd probably also need a bigger testing set to convince ourselves of the relative merits of each model. Some models can be over-trained on small datasets and perform very well with data similar to their training datasets but perform much worse for other data.</p>
+
+<h3>Universal Sentence Encoding</h3>
+
+<p>This example is inspired from the <a href="https://github.com/deepjavalibrary/djl/blob/master/examples/src/main/java/ai/djl/examples/inference/UniversalSentenceEncoder.java" target="_blank">UniversalSentenceEncoder</a> example in the <a href="https://github.com/deepjavalibrary/djl/tree/master/examples" target="_blank">DJL examples module</a>. It looks at using the universal sentence encoder model from <a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects" [...]
+
+<pre>Loading:     100% |========================================|
+<span style="color:#D02020;">2022-08-07 17:10:43.212697: ... This TensorFlow binary is optimized with oneAPI Deep Neural Network Library (oneDNN) to use the following CPU instructions in performance-critical operations:  AVX2
+...
+2022-08-07 17:10:52.589396: ... SavedModel load for tags { serve }; Status: success: OK...
+...</span>
+Embedding for: Cycling is low impact and great for cardio
+[-0.02865048497915268, 0.02069241739809513, 0.010843578726053238, -0.04450441896915436, ...]
+...
+Embedding for: The taste of radishes grows on you after a while
+[0.015841705724596977, -0.03129228577017784, 0.01183396577835083, 0.022753292694687843, ...]
+</pre>
+
+<p>The embeddings are an indication of similarity. Two sentences with similar meaning typically have similar embeddings.</p><p>The displayed graphic is shown below:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/812f4232-0334-4720-9408-9582489a93b4" style="width:100%;" alt="2022-08-06 22_18_05-Smile Plot 1.png"><br></p><p>This graphic shows that our first four sentences are somewhat related, as are the last four sentences, but that there is minimal relationship between tho [...]
+
+<h3>More information</h3>
+
+<p>Further examples can be found in the related repos:</p><p><a href="https://github.com/paulk-asert/groovy-data-science/blob/master/subprojects/LanguageProcessing" target="_blank">https://github.com/paulk-asert/groovy-data-science/blob/master/subprojects/LanguageProcessing</a></p><p><a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/LanguageProcessingSparkNLP" target="_blank">https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/Lang [...]
+
+<p>We have look at a range of NLP examples using various NLP libraries. Hopefully you can see some cases where you could use additional NLP technologies in some of your own applications.</p><p><br></p>
diff --git a/site/src/site/blog/parsing-json-with-groovy.md b/site/src/site/blog/parsing-json-with-groovy.md
new file mode 100644
index 0000000..0b915d5
--- /dev/null
+++ b/site/src/site/blog/parsing-json-with-groovy.md
@@ -0,0 +1,70 @@
+---
+layout: post
+title: Parsing JSON with Groovy
+date: '2022-07-10T14:00:51+00:00'
+permalink: parsing-json-with-groovy
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/e02078e2-6b0f-4086-a60c-e5f750910091" style="width: 10%;" align="right" alt="json logo">Groovy has excellent support for processing a range of structured data formats like JSON, TOML, YAML, etc. This blog post looks at <a href="https://www.json.org/json-en.html" target="_blank">JSON</a>.</p><p>There is quite good documentation on this topic as part of the <a href="https://groovy-lang.org/processing-json.html" target="_blank">Groo [...]
+<h3>Batteries included experience</h3>
+<p>If you have installed the Groovy installation zip (or .msi on windows), you will have the `groovy-json` module which includes&nbsp;<span style="font-family: &quot;JetBrains Mono&quot;, monospace;">JsonSlurper</span>, so the bulk of the examples shown here and in the other mentioned links should work out of the box.</p><p><span style="font-family: &quot;JetBrains Mono&quot;, monospace;">JsonSlurper</span>&nbsp;is the main class for parsing JSON.</p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/cf99e641-f03c-4627-bcc8-f7de9a7d3ba7" style="width: 75%;" alt="JsonSlurper in GroovyConsole"></p>
+<p>This example shows parsing JSON embedded in a string but there are other methods for parsing files, URLs and other streams.</p>
+<p>Another example using <span style="font-family:'JetBrains Mono',monospace;">groovysh</span>:</p>
+<p></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><font color="#4E9A06"><b>paulk@pop-os</b></font>:<font color="#3465A4"><b>~</b></font>$ groovysh
+<font color="#4E9A06">Groovy Shell</font> (4.0.3, JVM: 18.0.1)
+Type '<b>:help</b>' or '<b>:h</b>' for help.
+--------------------------------------------------------------------------------------------------
+<b>groovy:</b>000<b>&gt;</b> new groovy.json.JsonSlurper().parseText('{ "myList": [1, 3, 5] }').myList
+<b>===&gt;</b> [1, 3, 5]
+</pre><p></p>
+<p>Or using a Jupyter/BeakerX notebook:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/193552d7-2346-4387-adc6-4c83ac53fc19" style="width: 75%;" alt="JsonSlurper in Jupyter notebook"></p>
+
+<p>Similarly, if you point your IDE to your Groovy distribution, you should be able to run the examples directly.</p>
+<h3>Gradle</h3><p>If you are using a build tool like <a href="https://gradle.org/" target="_blank">Gradle</a><a href="https://gradle.org/" target="_blank"></a>, you may prefer to reference your dependencies from a dependency repository rather than having a locally installed distribution.</p>
+<p>Suppose you have the following test using <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">JsonSlurper</span> in the file <span style="font-family:'JetBrains Mono',monospace;">src/test/groovy/JsonTest.groovy</span>:</p>
+<p></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">import </span>groovy.json.<span style="color:#000000;">JsonSlurper<br></span><span style="color:#0033b3;">import </span>org.junit.<span style="color:#9e880d;">Test<br></span><span style="color:#9e880d;"><br></span><span style="color:#0033b3;">class </span><span style="color:#000000;">JsonTest </span>{<br>    <span style="color:#9e880d;">@Test<br> [...]
+<p>You can reference the relevant Groovy dependencies, in our case <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy-json</span> and <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy-test</span>, in a <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">build.gradle</span> file like below:<br></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">apply <span style="color:#0 [...]
+<p>Both these artifacts bring in the core <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy</span> artifact transitively, so there's no need to reference that explicitly.</p>
+<p>Running <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">gradle test</span> should run the tests and produce a report:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/869f376d-3973-4e50-bc7f-4814bba2e2b1" style="width: 50%;" alt="Test results for Class JsonTest.png"></p>
+
+<p>You can if you prefer, use the <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy-all</span> artifact like this:</p>
+<p></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">apply <span style="color:#067d17;">plugin</span>: <span style="color:#067d17;">'groovy'<br></span><span style="color:#067d17;"><br></span>repositories <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>mavenCentral()<br><span style="font-weight:bold;">}<br></span><span style="font-weight:bold;"><br></span>dependencies <span style="font-wei [...]
+
+<p>[<b>Note</b>: In early Groovy 4 versions you may have needed to reference Groovy as a platform, e.g.:&nbsp;<span style="color:#080808; font-family: &quot;JetBrains Mono&quot;, monospace;">testImplementation platform(</span><span style="font-family: &quot;JetBrains Mono&quot;, monospace; color:#067d17;">"org.apache.groovy:groovy-all:4.0.1")</span>. This is now only required when using the <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy-bom</span> artifact.]</p>
+
+<h3>Maven</h3>
+<p>When using the <a href="https://maven.apache.org/" target="_blank">Maven</a> build tool, you would instead create a <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">pom.xml</span> like this and make use of two plugins:&nbsp;<span style="color: rgb(8, 8, 8); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt;">gmavenplus-plugin </span>and&nbsp;<span style="color: rgb(8, 8, 8); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt;">mave [...]
+<p>Running the test should yield:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;">[<span style="color:#3465A4"><b>INFO</b></span>] -------------------------------------------------------
+[<span style="color:#3465A4"><b>INFO</b></span>]  T E S T S
+[<span style="color:#3465A4"><b>INFO</b></span>] -------------------------------------------------------
+[<span style="color:#3465A4"><b>INFO</b></span>] Running JsonTest
+[<span style="color:#3465A4"><b>INFO</b></span>] <span style="color:#4E9A06" <b="">Tests run: 1</span>, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.36 s - in JsonTest
+</pre>
+<h3>Advanced features</h3>
+<p>To cater for different scenarios, <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">JsonSlurper</span> is powered by several internal implementation classes. You don't access these classes directly but rather set a parser <i>type</i> when instantiating your slurper.</p>
+<p>
+</p><table cellspacing="0" cellpadding="0" border="1">
+<thead>
+<tr><th style="padding:2px">Type</th><th style="padding:2px">When to use</th></tr>
+</thead>
+<tbody>
+<tr><td style="padding:2px">CHAR_BUFFER</td><td style="padding:2px">Default, least surprise parser with eager parsing of ints, dates, etc.</td></tr>
+<tr><td style="padding:2px">INDEX_OVERLAY</td><td style="padding:2px">For REST calls, WebSocket messages, AJAX, inter process communication. Fastest parser which uses indexes to some existing char buffer.</td></tr>
+<tr><td style="padding:2px">CHARACTER_SOURCE</td><td style="padding:2px">For handling larger JSON files.</td></tr>
+<tr><td style="padding:2px">LAX</td><td style="padding:2px">Allows comments and no quotes or single quotes in numerous situations.</td></tr>
+</tbody></table>
+<p></p>
+<p>Here is an example:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">import </span>groovy.json.<span style="color:#000000;">JsonSlurper<br></span><span style="color:#0033b3;">import static </span>groovy.json.<span style="color:#000000;">JsonParserType</span>.*<br><br><span style="color:#0033b3;">def </span><span style="color:#000000;">slurper </span>= <span style="color:#0033b3;">new </span><spa [...]
+<h3>Other JSON libraries</h3>
+<p>Groovy doesn't require you to use the <span style="font-family: &quot;JetBrains Mono&quot;, monospace;">groovy-json</span> classes. You can use your favourite Java library with Groovy. You'll still benefit from many of Groovy's short-hand notations.</p><p>Here's an example using Gson:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#9e880d;">@Grab</span>(<span style="color:#067d17;">'com.google.code.gson [...]
+<h3>Integrated query</h3>
+<p>Groovy 4 also supports language integrated query syntax, known as GINQ or GQuery. We can use that with JSON too.</p><p>Suppose we have information in JSON format about fruits, their prices (per 100g) and the concentration of vitamin C (per 100g):<br></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">{<br>    <span style="color:#871094;">"prices"</span>: [<br>        {<span style="color:#871094;">"name"</span>: <span style="c [...]
+<h3>Quick performance comparison</h3>
+<p>As a very crude measure of performance, JsonSlurper with all 4 parser types as well as Gson and Jackson were used to parse the timezone values from&nbsp;<a href="https://github.com/flowcommerce/json-reference" target="_blank">https://github.com/flowcommerce/json-reference</a>&nbsp;and check that the current timezone in Brisbane is the same as the timezone in Sydney. The json file is by no means huge. It has just under 3000 lines and is under 60K in size. The best time taken (including [...]
+real    0m0.015s
+user    0m0.011s
+sys     0m0.004s
+</pre>
+<h3>Summary</h3>
+<p>We have seen the basics of setting up our projects to parse JSON using Groovy and some of the numerous options available to use depending on the scenario. We also saw how to use other JSON libraries, utilize GQuery syntax during our processing, and looked at some very crude performance figures.</p><p><br></p>
diff --git a/site/src/site/blog/reading-and-writing-csv-files.md b/site/src/site/blog/reading-and-writing-csv-files.md
new file mode 100644
index 0000000..9af686c
--- /dev/null
+++ b/site/src/site/blog/reading-and-writing-csv-files.md
@@ -0,0 +1,26 @@
+---
+layout: post
+title: Reading and Writing CSV files with Groovy
+date: '2022-07-25T14:26:20+00:00'
+permalink: reading-and-writing-csv-files
+---
+<p>In this post, we'll look at reading and writing CSV files using Groovy.</p>
+<h3>Aren't CSV files just text files?</h3>
+<p>For simple cases, we can treat CSV files no differently than we would other text files. Suppose we have the following data that we would like to write to a CSV file:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>data = [<br>        [<span style="color:#6a8759;">'place'</span>, <span style="color:#6a8759;">'firstname'</span>, <span style="color:#6a8759;">'lastname'</span>, <span style="color:#6a8759;">'team'</span>],<br>        [<span style="color:#6a8759;">'1'</span>, <span style="color:#6a8759;">'Lorena'</span>, <span style="color:#6a8759;">'Wiebes' [...]
+<p>Groovy uses <code>File</code> or <code>Path</code> objects similar to Java. We'll use a <code>File</code> object here and, for our purposes, we'll just use a temporary file since we are just going to read it back in and check it against our data. Here is how to create a temporary file:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>file = File.<span style="color:#9876aa;font-style:italic;">createTempFile</span>(<span style="color:#6a8759;">'FemmesStage1Podium'</span>, <span style="color:#6a8759;">'.csv'</span>)</pre>
+<p>Writing our CSV (in this simple example) is as simple as joining the data with commas and the lines with line separator character(s):</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">file.<span style="color:#9876aa;">text </span>= data*.join(<span style="color:#6a8759;">','</span>).join(System.<span style="color:#9876aa;font-style:italic;">lineSeparator</span>())</pre>
+<p>Here we "wrote" the entire file contents in one go but there are options for writing a line or character or byte at a time.</p><p>Reading the data in is just as simple. We read the lines and split on commas:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">assert </span>file.readLines()*.split(<span style="color:#6a8759;">'</span><span style="color:#6a8759;background-color:#364135;">,</span><spa [...]
+<p>In general, we might want to further process the data. Groovy provides nice options for this too. Suppose we have the following existing CSV file:<br>
+<img src="https://blogs.apache.org/groovy/mediaresource/0128cd28-23e8-42ca-b408-c2eaf1c82d1c" style="border:1px solid grey; width:60%;" alt="HommesOverall.png"><br>We can read in the file and select various columns of interest with code like below:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>file = <span style="color:#cc7832;">new </span>File(<span style="color:#6a8759;">'HommesStag [...]
+<h3>Commons CSV</h3>
+<p>The <a href="https://commons.apache.org/proper/commons-csv/" target="_blank">Apache Commons CSV</a> library makes writing and parsing CSV files easier. Here is the code for writing our CSV which makes use of the <code>CSVPrinter</code> class:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">file.withWriter <span style="font-weight:bold;">{ </span>w <span style="font-weight:bold;">-&gt;<br></span><span style="font-weight:bol [...]
+<h3>OpenCSV</h3>
+<p>The <a href="http://opencsv.sourceforge.net/" target="_blank">OpenCSV</a> library handles the messy CSV details when needed but doesn't get in the way for simple cases. For our first example, the <code>CSVReader</code> and <code>CSVWriter</code> classes will be suitable. Here is the code for writing our CSV file in the same way as earlier:<br></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">file.withWriter <span style="fon [...]
+<p>And here is the code for reading data:<br></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">file.withReader <span style="font-weight:bold;">{ </span>r <span style="font-weight:bold;">-&gt;<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">assert new </span>CSVReader(r).readAll() == data<br><span style="font-weight:bold;">}<br></span></pre><p>If we look at the produced file, it is already a li [...]
+<h3>Jackson Databind CSV</h3>
+<p>The <a href="https://github.com/FasterXML/jackson-databind" target="_blank">Jackson Databind</a> library supports the&nbsp;<a href="https://github.com/FasterXML/jackson-dataformats-text/tree/master/csv" target="_blank">CSV</a> format (as well as many others).</p><p>Writing CSV files from existing data is simple as shown here for running example:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">file.withWriter <span style="f [...]
+<h3>Conclusion</h3>
+<p>We have looked at writing and reading CSV files to Strings and domain classes and records. We had a look at handling simple cases by hand and also looked at the OpenCSV, Commons CSV and Jackson Databind CSV libraries.</p><p>Code for these examples:<br><a href="https://github.com/paulk-asert/CsvGroovy" target="_blank">https://github.com/paulk-asert/CsvGroovy</a><br></p><p>Code for other examples of using Groovy for Data Science:<br><a href="https://github.com/paulk-asert/groovy-data-sc [...]
diff --git a/site/src/site/blog/solving-cryptarithmetic-puzzles-with-groovy.md b/site/src/site/blog/solving-cryptarithmetic-puzzles-with-groovy.md
new file mode 100644
index 0000000..b5e2529
--- /dev/null
+++ b/site/src/site/blog/solving-cryptarithmetic-puzzles-with-groovy.md
@@ -0,0 +1,138 @@
+---
+layout: post
+title: Solving cryptarithmetic puzzles with Groovy and constraint programming using
+  Choco, JaCoP, and OR-Tools
+date: '2022-09-05T13:43:31+00:00'
+permalink: solving-cryptarithmetic-puzzles-with-groovy
+---
+<p><br></p>
+<h3>Introduction</h3><p>When writing solutions to problems, we frequently strive to hide away implementation details. In Object-oriented (OO) programming, we might build a rich hierarchy of classes with well-thought out methods so that our final solution can be expressed in terms of simple nouns and verbs (methods and class instances) in our domain model. When applying functional programming idioms, we will strive to emphasise the relationship between inputs and outputs and hide away sid [...]
+
+<h3>Cryptarithmetic Problems</h3>
+
+<p><a href="https://en.wikipedia.org/wiki/Verbal_arithmetic" target="_blank">Cryptarithmetic problems</a> (also known as alphametics, verbal arithmetic, cryptarithm, and word addition) are a type of mathematical game where a mathematical equation is presented where digits in the equation are replaced by letters. Traditionally, each letter usually represents a unique number, and numbers don't start with the digit zero. If we look at one <a href="https://en.wikipedia.org/wiki/Verbal_arithm [...]
+<p></p><p></p>
+<table><tbody>
+<tr><td style="text-align:center; padding-top:0px; padding-bottom:0px;"></td><td style="text-align:center; padding-top:0px; padding-bottom:0px;"></td><td style="text-align:center; padding-top:0px; padding-bottom:0px; font-family: monospace; font-size: 22px;">T</td><td style="text-align:center; padding-left:3px; padding-right:3px; font-family: monospace; font-size: 22px;">O</td></tr>
+<tr style="border-bottom:1pt solid black;"><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">+</td><td></td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">G</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">O</td></tr>
+<tr><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">=</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">O</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">U</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">T</td></tr>
+</tbody>
+</table><p></p>
+<p>We can reason about what the solution can be by hand:</p><ul><li>T, O, U, and G must be all different (game rule)<br></li><li>T, G, and O will be between 1 and 9, and U is between 0 and 9 (game rule)</li><li>If we added the two biggest 2-digit numbers, (99 + 99) we'd get 198, so <i><b>O must be 1</b></i></li><li>Looking at the right-most "units" column, 1 + 1 equals 2, so <i><b>T must be 2</b></i></li><li>Looking at the "tens" column, we know there is a carry of 1 (since O is 1) and w [...]
+<table><tbody>
+
+<tr><td style="font-family:monospace; font-size: 22px; text-align:center; padding-top:0px; padding-bottom:0px;"></td><td style="text-align:center; padding-top:0px; padding-bottom:0px;"></td><td style="font-family:monospace; font-size: 22px; text-align:center; padding-top:0px; padding-bottom:0px;">S</td><td style="font-family:monospace; font-size: 22px; text-align:center; padding-top:0px; padding-bottom:0px;">E</td><td style="text-align:center; padding-top:0px; padding-bottom:0px; font-fa [...]
+
+<tr style="border-bottom:1pt solid black;"><td style="font-family:monospace; font-size: 22px; text-align:center; padding-top:0px; padding-bottom:0px;">+</td><td style="text-align:center; padding-top:0px; padding-bottom:0px;"></td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">M</td><td style="font-family:monospace; font-size: 22px; text-align:center; padding-top:0px; padding-bottom:0px;">O</td><td style=" text-align:center; padding:3px; font-family:m [...]
+
+<tr><td style="font-family:monospace; font-size: 22px; text-align:center; padding:3px;">=</td><td style="text-align:center; padding:3px; font-family:monospace; font-size: 22px;">M</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">O</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">N</td><td style="text-align:center; padding:3px; font-family: monospace; font-size: 22px;">E</td><td style="font-family:monospace; f [...]
+
+</tbody>
+</table>
+<h3>Solving with Brute Force</h3>
+
+<p>This problem isn't huge, so we can solve with brute force. We simply try all possible values for the letters in the puzzle:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">for </span>(s <span style="color:#cc7832;">in </span><span style="color:#6897bb;">1</span>..<span style="color:#6897bb;">9</span>)<br>    <span style="color:#cc7832;">for </span>(e <span style="color:#cc7832;">in </span><span [...]
+<pre>s = 9, e = 5, n = 6, d = 7
+m = 1, o = 0, r = 8, y = 2
+</pre>
+
+<h3>Using Constraint Programming</h3>
+
+<p>For the brute force approaches, we had a condition which checked any potential candidate answer to see if it was a correct solution. We had to be very explicit in how we wanted the potential candidates to be created. For constraint programming, we instead define variables to represent the problem, any known bounds on those variables, and we specify any other known properties of the solution, which in our case will be something similar to the condition we had to check if the answer was [...]
+
+<h4>Choco</h4><p>Here is the code using the <a href="https://choco-solver.org/" target="_blank">Choco</a> library:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">new </span>Model(<span style="color:#6a8759;">"SEND+MORE=MONEY"</span>).with <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span><span style="color:#cc7832;">def </span>(S, M) = [<span style="color:#6a8 [...]
+<h4 style="font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; color: rgb(0, 0, 0);"><span style="color: inherit; font-family: inherit;">JaCoP</span><br></h4>
+<p>We can solve the same problem using <a href="https://github.com/radsz/jacop" target="_blank">JaCoP</a>:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#cc7832;">def </span>store = <span style="color:#cc7832;">new </span>Store()<br><span style="color:#cc7832;">def </span>(S, M) = [<span style="color:#6a8759;">'S'</span>, <span style="color:#6a8759;">'M'</span>].collect <span style="font-weight:bold;">{ < [...]
+<pre>Labeling has finished with return value of true
+DFS1: DFS([S = 9, E = 5, N = 6, D = 7, M = 1, O = 0, R = 8, Y = 2], InputOrder, (org.jacop.search.IndomainMin@45394b31))
+</pre>
+<p>We can see here the code is very similar as is the execution time.</p>
+
+<h4>OR-Tools</h4><p>We can repeat the solution using <a href="https://developers.google.com/optimization/cp" target="_blank">OR-Tools</a>. Here is the code:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">Loader.<span style="color:#9876aa;font-style:italic;">loadNativeLibraries</span>()<br><br><span style="color:#cc7832;">new </span>Solver(<span style="color:#6a8759;">'Send+More=Money'</span>).with <span style="font-weight:bo [...]
+<pre>s(9) e(5) n(6) d(7) m(1) o(0) r(8) y(2)
+Solutions: 1
+Failures: 5
+Branches: 10
+Wall time: 60ms
+</pre>
+<p>OR-Tools is written in C++ but has interfaces for numerous languages including Java - which is perfect for Groovy use.</p><h4 style="font-family: &quot;Helvetica Neue&quot;, Helvetica, Arial, sans-serif; color: rgb(0, 0, 0);">Choco with JSR331</h4><p>It is great to have multiple libraries to pick from but having a standard API can help switching between such libraries. This is where JSR331 comes in. It defines a standard API for interacting with constraint solvers and linear solves. H [...]
+<pre>Solution #1:
+	 S[9] M[1] E[5] N[6] D[7] O[0] R[8] Y[2]
+</pre>
+<p>Having said that, at the time of writing, JSR331 popularity doesn't appear to be on the rise. Most folks using constraint programming libraries seem to be using the direct library classes. Indeed, the version of the Choco implementation used by the JSR331 implementation is over 10 years old.</p>
+
+<h3>Incorporating Carry</h3>
+
+<p>The scalar product global constraint we have used in the previous examples is very powerful and probably would be our first choice for this problem. We can, however, model constraint programming problems in multiple ways, so let's look at a solution that avoids that global constraint.</p><p>Instead, we will develop a model that mirrors how we reasoned about the original <code>TO + GO = OUT</code> problem that we solved by hand. For that, we just considered a column at a time and accou [...]
+<pre>Solution: S=9, M=1, E=5, N=6, D=7, O=0, R=8, Y=2, C0=1, C1=1, C2=0, C3=1, sum_exp_1=9,
+sum_exp_2=10, (C3*10)=10, sum_exp_3=10, sum_exp_4=6, sum_exp_5=6, (C2*10)=0, sum_exp_6=6,
+sum_exp_7=7, sum_exp_8=15, (C1*10)=10, sum_exp_9=15, sum_exp_10=12, (C0*10)=10, sum_exp_11=12,</pre>
+<p>We can see that as we were defining our constraints for each column, subexpressions were being created in the model which are reflected in the solution. They are if you like, temporary calculations along the way to getting the answer - or more accurately a snapshot of ever changing temporary calculations. They don't form part of the answer that interests us, so we would be free to just print out the part of the solution which interests us if we wanted.</p>
+
+<h3>Creating a DSL</h3>
+
+<p>The previous example has lots of calls to <code>add</code> and <code>mul</code> methods. We can create a little bit of a DSL to provide some syntactic sugar to our previous examples to allow use of Groovy's operator overloading, support ranges when specifying the domain of a variable, and a few other niceties. Our code becomes:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">model(<span style="color:#6a8759;">"SEND+MORE=MO [...]
+<p><img src="https://blogs.apache.org/groovy/mediaresource/bdb17727-caee-473c-b450-3ec60e74e13b" style="width:80%;" alt="choco_step1.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/171a4583-806a-4c1b-9557-892d87e5670c" style="width:80%;" alt=" choco_step2.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/6807b9ad-8390-45ec-ad58-10dd1346bf45" style="width:80%;" alt=" choco_step3.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/b2b2221a-60fa-4d9a-9fa1-16ddb213fcce" style="width:80%;" alt="choco_step4.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/6303ed53-ff6c-4572-b70d-52b299d4fff7" style="width:80%;" alt="choco_step5.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/658ff512-433f-452a-9a81-904449dfb623" style="width:80%;" alt="choco_step6.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/f81d5630-ede4-4b75-9e74-b73b81be0b21" style="width:80%;" alt="choco_step7.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/8de231cc-c0da-4170-845a-6653b84779b9" style="width:80%;" alt="choco_step8.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/46227911-c406-4234-88d1-fe1f9ac9c517" style="width:80%;" alt="choco_step9.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/31060d5c-6716-4efe-8f99-910c1771ef28" style="width:80%;" alt="choco_step10.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/4b9324d7-2bf3-48c9-af8b-b35872aaf5cf" style="width:80%;" alt="choco_step11.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/71197695-f379-4777-9ed5-ddae1577ee3d" style="width:80%;" alt="choco_step12.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/6ff23a4e-b444-4794-bc79-e6591582bff9" style="width:80%;" alt="choco_step13.png"></p>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/6262d9bc-7f14-4b8f-a952-18668c6f1340" style="width:30%;" alt="choco_step14.png"></p>
+<p>As we are locking in the value of variables, we can substitute them into and simplify our constraints. When we reapply them, they will be quicker to evaluate and may reveal more information.</p><p>At this point we only have 2 of our variables locked down but our search space is nearly half what we started with and we have simplified some of our constraints. We would continue branching and solving at this point until we find our solution or determine that no solution is possible.</p>
+
+<h3>Looking at other languages</h3>
+
+<p>The example repo also contains solutions for this problem in other languages so you can compare and contrast
+including
+<a href="https://clojure.org/" rel="nofollow">Clojure</a>,
+Haskell (<a href="https://github.com/Frege/frege">Frege</a>),
+<a href="https://www.java.com/" rel="nofollow">Java</a>,
+JavaScript (<a href="https://docs.oracle.com/javase/10/nashorn/" rel="nofollow">Nashorn</a>),
+Ruby (<a href="https://www.jruby.org/" rel="nofollow">JRuby</a>),
+Python (<a href="https://www.jython.org/" rel="nofollow">Jython</a>),
+<a href="https://kotlinlang.org/" rel="nofollow">Kotlin</a>,
+Lua (<a href="https://github.com/luaj/luaj">Luaj</a>),
+Prolog (<a href="http://apice.unibo.it/xwiki/bin/view/Tuprolog/" rel="nofollow">tuprolog</a>),
+and <a href="https://www.scala-lang.org/" rel="nofollow">Scala</a>.</p>
+
+<p><img src="https://blogs.apache.org/groovy/mediaresource/a1fc3f0b-3997-4e91-987a-51a5423581e4" style="width:80%;" alt="other language logos"></p>
+
+<h3>Other examples</h3>
+
+<p>To wrap up, let's look at solving a few more examples (using Choco). We'll solve some of the examples from an interesting blog on the <a href="https://pballew.blogspot.com/2015/02/some-history-notes-about-alphametrics.html" target="_blank">history of Cryptarithmetic problems</a>:</p><ul><li><code>ABCD * 4 = DCBA</code></li><li><code>AA + BB + CC = ABC</code></li><li><code>HALF + HALF = WHOLE</code></li><li><code>HALF + FIFTH + TENTH + TENTH + TENTH = WHOLE</code></li></ul><p>Here is t [...]
+<p>which has this output:</p>
+<pre>ABCD*4=DCBA: 2178 * 4 = 8712
+Solution: A=2, D=8, B=1, C=7, IV_1=3, IV_2=3, IV_3=0, (A*4)=8, sum_exp_4=8, (B*4)=4, ..., 
+
+AA+BB+CC=ABC: 11 + 99 + 88 = 198
+Solution: A=1, B=9, C=8, (A*11)=11, (B*11)=99, (C*11)=88, ..., 
+
+HALF+HALF=WHOLE: 9604 + 9604 = 19208
+Solution: H=9, W=1, A=6, E=8, F=4, L=0, O=2, 
+
+HALF+HALF=WHOLE: 9703 + 9703 = 19406
+Solution: H=9, W=1, A=7, E=6, F=3, L=0, O=4, 
+
+HALF+HALF=WHOLE: 9802 + 9802 = 19604
+Solution: H=9, W=1, A=8, E=4, F=2, L=0, O=6, 
+
+HALF+FIFTH+TENTH+TENTH+TENTH=WHOLE: 6701+14126+25326+25326+25326=96805
+Solution: H=6, F=1, T=2, W=9, A=7, L=0, I=4, E=5, N=3, O=8, 
+</pre>
+<p>You should see the common patterns used for solving these puzzles.</p>
+
+<h3>Further Information</h3>
+
+<ul><li><a href="https://github.com/radsz/jacop" target="_blank">JaCoP</a> Java Constraint Programming solver</li><li><a href="https://choco-solver.org/" target="_blank">Choco</a> open source library for constraint programming</li><li><a href="https://developers.google.com/optimization/cp" target="_blank">OR-Tools</a> constraint optimization</li><li><a href="https://en.wikipedia.org/wiki/Verbal_arithmetic" target="_blank">Verbal arithmetic</a> problems described (wikipedia)</li><li><a hr [...]
+
+<h3>Conclusion</h3>
+
+<p>We have looked at using Groovy and a few constraint programming libraries to solve a cryptarithmetic puzzles. Why not try solving some of your own puzzles.</p>
diff --git a/site/src/site/blog/testing-your-java-with-groovy.md b/site/src/site/blog/testing-your-java-with-groovy.md
new file mode 100644
index 0000000..4d3fb3a
--- /dev/null
+++ b/site/src/site/blog/testing-your-java-with-groovy.md
@@ -0,0 +1,99 @@
+---
+layout: post
+title: Testing your Java with Groovy, Spock, JUnit5, Jacoco, Jqwik and Pitest
+date: '2022-07-15T08:26:15+00:00'
+permalink: testing-your-java-with-groovy
+---
+<meta name="twitter:card" content="summary_large_image">
+<p><img src="https://blogs.apache.org/groovy/mediaresource/694c4230-893a-4f6b-8cf5-6160be80eeed" align="right" style="width:10%;" alt="spock-main-logo.png">This blog post covers a common scenario seen in the Groovy community which is projects which use Java for their production code and Groovy for their tests. This can be a low risk way for Java shops to try out and become more familiar with Groovy. We'll write our initial tests using the <a href="https://spockframework.org/" target="_bl [...]
+<p>For illustrative purposes, we will test a Java mathematics utility function <code>sumBiggestPair</code>. Given three numbers, it finds the two biggest and then adds them up. An initial stab at the code for this might look something like this:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">public class </span><span style="color:#000000;">MathUtil </span>{<br><br><b>    <span style="color:#0033b [...]
+<h3>Testing with Spock</h3>
+<p>An initial test could look like this:<br></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">class </span><span style="color:#000000;">MathUtilSpec </span><span style="color:#0033b3;">extends </span><span style="color:#000000;">Specification </span>{<br><b>    <span style="color:#0033b3;">def </span><span style="color:#067d17;">"sum of two biggest numbers"</span>() {<br>        expect:<br>         [...]
+<p>When we run this test, all tests pass:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/49da872c-562d-4137-9875-cfa76b932f72" style="width:50%;" alt="test result success image"><br>But if we look at the coverage report, generated with <a href="https://github.com/jacoco/jacoco" target="_blank">Jacoco</a>, we see that our test hasn't covered all lines of code:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/814b3355-c3b7-4a03-9396-f790c606540d" style="width:50 [...]
+<p>We can check our coverage again:</p><p><img src="https://blogs.apache.org/groovy/mediaresource/a1cba09e-a217-4832-a7f3-b3e35d8969f4" style="width:50%;" alt="2022-07-14 22_35_22-MathUtil.java.png"><br></p><p>That is a little better. We now have 100% line coverage but not 100% branch coverage. Let's add one more testcase:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">    <span style="color:#0033b3;">def </span><span style= [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><b>&gt; Task :SumBiggestPairPitest:test</b>
+<span style="color:#4E9A06;">✔</span> Test sum of two biggest numbers [Tests: 4/<span style="color:#4E9A06;">4</span>/<span style="color:#CC0000;">0</span>/<span style="color:#C4A000;">0</span>] [Time: 0.317 s]
+<span style="color:#4E9A06;">✔</span> Test util.MathUtilSpec [Tests: 4/<span style="color:#4E9A06;">4</span>/<span style="color:#CC0000;">0</span>/<span style="color:#C4A000;">0</span>] [Time: 0.320 s]
+<span style="color:#4E9A06;">✔</span> Test Gradle Test Run :SumBiggestPairPitest:test [Tests: 4/<span style="color:#4E9A06">4</span>/<span style="color:#CC0000">0</span>/<span style="color:#C4A000;">0</span>]
+</pre>
+<p>But haven't we been here before? How can we be sure there isn't some additional test cases that might reveal another flaw in our algorithm? We could keep writing lots more testcases but we'll look at two other techniques that can help.</p><h3>Mutation testing with Pitest</h3><p>An interesting but not widely used technique is mutation testing. It probably deserves to be more widely used. It can test the quality of a testsuite but has the drawback of sometimes being quite resource inten [...]
+- Statistics
+================================================================================
+&gt;&gt; Line Coverage: 7/8 (88%)
+&gt;&gt; Generated 6 mutations Killed 4 (67%)
+&gt;&gt; Mutations with no coverage 0. Test strength 67%
+&gt;&gt; Ran 26 tests (4.33 tests per mutation)</pre>
+<p>What is this telling us? Pitest mutated our code in ways that you might expect to break it but our testsuite passed (survived) in a couple of instances. That means one of two things. Either, there are multiple valid implementations of our algorithm and Pitest found one of those equivalent solutions, or our testsuite is lacking some key testcases. In our case, we know that the testsuite was insufficient.</p><p>Let's run it again but this time with all of our tests and the corrected alg [...]
+<pre>================================================================================
+- Statistics
+================================================================================
+&gt;&gt; Line Coverage: 6/7 (86%)
+&gt;&gt; Generated 4 mutations Killed 3 (75%)
+&gt;&gt; Mutations with no coverage 0. Test strength 75%
+&gt;&gt; Ran 25 tests (6.25 tests per mutation)</pre>
+<p>Our warnings from Pitest have reduced but not gone completely away and our test strength has gone up but is still not 100%. It does mean that we are in better shape than before. But should we be concerned?</p><p>It turns out in this case, we don't need to worry (too much). As an example, an equally valid algorithm for our function under test would be to replace the conditional with "<code>c &gt;= Math.min(a, b)</code>". Note the <i>greater-than-equals</i> operator rather than just <i> [...]
+<pre style="background-color: rgb(255, 255, 255);"><font color="#080808" face="JetBrains Mono, monospace"><span style="font-size: 9.6pt;">plugins </span></font><span style="color: rgb(8, 8, 8); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt; font-weight: bold;">{<br></span><span style="color: rgb(8, 8, 8); font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt; font-weight: bold;">    </span><font color="#080808" face="JetBrains Mono, monospace"><span  [...]
+</span><span style="font-weight:bold;">    </span>junit5PluginVersion = <span style="color:#067d17;">'1.0.0'
+</span><span style="font-weight:bold;">    </span>pitestVersion = <span style="color:#067d17;">'1.9.2'
+</span><span style="color:#067d17;">    </span>timestampedReports = <span style="color:#0033b3;">false<br></span><span style="color:#0033b3;">    </span>targetClasses = [<span style="color:#067d17;">'util.*'</span>]<br><span style="font-weight:bold;">}<br></span><span style="font-weight:bold;"><br></span>tasks.named(<span style="color:#067d17;">'test'</span>) <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>useJUnitPlatform()<br><span style="font-wei [...]
+<p>The astute reader might note some subtle hints which show that the latest Spock versions run on top of the JUnit 5 platform.</p><h3>Using Property-based Testing</h3><p>Property-based testing is another technology which probably deserves much more attention. Here we'll use <a href="https://jqwik.net/" target="_blank">jqwik</a>&nbsp;which runs on top of JUnit5 but you might also like to consider <a href="https://github.com/Bijnagte/spock-genesis" target="_blank">Genesis</a> which provid [...]
+tries = 1000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | # of calls to property
+checks = 1000&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| # of not rejected calls
+generation = RANDOMIZED&nbsp; &nbsp; &nbsp; &nbsp;| parameters are randomly generated
+after-failure = PREVIOUS_SEED | use the previous seed
+when-fixed-seed = ALLOW&nbsp; &nbsp; &nbsp; &nbsp;| fixing the random seed is allowed
+edge-cases#mode = MIXIN&nbsp; &nbsp; &nbsp; &nbsp;| edge cases are mixed in
+edge-cases#total = 125&nbsp; &nbsp; &nbsp; &nbsp; | # of all combined edge cases
+edge-cases#tried = 117&nbsp; &nbsp; &nbsp; &nbsp; | # of edge cases tried in current run
+seed = -311315135281003183&nbsp; &nbsp; | random seed to reproduce generated values</p></pre><p>So, we wrote 1 test and 1000 testcases were executed. The number of tests run is configurable. We won't go into the details here. This looks great at first glance. It turns out however, that this particular property is not very discriminating in terms of the bugs it can find. This test passes for both our original flawed algorithm as well as the fixed one. Let's try a different property:</p><p [...]
+&nbsp; &nbsp; assert [a + b, b + c, c + a].every { sumOfPair -&gt; result &gt;= sumOfPair }
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | | |&nbsp; | | |&nbsp; | | |&nbsp; |
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 1 1 0&nbsp; 0 2 2&nbsp; 2 3 1&nbsp; false<p>&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; |--------------------jqwik--------------------
+tries = 12&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | # of calls to property
+checks = 12&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| # of not rejected calls
+generation = RANDOMIZED&nbsp; &nbsp; &nbsp; &nbsp;| parameters are randomly generated
+after-failure = PREVIOUS_SEED | use the previous seed
+when-fixed-seed = ALLOW&nbsp; &nbsp; &nbsp; &nbsp;| fixing the random seed is allowed
+edge-cases#mode = MIXIN&nbsp; &nbsp; &nbsp; &nbsp;| edge cases are mixed in
+edge-cases#total = 125&nbsp; &nbsp; &nbsp; &nbsp; | # of all combined edge cases
+edge-cases#tried = 2&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | # of edge cases tried in current run
+seed = 4830696361996686755&nbsp; &nbsp; | random seed to reproduce generated values
+</p><p>Shrunk Sample (6 steps)
+-----------------------
+&nbsp; arg0: 1
+&nbsp; arg1: 0
+&nbsp; arg2: 2
+</p><p>Original Sample
+---------------
+&nbsp; arg0: 247
+&nbsp; arg1: 32
+&nbsp; arg2: 267</p><p>&nbsp; Original Error
+&nbsp; --------------
+&nbsp; org.codehaus.groovy.runtime.powerassert.PowerAssertionError:
+&nbsp; &nbsp; assert [a + b, b + c, c + a].every { sumOfPair -&gt; result &gt;= sumOfPair }
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | | |&nbsp; | | |&nbsp; | | |&nbsp; |
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | | 32 32| 267| | |&nbsp; false
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; | 279&nbsp; &nbsp; 299&nbsp; | | 247
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 247&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp;| 514
+&nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; 267<span style="background-color: rgb(245, 245, 245);">
+</span></p></pre>
+<p>Not only did it find a case which highlighted the flaw, but it <i>shrunk</i> it down to a very simple example. On our fixed algorithm, the 1000 tests pass!</p><p>The previous property can be refactored a little to not only calculate all three pairs but then find the maximum of those. This simplifies the condition somewhat:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#9e880d;">@Property<br></span><spa [...]
+<pre>  org.codehaus.groovy.runtime.powerassert.PowerAssertionError:
+    assert sumBiggestPair(a, b, c) == [a+b, a+c, b+c].max()
+           |              |  |  |  |   |||  |||  |||  |
+           -2147483648    0  1  |  |   0|1  0||  1||  2147483647
+                                |  |    1    ||   |2147483647
+                                |  false     ||   -2147483648
+                                2147483647   |2147483647
+                                             2147483647
+Shrunk Sample (13 steps)
+------------------------
+  arg0: 0
+  arg1: 1
+  arg2: 2147483647
+</pre>
+<p>It fails! Is this another bug in our algorithm? Possibly? But it could equally be a bug in our property test. Further investigation is warranted.</p><p>It turns out that our algorithm suffers from Integer overflow when trying to add <code>1</code> to <code>Integer.MAX_VALUE</code>. Our test partially suffers from the same problem but when we call <code>max()</code>, the negative value will be discarded. There is no always correct answer as to what should happen in this scenario. We go [...]
+<p>Finally, let's again look at our Gradle build file:<br></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">apply <span style="color:#067d17;">plugin</span>: <span style="color:#067d17;">'groovy'<br></span><span style="color:#067d17;"><br></span>repositories <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>mavenCentral()<br><span style="font-weight:bold;">}<br></span><span style="font-weig [...]
+<p>The examples in this blog post are excerpts from the following repo:</p><p><a href="https://github.com/paulk-asert/property-based-testing" target="_blank">https://github.com/paulk-asert/property-based-testing</a><br><br>Versions used: Gradle 7.5, Groovy 4.0.3, jqwik&nbsp;1.6.5, pitest 1.9.2, Spock&nbsp;2.2-M3-groovy-4.0, Jacoco 0.8.8. Tested with JDK 8, 11, 17, 18.<br></p><p>There are many sites with valuable information about the technologies covered here. There are also some great b [...]
+<h3>Conclusion</h3>
+<p>We have looked at testing Java code using Groovy and Spock with some additional tools like Jacoco, jqwik and Pitest. Generally using Groovy to test Java is a straight-forward experience. Groovy also lends itself to writing testing DSLs which allow non-hard-core programmers to write very simple looking tests; but that's a topic for another blog!</p>
diff --git a/site/src/site/blog/using-groovy-with-apache-wayang.md b/site/src/site/blog/using-groovy-with-apache-wayang.md
new file mode 100644
index 0000000..74421b1
--- /dev/null
+++ b/site/src/site/blog/using-groovy-with-apache-wayang.md
@@ -0,0 +1,34 @@
+---
+layout: post
+title: Using Groovy with Apache Wayang and Apache Spark
+date: '2022-06-19T13:01:07+00:00'
+permalink: using-groovy-with-apache-wayang
+---
+<p><img src="https://blogs.apache.org/groovy/mediaresource/870eadc0-670a-4b58-86d0-0007c3f2f4b1" align="right" style="width: 10%;" alt="wayang.png"><a href="https://wayang.apache.org/" target="_blank">Apache Wayang</a>&nbsp;(incubating) is an API for big data cross-platform processing. It provides an abstraction over other platforms like <a href="https://spark.apache.org/" target="_blank">Apache Spark</a>&nbsp;and <a href="https://flink.apache.org/" target="_blank">Apache Flink</a> as we [...]
+<h3>Whiskey Clustering</h3>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/c5ba5e59-737e-4ebf-91c9-08fa67dc8f70" align="right" alt="groovy.png" style="width: 15%;">We'll take a look at using Apache Wayang with Groovy to help us in the quest to find the perfect&nbsp;single-malt Scotch whiskey. The whiskies produced from&nbsp;<a href="https://www.niss.org/sites/default/files/ScotchWhisky01.txt" rel="nofollow" style="transition: color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s, background-color 0s ease 0s, box [...]
+<h3>Implementation Details</h3>
+<p>We'll start with defining a Point record:</p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><span style="color:#0033b3;">record </span><span style="color:#000000;">Point</span>(<span style="color:#0033b3;">double</span>[] pts) <span style="color:#0033b3;">implements </span><span style="color:#000000;">Serializable </span>{<br>    <span style="color:#0033b3;">static </span><span style="color:#000000;">Point </span><span style [...]
+</p><h3>Running with the Java streams-backed platform</h3>As we mentioned earlier, Wayang selects which platform(s) will run our application. It has numerous capabilities whereby cost functions and load estimators can be used to influence and optimize how the application is run. For our simple example, it is enough to know that even though we specified Java or Spark as options, Wayang knows that for our small data set, the Java streams option is the way to go.<p></p><p>Since we prime the [...]
+the script is run, but here is one output:</p><p></p><pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">&gt; Task :WhiskeyWayang:run<br>Centroids:<br>Cluster0: <span style="color:#1750eb;">2.548</span>, <span style="color:#1750eb;">2.419</span>, <span style="color:#1750eb;">1.613</span>, <span style="color:#1750eb;">0.194</span>, <span style="color:#1750eb;">0.097</span>, <span style="color:#1750eb;">1.871</span>, <span style="colo [...]
+...</span></pre><p style="">Which if plotted looks like this:</p><p><a href="https://blogs.apache.org/groovy/mediaresource/a74aff16-03f8-4aec-b7a8-e1ce7133efef"><img src="https://blogs.apache.org/groovy/mediaresource/a74aff16-03f8-4aec-b7a8-e1ce7133efef" alt="WhiskeyWayang Centroid Spider Plot" style="width: 50%;"></a><br></p><p>If you are interested, check out the examples in the repo links at the end of this article to see the code for producing this centroid spider plot or the Jupyter [...]
+<h3>Running with Apache Spark</h3>
+<p><img src="https://blogs.apache.org/groovy/mediaresource/ab92d040-080c-414b-b33f-193772a341fc" align="right" style="width: 10%;" alt="spark.png">Given our small dataset size and no other customization, Wayang will choose the Java streams based solution. We could use Wayang optimization features to influence which processing platform it chooses, but to keep things simple, we'll just disable the Java streams platform in our configuration by making the following change in our code:</p><p> [...]
+<p>Now when we run the application, the output will be something like this (a solution similar to before but with 1000+ extra lines of Spark and Wayang log information - truncated for presentation purposes):</p>
+<pre style="background-color:#ffffff;color:#080808;font-family:'JetBrains Mono',monospace;font-size:9.6pt;"><p><span style="color: rgb(156, 0, 0);">[main] INFO org.apache.spark.SparkContext - Running Spark version 3.3.0<br>[main] INFO org.apache.spark.util.Utils - Successfully started service 'sparkDriver' on port 62081.<br>...<br></span>Centroids:<br>Cluster4: 1.414, 2.448, 0.966, 0.138, 0.034, 0.862, 1.000, 0.483, 1.345, 1.690, 2.103, 2.138<br>Cluster0: 2.773, 2.455, 1.455, 0.000, 0.00 [...]
+<h3>Discussion</h3>
+<p>A goal of Apache Wayang is to allow developers to write platform-agnostic applications. While this is mostly true, the abstractions aren't perfect. As an example, if I know I am only using the streams-backed platform, I don't need to worry about making any of my classes serializable (which is a Spark requirement). In our example, we could have omitted the "<span style="font-family: &quot;JetBrains Mono&quot;, monospace; font-size: 9.6pt; color: rgb(0, 51, 179);">implements </span><spa [...]
+<h3>Conclusion</h3><p>We have looked at using Apache Wayang to implement a KMeans algorithm that runs either backed by the JDK streams capabilities or by Apache Spark. The Wayang API hid from us some of the complexities of writing code that works on a distributed platform and some of the intricacies of dealing with the Spark platform. The abstractions aren't perfect but they certainly aren't hard to use and provide extra protection should we wish to move between platforms. As an added bo [...]
+<p></p>
+<h3>More Information</h3>
+<p></p><ul>
+<li>Repo containing the source code:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/WhiskeyWayang">WhiskeyWayang</a></li>
+<li>Repo containing similar examples using a variety of libraries including Apache Commons CSV,
+Weka, Smile, Tribuo and others:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/Whiskey">Whiskey</a></li>
+<li>A similar example using Apache Spark directly but with a built-in parallelized KMeans from the spark-mllib library rather than a hand-crafted algorithm:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/WhiskeySpark" style="background-color: rgb(255, 255, 255);">WhiskeySpark</a><br></li>
+<li>A similar example using Apache Ignite directly but with a built-in clustered KMeans from the ignite-ml library rather than a hand-crafted algorithm:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/WhiskeyIgnite" style="background-color: rgb(255, 255, 255);">WhiskeyIgnite</a><br></li>
+</ul><p></p>
diff --git a/site/src/site/blog/whiskey-clustering-with-groovy-and.md b/site/src/site/blog/whiskey-clustering-with-groovy-and.md
new file mode 100644
index 0000000..ff79f7b
--- /dev/null
+++ b/site/src/site/blog/whiskey-clustering-with-groovy-and.md
@@ -0,0 +1,63 @@
+---
+layout: post
+title: Whiskey Clustering with Groovy and Apache Ignite
+date: '2022-10-27T11:13:37+00:00'
+permalink: whiskey-clustering-with-groovy-and
+---
+<p>In a previous <a href="https://blogs.apache.org/groovy/entry/using-groovy-with-apache-wayang" target="_blank">blog post</a>, <img src="https://ignite.apache.org/img/logo.svg" align="right"> we looked at using <a href="https://wayang.apache.org/" target="_blank" style="background-color: rgb(255, 255, 255);">Apache Wayang</a>&nbsp;(incubating) and <a href="https://spark.apache.org/" target="_blank">Apache Spark</a> to scale up the <a href="https://en.wikipedia.org/wiki/K-means_clusterin [...]
+
+<h2>Whiskey Clustering</h2>
+
+<p><img src="https://blogs.apache.org/groovy/mediaresource/c5ba5e59-737e-4ebf-91c9-08fa67dc8f70" align="right" alt="groovy.png" style="width: 15%;">This problem looks at the quest of finding the perfect&nbsp;single-malt Scotch whiskey. The whiskies produced from&nbsp;<a href="https://www.niss.org/sites/default/files/ScotchWhisky01.txt" rel="nofollow" style="transition: color 80ms cubic-bezier(0.33, 1, 0.68, 1) 0s, background-color 0s ease 0s, box-shadow 0s ease 0s, border-color 0s ease 0 [...]
+
+<h2>Apache Ignite</h2>
+
+<p>Apache Ignite is a distributed database for high-performance computing with in-memory speed. It makes a cluster (or <i>grid</i>) of nodes appear like an in-memory cache.</p><p>This explanation drastically simplifies Ignite's feature set. Ignite can be used as:</p><ul><li>an in-memory cache with special features like SQL querying and transactional properties</li><li>an in-memory data-grid with advanced read-through &amp; write-through capabilities on top of one or more distributed data [...]
+
+<h2>Implementation Details</h2>
+
+<p>Apache Ignite has special capabilities for reading data into the cache. We could use <code>IgniteDataStreamer</code> or <code>IgniteCache.loadCache()</code> and load data from files, stream sources, various database sources and so forth. This is particularly relevant when using a cluster.</p><p>For our little example, our data is in a relatively small CSV file and we will be using a single node, so we'll just read our data using&nbsp;<a href="https://commons.apache.org/csv/" target="_ [...]
+
+<h2>Results</h2>
+
+<p>Here is the output:</p>
+
+<pre>[18:13:11]    __________  ________________
+[18:13:11]   /  _/ ___/ |/ /  _/_  __/ __/
+[18:13:11]  _/ // (7 7    // /  / / / _/
+[18:13:11] /___/\___/_/|_/___/ /_/ /x___/
+[18:13:11]
+[18:13:11] ver. 2.14.0#20220929-sha1:951e8deb
+[18:13:11] 2022 Copyright(C) Apache Software Foundation
+...
+[18:13:11] Configured plugins:
+[18:13:11]   ^-- ml-inference-plugin 1.0.0
+[18:13:14] Ignite node started OK (id=f731e4ab)
+...
+&gt;&gt;&gt; Ignite grid started for data: 86 rows X 13 cols
+&gt;&gt;&gt; KMeans centroids
+Body, Sweetness, Smoky, Medicinal, Tobacco, Honey, Spicy, Winey, Nutty, Malty, Fruity, Floral
+2.7037, 2.4444, 1.4074, 0.0370, 0.0000, 1.8519, 1.6667, 1.8519, 1.8889, 2.0370, 2.1481, 1.6667
+1.8500, 1.9000, 2.0000, 0.9500, 0.1500, 1.1000, 1.5000, 0.6000, 1.5500, 1.7000, 1.3000, 1.5000
+1.2667, 2.1333, 0.9333, 0.1333, 0.0000, 1.0667, 0.8000, 0.5333, 1.8000, 1.7333, 2.2667, 2.2667
+3.6667, 1.5000, 3.6667, 3.3333, 0.6667, 0.1667, 1.6667, 0.5000, 1.1667, 1.3333, 1.1667, 0.1667
+1.5000, 2.8889, 1.0000, 0.2778, 0.1667, 1.0000, 1.2222, 0.6111, 0.5556, 1.7778, 1.6667, 2.0000
+[18:13:15] Ignite node stopped OK [uptime=00:00:00.663]
+</pre>
+
+<p>We can plot the centroid characteristics in a spider plot.</p><p><img style="width:50%" src="https://blogs.apache.org/groovy/mediaresource/9a73886e-9cf6-4937-a70d-e366a784c21c" alt="2022-10-27 20_42_01-Whiskey clusters with Apache Ignite.png"><br></p>
+
+<p><br></p>
+
+<h2>More Information</h2>
+
+<p></p><ul>
+<li>Repo containing the source code:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/WhiskeyIgnite" style="background-color: rgb(255, 255, 255);">WhiskeyIgnite</a><br></li>
+<li>Repo containing similar examples using a variety of libraries including Apache Commons CSV,
+Weka, Smile, Tribuo and others:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/Whiskey" style="background-color: rgb(255, 255, 255);">Whiskey</a><br></li>
+<li>A similar example using Apache Spark directly but with a built-in parallelized k-means from the spark-mllib library rather than a hand-crafted algorithm:
+<a href="https://github.com/paulk-asert/groovy-data-science/tree/master/subprojects/WhiskeySpark" style="background-color: rgb(255, 255, 255);">WhiskeySpark</a><br></li>
+
+</ul><p></p>
diff --git a/site/src/site/blog/working-with-sql-databases-with.md b/site/src/site/blog/working-with-sql-databases-with.md
new file mode 100644
index 0000000..67c8cec
--- /dev/null
+++ b/site/src/site/blog/working-with-sql-databases-with.md
@@ -0,0 +1,87 @@
+---
+layout: post
+title: Working with SQL databases with Groovy and GraalVM
+date: '2022-07-29T14:07:41+00:00'
+permalink: working-with-sql-databases-with
+---
+<p>During the week, there was an interesting <a href="https://www.youtube.com/watch?v=rpZJz4qbhCU" target="_blank">video</a> and <a href="https://medium.com/graalvm/graalvm-22-2-smaller-jdk-size-improved-memory-usage-better-library-support-and-more-cb34b5b68ec0" target="_blank">blog post</a> on the latest <a href="https://www.graalvm.org/" target="_blank">GraalVM</a> 22.2 Release. The release has numerous new features and improvements including:</p><ul><li>smaller native executables</li> [...]
+<h3>Native Metadata</h3>
+<p>For anyone who has used GraalVM, they will know that frequently certain information must be given to the native compiler. Certain classes can be initialized at build time, others should be initialized at runtime. If accessing certain kinds of resources, knowledge of those resources must be given to the compiler. Parts of the application which might be invoked through reflection or involve serialization, might not be deemed reachable and won't automatically be included by the compiler. [...]
+<h3>Working with SQL in Groovy</h3>
+<p>The application creates and then populates a <i>customer</i> database with four customers. It then prints them out:<br></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#cc7832;">import </span>groovy.sql.Sql<br><span style="color:#cc7832;">import </span>groovy.transform.<span style="color:#bbb529;">CompileStatic<br></span><span style="color:#bbb529;"><br></span><span style="color:#bbb529;">@CompileStatic< [...]
+<p>Groovy's <code>Sql</code> class makes this relatively easy. The <code>withInstance</code> method will create a database connection and close it down when finished with. The <code>executeInsert</code> method is using a Groovy interpolated String (GString) which creates a prepared statement under the covers.</p>
+<h3>Configuring our native build</h3>
+<p>Here is our build file:<br></p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;">plugins <span style="font-weight:bold;">{<br></span><span style="font-weight:bold;">    </span>id <span style="color:#6a8759;">'application'<br></span><span style="color:#6a8759;">    </span>id <span style="color:#6a8759;">'groovy'<br></span><span style="color:#6a8759;">    </span>id <span style="color:#6a8759;">'org.graalvm.buildtools.native'<br>< [...]
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/groovy-graalvm-h2</b></span>$ ./gradlew clean nativeRun
+...
+<b>&gt; Task :nativeCompile</b>
+[native-image-plugin] Using executable path: /extra/devtools/graalvm-ce-java17-22.2.0/bin/native-image
+<span style="color:#A1A1A1">========================================================================================================================</span>
+<span style="color:#3465A4"><b>GraalVM Native Image</b></span>: Generating '<b>H2Demo</b>' (executable)...
+<span style="color:#A1A1A1">========================================================================================================================</span>
+...
+<span style="color:#3465A4">[1/7] </span><span style="color:#3465A4"><b>Initializing</b></span><span style="color:#3465A4"><b>...</b></span>                                                                                    (5.3s @ 0.26GB)
+ Version info: 'GraalVM 22.2.0 Java 17 CE'
+ Java version info: '17.0.4+8-jvmci-22.2-b06'
+ C compiler: gcc (linux, x86_64, 11.2.0)
+ Garbage collector: Serial GC
+ 1 user-specific feature(s)
+ - com.oracle.svm.polyglot.groovy.GroovyIndyInterfaceFeature
+<span style="color:#3465A4">[2/7] </span><span style="color:#3465A4"><b>Performing analysis</b></span><span style="color:#3465A4"><b>...</b></span>  [************]                                                            (51.7s @ 1.82GB)
+  10,597 (90.60%) of 11,697 classes reachable
+  17,002 (64.13%) of 26,510 fields reachable
+  58,165 (63.45%) of 91,666 methods reachable
+     393 classes,   100 fields, and 2,057 methods registered for reflection
+      65 classes,    74 fields, and    55 methods registered for JNI access
+       4 native libraries: dl, pthread, rt, z
+<span style="color:#3465A4">[3/7] </span><span style="color:#3465A4"><b>Building universe</b></span><span style="color:#3465A4"><b>...</b></span>                                                                               (8.0s @ 4.02GB)
+<span style="color:#3465A4">[4/7] </span><span style="color:#3465A4"><b>Parsing methods</b></span><span style="color:#3465A4"><b>...</b></span>      [**]                                                                       (4.8s @ 3.85GB)
+<span style="color:#3465A4">[5/7] </span><span style="color:#3465A4"><b>Inlining methods</b></span><span style="color:#3465A4"><b>...</b></span>     [***]                                                                      (3.0s @ 1.72GB)
+<span style="color:#3465A4">[6/7] </span><span style="color:#3465A4"><b>Compiling methods</b></span><span style="color:#3465A4"><b>...</b></span>    [******]                                                                  (38.0s @ 3.63GB)
+<span style="color:#3465A4">[7/7] </span><span style="color:#3465A4"><b>Creating image</b></span><span style="color:#3465A4"><b>...</b></span>                                                                                  (5.9s @ 1.70GB)
+  26.65MB (46.64%) for code area:    38,890 compilation units
+  28.04MB (49.05%) for image heap:  359,812 objects and 66 resources
+   2.46MB ( 4.31%) for other data
+  57.15MB in total
+<span style="color:#A1A1A1">------------------------------------------------------------------------------------------------------------------------</span>
+<span style="color:#C4A000"><b>Top 10 packages in code area:                               Top 10 object types in image heap:</b></span>
+   1.48MB sun.security.ssl                                     5.85MB byte[] for code metadata
+   1.06MB java.util                                            2.82MB java.lang.String
+ 979.43KB java.lang.invoke                                     2.78MB java.lang.Class
+ 758.29KB org.apache.groovy.parser.antlr4                      2.47MB byte[] for general heap data
+ 723.92KB com.sun.crypto.provider                              2.04MB byte[] for java.lang.String
+ 588.57KB org.h2.table                                       910.68KB com.oracle.svm.core.hub.DynamicHubCompanion
+ 582.06KB org.h2.command                                     764.95KB java.util.HashMap$Node
+ 494.23KB org.codehaus.groovy.classgen                       761.53KB java.lang.Object[]
+ 476.03KB c.s.org.apache.xerces.internal.impl.xs.traversers  715.65KB byte[] for embedded resources
+ 468.69KB java.lang                                          584.75KB java.util.HashMap$Node[]
+  18.87MB for 370 more packages                                8.28MB for 2535 more object types
+<span style="color:#A1A1A1">------------------------------------------------------------------------------------------------------------------------</span>
+                        3.9s (3.2% of total time) in 30 GCs | Peak RSS: 6.22GB | CPU load: 6.48
+<span style="color:#A1A1A1">------------------------------------------------------------------------------------------------------------------------</span>
+<span style="color:#C4A000"><b>Produced artifacts:</b></span>
+ /extra/projects/groovy-graalvm-h2/build/native/nativeCompile/H2Demo<span style="color:#A1A1A1"> (executable)</span>
+ /extra/projects/groovy-graalvm-h2/build/native/nativeCompile/H2Demo.build_artifacts.txt<span style="color:#A1A1A1"> (txt)</span>
+<span style="color:#A1A1A1">========================================================================================================================</span>
+Finished generating '<b>H2Demo</b>' in 2m 1s.
+    [native-image-plugin] Native Image written to: /extra/projects/groovy-graalvm-h2/build/native/nativeCompile
+
+<b>&gt; Task :nativeRun</b>
+[ID:1, NAME:Lord Archimonde]
+[ID:2, NAME:Arthur]
+[ID:3, NAME:Gilbert]
+[ID:4, NAME:Grug]
+</pre>
+<h3>Checking the native image speed</h3>
+<p>We can also check the speed once the native image is built:<br></p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="color:#4E9A06"><b>paulk@pop-os</b></span>:<span style="color:#3465A4"><b>/extra/projects/groovy-graalvm-h2</b></span>$ time build/native/nativeCompile/H2Demo
+[ID:1, NAME:Lord Archimonde]
+[ID:2, NAME:Arthur]
+[ID:3, NAME:Gilbert]
+[ID:4, NAME:Grug]
+
+real	0m0.027s
+user	0m0.010s
+sys	0m0.011s</pre>
+<h3>More information</h3><p>Check out the full source code from the repo:&nbsp;<a href="https://github.com/paulk-asert/groovy-graalvm-h2" target="_blank">https://github.com/paulk-asert/groovy-graalvm-h2</a>.</p><h3>Conclusion</h3>
+<p>We have looked at a simple H2 database application and the steps involved in creating a native application with Groovy and GraalVM.</p>
diff --git a/site/src/site/blog/zipping-collections-with-groovy.md b/site/src/site/blog/zipping-collections-with-groovy.md
new file mode 100644
index 0000000..b676162
--- /dev/null
+++ b/site/src/site/blog/zipping-collections-with-groovy.md
@@ -0,0 +1,59 @@
+---
+layout: post
+title: Zipping Collections with Groovy
+date: '2022-11-17T12:50:08+00:00'
+permalink: zipping-collections-with-groovy
+---
+<p></p><p>In computer science, <a href="https://en.wikipedia.org/wiki/Zipping_(computer_science)" target="_blank"><i>zipping</i></a>&nbsp;translates sequences into sequences where, if visualized in two dimensions, the rows and columns are swapped. So the <i>zip</i> of:</p><pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">[[<span style="color:#6a8759;">'a'</span>, <span style="color:#6a8759;">'b'</span>, <span style="color:#6a8759; [...]
+ [<span style="color:#6897bb;"> 1 </span>, <span style="color:#6897bb;"> 2 </span>, <span style="color:#6897bb;"> 3 </span>]]<br></pre>
+<p>would be:</p>
+<pre style="background-color:#2b2b2b;color:#a9b7c6;font-family:'JetBrains Mono',monospace;font-size:9.6pt;">[[<span style="color:#6a8759;">'a'</span>, <span style="color:#6897bb;">1</span>],
+ [<span style="color:#6a8759;">'b'</span>, <span style="color:#6897bb;">2</span>],
+ [<span style="color:#6a8759;">'c'</span>, <span style="color:#6897bb;">3</span>]]<br></pre><p>
+
+It's a very handy operation and depending on the language, may be supported for tuples, lists, streams and other sequences or aggregates.</p><p> Java collections and streams don't currently support such functionality out-of-the-box with various workarounds discussed <a href="https://dzone.com/articles/bridge-the-gap-of-zip-operation" target="_blank">here</a>. The summary: language and library design is hard; any <i>zip </i>implementation that Java provides would have some limitations bak [...]
+<p><br></p>
+<p><img style="width:75%" src="https://blogs.apache.org/groovy/mediaresource/d5dce79c-64a1-4f41-96cf-081e19876f5a" alt="fall.png"></p>
+
+<p><br></p>
+
+<h3>Groovy</h3>
+
+<p><a href="https://groovy-lang.org/" target="_blank">Groovy</a> uses the <code>transpose</code> method for zipping:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/67ebb175-e131-43d3-99a6-93ee295d98e7" alt="ZippingCollectionsGroovy.png"></p>
+
+<h3>Eclipse Collections</h3>
+
+<p><a href="https://www.eclipse.org/collections/" target="_blank">Eclipse Collections</a> has a <code>zip</code> method on its list classes:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/372e7ece-5b2e-4257-936a-5586c5264732" alt="ZippingCollectionsEC.png"></p>
+
+<h3>Guava</h3>
+
+<p><a href="https://github.com/google/guava" target="_blank">Guava</a> has a streams utility class with a <code>zip</code> method:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/c09f2360-15b5-4d55-b1ca-e60fb64b1a56" alt="ZippingCollectionsGuava.png"></p>
+
+<h3>StreamEx</h3>
+
+<p><a href="https://github.com/amaembo/streamex" target="_blank">StreamEx</a> provides an enhanced stream library which supports <code>zipWith</code>:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/ceb0bd2e-378d-4d84-bd24-42978a17f4f4" alt="ZippingCollectionsStreamEx.png"></p>
+
+<h3>Vavr</h3>
+
+<p><a href="https://github.com/vavr-io/vavr" target="_blank">Vavr</a> has a <code>zipWith</code> method on its list class:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/55f1456a-cdcf-4ac5-9428-3423380c902e" alt="ZippingCollectionsVavr.png"></p>
+
+<h3>jOOλ</h3>
+
+<p><a href="https://github.com/jOOQ/jOOL" target="_blank">jOOλ</a> has a <code>zip</code> method for its sequences:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/4f4de9e9-d75f-401a-9adc-cb3673e12bb8" alt="ZippingCollectionsJool.png"></p>
+
+<h3>Groovy GQuery</h3>
+
+<p>If you are a fan of query-like DSLs, Groovy's language integrated query, <i>gquery</i>, can also be used:</p>
+<p><img style="width:100%" src="https://blogs.apache.org/groovy/mediaresource/2a95e003-cce5-4c1b-8979-06b0747d438e" alt="ZippingCollectionsGQ.png"></p>
+<p>This uses a special <code>_rn</code> "row number" pre-defined variable in GQ expressions. It follows the same strategy as the IntStream "<i>workaround</i>" for Java mentioned in this&nbsp;<a href="https://www.baeldung.com/java-collections-zip" target="_blank">blog</a>.</p>
+
+<h3>More information</h3>
+
+<ul><li>The code examples can be found in the <a href="https://github.com/paulk-asert/zipping-collections" target="_blank">repo</a></li></ul>
+<p></p>