You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@grails.apache.org by as...@apache.org on 2026/05/02 13:51:35 UTC

(grails-website) branch asf-site-production updated: Updating apache/grails-website asf-site-production branch for GitHub Actions run:25253242549

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

asf-ci-deploy pushed a commit to branch asf-site-production
in repository https://gitbox.apache.org/repos/asf/grails-website.git


The following commit(s) were added to refs/heads/asf-site-production by this push:
     new 299a82f238d Updating apache/grails-website asf-site-production branch for GitHub Actions run:25253242549
299a82f238d is described below

commit 299a82f238db16077911b6003daea3db0207c76c
Author: jamesfredley <ja...@users.noreply.github.com>
AuthorDate: Sat May 2 13:51:28 2026 +0000

    Updating apache/grails-website asf-site-production branch for GitHub Actions run:25253242549
---
 guides/_redirects.json                             |   2 +-
 guides/adding-commit-info/3/guide/index.html       |  15 +-
 .../3/guide/pages/gradlePlugin.html                |  15 +-
 guides/adding-commit-info/3/guide/single.html      |  15 +-
 .../adding-commit-info/3/guide/writingTheApp.html  |  15 +-
 guides/adding-commit-info/4/guide/index.html       |  15 +-
 .../4/guide/pages/gradlePlugin.html                |  15 +-
 guides/adding-commit-info/4/guide/single.html      |  15 +-
 .../adding-commit-info/4/guide/writingTheApp.html  |  15 +-
 .../4/guide/index.html                             | 457 ++++++++++-
 .../4/guide/pages/detailActivity.html              |  69 +-
 .../4/guide/pages/networkingCode.html              | 294 ++++++-
 .../4/guide/pages/v2Android.html                   |  94 ++-
 .../4/guide/single.html                            | 457 ++++++++++-
 .../4/guide/version2.html                          |  94 ++-
 .../4/guide/writingTheAndroidApp.html              | 363 +++++++-
 .../4/guide/index.html                             | 909 ++++++++++++++++++++-
 .../4/guide/pages/detailViewController.html        |  71 +-
 .../4/guide/pages/iosJsonToModel.html              | 238 +++++-
 .../4/guide/pages/iosModel.html                    |  16 +-
 .../4/guide/pages/networkingCode.html              | 363 +++++++-
 .../4/guide/pages/v2iOS.html                       | 221 ++++-
 .../4/guide/single.html                            | 909 ++++++++++++++++++++-
 .../4/guide/version2.html                          | 221 ++++-
 .../4/guide/writingTheiOSApp.html                  | 688 +++++++++++++++-
 .../4/guide/index.html                             | 435 +++++++++-
 .../4/guide/pages/detailViewController.html        |  66 +-
 .../4/guide/pages/iosJsonToModel.html              |  24 +-
 .../4/guide/pages/iosModel.html                    |  11 +-
 .../4/guide/pages/networkingCode.html              | 175 +++-
 .../4/guide/pages/v2iOS.html                       | 159 +++-
 .../4/guide/single.html                            | 435 +++++++++-
 .../4/guide/version2.html                          | 159 +++-
 .../4/guide/writingTheiOSApp.html                  | 276 ++++++-
 guides/discriminator-per-tenant/4/guide/index.html |  17 +-
 .../4/guide/pages/tenantSelection.html             |  17 +-
 .../discriminator-per-tenant/4/guide/single.html   |  17 +-
 .../4/guide/writingTheApp.html                     |  17 +-
 guides/grails-basicauth/3/guide/index.html         | 101 ++-
 .../grails-basicauth/3/guide/pages/controller.html |  34 +-
 .../3/guide/pages/dependencies.html                |   4 +-
 .../grails-basicauth/3/guide/pages/services.html   |  14 +-
 guides/grails-basicauth/3/guide/pages/test.html    |  41 +-
 guides/grails-basicauth/3/guide/pages/views.html   |   8 +-
 guides/grails-basicauth/3/guide/single.html        | 101 ++-
 guides/grails-basicauth/3/guide/writingTheApp.html | 101 ++-
 guides/grails-basicauth/4/guide/index.html         | 109 ++-
 .../grails-basicauth/4/guide/pages/controller.html |  34 +-
 .../4/guide/pages/dependencies.html                |   4 +-
 .../grails-basicauth/4/guide/pages/services.html   |  14 +-
 guides/grails-basicauth/4/guide/pages/test.html    |  49 +-
 guides/grails-basicauth/4/guide/pages/views.html   |   8 +-
 guides/grails-basicauth/4/guide/single.html        | 109 ++-
 guides/grails-basicauth/4/guide/writingTheApp.html | 109 ++-
 .../4/guide/index.html                             |  56 +-
 .../4/guide/pages/acceptanceTests.html             |  17 +-
 .../4/guide/pages/configurationProperties.html     |  18 +-
 .../4/guide/pages/taglib.html                      |  21 +-
 .../4/guide/single.html                            |  56 +-
 .../4/guide/writingTheApp.html                     |  56 +-
 .../6/guide/index.html                             |  56 +-
 .../6/guide/pages/acceptanceTests.html             |  17 +-
 .../6/guide/pages/configurationProperties.html     |  18 +-
 .../6/guide/pages/taglib.html                      |  21 +-
 .../6/guide/single.html                            |  56 +-
 .../6/guide/writingTheApp.html                     |  56 +-
 .../3/guide/index.html                             |  91 ++-
 .../3/guide/pages/acceptanceTests.html             |  19 +-
 .../3/guide/pages/configurationProperties.html     |  34 +-
 .../3/guide/pages/taglib.html                      |  18 +-
 .../3/guide/pages/tests.html                       |  20 +-
 .../3/guide/single.html                            |  91 ++-
 .../3/guide/writingTheApp.html                     |  91 ++-
 .../4/guide/index.html                             |  94 ++-
 .../4/guide/pages/acceptanceTests.html             |  18 +-
 .../4/guide/pages/configurationProperties.html     |  34 +-
 .../4/guide/pages/taglib.html                      |  18 +-
 .../4/guide/pages/tests.html                       |  24 +-
 .../4/guide/single.html                            |  94 ++-
 .../4/guide/writingTheApp.html                     |  94 ++-
 guides/grails-email/3/guide/index.html             | 409 ++++++++-
 .../grails-email/3/guide/pages/awsSesService.html  | 144 +++-
 guides/grails-email/3/guide/pages/controller.html  |  54 +-
 guides/grails-email/3/guide/pages/resources.html   |  15 +-
 .../3/guide/pages/sendGridService.html             | 106 ++-
 guides/grails-email/3/guide/pages/services.html    | 274 ++++++-
 guides/grails-email/3/guide/pages/test.html        |  66 +-
 guides/grails-email/3/guide/single.html            | 409 ++++++++-
 guides/grails-email/3/guide/writingTheApp.html     | 409 ++++++++-
 guides/grails-email/4/guide/index.html             | 367 ++++++++-
 .../grails-email/4/guide/pages/awsSesService.html  |  94 ++-
 guides/grails-email/4/guide/pages/controller.html  |  54 +-
 guides/grails-email/4/guide/pages/resources.html   |  13 +-
 .../4/guide/pages/sendGridService.html             | 112 ++-
 guides/grails-email/4/guide/pages/services.html    | 230 +++++-
 guides/grails-email/4/guide/pages/test.html        |  70 +-
 guides/grails-email/4/guide/single.html            | 367 ++++++++-
 guides/grails-email/4/guide/writingTheApp.html     | 367 ++++++++-
 .../grails-file-download-excel/3/guide/index.html  | 253 +++++-
 .../3/guide/pages/books.html                       |  30 +-
 .../3/guide/pages/controller.html                  |  36 +-
 .../3/guide/pages/excel.html                       |  58 +-
 .../3/guide/pages/spreadsheetBuilder.html          |   3 +-
 .../3/guide/pages/tests.html                       | 126 ++-
 .../grails-file-download-excel/3/guide/single.html | 253 +++++-
 .../3/guide/writingTheApp.html                     | 253 +++++-
 .../grails-file-download-excel/4/guide/index.html  | 266 +++++-
 .../4/guide/pages/books.html                       |  30 +-
 .../4/guide/pages/controller.html                  |  36 +-
 .../4/guide/pages/excel.html                       |  58 +-
 .../4/guide/pages/spreadsheetBuilder.html          |   3 +-
 .../4/guide/pages/tests.html                       | 139 +++-
 .../grails-file-download-excel/4/guide/single.html | 266 +++++-
 .../4/guide/writingTheApp.html                     | 266 +++++-
 rss.xml                                            |   2 +-
 115 files changed, 14397 insertions(+), 663 deletions(-)

diff --git a/guides/_redirects.json b/guides/_redirects.json
index 928f9ba4da2..322357c4666 100644
--- a/guides/_redirects.json
+++ b/guides/_redirects.json
@@ -1,6 +1,6 @@
 {
     "version": 1,
-    "generated": "2026-05-02T13:17:25.054483945Z",
+    "generated": "2026-05-02T13:44:41.895297772Z",
     "from_base": "https://guides.grails.org",
     "to_base": "https://grails.apache.org/guides",
     "count": 1731,
diff --git a/guides/adding-commit-info/3/guide/index.html b/guides/adding-commit-info/3/guide/index.html
index 9173334c606..703a85bf956 100644
--- a/guides/adding-commit-info/3/guide/index.html
+++ b/guides/adding-commit-info/3/guide/index.html
@@ -452,7 +452,20 @@ The build-info plugin works by utilizing the environment variables available via
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/3/guide/pages/gradlePlugin.html b/guides/adding-commit-info/3/guide/pages/gradlePlugin.html
index f5b882b1f45..34dfc301f4f 100644
--- a/guides/adding-commit-info/3/guide/pages/gradlePlugin.html
+++ b/guides/adding-commit-info/3/guide/pages/gradlePlugin.html
@@ -95,7 +95,20 @@ function addJsClass() {
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/3/guide/single.html b/guides/adding-commit-info/3/guide/single.html
index 9173334c606..703a85bf956 100644
--- a/guides/adding-commit-info/3/guide/single.html
+++ b/guides/adding-commit-info/3/guide/single.html
@@ -452,7 +452,20 @@ The build-info plugin works by utilizing the environment variables available via
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/3/guide/writingTheApp.html b/guides/adding-commit-info/3/guide/writingTheApp.html
index a04ecc7ab0f..8fb7c16fbdd 100644
--- a/guides/adding-commit-info/3/guide/writingTheApp.html
+++ b/guides/adding-commit-info/3/guide/writingTheApp.html
@@ -133,7 +133,20 @@ function addJsClass() {
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/4/guide/index.html b/guides/adding-commit-info/4/guide/index.html
index f77be79e2cd..0be4a0c1ded 100644
--- a/guides/adding-commit-info/4/guide/index.html
+++ b/guides/adding-commit-info/4/guide/index.html
@@ -452,7 +452,20 @@ The build-info plugin works by utilizing the environment variables available via
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/4/guide/pages/gradlePlugin.html b/guides/adding-commit-info/4/guide/pages/gradlePlugin.html
index e211b405c47..97bca37c75c 100644
--- a/guides/adding-commit-info/4/guide/pages/gradlePlugin.html
+++ b/guides/adding-commit-info/4/guide/pages/gradlePlugin.html
@@ -95,7 +95,20 @@ function addJsClass() {
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/4/guide/single.html b/guides/adding-commit-info/4/guide/single.html
index f77be79e2cd..0be4a0c1ded 100644
--- a/guides/adding-commit-info/4/guide/single.html
+++ b/guides/adding-commit-info/4/guide/single.html
@@ -452,7 +452,20 @@ The build-info plugin works by utilizing the environment variables available via
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/adding-commit-info/4/guide/writingTheApp.html b/guides/adding-commit-info/4/guide/writingTheApp.html
index e9a3613e6e1..a5518d3f7a0 100644
--- a/guides/adding-commit-info/4/guide/writingTheApp.html
+++ b/guides/adding-commit-info/4/guide/writingTheApp.html
@@ -133,7 +133,20 @@ function addJsClass() {
 The goal of this plugin is to capture the commit information and store it in a file called <code>git.properties</code></p>
 </div>
 <div class="paragraph">
-<p><a href="{commondir}/commmon-addingAGradlePlugin.adoc" class="bare include">{commondir}/commmon-addingAGradlePlugin.adoc</a></p>
+<p>Adding a Gradle plugin is fairly straight forward.  This involves a few steps.</p>
+</div>
+<div class="olist arabic">
+<ol class="arabic">
+<li>
+<p>Adding the dependency to the <code>buildscript { &#8230;&#8203; }</code> block in <code>build.gradle</code>. This means that you are adding the dependency to the build and not your deliverable application.</p>
+</li>
+<li>
+<p>Ensuring the build script dependency will be resolved via the appropriate maven repositories</p>
+</li>
+<li>
+<p>Applying the plugin</p>
+</li>
+</ol>
 </div>
 <div class="listingblock">
 <div class="title">/complete/build.gradle</div>
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/index.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/index.html
index 87898282de4..fbb66ed64cd 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/index.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/index.html
@@ -877,7 +877,13 @@ dependency is added when we create an app with the <em>rest-api</em> profile.</p
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="1"></i><b>(1)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="2"></i><b>(2)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">1.0</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -916,7 +922,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/model/Announcement.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/model/Announcement.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network.model</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Announcement</span> {
+    <span class="directive">private</span> <span class="predefined-type">Long</span> id;
+    <span class="directive">private</span> <span class="predefined-type">String</span> title;
+    <span class="directive">private</span> <span class="predefined-type">String</span> body;
+
+    <span class="directive">public</span> <span class="predefined-type">Long</span> getId() {
+        <span class="keyword">return</span> id;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setId(<span class="predefined-type">Long</span> id) {
+        <span class="local-variable">this</span>.id = id;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getTitle() {
+        <span class="keyword">return</span> title;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setTitle(<span class="predefined-type">String</span> title) {
+        <span class="local-variable">this</span>.title = title;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getBody() {
+        <span class="keyword">return</span> body;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setBody(<span class="predefined-type">String</span> body) {
+        <span class="local-variable">this</span>.body = body;
+    }
+}</code></pre>
 </div>
 </div>
 </div>
@@ -928,7 +964,7 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">    <span class="tag">&lt;uses-permission</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">android.permission.INTERNET</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="sect3">
@@ -943,7 +979,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.squareup.okhttp3:okhttp:4.2.2</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 </div>
@@ -965,7 +1001,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.google.code.gson:gson:2.8.6</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -975,7 +1011,18 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/NetworkTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/NetworkTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+
+<span class="type">class</span> <span class="class">NetworkTask</span> {
+    <span class="directive">static</span> Request requestWithUrl(<span class="predefined-type">String</span> url) {
+        <span class="keyword">return</span> <span class="keyword">new</span> Request.Builder()
+                .url(url)
+                .header(<span class="string"><span class="delimiter">&quot;</span><span class="content">Accept-Version</span><span class="delimiter">&quot;</span></span>, Constants.ACCEPT_VERSION)
+                .build();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -984,7 +1031,49 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">android.util.Log</span>;
+
+<span class="keyword">import</span> <span class="include">com.google.gson.Gson</span>;
+<span class="keyword">import</span> <span class="include">com.google.gson.reflect.TypeToken</span>;
+
+<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
+<span class="keyword">import</span> <span class="include">java.lang.reflect.Type</span>;
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.OkHttpClient</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Response</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementsFetcher</span> {
+
+    <span class="directive">private</span> <span class="directive">final</span> <span class="directive">static</span> <span class="predefined-type">String</span> TAG = AnnouncementsFetcher.class.getSimpleName();
+
+    <span class="directive">private</span> OkHttpClient client = <span class="keyword">new</span> OkHttpClient();
+    <span class="directive">private</span> <span class="directive">final</span> Gson gson = <span class="keyword">new</span> Gson();
+
+    <span class="directive">public</span> <span class="predefined-type">List</span>&lt;Announcement&gt; fetchAnnouncements() {
+        <span class="predefined-type">Type</span> listType = <span class="keyword">new</span> TypeToken&lt;<span class="predefined-type">List</span>&lt;Announcement&gt;&gt;() {}.getType();
+        <span class="keyword">try</span> {
+            <span class="predefined-type">String</span> url = Constants.GRAILS_APP_URL + Constants.ANNOUNCEMENTS_PATH;
+            <span class="predefined-type">String</span> jsonString = fetchAnnouncementsJsonString(url);
+            <span class="keyword">return</span> gson.fromJson(jsonString, listType);
+
+        } <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {
+            Log.e(TAG, e.toString());
+            <span class="keyword">return</span> <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;();
+        }
+    }
+
+    <span class="directive">private</span> <span class="predefined-type">String</span> fetchAnnouncementsJsonString(<span class="predefined-type">String</span> url) <span class="directive">throws</span> <span class="exception">IOException</span> {
+        Request request = NetworkTask.requestWithUrl(url);
+        Response response = client.newCall(request).execute();
+        <span class="keyword">return</span> response.body().string();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -994,7 +1083,36 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementsFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementsTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Void</span>, <span class="predefined-type">Void</span>, <span class="predefined-type">List</span>&lt;Announcement&gt;&gt; {
+
+    <span class="directive">private</span> AnnouncementsFetcher fetcher = <span class="keyword">new</span> AnnouncementsFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementsDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementsTask(RetrieveAnnouncementsDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="predefined-type">List</span>&lt;Announcement&gt; doInBackground(<span class="predefined-type">Void</span>... voids) {
+        <span class="keyword">return</span> fetcher.fetchAnnouncements();
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementsFetched(announcements);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1003,7 +1121,15 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementsDelegate</span> {
+    <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1012,7 +1138,62 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/MainActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/android/activities/MainActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ListView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.adapters.AnnouncementAdapter</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementsTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">MainActivity</span> <span class="directive">extends</span> Activity
+        <span class="directive">implements</span> RetrieveAnnouncementsDelegate, AnnouncementAdapterDelegate {
+
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_ID = <span class="string"><span class="delimiter">&quot;</span><span class="content">id</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_TITLE = <span class="string"><span class="delimiter">&quot;</span><span class="content">title</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_BODY = <span class="string"><span class="delimiter">&quot;</span><span class="content">body</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">private</span> AnnouncementAdapter adapter;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        <span class="predefined-type">ListView</span> announcementsListView = (<span class="predefined-type">ListView</span>) findViewById(R.id.announcementsListView);
+        adapter = <span class="keyword">new</span> AnnouncementAdapter(<span class="local-variable">this</span>, <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;Announcement&gt;(), <span class="local-variable">this</span>);
+        announcementsListView.setAdapter(adapter);
+
+        <span class="keyword">new</span> RetrieveAnnouncementsTask(<span class="local-variable">this</span>).execute(); <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        adapter.clear();
+        adapter.addAll(announcements);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementTapped(Announcement announcement) {
+        segueToAnnouncementActivity(announcement);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> segueToAnnouncementActivity(Announcement announcement) {
+        Intent i = <span class="keyword">new</span> Intent(<span class="local-variable">this</span>, AnnouncementActivity.class);
+        i.putExtra(EXTRA_ID, announcement.getId());
+        i.putExtra(EXTRA_TITLE, announcement.getTitle());
+        i.putExtra(EXTRA_BODY, announcement.getBody());
+        startActivity(i);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1033,7 +1214,25 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_main.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_main.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;ListView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/announcementsListView</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+    <span class="tag">&lt;/ListView&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1042,19 +1241,86 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.adapters</span>;
+
+<span class="keyword">import</span> <span class="include">android.content.Context</span>;
+<span class="keyword">import</span> <span class="include">android.view.LayoutInflater</span>;
+<span class="keyword">import</span> <span class="include">android.view.View</span>;
+<span class="keyword">import</span> <span class="include">android.view.ViewGroup</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ArrayAdapter</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">androidx.annotation.NonNull</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementAdapter</span> <span class="directive">extends</span> ArrayAdapter&lt;Announcement&gt; {
+    <span class="directive">private</span> AnnouncementAdapterDelegate delegate;
+
+    <span class="directive">public</span> AnnouncementAdapter(<span class="predefined-type">Context</span> context, <span class="predefined-type">List</span>&lt;Announcement&gt; announcements, AnnouncementAdapterDelegate delegate) {
+        <span class="local-variable">super</span>(context, <span class="integer">0</span>, announcements);
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@NonNull</span>
+    <span class="directive">public</span> <span class="predefined-type">View</span> getView(<span class="type">int</span> position, <span class="predefined-type">View</span> convertView, <span class="annotation">@NonNull</span> ViewGroup parent) {
+        <span class="keyword">if</span> (convertView == <span class="predefined-constant">null</span>) {
+            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_announcement, parent, <span class="predefined-constant">false</span>);
+        }
+        TextView tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
+        Announcement announcement = getItem(position);
+        <span class="keyword">if</span> ( announcement != <span class="predefined-constant">null</span> ) {
+            tvTitle.setText(announcement.getTitle());
+            tvTitle.setOnClickListener(<span class="keyword">new</span> AnnouncementClickListener(announcement));
+        }
+        <span class="keyword">return</span> convertView;
+    }
+
+    <span class="directive">private</span> <span class="type">class</span> <span class="class">AnnouncementClickListener</span> <span class="directive">implements</span> <span class="predefined-type">View</span>.OnClickListener {
+        <span class="directive">private</span> Announcement announcement;
+
+        AnnouncementClickListener(Announcement announcement) {
+            <span class="local-variable">this</span>.announcement = announcement;
+        }
+
+        <span class="annotation">@Override</span>
+        <span class="directive">public</span> <span class="type">void</span> onClick(<span class="predefined-type">View</span> view) {
+            <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+                delegate.onAnnouncementTapped(announcement);
+            }
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">AnnouncementAdapterDelegate</span> {
+    <span class="type">void</span> onAnnouncementTapped(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/item_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/item_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;LinearLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span> <span class="tag">&gt;</span>
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span>
+<span class="tag">&lt;/LinearLayout&gt;</span></code></pre>
 </div>
 </div>
 </div>
@@ -1084,19 +1350,82 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">        <span class="tag">&lt;activity</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">.android.activities.AnnouncementActivity</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+        populateUi();
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUi() {
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">String</span> title = intent.getStringExtra(MainActivity.EXTRA_TITLE);
+        <span class="directive">final</span> <span class="predefined-type">String</span> body = intent.getStringExtra(MainActivity.EXTRA_BODY);
+        populateUiWithTitleAndBody(title, body);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">tools:text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">Announcement Title</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:textSize</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">20dp</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+    <span class="tag">&lt;WebView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/wvBody</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_below</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 
@@ -1340,7 +1669,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">2.0</span><span class="delimiter">&quot;</span></span>;
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1349,7 +1684,39 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Long</span>, <span class="predefined-type">Void</span>, Announcement&gt; {
+    <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> TAG = RetrieveAnnouncementTask.class.getSimpleName();
+    AnnouncementFetcher fetcher = <span class="keyword">new</span> AnnouncementFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementTask(RetrieveAnnouncementDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> Announcement doInBackground(<span class="predefined-type">Long</span>... ids) {
+        <span class="keyword">if</span> ( ids != <span class="predefined-constant">null</span> &amp;&amp; ids.length &gt;= <span class="integer">1</span>) {
+            <span class="predefined-type">Long</span> announcementId = ids[<span class="integer">0</span>];
+            <span class="keyword">return</span> fetcher.fetchAnnouncement(announcementId);
+        }
+
+        <span class="keyword">return</span> <span class="predefined-constant">null</span>;
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(Announcement announcement) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementFetched(announcement);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1358,7 +1725,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementDelegate</span> {
+    <span class="type">void</span> onAnnouncementFetched(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1367,7 +1740,49 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity <span class="directive">implements</span> RetrieveAnnouncementDelegate {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">Long</span> announcementId = intent.getLongExtra(MainActivity.EXTRA_ID, <span class="integer">0L</span>);
+        <span class="keyword">new</span> RetrieveAnnouncementTask(<span class="local-variable">this</span>).execute(announcementId);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementFetched(Announcement announcement) {
+        populateUiWithTitleAndBody(announcement.getTitle(), announcement.getBody());
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/detailActivity.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/detailActivity.html
index 9a04491daec..18c81258e36 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/detailActivity.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/detailActivity.html
@@ -104,19 +104,82 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">        <span class="tag">&lt;activity</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">.android.activities.AnnouncementActivity</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+        populateUi();
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUi() {
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">String</span> title = intent.getStringExtra(MainActivity.EXTRA_TITLE);
+        <span class="directive">final</span> <span class="predefined-type">String</span> body = intent.getStringExtra(MainActivity.EXTRA_BODY);
+        populateUiWithTitleAndBody(title, body);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">tools:text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">Announcement Title</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:textSize</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">20dp</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+    <span class="tag">&lt;WebView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/wvBody</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_below</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
index 54ffc87e4bf..d5755c73dfe 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
@@ -96,7 +96,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="1"></i><b>(1)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="2"></i><b>(2)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">1.0</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -135,7 +141,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/model/Announcement.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/model/Announcement.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network.model</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Announcement</span> {
+    <span class="directive">private</span> <span class="predefined-type">Long</span> id;
+    <span class="directive">private</span> <span class="predefined-type">String</span> title;
+    <span class="directive">private</span> <span class="predefined-type">String</span> body;
+
+    <span class="directive">public</span> <span class="predefined-type">Long</span> getId() {
+        <span class="keyword">return</span> id;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setId(<span class="predefined-type">Long</span> id) {
+        <span class="local-variable">this</span>.id = id;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getTitle() {
+        <span class="keyword">return</span> title;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setTitle(<span class="predefined-type">String</span> title) {
+        <span class="local-variable">this</span>.title = title;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getBody() {
+        <span class="keyword">return</span> body;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setBody(<span class="predefined-type">String</span> body) {
+        <span class="local-variable">this</span>.body = body;
+    }
+}</code></pre>
 </div>
 </div>
 </div>
@@ -147,7 +183,7 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">    <span class="tag">&lt;uses-permission</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">android.permission.INTERNET</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="sect3">
@@ -162,7 +198,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.squareup.okhttp3:okhttp:4.2.2</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 </div>
@@ -184,7 +220,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.google.code.gson:gson:2.8.6</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -194,7 +230,18 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/NetworkTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/NetworkTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+
+<span class="type">class</span> <span class="class">NetworkTask</span> {
+    <span class="directive">static</span> Request requestWithUrl(<span class="predefined-type">String</span> url) {
+        <span class="keyword">return</span> <span class="keyword">new</span> Request.Builder()
+                .url(url)
+                .header(<span class="string"><span class="delimiter">&quot;</span><span class="content">Accept-Version</span><span class="delimiter">&quot;</span></span>, Constants.ACCEPT_VERSION)
+                .build();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -203,7 +250,49 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">android.util.Log</span>;
+
+<span class="keyword">import</span> <span class="include">com.google.gson.Gson</span>;
+<span class="keyword">import</span> <span class="include">com.google.gson.reflect.TypeToken</span>;
+
+<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
+<span class="keyword">import</span> <span class="include">java.lang.reflect.Type</span>;
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.OkHttpClient</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Response</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementsFetcher</span> {
+
+    <span class="directive">private</span> <span class="directive">final</span> <span class="directive">static</span> <span class="predefined-type">String</span> TAG = AnnouncementsFetcher.class.getSimpleName();
+
+    <span class="directive">private</span> OkHttpClient client = <span class="keyword">new</span> OkHttpClient();
+    <span class="directive">private</span> <span class="directive">final</span> Gson gson = <span class="keyword">new</span> Gson();
+
+    <span class="directive">public</span> <span class="predefined-type">List</span>&lt;Announcement&gt; fetchAnnouncements() {
+        <span class="predefined-type">Type</span> listType = <span class="keyword">new</span> TypeToken&lt;<span class="predefined-type">List</span>&lt;Announcement&gt;&gt;() {}.getType();
+        <span class="keyword">try</span> {
+            <span class="predefined-type">String</span> url = Constants.GRAILS_APP_URL + Constants.ANNOUNCEMENTS_PATH;
+            <span class="predefined-type">String</span> jsonString = fetchAnnouncementsJsonString(url);
+            <span class="keyword">return</span> gson.fromJson(jsonString, listType);
+
+        } <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {
+            Log.e(TAG, e.toString());
+            <span class="keyword">return</span> <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;();
+        }
+    }
+
+    <span class="directive">private</span> <span class="predefined-type">String</span> fetchAnnouncementsJsonString(<span class="predefined-type">String</span> url) <span class="directive">throws</span> <span class="exception">IOException</span> {
+        Request request = NetworkTask.requestWithUrl(url);
+        Response response = client.newCall(request).execute();
+        <span class="keyword">return</span> response.body().string();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -213,7 +302,36 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementsFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementsTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Void</span>, <span class="predefined-type">Void</span>, <span class="predefined-type">List</span>&lt;Announcement&gt;&gt; {
+
+    <span class="directive">private</span> AnnouncementsFetcher fetcher = <span class="keyword">new</span> AnnouncementsFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementsDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementsTask(RetrieveAnnouncementsDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="predefined-type">List</span>&lt;Announcement&gt; doInBackground(<span class="predefined-type">Void</span>... voids) {
+        <span class="keyword">return</span> fetcher.fetchAnnouncements();
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementsFetched(announcements);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -222,7 +340,15 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementsDelegate</span> {
+    <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -231,7 +357,62 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/MainActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/android/activities/MainActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ListView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.adapters.AnnouncementAdapter</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementsTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">MainActivity</span> <span class="directive">extends</span> Activity
+        <span class="directive">implements</span> RetrieveAnnouncementsDelegate, AnnouncementAdapterDelegate {
+
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_ID = <span class="string"><span class="delimiter">&quot;</span><span class="content">id</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_TITLE = <span class="string"><span class="delimiter">&quot;</span><span class="content">title</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_BODY = <span class="string"><span class="delimiter">&quot;</span><span class="content">body</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">private</span> AnnouncementAdapter adapter;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        <span class="predefined-type">ListView</span> announcementsListView = (<span class="predefined-type">ListView</span>) findViewById(R.id.announcementsListView);
+        adapter = <span class="keyword">new</span> AnnouncementAdapter(<span class="local-variable">this</span>, <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;Announcement&gt;(), <span class="local-variable">this</span>);
+        announcementsListView.setAdapter(adapter);
+
+        <span class="keyword">new</span> RetrieveAnnouncementsTask(<span class="local-variable">this</span>).execute(); <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        adapter.clear();
+        adapter.addAll(announcements);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementTapped(Announcement announcement) {
+        segueToAnnouncementActivity(announcement);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> segueToAnnouncementActivity(Announcement announcement) {
+        Intent i = <span class="keyword">new</span> Intent(<span class="local-variable">this</span>, AnnouncementActivity.class);
+        i.putExtra(EXTRA_ID, announcement.getId());
+        i.putExtra(EXTRA_TITLE, announcement.getTitle());
+        i.putExtra(EXTRA_BODY, announcement.getBody());
+        startActivity(i);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -252,7 +433,25 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_main.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_main.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;ListView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/announcementsListView</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+    <span class="tag">&lt;/ListView&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -261,19 +460,86 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.adapters</span>;
+
+<span class="keyword">import</span> <span class="include">android.content.Context</span>;
+<span class="keyword">import</span> <span class="include">android.view.LayoutInflater</span>;
+<span class="keyword">import</span> <span class="include">android.view.View</span>;
+<span class="keyword">import</span> <span class="include">android.view.ViewGroup</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ArrayAdapter</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">androidx.annotation.NonNull</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementAdapter</span> <span class="directive">extends</span> ArrayAdapter&lt;Announcement&gt; {
+    <span class="directive">private</span> AnnouncementAdapterDelegate delegate;
+
+    <span class="directive">public</span> AnnouncementAdapter(<span class="predefined-type">Context</span> context, <span class="predefined-type">List</span>&lt;Announcement&gt; announcements, AnnouncementAdapterDelegate delegate) {
+        <span class="local-variable">super</span>(context, <span class="integer">0</span>, announcements);
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@NonNull</span>
+    <span class="directive">public</span> <span class="predefined-type">View</span> getView(<span class="type">int</span> position, <span class="predefined-type">View</span> convertView, <span class="annotation">@NonNull</span> ViewGroup parent) {
+        <span class="keyword">if</span> (convertView == <span class="predefined-constant">null</span>) {
+            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_announcement, parent, <span class="predefined-constant">false</span>);
+        }
+        TextView tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
+        Announcement announcement = getItem(position);
+        <span class="keyword">if</span> ( announcement != <span class="predefined-constant">null</span> ) {
+            tvTitle.setText(announcement.getTitle());
+            tvTitle.setOnClickListener(<span class="keyword">new</span> AnnouncementClickListener(announcement));
+        }
+        <span class="keyword">return</span> convertView;
+    }
+
+    <span class="directive">private</span> <span class="type">class</span> <span class="class">AnnouncementClickListener</span> <span class="directive">implements</span> <span class="predefined-type">View</span>.OnClickListener {
+        <span class="directive">private</span> Announcement announcement;
+
+        AnnouncementClickListener(Announcement announcement) {
+            <span class="local-variable">this</span>.announcement = announcement;
+        }
+
+        <span class="annotation">@Override</span>
+        <span class="directive">public</span> <span class="type">void</span> onClick(<span class="predefined-type">View</span> view) {
+            <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+                delegate.onAnnouncementTapped(announcement);
+            }
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">AnnouncementAdapterDelegate</span> {
+    <span class="type">void</span> onAnnouncementTapped(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/item_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/item_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;LinearLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span> <span class="tag">&gt;</span>
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span>
+<span class="tag">&lt;/LinearLayout&gt;</span></code></pre>
 </div>
 </div>
 </div>
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/v2Android.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/v2Android.html
index 9461ea16877..9a1b2e96206 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/v2Android.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/pages/v2Android.html
@@ -96,7 +96,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">2.0</span><span class="delimiter">&quot;</span></span>;
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -105,7 +111,39 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Long</span>, <span class="predefined-type">Void</span>, Announcement&gt; {
+    <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> TAG = RetrieveAnnouncementTask.class.getSimpleName();
+    AnnouncementFetcher fetcher = <span class="keyword">new</span> AnnouncementFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementTask(RetrieveAnnouncementDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> Announcement doInBackground(<span class="predefined-type">Long</span>... ids) {
+        <span class="keyword">if</span> ( ids != <span class="predefined-constant">null</span> &amp;&amp; ids.length &gt;= <span class="integer">1</span>) {
+            <span class="predefined-type">Long</span> announcementId = ids[<span class="integer">0</span>];
+            <span class="keyword">return</span> fetcher.fetchAnnouncement(announcementId);
+        }
+
+        <span class="keyword">return</span> <span class="predefined-constant">null</span>;
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(Announcement announcement) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementFetched(announcement);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -114,7 +152,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementDelegate</span> {
+    <span class="type">void</span> onAnnouncementFetched(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -123,7 +167,49 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity <span class="directive">implements</span> RetrieveAnnouncementDelegate {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">Long</span> announcementId = intent.getLongExtra(MainActivity.EXTRA_ID, <span class="integer">0L</span>);
+        <span class="keyword">new</span> RetrieveAnnouncementTask(<span class="local-variable">this</span>).execute(announcementId);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementFetched(Announcement announcement) {
+        populateUiWithTitleAndBody(announcement.getTitle(), announcement.getBody());
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/single.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/single.html
index 87898282de4..fbb66ed64cd 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/single.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/single.html
@@ -877,7 +877,13 @@ dependency is added when we create an app with the <em>rest-api</em> profile.</p
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="1"></i><b>(1)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="2"></i><b>(2)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">1.0</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -916,7 +922,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/model/Announcement.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/model/Announcement.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network.model</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Announcement</span> {
+    <span class="directive">private</span> <span class="predefined-type">Long</span> id;
+    <span class="directive">private</span> <span class="predefined-type">String</span> title;
+    <span class="directive">private</span> <span class="predefined-type">String</span> body;
+
+    <span class="directive">public</span> <span class="predefined-type">Long</span> getId() {
+        <span class="keyword">return</span> id;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setId(<span class="predefined-type">Long</span> id) {
+        <span class="local-variable">this</span>.id = id;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getTitle() {
+        <span class="keyword">return</span> title;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setTitle(<span class="predefined-type">String</span> title) {
+        <span class="local-variable">this</span>.title = title;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getBody() {
+        <span class="keyword">return</span> body;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setBody(<span class="predefined-type">String</span> body) {
+        <span class="local-variable">this</span>.body = body;
+    }
+}</code></pre>
 </div>
 </div>
 </div>
@@ -928,7 +964,7 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">    <span class="tag">&lt;uses-permission</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">android.permission.INTERNET</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="sect3">
@@ -943,7 +979,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.squareup.okhttp3:okhttp:4.2.2</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 </div>
@@ -965,7 +1001,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.google.code.gson:gson:2.8.6</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -975,7 +1011,18 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/NetworkTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/NetworkTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+
+<span class="type">class</span> <span class="class">NetworkTask</span> {
+    <span class="directive">static</span> Request requestWithUrl(<span class="predefined-type">String</span> url) {
+        <span class="keyword">return</span> <span class="keyword">new</span> Request.Builder()
+                .url(url)
+                .header(<span class="string"><span class="delimiter">&quot;</span><span class="content">Accept-Version</span><span class="delimiter">&quot;</span></span>, Constants.ACCEPT_VERSION)
+                .build();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -984,7 +1031,49 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">android.util.Log</span>;
+
+<span class="keyword">import</span> <span class="include">com.google.gson.Gson</span>;
+<span class="keyword">import</span> <span class="include">com.google.gson.reflect.TypeToken</span>;
+
+<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
+<span class="keyword">import</span> <span class="include">java.lang.reflect.Type</span>;
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.OkHttpClient</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Response</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementsFetcher</span> {
+
+    <span class="directive">private</span> <span class="directive">final</span> <span class="directive">static</span> <span class="predefined-type">String</span> TAG = AnnouncementsFetcher.class.getSimpleName();
+
+    <span class="directive">private</span> OkHttpClient client = <span class="keyword">new</span> OkHttpClient();
+    <span class="directive">private</span> <span class="directive">final</span> Gson gson = <span class="keyword">new</span> Gson();
+
+    <span class="directive">public</span> <span class="predefined-type">List</span>&lt;Announcement&gt; fetchAnnouncements() {
+        <span class="predefined-type">Type</span> listType = <span class="keyword">new</span> TypeToken&lt;<span class="predefined-type">List</span>&lt;Announcement&gt;&gt;() {}.getType();
+        <span class="keyword">try</span> {
+            <span class="predefined-type">String</span> url = Constants.GRAILS_APP_URL + Constants.ANNOUNCEMENTS_PATH;
+            <span class="predefined-type">String</span> jsonString = fetchAnnouncementsJsonString(url);
+            <span class="keyword">return</span> gson.fromJson(jsonString, listType);
+
+        } <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {
+            Log.e(TAG, e.toString());
+            <span class="keyword">return</span> <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;();
+        }
+    }
+
+    <span class="directive">private</span> <span class="predefined-type">String</span> fetchAnnouncementsJsonString(<span class="predefined-type">String</span> url) <span class="directive">throws</span> <span class="exception">IOException</span> {
+        Request request = NetworkTask.requestWithUrl(url);
+        Response response = client.newCall(request).execute();
+        <span class="keyword">return</span> response.body().string();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -994,7 +1083,36 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementsFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementsTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Void</span>, <span class="predefined-type">Void</span>, <span class="predefined-type">List</span>&lt;Announcement&gt;&gt; {
+
+    <span class="directive">private</span> AnnouncementsFetcher fetcher = <span class="keyword">new</span> AnnouncementsFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementsDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementsTask(RetrieveAnnouncementsDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="predefined-type">List</span>&lt;Announcement&gt; doInBackground(<span class="predefined-type">Void</span>... voids) {
+        <span class="keyword">return</span> fetcher.fetchAnnouncements();
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementsFetched(announcements);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1003,7 +1121,15 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementsDelegate</span> {
+    <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1012,7 +1138,62 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/MainActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/android/activities/MainActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ListView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.adapters.AnnouncementAdapter</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementsTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">MainActivity</span> <span class="directive">extends</span> Activity
+        <span class="directive">implements</span> RetrieveAnnouncementsDelegate, AnnouncementAdapterDelegate {
+
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_ID = <span class="string"><span class="delimiter">&quot;</span><span class="content">id</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_TITLE = <span class="string"><span class="delimiter">&quot;</span><span class="content">title</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_BODY = <span class="string"><span class="delimiter">&quot;</span><span class="content">body</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">private</span> AnnouncementAdapter adapter;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        <span class="predefined-type">ListView</span> announcementsListView = (<span class="predefined-type">ListView</span>) findViewById(R.id.announcementsListView);
+        adapter = <span class="keyword">new</span> AnnouncementAdapter(<span class="local-variable">this</span>, <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;Announcement&gt;(), <span class="local-variable">this</span>);
+        announcementsListView.setAdapter(adapter);
+
+        <span class="keyword">new</span> RetrieveAnnouncementsTask(<span class="local-variable">this</span>).execute(); <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        adapter.clear();
+        adapter.addAll(announcements);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementTapped(Announcement announcement) {
+        segueToAnnouncementActivity(announcement);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> segueToAnnouncementActivity(Announcement announcement) {
+        Intent i = <span class="keyword">new</span> Intent(<span class="local-variable">this</span>, AnnouncementActivity.class);
+        i.putExtra(EXTRA_ID, announcement.getId());
+        i.putExtra(EXTRA_TITLE, announcement.getTitle());
+        i.putExtra(EXTRA_BODY, announcement.getBody());
+        startActivity(i);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1033,7 +1214,25 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_main.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_main.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;ListView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/announcementsListView</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+    <span class="tag">&lt;/ListView&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1042,19 +1241,86 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.adapters</span>;
+
+<span class="keyword">import</span> <span class="include">android.content.Context</span>;
+<span class="keyword">import</span> <span class="include">android.view.LayoutInflater</span>;
+<span class="keyword">import</span> <span class="include">android.view.View</span>;
+<span class="keyword">import</span> <span class="include">android.view.ViewGroup</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ArrayAdapter</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">androidx.annotation.NonNull</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementAdapter</span> <span class="directive">extends</span> ArrayAdapter&lt;Announcement&gt; {
+    <span class="directive">private</span> AnnouncementAdapterDelegate delegate;
+
+    <span class="directive">public</span> AnnouncementAdapter(<span class="predefined-type">Context</span> context, <span class="predefined-type">List</span>&lt;Announcement&gt; announcements, AnnouncementAdapterDelegate delegate) {
+        <span class="local-variable">super</span>(context, <span class="integer">0</span>, announcements);
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@NonNull</span>
+    <span class="directive">public</span> <span class="predefined-type">View</span> getView(<span class="type">int</span> position, <span class="predefined-type">View</span> convertView, <span class="annotation">@NonNull</span> ViewGroup parent) {
+        <span class="keyword">if</span> (convertView == <span class="predefined-constant">null</span>) {
+            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_announcement, parent, <span class="predefined-constant">false</span>);
+        }
+        TextView tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
+        Announcement announcement = getItem(position);
+        <span class="keyword">if</span> ( announcement != <span class="predefined-constant">null</span> ) {
+            tvTitle.setText(announcement.getTitle());
+            tvTitle.setOnClickListener(<span class="keyword">new</span> AnnouncementClickListener(announcement));
+        }
+        <span class="keyword">return</span> convertView;
+    }
+
+    <span class="directive">private</span> <span class="type">class</span> <span class="class">AnnouncementClickListener</span> <span class="directive">implements</span> <span class="predefined-type">View</span>.OnClickListener {
+        <span class="directive">private</span> Announcement announcement;
+
+        AnnouncementClickListener(Announcement announcement) {
+            <span class="local-variable">this</span>.announcement = announcement;
+        }
+
+        <span class="annotation">@Override</span>
+        <span class="directive">public</span> <span class="type">void</span> onClick(<span class="predefined-type">View</span> view) {
+            <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+                delegate.onAnnouncementTapped(announcement);
+            }
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">AnnouncementAdapterDelegate</span> {
+    <span class="type">void</span> onAnnouncementTapped(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/item_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/item_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;LinearLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span> <span class="tag">&gt;</span>
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span>
+<span class="tag">&lt;/LinearLayout&gt;</span></code></pre>
 </div>
 </div>
 </div>
@@ -1084,19 +1350,82 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">        <span class="tag">&lt;activity</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">.android.activities.AnnouncementActivity</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+        populateUi();
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUi() {
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">String</span> title = intent.getStringExtra(MainActivity.EXTRA_TITLE);
+        <span class="directive">final</span> <span class="predefined-type">String</span> body = intent.getStringExtra(MainActivity.EXTRA_BODY);
+        populateUiWithTitleAndBody(title, body);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">tools:text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">Announcement Title</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:textSize</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">20dp</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+    <span class="tag">&lt;WebView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/wvBody</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_below</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 
@@ -1340,7 +1669,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">2.0</span><span class="delimiter">&quot;</span></span>;
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1349,7 +1684,39 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Long</span>, <span class="predefined-type">Void</span>, Announcement&gt; {
+    <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> TAG = RetrieveAnnouncementTask.class.getSimpleName();
+    AnnouncementFetcher fetcher = <span class="keyword">new</span> AnnouncementFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementTask(RetrieveAnnouncementDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> Announcement doInBackground(<span class="predefined-type">Long</span>... ids) {
+        <span class="keyword">if</span> ( ids != <span class="predefined-constant">null</span> &amp;&amp; ids.length &gt;= <span class="integer">1</span>) {
+            <span class="predefined-type">Long</span> announcementId = ids[<span class="integer">0</span>];
+            <span class="keyword">return</span> fetcher.fetchAnnouncement(announcementId);
+        }
+
+        <span class="keyword">return</span> <span class="predefined-constant">null</span>;
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(Announcement announcement) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementFetched(announcement);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1358,7 +1725,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementDelegate</span> {
+    <span class="type">void</span> onAnnouncementFetched(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1367,7 +1740,49 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity <span class="directive">implements</span> RetrieveAnnouncementDelegate {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">Long</span> announcementId = intent.getLongExtra(MainActivity.EXTRA_ID, <span class="integer">0L</span>);
+        <span class="keyword">new</span> RetrieveAnnouncementTask(<span class="local-variable">this</span>).execute(announcementId);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementFetched(Announcement announcement) {
+        populateUiWithTitleAndBody(announcement.getTitle(), announcement.getBody());
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/version2.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/version2.html
index ad66459f56a..178de4d67a0 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/version2.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/version2.html
@@ -334,7 +334,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">2.0</span><span class="delimiter">&quot;</span></span>;
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -343,7 +349,39 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Long</span>, <span class="predefined-type">Void</span>, Announcement&gt; {
+    <span class="directive">private</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> TAG = RetrieveAnnouncementTask.class.getSimpleName();
+    AnnouncementFetcher fetcher = <span class="keyword">new</span> AnnouncementFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementTask(RetrieveAnnouncementDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> Announcement doInBackground(<span class="predefined-type">Long</span>... ids) {
+        <span class="keyword">if</span> ( ids != <span class="predefined-constant">null</span> &amp;&amp; ids.length &gt;= <span class="integer">1</span>) {
+            <span class="predefined-type">Long</span> announcementId = ids[<span class="integer">0</span>];
+            <span class="keyword">return</span> fetcher.fetchAnnouncement(announcementId);
+        }
+
+        <span class="keyword">return</span> <span class="predefined-constant">null</span>;
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(Announcement announcement) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementFetched(announcement);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -352,7 +390,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementDelegate.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementDelegate</span> {
+    <span class="type">void</span> onAnnouncementFetched(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -361,7 +405,49 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v2/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity <span class="directive">implements</span> RetrieveAnnouncementDelegate {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">Long</span> announcementId = intent.getLongExtra(MainActivity.EXTRA_ID, <span class="integer">0L</span>);
+        <span class="keyword">new</span> RetrieveAnnouncementTask(<span class="local-variable">this</span>).execute(announcementId);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementFetched(Announcement announcement) {
+        populateUiWithTitleAndBody(announcement.getTitle(), announcement.getBody());
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/writingTheAndroidApp.html b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/writingTheAndroidApp.html
index 7553f77ead9..69ee1809355 100644
--- a/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/writingTheAndroidApp.html
+++ b/guides/building-an-android-client-powered-by-a-grails-backend/4/guide/writingTheAndroidApp.html
@@ -141,7 +141,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/Constants.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/Constants.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Constants</span> {
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> GRAILS_APP_URL = <span class="string"><span class="delimiter">&quot;</span><span class="content">http://192.168.1.42:8080/</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="1"></i><b>(1)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ANNOUNCEMENTS_PATH = <span class="string"><span class="delimiter">&quot;</span><span class="content">announcements</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="2"></i><b>(2)</b>
+    <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> ACCEPT_VERSION = <span class="string"><span class="delimiter">&quot;</span><span class="content">1.0</span><span class="delimiter">&quot;</span></span>; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -180,7 +186,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/model/Announcement.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/model/Announcement.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network.model</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">Announcement</span> {
+    <span class="directive">private</span> <span class="predefined-type">Long</span> id;
+    <span class="directive">private</span> <span class="predefined-type">String</span> title;
+    <span class="directive">private</span> <span class="predefined-type">String</span> body;
+
+    <span class="directive">public</span> <span class="predefined-type">Long</span> getId() {
+        <span class="keyword">return</span> id;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setId(<span class="predefined-type">Long</span> id) {
+        <span class="local-variable">this</span>.id = id;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getTitle() {
+        <span class="keyword">return</span> title;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setTitle(<span class="predefined-type">String</span> title) {
+        <span class="local-variable">this</span>.title = title;
+    }
+
+    <span class="directive">public</span> <span class="predefined-type">String</span> getBody() {
+        <span class="keyword">return</span> body;
+    }
+
+    <span class="directive">public</span> <span class="type">void</span> setBody(<span class="predefined-type">String</span> body) {
+        <span class="local-variable">this</span>.body = body;
+    }
+}</code></pre>
 </div>
 </div>
 </div>
@@ -192,7 +228,7 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">    <span class="tag">&lt;uses-permission</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">android.permission.INTERNET</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="sect3">
@@ -207,7 +243,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.squareup.okhttp3:okhttp:4.2.2</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 </div>
@@ -229,7 +265,7 @@ dependencies block, the next line:</p>
 <div class="listingblock">
 <div class="title">/app/build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:{sourcedir}/..<span class="regexp"><span class="delimiter">/</span><span class="content">complete-android-v1</span><span class="delimiter">/</span></span>app/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">    implementation <span class="string"><span class="delimiter">'</span><span class="content">com.google.code.gson:gson:2.8.6</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -239,7 +275,18 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/NetworkTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/NetworkTask.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+
+<span class="type">class</span> <span class="class">NetworkTask</span> {
+    <span class="directive">static</span> Request requestWithUrl(<span class="predefined-type">String</span> url) {
+        <span class="keyword">return</span> <span class="keyword">new</span> Request.Builder()
+                .url(url)
+                .header(<span class="string"><span class="delimiter">&quot;</span><span class="content">Accept-Version</span><span class="delimiter">&quot;</span></span>, Constants.ACCEPT_VERSION)
+                .build();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -248,7 +295,49 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/network/AnnouncementsFetcher.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.network</span>;
+
+<span class="keyword">import</span> <span class="include">android.util.Log</span>;
+
+<span class="keyword">import</span> <span class="include">com.google.gson.Gson</span>;
+<span class="keyword">import</span> <span class="include">com.google.gson.reflect.TypeToken</span>;
+
+<span class="keyword">import</span> <span class="include">java.io.IOException</span>;
+<span class="keyword">import</span> <span class="include">java.lang.reflect.Type</span>;
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.OkHttpClient</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Request</span>;
+<span class="keyword">import</span> <span class="include">okhttp3.Response</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementsFetcher</span> {
+
+    <span class="directive">private</span> <span class="directive">final</span> <span class="directive">static</span> <span class="predefined-type">String</span> TAG = AnnouncementsFetcher.class.getSimpleName();
+
+    <span class="directive">private</span> OkHttpClient client = <span class="keyword">new</span> OkHttpClient();
+    <span class="directive">private</span> <span class="directive">final</span> Gson gson = <span class="keyword">new</span> Gson();
+
+    <span class="directive">public</span> <span class="predefined-type">List</span>&lt;Announcement&gt; fetchAnnouncements() {
+        <span class="predefined-type">Type</span> listType = <span class="keyword">new</span> TypeToken&lt;<span class="predefined-type">List</span>&lt;Announcement&gt;&gt;() {}.getType();
+        <span class="keyword">try</span> {
+            <span class="predefined-type">String</span> url = Constants.GRAILS_APP_URL + Constants.ANNOUNCEMENTS_PATH;
+            <span class="predefined-type">String</span> jsonString = fetchAnnouncementsJsonString(url);
+            <span class="keyword">return</span> gson.fromJson(jsonString, listType);
+
+        } <span class="keyword">catch</span> (<span class="exception">IOException</span> e) {
+            Log.e(TAG, e.toString());
+            <span class="keyword">return</span> <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;&gt;();
+        }
+    }
+
+    <span class="directive">private</span> <span class="predefined-type">String</span> fetchAnnouncementsJsonString(<span class="predefined-type">String</span> url) <span class="directive">throws</span> <span class="exception">IOException</span> {
+        Request request = NetworkTask.requestWithUrl(url);
+        Response response = client.newCall(request).execute();
+        <span class="keyword">return</span> response.body().string();
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -258,7 +347,36 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/asynctasks/RetrieveAnnouncementsTask.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.asynctasks</span>;
+
+<span class="keyword">import</span> <span class="include">android.os.AsyncTask</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.AnnouncementsFetcher</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">RetrieveAnnouncementsTask</span> <span class="directive">extends</span> AsyncTask&lt;<span class="predefined-type">Void</span>, <span class="predefined-type">Void</span>, <span class="predefined-type">List</span>&lt;Announcement&gt;&gt; {
+
+    <span class="directive">private</span> AnnouncementsFetcher fetcher = <span class="keyword">new</span> AnnouncementsFetcher();
+    <span class="directive">private</span> RetrieveAnnouncementsDelegate delegate;
+
+    <span class="directive">public</span> RetrieveAnnouncementsTask(RetrieveAnnouncementsDelegate delegate) {
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="predefined-type">List</span>&lt;Announcement&gt; doInBackground(<span class="predefined-type">Void</span>... voids) {
+        <span class="keyword">return</span> fetcher.fetchAnnouncements();
+    }
+
+    <span class="directive">protected</span> <span class="type">void</span> onPostExecute(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {
+        <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+            delegate.onAnnouncementsFetched(announcements);
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -267,7 +385,15 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/RetrieveAnnouncementsDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">RetrieveAnnouncementsDelegate</span> {
+    <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements);
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -276,7 +402,62 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/MainActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1/app/src/main/java/intranet/client/android/activities/MainActivity.java[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ListView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.ArrayList</span>;
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.adapters.AnnouncementAdapter</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.asynctasks.RetrieveAnnouncementsTask</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.RetrieveAnnouncementsDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">MainActivity</span> <span class="directive">extends</span> Activity
+        <span class="directive">implements</span> RetrieveAnnouncementsDelegate, AnnouncementAdapterDelegate {
+
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_ID = <span class="string"><span class="delimiter">&quot;</span><span class="content">id</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_TITLE = <span class="string"><span class="delimiter">&quot;</span><span class="content">title</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">public</span> <span class="directive">static</span> <span class="directive">final</span> <span class="predefined-type">String</span> EXTRA_BODY = <span class="string"><span class="delimiter">&quot;</span><span class="content">body</span><span class="delimiter">&quot;</span></span>;
+    <span class="directive">private</span> AnnouncementAdapter adapter;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_main);
+
+        <span class="predefined-type">ListView</span> announcementsListView = (<span class="predefined-type">ListView</span>) findViewById(R.id.announcementsListView);
+        adapter = <span class="keyword">new</span> AnnouncementAdapter(<span class="local-variable">this</span>, <span class="keyword">new</span> <span class="predefined-type">ArrayList</span>&lt;Announcement&gt;(), <span class="local-variable">this</span>);
+        announcementsListView.setAdapter(adapter);
+
+        <span class="keyword">new</span> RetrieveAnnouncementsTask(<span class="local-variable">this</span>).execute(); <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementsFetched(<span class="predefined-type">List</span>&lt;Announcement&gt; announcements) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        adapter.clear();
+        adapter.addAll(announcements);
+    }
+
+    <span class="annotation">@Override</span>
+    <span class="directive">public</span> <span class="type">void</span> onAnnouncementTapped(Announcement announcement) {
+        segueToAnnouncementActivity(announcement);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> segueToAnnouncementActivity(Announcement announcement) {
+        Intent i = <span class="keyword">new</span> Intent(<span class="local-variable">this</span>, AnnouncementActivity.class);
+        i.putExtra(EXTRA_ID, announcement.getId());
+        i.putExtra(EXTRA_TITLE, announcement.getTitle());
+        i.putExtra(EXTRA_BODY, announcement.getBody());
+        startActivity(i);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -297,7 +478,25 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_main.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_main.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;ListView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/announcementsListView</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+    <span class="tag">&lt;/ListView&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -306,19 +505,86 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/adapters/AnnouncementAdapter.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.adapters</span>;
+
+<span class="keyword">import</span> <span class="include">android.content.Context</span>;
+<span class="keyword">import</span> <span class="include">android.view.LayoutInflater</span>;
+<span class="keyword">import</span> <span class="include">android.view.View</span>;
+<span class="keyword">import</span> <span class="include">android.view.ViewGroup</span>;
+<span class="keyword">import</span> <span class="include">android.widget.ArrayAdapter</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">java.util.List</span>;
+
+<span class="keyword">import</span> <span class="include">androidx.annotation.NonNull</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.android.delegates.AnnouncementAdapterDelegate</span>;
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementAdapter</span> <span class="directive">extends</span> ArrayAdapter&lt;Announcement&gt; {
+    <span class="directive">private</span> AnnouncementAdapterDelegate delegate;
+
+    <span class="directive">public</span> AnnouncementAdapter(<span class="predefined-type">Context</span> context, <span class="predefined-type">List</span>&lt;Announcement&gt; announcements, AnnouncementAdapterDelegate delegate) {
+        <span class="local-variable">super</span>(context, <span class="integer">0</span>, announcements);
+        <span class="local-variable">this</span>.delegate = delegate;
+    }
+
+    <span class="annotation">@NonNull</span>
+    <span class="directive">public</span> <span class="predefined-type">View</span> getView(<span class="type">int</span> position, <span class="predefined-type">View</span> convertView, <span class="annotation">@NonNull</span> ViewGroup parent) {
+        <span class="keyword">if</span> (convertView == <span class="predefined-constant">null</span>) {
+            convertView = LayoutInflater.from(getContext()).inflate(R.layout.item_announcement, parent, <span class="predefined-constant">false</span>);
+        }
+        TextView tvTitle = (TextView) convertView.findViewById(R.id.tvTitle);
+        Announcement announcement = getItem(position);
+        <span class="keyword">if</span> ( announcement != <span class="predefined-constant">null</span> ) {
+            tvTitle.setText(announcement.getTitle());
+            tvTitle.setOnClickListener(<span class="keyword">new</span> AnnouncementClickListener(announcement));
+        }
+        <span class="keyword">return</span> convertView;
+    }
+
+    <span class="directive">private</span> <span class="type">class</span> <span class="class">AnnouncementClickListener</span> <span class="directive">implements</span> <span class="predefined-type">View</span>.OnClickListener {
+        <span class="directive">private</span> Announcement announcement;
+
+        AnnouncementClickListener(Announcement announcement) {
+            <span class="local-variable">this</span>.announcement = announcement;
+        }
+
+        <span class="annotation">@Override</span>
+        <span class="directive">public</span> <span class="type">void</span> onClick(<span class="predefined-type">View</span> view) {
+            <span class="keyword">if</span> ( delegate != <span class="predefined-constant">null</span> ) {
+                delegate.onAnnouncementTapped(announcement);
+            }
+        }
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/delegates/AnnouncementAdapterDelegate.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.delegates</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.network.model.Announcement</span>;
+
+<span class="directive">public</span> <span class="type">interface</span> <span class="class">AnnouncementAdapterDelegate</span> {
+    <span class="type">void</span> onAnnouncementTapped(Announcement announcement);
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/item_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/item_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="tag">&lt;LinearLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span> <span class="tag">&gt;</span>
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span><span class="tag">/&gt;</span>
+<span class="tag">&lt;/LinearLayout&gt;</span></code></pre>
 </div>
 </div>
 </div>
@@ -348,19 +614,82 @@ always set with the value defined in the <em>Constants.java</em> class</p>
 <div class="listingblock">
 <div class="title">/app/src/main/AndroidManifest.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/AndroidManifest.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml">        <span class="tag">&lt;activity</span> <span class="attribute-name">android:name</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">.android.activities.AnnouncementActivity</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span></code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="java">link:{sourcedir}/../complete-android-v1<span class="comment">//app/src/main/java/intranet/client/android/activities/AnnouncementActivity.java[role=include]</span></code></pre>
+<pre class="CodeRay highlight"><code data-lang="java"><span class="keyword">package</span> <span class="namespace">intranet.client.android.activities</span>;
+
+<span class="keyword">import</span> <span class="include">android.app.Activity</span>;
+<span class="keyword">import</span> <span class="include">android.content.Intent</span>;
+<span class="keyword">import</span> <span class="include">android.os.Bundle</span>;
+<span class="keyword">import</span> <span class="include">android.webkit.WebView</span>;
+<span class="keyword">import</span> <span class="include">android.widget.TextView</span>;
+
+<span class="keyword">import</span> <span class="include">intranet.client.R</span>;
+
+<span class="directive">public</span> <span class="type">class</span> <span class="class">AnnouncementActivity</span> <span class="directive">extends</span> Activity {
+
+    <span class="directive">private</span> TextView tvTitle;
+    <span class="directive">private</span> WebView wvBody;
+
+    <span class="annotation">@Override</span>
+    <span class="directive">protected</span> <span class="type">void</span> onCreate(Bundle savedInstanceState) {
+        <span class="local-variable">super</span>.onCreate(savedInstanceState);
+        setContentView(R.layout.activity_announcement);
+
+        tvTitle = (TextView) findViewById(R.id.tvTitle);
+        wvBody = (WebView) findViewById(R.id.wvBody);
+        populateUi();
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUi() {
+        Intent intent = getIntent();
+        <span class="directive">final</span> <span class="predefined-type">String</span> title = intent.getStringExtra(MainActivity.EXTRA_TITLE);
+        <span class="directive">final</span> <span class="predefined-type">String</span> body = intent.getStringExtra(MainActivity.EXTRA_BODY);
+        populateUiWithTitleAndBody(title, body);
+    }
+
+    <span class="directive">private</span> <span class="type">void</span> populateUiWithTitleAndBody(<span class="directive">final</span> <span class="predefined-type">String</span> title, <span class="directive">final</span> <span class="predefined-type">String</span> body) {
+        tvTitle.setText(title);
+        <span class="directive">final</span> <span class="predefined-type">String</span> mime = <span class="string"><span class="delimiter">&quot;</span><span class="content">text/html</span><span class="delimiter">&quot;</span></span>;
+        <span class="directive">final</span> <span class="predefined-type">String</span> encoding = <span class="string"><span class="delimiter">&quot;</span><span class="content">utf-8</span><span class="delimiter">&quot;</span></span>;
+        wvBody.loadDataWithBaseURL(<span class="predefined-constant">null</span>, body, mime, encoding, <span class="predefined-constant">null</span>);
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/app/src/main/res/layout/activity_announcement.xml</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="xml">link:{sourcedir}/../complete-android-v1/app/src/main/res/layout/activity_announcement.xml[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="xml"><span class="preprocessor">&lt;?xml version=&quot;1.0&quot; encoding=&quot;utf-8&quot;?&gt;</span>
+<span class="tag">&lt;RelativeLayout</span> <span class="attribute-name">xmlns:android</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/apk/res/android</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">xmlns:tools</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">http://schemas.android.com/tools</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/activity_main</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingBottom</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingLeft</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingRight</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_horizontal_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">android:paddingTop</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@dimen/activity_vertical_margin</span><span class="delimiter">&quot;</span></span>
+    <span class="attribute-name">tools:context</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">grails.company.client.intranet.client.MainActivity</span><span class="delimiter">&quot;</span></span><span class="tag">&gt;</span>
+
+    <span class="tag">&lt;TextView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">tools:text</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">Announcement Title</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:textSize</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">20dp</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">match_parent</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+    <span class="tag">&lt;WebView</span>
+        <span class="attribute-name">android:id</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/wvBody</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_below</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">@+id/tvTitle</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_width</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span>
+        <span class="attribute-name">android:layout_height</span>=<span class="string"><span class="delimiter">&quot;</span><span class="content">wrap_content</span><span class="delimiter">&quot;</span></span> <span class="tag">/&gt;</span>
+
+<span class="tag">&lt;/RelativeLayout&gt;</span></code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/index.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/index.html
index 8293b428ea6..4dc15516aab 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/index.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/index.html
@@ -887,13 +887,25 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface Announcement : NSObject
+
+@property (nonatomic, copy)NSNumber *primaryKey;
+@property (nonatomic, copy)NSString *title;
+@property (nonatomic, copy)NSString *body;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;Announcement.h&quot;
+
+@implementation Announcement
+
+@end</code></pre>
 </div>
 </div>
 
@@ -913,25 +925,255 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+#import &quot;ElementBuilder.h&quot;
+
+extern NSString *kAnnouncementBuilderErrorDomain;
+
+enum {
+    kAnnouncementBuilderInvalidJSONError,
+    kAnnouncementBuilderMissingDataError,
+};
+
+@interface AnnouncementBuilder : ElementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementBuilder.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kJSONKeyId = @&quot;id&quot;;
+static NSString *kJSONKeyTitle = @&quot;title&quot;;
+static NSString *kJSONKeyBody = @&quot;body&quot;;
+
+@implementation AnnouncementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error {
+
+    return [super arrayFromJSON:objectNotation
+                            key:nil
+                          error:error
+           invalidJSONErrorCode:kAnnouncementBuilderInvalidJSONError
+          missingDataErrorCode:kAnnouncementBuilderMissingDataError
+                   errorDomain:kAnnouncementBuilderErrorDomain];
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+
+    Announcement *announcement = [[Announcement alloc] init];
+
+    if([[dict objectForKey:kJSONKeyId] isKindOfClass:[NSNumber class]]) {
+        announcement.primaryKey = (NSNumber *)[dict objectForKey:kJSONKeyId];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyTitle] isKindOfClass:[NSString class]]) {
+        announcement.title = (NSString *)[dict objectForKey:kJSONKeyTitle];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyBody] isKindOfClass:[NSString class]]) {
+        announcement.body = (NSString *)[dict objectForKey:kJSONKeyBody];
+    }
+
+    return announcement;
+
+}
+
+- ( NSError *)invalidJsonError {
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+    return [NSError errorWithDomain:kAnnouncementBuilderErrorDomain
+                               code:kAnnouncementBuilderInvalidJSONError
+                           userInfo:userInfo];
+}
+
+@end
+
+NSString *kAnnouncementBuilderErrorDomain = @&quot;kAnnouncementBuilderErrorDomain&quot;;</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface ElementBuilder : NSObject
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain;
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;ElementBuilder.h&quot;
+
+@implementation ElementBuilder
+
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain {
+
+    id parsedObject = [self parseJSON:objectNotation
+                                error:error
+                 invalidJSONErrorCode:invalidJSONErrorCode
+                          errorDomain:errorDomain];
+
+    NSArray *elements = nil;
+    if ( [parsedObject isKindOfClass:[NSDictionary class]]) {
+        elements = [((NSDictionary *)parsedObject) objectForKey:key];
+
+    } else if ( [parsedObject isKindOfClass:[NSArray class]] ) {
+        elements = (NSArray *)parsedObject;
+    }
+
+    if (elements == nil) {
+        if (error != NULL) {
+            *error = [NSError errorWithDomain:errorDomain code:missingDataErrorCode userInfo:nil];
+        }
+        return nil;
+    }
+
+    NSMutableArray *results = [NSMutableArray arrayWithCapacity:[elements count]];
+    for (NSDictionary *parsedEl in elements) {
+        id el = [self newElementWithDictionary:parsedEl
+                                         error:error
+                          invalidJSONErrorCode:invalidJSONErrorCode
+                          missingDataErrorCode:missingDataErrorCode
+                                   errorDomain:errorDomain];
+        // Return nil becuase there has been an error in the previous method call
+        if(!el) {
+            return nil;
+        }
+
+        if([self isElementValid:el]) {
+            [results addObject:el];
+        }
+    }
+    return [results copy];
+}
+
+
+- (BOOL)isElementValid:(id)el {
+    // This may be overriden in a subclass
+    return YES;
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+    @throw [NSException exceptionWithName:NSInternalInconsistencyException
+                                   reason:[NSString stringWithFormat:@&quot;You must override %@ in a subclass&quot;, NSStringFromSelector(_cmd)]
+                                 userInfo:nil];
+}
+
+
+- (id)parseJSON:(NSString *)objectNotation
+          error:(NSError **)error
+invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+    errorDomain:(NSString *)errorDomain  {
+
+    NSParameterAssert(objectNotation != nil);
+    id jsonObject;
+
+    NSError *localError = nil;
+    if(objectNotation != nil) {
+        NSData *unicodeNotation = [objectNotation dataUsingEncoding:NSUTF8StringEncoding];
+        jsonObject = [NSJSONSerialization JSONObjectWithData:unicodeNotation
+                                                     options:0
+                                                       error:&amp;localError];
+    }
+    if (jsonObject == nil) {
+        if (error != NULL) {
+            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+            if (localError != nil) {
+                [userInfo setObject:localError forKey:NSUnderlyingErrorKey];
+            }
+            *error = [NSError errorWithDomain:errorDomain code:invalidJSONErrorCode userInfo:userInfo];
+        }
+        return nil;
+    }
+    return jsonObject;
+}
+
++ (id)objectOrNull:(id)object {
+    if (!object || object == [NSNull null]) return nil;
+    return object;
+}
+
++ (BOOL)isNotNilAndNotArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isArrayTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isNumberTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isStringTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSString class]]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSNumber class]]) {
+        return YES;
+    }
+    return NO;
+}
++ (BOOL)isArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSArray class]]) {
+        return YES;
+    }
+    return NO;
+}
+
+@end</code></pre>
 </div>
 </div>
 
@@ -970,7 +1212,22 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;1.0&quot;;
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1004,7 +1261,52 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;GrailsFetcher.h&quot;
+
+@interface GrailsFetcher () &lt;NSURLSessionDelegate&gt;
+
+@end
+
+@implementation GrailsFetcher
+
+#pragma mark - LifeCycle
+
+- (id)init {
+    if(self = [super init]) {
+        NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
+        self.session = [NSURLSession sessionWithConfiguration:configuration
+                                                     delegate:self
+                                                delegateQueue:[NSOperationQueue mainQueue]];
+    }
+    return self;
+}
+
+
+#pragma mark - Public
+
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval {
+    NSURL *url = [NSURL URLWithString:urlString];
+    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url
+                                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                                                          timeoutInterval:FAST_TIME_INTERVAL];
+    [urlRequest setHTTPMethod:@&quot;GET&quot;];
+
+    [[self headers] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop) {
+        [urlRequest setValue:obj forHTTPHeaderField:key];
+    }];
+    return urlRequest;
+}
+
+#pragma mark - Private
+
+- (NSDictionary *)headers {
+    return @{@&quot;Accept-Version&quot;: kApiVersion}; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1018,13 +1320,97 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+
+@protocol AnnouncementsFetcherDelegate;
+
+@interface AnnouncementsFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+
+@interface AnnouncementsFetcher ()
+
+@property ( nonatomic, weak) id&lt;AnnouncementsFetcherDelegate&gt; delegate;
+
+@property ( nonatomic, strong) AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+- (void)fetchAnnouncements {
+
+    [self fetchAnnouncementsWithCompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        NSArray *announcements = [self.builder announcementsFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementsFetched:announcements];
+        }
+
+    }];
+}
+
+- (void)fetchAnnouncementsWithCompletionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementsURLRequest] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementsURLRequest {
+    NSString *urlStr = [self announcementsURLString];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementsURLString {
+    return [NSString stringWithFormat:@&quot;%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1033,7 +1419,16 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@protocol AnnouncementsFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementsFetchingFailed;
+
+- (void)announcementsFetched:(NSArray *)announcements;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1042,13 +1437,139 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@class DetailViewController;
+
+@interface MasterViewController : UITableViewController
+
+@property (strong, nonatomic) DetailViewController *detailViewController;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;MasterViewController.h&quot;
+#import &quot;DetailViewController.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kSegueShowDetail = @&quot;showDetail&quot;;
+
+@interface MasterViewController () &lt;AnnouncementsFetcherDelegate&gt;
+
+@property NSMutableArray *objects;
+
+@property ( nonatomic, strong ) AnnouncementsFetcher *fetcher;
+
+@property ( nonatomic, strong) id&lt;UITableViewDataSource&gt; tableViewDataSource;
+@property ( nonatomic, strong) id&lt;UITableViewDelegate&gt; tableViewDelegate;
+
+@end
+
+@implementation MasterViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    self.tableViewDataSource = [[AnnouncementsTableViewDataSource alloc] init];
+    self.tableViewDelegate = [[AnnouncementsTableViewDelegate alloc] init];
+    self.tableView.dataSource = self.tableViewDataSource;
+    self.tableView.delegate = self.tableViewDelegate;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    self.clearsSelectionOnViewWillAppear = self.splitViewController.isCollapsed;
+    [super viewWillAppear:animated];
+
+    [self registerNotifications];
+    [self fetchAnnouncements]; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [self unregisterNotifications];
+}
+
+#pragma mark - Notifications
+
+-(void)registerNotifications {
+
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc addObserver:self selector:@selector(announcementTapped:) name:kAnnouncementTappedNotification object:nil];
+}
+
+- (void)unregisterNotifications {
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:kAnnouncementTappedNotification object:nil];
+}
+
+#pragma mark - Segues
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}
+
+#pragma mark - Private Methods
+
+- (void)announcementTapped:(NSNotification *)notification {
+    if([[notification object] isKindOfClass:[Announcement class]]) {
+        Announcement *announcement = (Announcement *)[notification object];
+        [self performSegueWithIdentifier:kSegueShowDetail sender:announcement];
+    }
+}
+
+- (void)setNetworkActivityIndicator:(BOOL)visible {
+    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:visible];
+}
+
+- (void)fetchAnnouncements {
+    [self setNetworkActivityIndicator:YES];
+    [self.fetcher fetchAnnouncements];
+}
+
+#pragma mark - AnnouncementsFetcherDelegate
+
+- (void)announcementsFetchingFailed {
+    [self setNetworkActivityIndicator:NO];
+}
+
+- (void)announcementsFetched:(NSArray *)announcements {
+    [self setNetworkActivityIndicator:NO];
+
+    if ( [self.tableViewDataSource isKindOfClass:[AnnouncementsTableViewDataSource class]]) {
+        ((AnnouncementsTableViewDataSource *)self.tableViewDataSource).announcements = announcements;
+    }
+    if ( [self.tableViewDelegate isKindOfClass:[AnnouncementsTableViewDelegate class]]) {
+        ((AnnouncementsTableViewDelegate *)self.tableViewDelegate).announcements = announcements;
+    }
+    [self.tableView reloadData];  <i class="conum" data-value="2"></i><b>(2)</b>
+}
+
+#pragma mark - Lazy
+
+- (AnnouncementsFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementsFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1069,25 +1590,87 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@interface AnnouncementsTableViewDataSource : NSObject &lt;UITableViewDataSource&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDataSource
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return [self.announcements count];
+}
+
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@&quot;Cell&quot; forIndexPath:indexPath];
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            cell.textLabel.text = announcement.title;
+        }
+    }
+
+    return cell;
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+static NSString *kAnnouncementTappedNotification = @&quot;AnnouncementTappedNotification&quot;;
+
+@interface AnnouncementsTableViewDelegate : NSObject &lt;UITableViewDelegate&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDelegate
+
+#pragma mark - UITableViewDelegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            [[NSNotificationCenter defaultCenter] postNotificationName:kAnnouncementTappedNotification <i class="conum" data-value="1"></i><b>(1)</b>
+                                                                object:announcement
+                                                              userInfo:nil];
+        }
+    }
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1118,7 +1701,17 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -1140,13 +1733,68 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+@end</code></pre>
 </div>
 </div>
 
@@ -1394,7 +2042,22 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;2.0&quot;; <i class="conum" data-value="1"></i><b>(1)</b>
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1414,7 +2077,17 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcementPrimaryKey = announcement.primaryKey; <i class="conum" data-value="1"></i><b>(1)</b>
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1431,13 +2104,99 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, assign) NSNumber *announcementPrimaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+#import &quot;AnnouncementFetcher.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate, AnnouncementFetcherDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@property ( nonatomic, strong ) AnnouncementFetcher *fetcher;
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+
+    if ( self.announcementPrimaryKey ) {
+        [self.fetcher fetchAnnouncement:self.announcementPrimaryKey];
+    }
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+#pragma mark - AnnouncementFetcherDelegate
+
+- (void)announcementFetchingFailed {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+- (void)announcementFetched:(Announcement *)announcement {
+    [[self activityIndicatorView] stopAnimating];
+    self.announcement = announcement;
+}
+
+
+#pragma mark - Lazy
+
+- (AnnouncementFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1446,13 +2205,100 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+
+@interface AnnouncementFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+@interface AnnouncementFetcher ()
+
+@property ( nonatomic, weak )id&lt;AnnouncementFetcherDelegate&gt; delegate;
+@property ( nonatomic, strong )AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementFetcher
+
+#pragma mark - LifeCycle
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+#pragma mark - Public Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey {
+
+    [self fetchAnnouncement:primaryKey completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        Announcement *announcement = [self.builder announcementFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementFetched:announcement];
+        }
+    }];
+
+}
+
+#pragma mark - Private Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey completionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementURLRequest:primaryKey] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementURLRequest:(NSNumber *)primaryKey {
+    NSString *urlStr = [self announcementURLString:primaryKey];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementURLString:(NSNumber *)primaryKey {
+    return [NSString stringWithFormat:@&quot;%@/%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath, primaryKey];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1461,7 +2307,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+@class Announcement;
+
+@protocol AnnouncementFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementFetchingFailed;
+
+- (void)announcementFetched:(Announcement *)announcement;
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
index c7b7c24cb39..a40fa6f671f 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
@@ -98,7 +98,17 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -120,13 +130,68 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
index 60808000900..7f2718968ca 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
@@ -96,25 +96,255 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+#import &quot;ElementBuilder.h&quot;
+
+extern NSString *kAnnouncementBuilderErrorDomain;
+
+enum {
+    kAnnouncementBuilderInvalidJSONError,
+    kAnnouncementBuilderMissingDataError,
+};
+
+@interface AnnouncementBuilder : ElementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementBuilder.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kJSONKeyId = @&quot;id&quot;;
+static NSString *kJSONKeyTitle = @&quot;title&quot;;
+static NSString *kJSONKeyBody = @&quot;body&quot;;
+
+@implementation AnnouncementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error {
+
+    return [super arrayFromJSON:objectNotation
+                            key:nil
+                          error:error
+           invalidJSONErrorCode:kAnnouncementBuilderInvalidJSONError
+          missingDataErrorCode:kAnnouncementBuilderMissingDataError
+                   errorDomain:kAnnouncementBuilderErrorDomain];
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+
+    Announcement *announcement = [[Announcement alloc] init];
+
+    if([[dict objectForKey:kJSONKeyId] isKindOfClass:[NSNumber class]]) {
+        announcement.primaryKey = (NSNumber *)[dict objectForKey:kJSONKeyId];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyTitle] isKindOfClass:[NSString class]]) {
+        announcement.title = (NSString *)[dict objectForKey:kJSONKeyTitle];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyBody] isKindOfClass:[NSString class]]) {
+        announcement.body = (NSString *)[dict objectForKey:kJSONKeyBody];
+    }
+
+    return announcement;
+
+}
+
+- ( NSError *)invalidJsonError {
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+    return [NSError errorWithDomain:kAnnouncementBuilderErrorDomain
+                               code:kAnnouncementBuilderInvalidJSONError
+                           userInfo:userInfo];
+}
+
+@end
+
+NSString *kAnnouncementBuilderErrorDomain = @&quot;kAnnouncementBuilderErrorDomain&quot;;</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface ElementBuilder : NSObject
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain;
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;ElementBuilder.h&quot;
+
+@implementation ElementBuilder
+
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain {
+
+    id parsedObject = [self parseJSON:objectNotation
+                                error:error
+                 invalidJSONErrorCode:invalidJSONErrorCode
+                          errorDomain:errorDomain];
+
+    NSArray *elements = nil;
+    if ( [parsedObject isKindOfClass:[NSDictionary class]]) {
+        elements = [((NSDictionary *)parsedObject) objectForKey:key];
+
+    } else if ( [parsedObject isKindOfClass:[NSArray class]] ) {
+        elements = (NSArray *)parsedObject;
+    }
+
+    if (elements == nil) {
+        if (error != NULL) {
+            *error = [NSError errorWithDomain:errorDomain code:missingDataErrorCode userInfo:nil];
+        }
+        return nil;
+    }
+
+    NSMutableArray *results = [NSMutableArray arrayWithCapacity:[elements count]];
+    for (NSDictionary *parsedEl in elements) {
+        id el = [self newElementWithDictionary:parsedEl
+                                         error:error
+                          invalidJSONErrorCode:invalidJSONErrorCode
+                          missingDataErrorCode:missingDataErrorCode
+                                   errorDomain:errorDomain];
+        // Return nil becuase there has been an error in the previous method call
+        if(!el) {
+            return nil;
+        }
+
+        if([self isElementValid:el]) {
+            [results addObject:el];
+        }
+    }
+    return [results copy];
+}
+
+
+- (BOOL)isElementValid:(id)el {
+    // This may be overriden in a subclass
+    return YES;
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+    @throw [NSException exceptionWithName:NSInternalInconsistencyException
+                                   reason:[NSString stringWithFormat:@&quot;You must override %@ in a subclass&quot;, NSStringFromSelector(_cmd)]
+                                 userInfo:nil];
+}
+
+
+- (id)parseJSON:(NSString *)objectNotation
+          error:(NSError **)error
+invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+    errorDomain:(NSString *)errorDomain  {
+
+    NSParameterAssert(objectNotation != nil);
+    id jsonObject;
+
+    NSError *localError = nil;
+    if(objectNotation != nil) {
+        NSData *unicodeNotation = [objectNotation dataUsingEncoding:NSUTF8StringEncoding];
+        jsonObject = [NSJSONSerialization JSONObjectWithData:unicodeNotation
+                                                     options:0
+                                                       error:&amp;localError];
+    }
+    if (jsonObject == nil) {
+        if (error != NULL) {
+            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+            if (localError != nil) {
+                [userInfo setObject:localError forKey:NSUnderlyingErrorKey];
+            }
+            *error = [NSError errorWithDomain:errorDomain code:invalidJSONErrorCode userInfo:userInfo];
+        }
+        return nil;
+    }
+    return jsonObject;
+}
+
++ (id)objectOrNull:(id)object {
+    if (!object || object == [NSNull null]) return nil;
+    return object;
+}
+
++ (BOOL)isNotNilAndNotArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isArrayTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isNumberTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isStringTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSString class]]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSNumber class]]) {
+        return YES;
+    }
+    return NO;
+}
++ (BOOL)isArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSArray class]]) {
+        return YES;
+    }
+    return NO;
+}
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
index 474452ff72b..724693eb047 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
@@ -96,13 +96,25 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface Announcement : NSObject
+
+@property (nonatomic, copy)NSNumber *primaryKey;
+@property (nonatomic, copy)NSString *title;
+@property (nonatomic, copy)NSString *body;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;Announcement.h&quot;
+
+@implementation Announcement
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
index 2dddd4e630f..aa301beb772 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
@@ -96,7 +96,22 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;1.0&quot;;
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -130,7 +145,52 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;GrailsFetcher.h&quot;
+
+@interface GrailsFetcher () &lt;NSURLSessionDelegate&gt;
+
+@end
+
+@implementation GrailsFetcher
+
+#pragma mark - LifeCycle
+
+- (id)init {
+    if(self = [super init]) {
+        NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
+        self.session = [NSURLSession sessionWithConfiguration:configuration
+                                                     delegate:self
+                                                delegateQueue:[NSOperationQueue mainQueue]];
+    }
+    return self;
+}
+
+
+#pragma mark - Public
+
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval {
+    NSURL *url = [NSURL URLWithString:urlString];
+    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url
+                                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                                                          timeoutInterval:FAST_TIME_INTERVAL];
+    [urlRequest setHTTPMethod:@&quot;GET&quot;];
+
+    [[self headers] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop) {
+        [urlRequest setValue:obj forHTTPHeaderField:key];
+    }];
+    return urlRequest;
+}
+
+#pragma mark - Private
+
+- (NSDictionary *)headers {
+    return @{@&quot;Accept-Version&quot;: kApiVersion}; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -144,13 +204,97 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+
+@protocol AnnouncementsFetcherDelegate;
+
+@interface AnnouncementsFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+
+@interface AnnouncementsFetcher ()
+
+@property ( nonatomic, weak) id&lt;AnnouncementsFetcherDelegate&gt; delegate;
+
+@property ( nonatomic, strong) AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+- (void)fetchAnnouncements {
+
+    [self fetchAnnouncementsWithCompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        NSArray *announcements = [self.builder announcementsFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementsFetched:announcements];
+        }
+
+    }];
+}
+
+- (void)fetchAnnouncementsWithCompletionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementsURLRequest] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementsURLRequest {
+    NSString *urlStr = [self announcementsURLString];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementsURLString {
+    return [NSString stringWithFormat:@&quot;%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -159,7 +303,16 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@protocol AnnouncementsFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementsFetchingFailed;
+
+- (void)announcementsFetched:(NSArray *)announcements;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -168,13 +321,139 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@class DetailViewController;
+
+@interface MasterViewController : UITableViewController
+
+@property (strong, nonatomic) DetailViewController *detailViewController;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;MasterViewController.h&quot;
+#import &quot;DetailViewController.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kSegueShowDetail = @&quot;showDetail&quot;;
+
+@interface MasterViewController () &lt;AnnouncementsFetcherDelegate&gt;
+
+@property NSMutableArray *objects;
+
+@property ( nonatomic, strong ) AnnouncementsFetcher *fetcher;
+
+@property ( nonatomic, strong) id&lt;UITableViewDataSource&gt; tableViewDataSource;
+@property ( nonatomic, strong) id&lt;UITableViewDelegate&gt; tableViewDelegate;
+
+@end
+
+@implementation MasterViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    self.tableViewDataSource = [[AnnouncementsTableViewDataSource alloc] init];
+    self.tableViewDelegate = [[AnnouncementsTableViewDelegate alloc] init];
+    self.tableView.dataSource = self.tableViewDataSource;
+    self.tableView.delegate = self.tableViewDelegate;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    self.clearsSelectionOnViewWillAppear = self.splitViewController.isCollapsed;
+    [super viewWillAppear:animated];
+
+    [self registerNotifications];
+    [self fetchAnnouncements]; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [self unregisterNotifications];
+}
+
+#pragma mark - Notifications
+
+-(void)registerNotifications {
+
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc addObserver:self selector:@selector(announcementTapped:) name:kAnnouncementTappedNotification object:nil];
+}
+
+- (void)unregisterNotifications {
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:kAnnouncementTappedNotification object:nil];
+}
+
+#pragma mark - Segues
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}
+
+#pragma mark - Private Methods
+
+- (void)announcementTapped:(NSNotification *)notification {
+    if([[notification object] isKindOfClass:[Announcement class]]) {
+        Announcement *announcement = (Announcement *)[notification object];
+        [self performSegueWithIdentifier:kSegueShowDetail sender:announcement];
+    }
+}
+
+- (void)setNetworkActivityIndicator:(BOOL)visible {
+    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:visible];
+}
+
+- (void)fetchAnnouncements {
+    [self setNetworkActivityIndicator:YES];
+    [self.fetcher fetchAnnouncements];
+}
+
+#pragma mark - AnnouncementsFetcherDelegate
+
+- (void)announcementsFetchingFailed {
+    [self setNetworkActivityIndicator:NO];
+}
+
+- (void)announcementsFetched:(NSArray *)announcements {
+    [self setNetworkActivityIndicator:NO];
+
+    if ( [self.tableViewDataSource isKindOfClass:[AnnouncementsTableViewDataSource class]]) {
+        ((AnnouncementsTableViewDataSource *)self.tableViewDataSource).announcements = announcements;
+    }
+    if ( [self.tableViewDelegate isKindOfClass:[AnnouncementsTableViewDelegate class]]) {
+        ((AnnouncementsTableViewDelegate *)self.tableViewDelegate).announcements = announcements;
+    }
+    [self.tableView reloadData];  <i class="conum" data-value="2"></i><b>(2)</b>
+}
+
+#pragma mark - Lazy
+
+- (AnnouncementsFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementsFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -195,25 +474,87 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@interface AnnouncementsTableViewDataSource : NSObject &lt;UITableViewDataSource&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDataSource
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return [self.announcements count];
+}
+
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@&quot;Cell&quot; forIndexPath:indexPath];
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            cell.textLabel.text = announcement.title;
+        }
+    }
+
+    return cell;
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+static NSString *kAnnouncementTappedNotification = @&quot;AnnouncementTappedNotification&quot;;
+
+@interface AnnouncementsTableViewDelegate : NSObject &lt;UITableViewDelegate&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDelegate
+
+#pragma mark - UITableViewDelegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            [[NSNotificationCenter defaultCenter] postNotificationName:kAnnouncementTappedNotification <i class="conum" data-value="1"></i><b>(1)</b>
+                                                                object:announcement
+                                                              userInfo:nil];
+        }
+    }
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
index 84062e5937a..a586929708a 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
@@ -96,7 +96,22 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;2.0&quot;; <i class="conum" data-value="1"></i><b>(1)</b>
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -116,7 +131,17 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcementPrimaryKey = announcement.primaryKey; <i class="conum" data-value="1"></i><b>(1)</b>
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -133,13 +158,99 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, assign) NSNumber *announcementPrimaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+#import &quot;AnnouncementFetcher.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate, AnnouncementFetcherDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@property ( nonatomic, strong ) AnnouncementFetcher *fetcher;
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+
+    if ( self.announcementPrimaryKey ) {
+        [self.fetcher fetchAnnouncement:self.announcementPrimaryKey];
+    }
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+#pragma mark - AnnouncementFetcherDelegate
+
+- (void)announcementFetchingFailed {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+- (void)announcementFetched:(Announcement *)announcement {
+    [[self activityIndicatorView] stopAnimating];
+    self.announcement = announcement;
+}
+
+
+#pragma mark - Lazy
+
+- (AnnouncementFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -148,13 +259,100 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+
+@interface AnnouncementFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+@interface AnnouncementFetcher ()
+
+@property ( nonatomic, weak )id&lt;AnnouncementFetcherDelegate&gt; delegate;
+@property ( nonatomic, strong )AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementFetcher
+
+#pragma mark - LifeCycle
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+#pragma mark - Public Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey {
+
+    [self fetchAnnouncement:primaryKey completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        Announcement *announcement = [self.builder announcementFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementFetched:announcement];
+        }
+    }];
+
+}
+
+#pragma mark - Private Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey completionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementURLRequest:primaryKey] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementURLRequest:(NSNumber *)primaryKey {
+    NSString *urlStr = [self announcementURLString:primaryKey];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementURLString:(NSNumber *)primaryKey {
+    return [NSString stringWithFormat:@&quot;%@/%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath, primaryKey];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -163,7 +361,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+@class Announcement;
+
+@protocol AnnouncementFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementFetchingFailed;
+
+- (void)announcementFetched:(Announcement *)announcement;
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/single.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/single.html
index 8293b428ea6..4dc15516aab 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/single.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/single.html
@@ -887,13 +887,25 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface Announcement : NSObject
+
+@property (nonatomic, copy)NSNumber *primaryKey;
+@property (nonatomic, copy)NSString *title;
+@property (nonatomic, copy)NSString *body;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;Announcement.h&quot;
+
+@implementation Announcement
+
+@end</code></pre>
 </div>
 </div>
 
@@ -913,25 +925,255 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+#import &quot;ElementBuilder.h&quot;
+
+extern NSString *kAnnouncementBuilderErrorDomain;
+
+enum {
+    kAnnouncementBuilderInvalidJSONError,
+    kAnnouncementBuilderMissingDataError,
+};
+
+@interface AnnouncementBuilder : ElementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementBuilder.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kJSONKeyId = @&quot;id&quot;;
+static NSString *kJSONKeyTitle = @&quot;title&quot;;
+static NSString *kJSONKeyBody = @&quot;body&quot;;
+
+@implementation AnnouncementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error {
+
+    return [super arrayFromJSON:objectNotation
+                            key:nil
+                          error:error
+           invalidJSONErrorCode:kAnnouncementBuilderInvalidJSONError
+          missingDataErrorCode:kAnnouncementBuilderMissingDataError
+                   errorDomain:kAnnouncementBuilderErrorDomain];
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+
+    Announcement *announcement = [[Announcement alloc] init];
+
+    if([[dict objectForKey:kJSONKeyId] isKindOfClass:[NSNumber class]]) {
+        announcement.primaryKey = (NSNumber *)[dict objectForKey:kJSONKeyId];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyTitle] isKindOfClass:[NSString class]]) {
+        announcement.title = (NSString *)[dict objectForKey:kJSONKeyTitle];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyBody] isKindOfClass:[NSString class]]) {
+        announcement.body = (NSString *)[dict objectForKey:kJSONKeyBody];
+    }
+
+    return announcement;
+
+}
+
+- ( NSError *)invalidJsonError {
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+    return [NSError errorWithDomain:kAnnouncementBuilderErrorDomain
+                               code:kAnnouncementBuilderInvalidJSONError
+                           userInfo:userInfo];
+}
+
+@end
+
+NSString *kAnnouncementBuilderErrorDomain = @&quot;kAnnouncementBuilderErrorDomain&quot;;</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface ElementBuilder : NSObject
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain;
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;ElementBuilder.h&quot;
+
+@implementation ElementBuilder
+
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain {
+
+    id parsedObject = [self parseJSON:objectNotation
+                                error:error
+                 invalidJSONErrorCode:invalidJSONErrorCode
+                          errorDomain:errorDomain];
+
+    NSArray *elements = nil;
+    if ( [parsedObject isKindOfClass:[NSDictionary class]]) {
+        elements = [((NSDictionary *)parsedObject) objectForKey:key];
+
+    } else if ( [parsedObject isKindOfClass:[NSArray class]] ) {
+        elements = (NSArray *)parsedObject;
+    }
+
+    if (elements == nil) {
+        if (error != NULL) {
+            *error = [NSError errorWithDomain:errorDomain code:missingDataErrorCode userInfo:nil];
+        }
+        return nil;
+    }
+
+    NSMutableArray *results = [NSMutableArray arrayWithCapacity:[elements count]];
+    for (NSDictionary *parsedEl in elements) {
+        id el = [self newElementWithDictionary:parsedEl
+                                         error:error
+                          invalidJSONErrorCode:invalidJSONErrorCode
+                          missingDataErrorCode:missingDataErrorCode
+                                   errorDomain:errorDomain];
+        // Return nil becuase there has been an error in the previous method call
+        if(!el) {
+            return nil;
+        }
+
+        if([self isElementValid:el]) {
+            [results addObject:el];
+        }
+    }
+    return [results copy];
+}
+
+
+- (BOOL)isElementValid:(id)el {
+    // This may be overriden in a subclass
+    return YES;
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+    @throw [NSException exceptionWithName:NSInternalInconsistencyException
+                                   reason:[NSString stringWithFormat:@&quot;You must override %@ in a subclass&quot;, NSStringFromSelector(_cmd)]
+                                 userInfo:nil];
+}
+
+
+- (id)parseJSON:(NSString *)objectNotation
+          error:(NSError **)error
+invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+    errorDomain:(NSString *)errorDomain  {
+
+    NSParameterAssert(objectNotation != nil);
+    id jsonObject;
+
+    NSError *localError = nil;
+    if(objectNotation != nil) {
+        NSData *unicodeNotation = [objectNotation dataUsingEncoding:NSUTF8StringEncoding];
+        jsonObject = [NSJSONSerialization JSONObjectWithData:unicodeNotation
+                                                     options:0
+                                                       error:&amp;localError];
+    }
+    if (jsonObject == nil) {
+        if (error != NULL) {
+            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+            if (localError != nil) {
+                [userInfo setObject:localError forKey:NSUnderlyingErrorKey];
+            }
+            *error = [NSError errorWithDomain:errorDomain code:invalidJSONErrorCode userInfo:userInfo];
+        }
+        return nil;
+    }
+    return jsonObject;
+}
+
++ (id)objectOrNull:(id)object {
+    if (!object || object == [NSNull null]) return nil;
+    return object;
+}
+
++ (BOOL)isNotNilAndNotArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isArrayTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isNumberTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isStringTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSString class]]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSNumber class]]) {
+        return YES;
+    }
+    return NO;
+}
++ (BOOL)isArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSArray class]]) {
+        return YES;
+    }
+    return NO;
+}
+
+@end</code></pre>
 </div>
 </div>
 
@@ -970,7 +1212,22 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;1.0&quot;;
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1004,7 +1261,52 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;GrailsFetcher.h&quot;
+
+@interface GrailsFetcher () &lt;NSURLSessionDelegate&gt;
+
+@end
+
+@implementation GrailsFetcher
+
+#pragma mark - LifeCycle
+
+- (id)init {
+    if(self = [super init]) {
+        NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
+        self.session = [NSURLSession sessionWithConfiguration:configuration
+                                                     delegate:self
+                                                delegateQueue:[NSOperationQueue mainQueue]];
+    }
+    return self;
+}
+
+
+#pragma mark - Public
+
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval {
+    NSURL *url = [NSURL URLWithString:urlString];
+    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url
+                                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                                                          timeoutInterval:FAST_TIME_INTERVAL];
+    [urlRequest setHTTPMethod:@&quot;GET&quot;];
+
+    [[self headers] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop) {
+        [urlRequest setValue:obj forHTTPHeaderField:key];
+    }];
+    return urlRequest;
+}
+
+#pragma mark - Private
+
+- (NSDictionary *)headers {
+    return @{@&quot;Accept-Version&quot;: kApiVersion}; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1018,13 +1320,97 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+
+@protocol AnnouncementsFetcherDelegate;
+
+@interface AnnouncementsFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+
+@interface AnnouncementsFetcher ()
+
+@property ( nonatomic, weak) id&lt;AnnouncementsFetcherDelegate&gt; delegate;
+
+@property ( nonatomic, strong) AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+- (void)fetchAnnouncements {
+
+    [self fetchAnnouncementsWithCompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        NSArray *announcements = [self.builder announcementsFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementsFetched:announcements];
+        }
+
+    }];
+}
+
+- (void)fetchAnnouncementsWithCompletionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementsURLRequest] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementsURLRequest {
+    NSString *urlStr = [self announcementsURLString];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementsURLString {
+    return [NSString stringWithFormat:@&quot;%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1033,7 +1419,16 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@protocol AnnouncementsFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementsFetchingFailed;
+
+- (void)announcementsFetched:(NSArray *)announcements;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1042,13 +1437,139 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@class DetailViewController;
+
+@interface MasterViewController : UITableViewController
+
+@property (strong, nonatomic) DetailViewController *detailViewController;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;MasterViewController.h&quot;
+#import &quot;DetailViewController.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kSegueShowDetail = @&quot;showDetail&quot;;
+
+@interface MasterViewController () &lt;AnnouncementsFetcherDelegate&gt;
+
+@property NSMutableArray *objects;
+
+@property ( nonatomic, strong ) AnnouncementsFetcher *fetcher;
+
+@property ( nonatomic, strong) id&lt;UITableViewDataSource&gt; tableViewDataSource;
+@property ( nonatomic, strong) id&lt;UITableViewDelegate&gt; tableViewDelegate;
+
+@end
+
+@implementation MasterViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    self.tableViewDataSource = [[AnnouncementsTableViewDataSource alloc] init];
+    self.tableViewDelegate = [[AnnouncementsTableViewDelegate alloc] init];
+    self.tableView.dataSource = self.tableViewDataSource;
+    self.tableView.delegate = self.tableViewDelegate;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    self.clearsSelectionOnViewWillAppear = self.splitViewController.isCollapsed;
+    [super viewWillAppear:animated];
+
+    [self registerNotifications];
+    [self fetchAnnouncements]; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [self unregisterNotifications];
+}
+
+#pragma mark - Notifications
+
+-(void)registerNotifications {
+
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc addObserver:self selector:@selector(announcementTapped:) name:kAnnouncementTappedNotification object:nil];
+}
+
+- (void)unregisterNotifications {
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:kAnnouncementTappedNotification object:nil];
+}
+
+#pragma mark - Segues
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}
+
+#pragma mark - Private Methods
+
+- (void)announcementTapped:(NSNotification *)notification {
+    if([[notification object] isKindOfClass:[Announcement class]]) {
+        Announcement *announcement = (Announcement *)[notification object];
+        [self performSegueWithIdentifier:kSegueShowDetail sender:announcement];
+    }
+}
+
+- (void)setNetworkActivityIndicator:(BOOL)visible {
+    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:visible];
+}
+
+- (void)fetchAnnouncements {
+    [self setNetworkActivityIndicator:YES];
+    [self.fetcher fetchAnnouncements];
+}
+
+#pragma mark - AnnouncementsFetcherDelegate
+
+- (void)announcementsFetchingFailed {
+    [self setNetworkActivityIndicator:NO];
+}
+
+- (void)announcementsFetched:(NSArray *)announcements {
+    [self setNetworkActivityIndicator:NO];
+
+    if ( [self.tableViewDataSource isKindOfClass:[AnnouncementsTableViewDataSource class]]) {
+        ((AnnouncementsTableViewDataSource *)self.tableViewDataSource).announcements = announcements;
+    }
+    if ( [self.tableViewDelegate isKindOfClass:[AnnouncementsTableViewDelegate class]]) {
+        ((AnnouncementsTableViewDelegate *)self.tableViewDelegate).announcements = announcements;
+    }
+    [self.tableView reloadData];  <i class="conum" data-value="2"></i><b>(2)</b>
+}
+
+#pragma mark - Lazy
+
+- (AnnouncementsFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementsFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1069,25 +1590,87 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@interface AnnouncementsTableViewDataSource : NSObject &lt;UITableViewDataSource&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDataSource
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return [self.announcements count];
+}
+
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@&quot;Cell&quot; forIndexPath:indexPath];
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            cell.textLabel.text = announcement.title;
+        }
+    }
+
+    return cell;
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+static NSString *kAnnouncementTappedNotification = @&quot;AnnouncementTappedNotification&quot;;
+
+@interface AnnouncementsTableViewDelegate : NSObject &lt;UITableViewDelegate&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDelegate
+
+#pragma mark - UITableViewDelegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            [[NSNotificationCenter defaultCenter] postNotificationName:kAnnouncementTappedNotification <i class="conum" data-value="1"></i><b>(1)</b>
+                                                                object:announcement
+                                                              userInfo:nil];
+        }
+    }
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1118,7 +1701,17 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -1140,13 +1733,68 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+@end</code></pre>
 </div>
 </div>
 
@@ -1394,7 +2042,22 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;2.0&quot;; <i class="conum" data-value="1"></i><b>(1)</b>
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1414,7 +2077,17 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcementPrimaryKey = announcement.primaryKey; <i class="conum" data-value="1"></i><b>(1)</b>
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1431,13 +2104,99 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, assign) NSNumber *announcementPrimaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+#import &quot;AnnouncementFetcher.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate, AnnouncementFetcherDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@property ( nonatomic, strong ) AnnouncementFetcher *fetcher;
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+
+    if ( self.announcementPrimaryKey ) {
+        [self.fetcher fetchAnnouncement:self.announcementPrimaryKey];
+    }
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+#pragma mark - AnnouncementFetcherDelegate
+
+- (void)announcementFetchingFailed {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+- (void)announcementFetched:(Announcement *)announcement {
+    [[self activityIndicatorView] stopAnimating];
+    self.announcement = announcement;
+}
+
+
+#pragma mark - Lazy
+
+- (AnnouncementFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1446,13 +2205,100 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+
+@interface AnnouncementFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+@interface AnnouncementFetcher ()
+
+@property ( nonatomic, weak )id&lt;AnnouncementFetcherDelegate&gt; delegate;
+@property ( nonatomic, strong )AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementFetcher
+
+#pragma mark - LifeCycle
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+#pragma mark - Public Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey {
+
+    [self fetchAnnouncement:primaryKey completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        Announcement *announcement = [self.builder announcementFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementFetched:announcement];
+        }
+    }];
+
+}
+
+#pragma mark - Private Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey completionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementURLRequest:primaryKey] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementURLRequest:(NSNumber *)primaryKey {
+    NSString *urlStr = [self announcementURLString:primaryKey];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementURLString:(NSNumber *)primaryKey {
+    return [NSString stringWithFormat:@&quot;%@/%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath, primaryKey];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1461,7 +2307,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+@class Announcement;
+
+@protocol AnnouncementFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementFetchingFailed;
+
+- (void)announcementFetched:(Announcement *)announcement;
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/version2.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/version2.html
index 33cbd5631f8..a4b08196b3c 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/version2.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/version2.html
@@ -338,7 +338,22 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;2.0&quot;; <i class="conum" data-value="1"></i><b>(1)</b>
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -358,7 +373,17 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcementPrimaryKey = announcement.primaryKey; <i class="conum" data-value="1"></i><b>(1)</b>
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -375,13 +400,99 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, assign) NSNumber *announcementPrimaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+#import &quot;AnnouncementFetcher.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate, AnnouncementFetcherDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@property ( nonatomic, strong ) AnnouncementFetcher *fetcher;
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+
+    if ( self.announcementPrimaryKey ) {
+        [self.fetcher fetchAnnouncement:self.announcementPrimaryKey];
+    }
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+#pragma mark - AnnouncementFetcherDelegate
+
+- (void)announcementFetchingFailed {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+- (void)announcementFetched:(Announcement *)announcement {
+    [[self activityIndicatorView] stopAnimating];
+    self.announcement = announcement;
+}
+
+
+#pragma mark - Lazy
+
+- (AnnouncementFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -390,13 +501,100 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+
+@interface AnnouncementFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementFetcher.h&quot;
+#import &quot;AnnouncementFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+@interface AnnouncementFetcher ()
+
+@property ( nonatomic, weak )id&lt;AnnouncementFetcherDelegate&gt; delegate;
+@property ( nonatomic, strong )AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementFetcher
+
+#pragma mark - LifeCycle
+
+- (id)initWithDelegate:(id&lt;AnnouncementFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+#pragma mark - Public Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey {
+
+    [self fetchAnnouncement:primaryKey completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        Announcement *announcement = [self.builder announcementFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementFetched:announcement];
+        }
+    }];
+
+}
+
+#pragma mark - Private Methods
+
+- (void)fetchAnnouncement:(NSNumber *)primaryKey completionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementURLRequest:primaryKey] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementURLRequest:(NSNumber *)primaryKey {
+    NSString *urlStr = [self announcementURLString:primaryKey];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementURLString:(NSNumber *)primaryKey {
+    return [NSString stringWithFormat:@&quot;%@/%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath, primaryKey];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -405,7 +603,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v2/IntranetClient/AnnouncementFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+@class Announcement;
+
+@protocol AnnouncementFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementFetchingFailed;
+
+- (void)announcementFetched:(Announcement *)announcement;
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
index 6ce2da92864..6b8d4491d97 100644
--- a/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
+++ b/guides/building-an-ios-objectc-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
@@ -151,13 +151,25 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface Announcement : NSObject
+
+@property (nonatomic, copy)NSNumber *primaryKey;
+@property (nonatomic, copy)NSString *title;
+@property (nonatomic, copy)NSString *body;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/Announcement.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/Announcement.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;Announcement.h&quot;
+
+@implementation Announcement
+
+@end</code></pre>
 </div>
 </div>
 
@@ -177,25 +189,255 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+#import &quot;ElementBuilder.h&quot;
+
+extern NSString *kAnnouncementBuilderErrorDomain;
+
+enum {
+    kAnnouncementBuilderInvalidJSONError,
+    kAnnouncementBuilderMissingDataError,
+};
+
+@interface AnnouncementBuilder : ElementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementBuilder.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kJSONKeyId = @&quot;id&quot;;
+static NSString *kJSONKeyTitle = @&quot;title&quot;;
+static NSString *kJSONKeyBody = @&quot;body&quot;;
+
+@implementation AnnouncementBuilder
+
+- (NSArray *)announcementsFromJSON:(NSString *)objectNotation
+                             error:(NSError **)error {
+
+    return [super arrayFromJSON:objectNotation
+                            key:nil
+                          error:error
+           invalidJSONErrorCode:kAnnouncementBuilderInvalidJSONError
+          missingDataErrorCode:kAnnouncementBuilderMissingDataError
+                   errorDomain:kAnnouncementBuilderErrorDomain];
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+
+    Announcement *announcement = [[Announcement alloc] init];
+
+    if([[dict objectForKey:kJSONKeyId] isKindOfClass:[NSNumber class]]) {
+        announcement.primaryKey = (NSNumber *)[dict objectForKey:kJSONKeyId];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyTitle] isKindOfClass:[NSString class]]) {
+        announcement.title = (NSString *)[dict objectForKey:kJSONKeyTitle];
+    } else {
+        if(error != NULL) {
+            *error = [self invalidJsonError];
+        }
+        return nil;
+    }
+
+    if([[dict objectForKey:kJSONKeyBody] isKindOfClass:[NSString class]]) {
+        announcement.body = (NSString *)[dict objectForKey:kJSONKeyBody];
+    }
+
+    return announcement;
+
+}
+
+- ( NSError *)invalidJsonError {
+    NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+    return [NSError errorWithDomain:kAnnouncementBuilderErrorDomain
+                               code:kAnnouncementBuilderInvalidJSONError
+                           userInfo:userInfo];
+}
+
+@end
+
+NSString *kAnnouncementBuilderErrorDomain = @&quot;kAnnouncementBuilderErrorDomain&quot;;</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@interface ElementBuilder : NSObject
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain;
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/ElementBuilder.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;ElementBuilder.h&quot;
+
+@implementation ElementBuilder
+
+
+- (NSArray *)arrayFromJSON:(NSString *)objectNotation
+                       key:(NSString *)key
+                     error:(NSError **)error
+      invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+      missingDataErrorCode:(NSInteger)missingDataErrorCode
+               errorDomain:(NSString *)errorDomain {
+
+    id parsedObject = [self parseJSON:objectNotation
+                                error:error
+                 invalidJSONErrorCode:invalidJSONErrorCode
+                          errorDomain:errorDomain];
+
+    NSArray *elements = nil;
+    if ( [parsedObject isKindOfClass:[NSDictionary class]]) {
+        elements = [((NSDictionary *)parsedObject) objectForKey:key];
+
+    } else if ( [parsedObject isKindOfClass:[NSArray class]] ) {
+        elements = (NSArray *)parsedObject;
+    }
+
+    if (elements == nil) {
+        if (error != NULL) {
+            *error = [NSError errorWithDomain:errorDomain code:missingDataErrorCode userInfo:nil];
+        }
+        return nil;
+    }
+
+    NSMutableArray *results = [NSMutableArray arrayWithCapacity:[elements count]];
+    for (NSDictionary *parsedEl in elements) {
+        id el = [self newElementWithDictionary:parsedEl
+                                         error:error
+                          invalidJSONErrorCode:invalidJSONErrorCode
+                          missingDataErrorCode:missingDataErrorCode
+                                   errorDomain:errorDomain];
+        // Return nil becuase there has been an error in the previous method call
+        if(!el) {
+            return nil;
+        }
+
+        if([self isElementValid:el]) {
+            [results addObject:el];
+        }
+    }
+    return [results copy];
+}
+
+
+- (BOOL)isElementValid:(id)el {
+    // This may be overriden in a subclass
+    return YES;
+}
+
+- (id)newElementWithDictionary:(NSDictionary *)dict
+                         error:(NSError **)error
+          invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+          missingDataErrorCode:(NSInteger)missingDataErrorCode
+                   errorDomain:(NSString *)errorDomain {
+    @throw [NSException exceptionWithName:NSInternalInconsistencyException
+                                   reason:[NSString stringWithFormat:@&quot;You must override %@ in a subclass&quot;, NSStringFromSelector(_cmd)]
+                                 userInfo:nil];
+}
+
+
+- (id)parseJSON:(NSString *)objectNotation
+          error:(NSError **)error
+invalidJSONErrorCode:(NSInteger)invalidJSONErrorCode
+    errorDomain:(NSString *)errorDomain  {
+
+    NSParameterAssert(objectNotation != nil);
+    id jsonObject;
+
+    NSError *localError = nil;
+    if(objectNotation != nil) {
+        NSData *unicodeNotation = [objectNotation dataUsingEncoding:NSUTF8StringEncoding];
+        jsonObject = [NSJSONSerialization JSONObjectWithData:unicodeNotation
+                                                     options:0
+                                                       error:&amp;localError];
+    }
+    if (jsonObject == nil) {
+        if (error != NULL) {
+            NSMutableDictionary *userInfo = [NSMutableDictionary dictionaryWithCapacity:1];
+            if (localError != nil) {
+                [userInfo setObject:localError forKey:NSUnderlyingErrorKey];
+            }
+            *error = [NSError errorWithDomain:errorDomain code:invalidJSONErrorCode userInfo:userInfo];
+        }
+        return nil;
+    }
+    return jsonObject;
+}
+
++ (id)objectOrNull:(id)object {
+    if (!object || object == [NSNull null]) return nil;
+    return object;
+}
+
++ (BOOL)isNotNilAndNotArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isArrayTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isNumberTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilAndNotStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+
+    return [self isNotNilTheKey:key atDict:dict] &amp;&amp; ![self isStringTheKey:key atDict:dict];
+}
+
++ (BOOL)isNotNilTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isStringTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSString class]]) {
+        return YES;
+    }
+    return NO;
+}
+
++ (BOOL)isNumberTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSNumber class]]) {
+        return YES;
+    }
+    return NO;
+}
++ (BOOL)isArrayTheKey:(NSString *)key atDict:(NSDictionary *)dict {
+    if(dict[key] != (id)[NSNull null]  &amp;&amp; dict[key] &amp;&amp; [dict[key] isKindOfClass:[NSArray class]]) {
+        return YES;
+    }
+    return NO;
+}
+
+@end</code></pre>
 </div>
 </div>
 
@@ -234,7 +476,22 @@ announcements exposed by the Grails application</p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+static NSString *kServerUrl = @&quot;http://192.168.1.40:8080&quot;;
+static NSString *kApiVersion = @&quot;1.0&quot;;
+static NSString *kAnnouncementsResourcePath = @&quot;announcements&quot;;
+static NSInteger FAST_TIME_INTERVAL = 5.0;
+
+@interface GrailsFetcher : NSObject
+
+@property (nonatomic, strong) NSURLSession *session;
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval;
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -268,7 +525,52 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/GrailsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;GrailsFetcher.h&quot;
+
+@interface GrailsFetcher () &lt;NSURLSessionDelegate&gt;
+
+@end
+
+@implementation GrailsFetcher
+
+#pragma mark - LifeCycle
+
+- (id)init {
+    if(self = [super init]) {
+        NSURLSessionConfiguration* configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
+        self.session = [NSURLSession sessionWithConfiguration:configuration
+                                                     delegate:self
+                                                delegateQueue:[NSOperationQueue mainQueue]];
+    }
+    return self;
+}
+
+
+#pragma mark - Public
+
+
+- (NSURLRequest *)getURLRequestWithUrlString:(NSString *)urlString
+                                 cachePolicy:(NSURLRequestCachePolicy)cachePolicy
+                             timeoutInterval:(NSTimeInterval)timeoutInterval {
+    NSURL *url = [NSURL URLWithString:urlString];
+    NSMutableURLRequest *urlRequest = [NSMutableURLRequest requestWithURL:url
+                                                              cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                                                          timeoutInterval:FAST_TIME_INTERVAL];
+    [urlRequest setHTTPMethod:@&quot;GET&quot;];
+
+    [[self headers] enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL * stop) {
+        [urlRequest setValue:obj forHTTPHeaderField:key];
+    }];
+    return urlRequest;
+}
+
+#pragma mark - Private
+
+- (NSDictionary *)headers {
+    return @{@&quot;Accept-Version&quot;: kApiVersion}; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -282,13 +584,97 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+#import &quot;GrailsFetcher.h&quot;
+
+@protocol AnnouncementsFetcherDelegate;
+
+@interface AnnouncementsFetcher : GrailsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate;
+
+- (void)fetchAnnouncements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcher.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementBuilder.h&quot;
+
+
+@interface AnnouncementsFetcher ()
+
+@property ( nonatomic, weak) id&lt;AnnouncementsFetcherDelegate&gt; delegate;
+
+@property ( nonatomic, strong) AnnouncementBuilder *builder;
+
+@end
+
+@implementation AnnouncementsFetcher
+
+- (id)initWithDelegate:(id&lt;AnnouncementsFetcherDelegate&gt;)delegate {
+    if(self = [super init]) {
+        self.delegate = delegate;
+        self.builder = [[AnnouncementBuilder alloc] init];
+    }
+    return self;
+}
+
+- (void)fetchAnnouncements {
+
+    [self fetchAnnouncementsWithCompletionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
+        if(error) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSInteger statusCode = [((NSHTTPURLResponse*)response) statusCode];
+        if(statusCode != 200) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+
+        NSString *objectNotation = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
+        NSError *builderError;
+        NSArray *announcements = [self.builder announcementsFromJSON:objectNotation error:&amp;builderError];
+        if(builderError) {
+            if ( self.delegate ) {
+                [self.delegate announcementsFetchingFailed];
+            }
+            return;
+        }
+        if ( self.delegate ) {
+            [self.delegate announcementsFetched:announcements];
+        }
+
+    }];
+}
+
+- (void)fetchAnnouncementsWithCompletionHandler:(void (^)(NSData * data, NSURLResponse * response, NSError * error))completionHandler {
+    NSURLSessionDataTask *dataTask = [self.session dataTaskWithRequest:[self announcementsURLRequest] completionHandler:completionHandler];
+    [dataTask resume];
+}
+
+- (NSURLRequest *)announcementsURLRequest {
+    NSString *urlStr = [self announcementsURLString];
+    return [super getURLRequestWithUrlString:urlStr
+                                 cachePolicy:NSURLRequestReloadIgnoringLocalCacheData
+                             timeoutInterval:FAST_TIME_INTERVAL];
+}
+
+- (NSString *)announcementsURLString {
+    return [NSString stringWithFormat:@&quot;%@/%@&quot;, kServerUrl, kAnnouncementsResourcePath];
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -297,7 +683,16 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;Foundation/Foundation.h&gt;
+
+@protocol AnnouncementsFetcherDelegate &lt;NSObject&gt;
+
+- (void)announcementsFetchingFailed;
+
+- (void)announcementsFetched:(NSArray *)announcements;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -306,13 +701,139 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@class DetailViewController;
+
+@interface MasterViewController : UITableViewController
+
+@property (strong, nonatomic) DetailViewController *detailViewController;
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;MasterViewController.h&quot;
+#import &quot;DetailViewController.h&quot;
+#import &quot;AnnouncementsFetcherDelegate.h&quot;
+#import &quot;AnnouncementsFetcher.h&quot;
+#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+static NSString *kSegueShowDetail = @&quot;showDetail&quot;;
+
+@interface MasterViewController () &lt;AnnouncementsFetcherDelegate&gt;
+
+@property NSMutableArray *objects;
+
+@property ( nonatomic, strong ) AnnouncementsFetcher *fetcher;
+
+@property ( nonatomic, strong) id&lt;UITableViewDataSource&gt; tableViewDataSource;
+@property ( nonatomic, strong) id&lt;UITableViewDelegate&gt; tableViewDelegate;
+
+@end
+
+@implementation MasterViewController
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+
+    self.tableViewDataSource = [[AnnouncementsTableViewDataSource alloc] init];
+    self.tableViewDelegate = [[AnnouncementsTableViewDelegate alloc] init];
+    self.tableView.dataSource = self.tableViewDataSource;
+    self.tableView.delegate = self.tableViewDelegate;
+}
+
+- (void)viewWillAppear:(BOOL)animated {
+    self.clearsSelectionOnViewWillAppear = self.splitViewController.isCollapsed;
+    [super viewWillAppear:animated];
+
+    [self registerNotifications];
+    [self fetchAnnouncements]; <i class="conum" data-value="1"></i><b>(1)</b>
+}
+
+- (void)viewWillDisappear:(BOOL)animated {
+    [super viewWillDisappear:animated];
+    [self unregisterNotifications];
+}
+
+#pragma mark - Notifications
+
+-(void)registerNotifications {
+
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc addObserver:self selector:@selector(announcementTapped:) name:kAnnouncementTappedNotification object:nil];
+}
+
+- (void)unregisterNotifications {
+    NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+    [nc removeObserver:self name:kAnnouncementTappedNotification object:nil];
+}
+
+#pragma mark - Segues
+
+- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}
+
+#pragma mark - Private Methods
+
+- (void)announcementTapped:(NSNotification *)notification {
+    if([[notification object] isKindOfClass:[Announcement class]]) {
+        Announcement *announcement = (Announcement *)[notification object];
+        [self performSegueWithIdentifier:kSegueShowDetail sender:announcement];
+    }
+}
+
+- (void)setNetworkActivityIndicator:(BOOL)visible {
+    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:visible];
+}
+
+- (void)fetchAnnouncements {
+    [self setNetworkActivityIndicator:YES];
+    [self.fetcher fetchAnnouncements];
+}
+
+#pragma mark - AnnouncementsFetcherDelegate
+
+- (void)announcementsFetchingFailed {
+    [self setNetworkActivityIndicator:NO];
+}
+
+- (void)announcementsFetched:(NSArray *)announcements {
+    [self setNetworkActivityIndicator:NO];
+
+    if ( [self.tableViewDataSource isKindOfClass:[AnnouncementsTableViewDataSource class]]) {
+        ((AnnouncementsTableViewDataSource *)self.tableViewDataSource).announcements = announcements;
+    }
+    if ( [self.tableViewDelegate isKindOfClass:[AnnouncementsTableViewDelegate class]]) {
+        ((AnnouncementsTableViewDelegate *)self.tableViewDelegate).announcements = announcements;
+    }
+    [self.tableView reloadData];  <i class="conum" data-value="2"></i><b>(2)</b>
+}
+
+#pragma mark - Lazy
+
+- (AnnouncementsFetcher *)fetcher {
+    if(!_fetcher) {
+        _fetcher = [[AnnouncementsFetcher alloc] initWithDelegate:self];
+    }
+    return _fetcher;
+}
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -333,25 +854,87 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+@interface AnnouncementsTableViewDataSource : NSObject &lt;UITableViewDataSource&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDataSource.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDataSource
+
+#pragma mark - UITableViewDataSource
+
+- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
+    return [self.announcements count];
+}
+
+
+- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
+    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@&quot;Cell&quot; forIndexPath:indexPath];
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            cell.textLabel.text = announcement.title;
+        }
+    }
+
+    return cell;
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+
+static NSString *kAnnouncementTappedNotification = @&quot;AnnouncementTappedNotification&quot;;
+
+@interface AnnouncementsTableViewDelegate : NSObject &lt;UITableViewDelegate&gt;
+
+@property (nonatomic, strong) NSArray *announcements;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;AnnouncementsTableViewDelegate.h&quot;
+#import &quot;Announcement.h&quot;
+
+@implementation AnnouncementsTableViewDelegate
+
+#pragma mark - UITableViewDelegate
+
+- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
+
+    if ( [self.announcements count] &gt; indexPath.row ) {
+        id obj = self.announcements[indexPath.row];
+        if ( [obj isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)obj;
+            [[NSNotificationCenter defaultCenter] postNotificationName:kAnnouncementTappedNotification <i class="conum" data-value="1"></i><b>(1)</b>
+                                                                object:announcement
+                                                              userInfo:nil];
+        }
+    }
+}
+
+
+@end</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -382,7 +965,17 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/MasterViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/MasterViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
+    if ([[segue identifier] isEqualToString:kSegueShowDetail]) {
+        DetailViewController *controller = (DetailViewController *)[[segue destinationViewController] topViewController];
+        if([sender isKindOfClass:[Announcement class]]) {
+            Announcement *announcement = (Announcement *)sender;
+            controller.announcement = announcement;
+        }
+        controller.navigationItem.leftBarButtonItem = self.splitViewController.displayModeButtonItem;
+        controller.navigationItem.leftItemsSupplementBackButton = YES;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -404,13 +997,68 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.h[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &lt;UIKit/UIKit.h&gt;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController : UIViewController
+
+@property (nonatomic, strong) Announcement *announcement;
+
+@end</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-objectivec-ios-v1/IntranetClient/DetailViewController.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="objectivec">link:{sourcedir}/../complete-objectivec-ios-v1/IntranetClient/DetailViewController.m[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="objectivec">#import &quot;DetailViewController.h&quot;
+#import &quot;Announcement.h&quot;
+
+@interface DetailViewController () &lt;UIWebViewDelegate&gt;
+
+@property ( nonatomic, weak) IBOutlet UILabel *titleLabel;
+@property ( nonatomic, weak) IBOutlet UIWebView *webView;
+@property (weak, nonatomic) IBOutlet UIActivityIndicatorView *activityIndicatorView;
+
+@end
+
+@implementation DetailViewController
+
+- (void)configureView {
+    // Update the user interface for the detail item.
+    if (self.announcement) {
+        self.titleLabel.text = self.announcement.title;
+        [[self activityIndicatorView] startAnimating];
+        [self.webView loadHTMLString:self.announcement.body baseURL:nil];
+    }
+}
+
+- (void)viewDidLoad {
+    [super viewDidLoad];
+    self.webView.delegate = self;
+    // Do any additional setup after loading the view, typically from a nib.
+    [self configureView];
+}
+
+#pragma mark - Managing the detail item
+
+- (void)setAnnouncement:(Announcement *)announcement {
+    if (_announcement != announcement) {
+        _announcement = announcement;
+
+        // Update the view.
+        [self configureView];
+    }
+}
+
+#pragma mark - UIWebViewDelegate
+- (void)webViewDidFinishLoad:(UIWebView *)webView {
+    [[self activityIndicatorView] stopAnimating];
+}
+- (void)webView:(UIWebView *)webView didFailLoadWithError:(NSError *)error {
+    [[self activityIndicatorView] stopAnimating];
+}
+
+@end</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/index.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/index.html
index 07d2cb24617..352d709ec33 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/index.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/index.html
@@ -886,7 +886,16 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/Announcement.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">class Announcement {
+    let primaryKey: Int
+    let title: String
+    var body: String?
+
+    init(primaryKey: Int, title: String) {
+        self.primaryKey = primaryKey
+        self.title = title
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -906,7 +915,29 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementBuilder {
+
+    func announcementsFromJSON(_ data: Data?) -&gt; [Announcement] {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        var announcements = [Announcement]()
+        if let array = json as? [Any] {
+            for object in array {
+                if let dict = object as? Dictionary&lt;String, AnyObject&gt; {
+                    if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                        let announcement = Announcement(primaryKey: primaryKey, title: title)
+                        if let body = dict[&quot;body&quot;]  as? String {
+                            announcement.body = body
+                        }
+                        announcements.append(announcement)
+                    }
+                }
+            }
+        }
+        return announcements
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -926,7 +957,13 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/GrailsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot; <i class="conum" data-value="2"></i><b>(2)</b>
+    }
+    static let version = &quot;1.0&quot; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -960,7 +997,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementsFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate:AnnouncementsFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncements() {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementsFetchingFailed()
+                }
+                return
+            }
+            let announcements = self.builder.announcementsFromJSON(data)
+            if let delegate = self.delegate {
+                delegate.announcementsFetched(announcements)
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -977,7 +1044,12 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementsFetcherDelegate: class {
+
+    func announcementsFetchingFailed()
+
+    func announcementsFetched(_ announcements: [Announcement])
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -986,7 +1058,99 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class MasterViewController: UITableViewController, AnnouncementsFetcherDelegate {
+
+    var detailViewController: DetailViewController? = nil
+    var objects = [Any]()
+
+    var tableViewDataSource = AnnouncementsTableViewDataSource()
+    var tableViewDelegate = AnnouncementsTableViewDelegate()
+    let fetcher = AnnouncementsFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.dataSource = self.tableViewDataSource
+        self.tableView.delegate = self.tableViewDelegate
+        self.fetcher.delegate = self
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
+        super.viewWillAppear(animated)
+        self.registerNotifications()
+        self.fetchAnnouncements() <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        self.unregisterNotifications()
+    }
+
+    // MARK: - Notifications
+
+    func registerNotifications() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(self.announcementTapped),
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    func unregisterNotifications() {
+        NotificationCenter.default.removeObserver(
+            self,
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    // MARK: - Private Methods
+
+    @objc func announcementTapped(notification: NSNotification){
+
+        let announcement = notification.object as! Announcement
+        self.performSegue(withIdentifier: &quot;showDetail&quot;, sender: announcement)
+    }
+
+    func fetchAnnouncements() {
+        self.setNetworkActivityIndicator(true)
+        self.fetcher.fetchAnnouncements()
+    }
+
+    func setNetworkActivityIndicator(_ visible: Bool) {
+        UIApplication.shared.isNetworkActivityIndicatorVisible = visible
+    }
+
+    // MARK: - Segues
+
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }
+
+    // MARK: - AnnouncementsFetcherDelegate
+
+    func announcementsFetchingFailed() {
+        self.setNetworkActivityIndicator(false)
+    }
+
+    func announcementsFetched(_ announcements: [Announcement]) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        self.setNetworkActivityIndicator(false)
+
+        self.tableViewDataSource.announcements = announcements
+        self.tableViewDelegate.announcements = announcements
+        self.tableView.reloadData()
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1007,13 +1171,43 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDataSource : NSObject, UITableViewDataSource {
+
+    var announcements = [Announcement]()
+
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
+        return announcements.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
+
+        let cell = tableView.dequeueReusableCell(withIdentifier: &quot;Cell&quot;, for: indexPath)
+
+        let announcement = announcements[indexPath.row]
+        cell.textLabel!.text = announcement.title
+        return cell
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDelegate : NSObject, UITableViewDelegate {
+
+    var announcements = [Announcement]()
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let announcement = announcements[indexPath.row]
+        NotificationCenter.default.post(name: Notification.Name(&quot;AnnouncementTappedNotification&quot;), object: announcement) <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1044,7 +1238,15 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -1066,7 +1268,61 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        } else {
+            self.hideActivityIndicator()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view, typically from a nib.
+        self.configureView()
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            // Update the view.
+            self.configureView()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -1314,7 +1570,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/GrailsApi.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot;
+    static let version = &quot;2.0&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1334,7 +1596,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcementPrimaryKey = announcement.primaryKey
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1351,7 +1622,86 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate, AnnouncementFetcherDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    let fetcher = AnnouncementFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.fetcher.delegate = self
+        self.configureView()
+    }
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        }
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            self.configureView()
+        }
+    }
+
+    var announcementPrimaryKey: Int? {
+        didSet {
+            self.showActivityIndicator()
+            self.fetcher.fetchAnnouncement(self.announcementPrimaryKey!)
+        }
+    }
+
+    // MARK: - Private Methods
+    func showActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.startAnimating()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+
+    // Mark: - AnnouncementFetcherDelegate
+
+    func announcementFetchingFailed() {
+
+    }
+
+    func announcementFetched(_ announcement: Announcement) {
+        self.announcement = announcement
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1360,7 +1710,42 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate: AnnouncementFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncement(_ primaryKey: Int) {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)/\(primaryKey)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+                return
+            }
+            if let announcement = self.builder.announcementFromJSON(data) {
+                if let delegate = self.delegate {
+                    delegate.announcementFetched(announcement)
+                }
+            } else {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1369,7 +1754,20 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    func announcementFromJSON(_ data: Data?) -&gt; Announcement? {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        if let dict = json as? Dictionary&lt;String, AnyObject&gt; {
+            if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                let announcement = Announcement(primaryKey: primaryKey, title: title)
+                if let body = dict[&quot;body&quot;]  as? String {
+                    announcement.body = body
+                }
+                return announcement
+
+            }
+        }
+        return nil
+    }</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1378,7 +1776,12 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementFetcherDelegate: class {
+
+    func announcementFetchingFailed()
+
+    func announcementFetched(_ announcement: Announcement)
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
index 39317c2136a..19972d87f99 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/detailViewController.html
@@ -98,7 +98,15 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -120,7 +128,61 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        } else {
+            self.hideActivityIndicator()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view, typically from a nib.
+        self.configureView()
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            // Update the view.
+            self.configureView()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
index f4ffbf4ac05..44ea91e1255 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosJsonToModel.html
@@ -96,7 +96,29 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-swift-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementBuilder {
+
+    func announcementsFromJSON(_ data: Data?) -&gt; [Announcement] {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        var announcements = [Announcement]()
+        if let array = json as? [Any] {
+            for object in array {
+                if let dict = object as? Dictionary&lt;String, AnyObject&gt; {
+                    if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                        let announcement = Announcement(primaryKey: primaryKey, title: title)
+                        if let body = dict[&quot;body&quot;]  as? String {
+                            announcement.body = body
+                        }
+                        announcements.append(announcement)
+                    }
+                }
+            }
+        }
+        return announcements
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
index ee242606066..a09c7824e1f 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/iosModel.html
@@ -96,7 +96,16 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/Announcement.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">class Announcement {
+    let primaryKey: Int
+    let title: String
+    var body: String?
+
+    init(primaryKey: Int, title: String) {
+        self.primaryKey = primaryKey
+        self.title = title
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
index 7bdc5ee24f9..f166761bde3 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/networkingCode.html
@@ -96,7 +96,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/GrailsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot; <i class="conum" data-value="2"></i><b>(2)</b>
+    }
+    static let version = &quot;1.0&quot; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -130,7 +136,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementsFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate:AnnouncementsFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncements() {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementsFetchingFailed()
+                }
+                return
+            }
+            let announcements = self.builder.announcementsFromJSON(data)
+            if let delegate = self.delegate {
+                delegate.announcementsFetched(announcements)
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -147,7 +183,12 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementsFetcherDelegate: class {
+
+    func announcementsFetchingFailed()
+
+    func announcementsFetched(_ announcements: [Announcement])
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -156,7 +197,99 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class MasterViewController: UITableViewController, AnnouncementsFetcherDelegate {
+
+    var detailViewController: DetailViewController? = nil
+    var objects = [Any]()
+
+    var tableViewDataSource = AnnouncementsTableViewDataSource()
+    var tableViewDelegate = AnnouncementsTableViewDelegate()
+    let fetcher = AnnouncementsFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.dataSource = self.tableViewDataSource
+        self.tableView.delegate = self.tableViewDelegate
+        self.fetcher.delegate = self
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
+        super.viewWillAppear(animated)
+        self.registerNotifications()
+        self.fetchAnnouncements() <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        self.unregisterNotifications()
+    }
+
+    // MARK: - Notifications
+
+    func registerNotifications() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(self.announcementTapped),
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    func unregisterNotifications() {
+        NotificationCenter.default.removeObserver(
+            self,
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    // MARK: - Private Methods
+
+    @objc func announcementTapped(notification: NSNotification){
+
+        let announcement = notification.object as! Announcement
+        self.performSegue(withIdentifier: &quot;showDetail&quot;, sender: announcement)
+    }
+
+    func fetchAnnouncements() {
+        self.setNetworkActivityIndicator(true)
+        self.fetcher.fetchAnnouncements()
+    }
+
+    func setNetworkActivityIndicator(_ visible: Bool) {
+        UIApplication.shared.isNetworkActivityIndicatorVisible = visible
+    }
+
+    // MARK: - Segues
+
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }
+
+    // MARK: - AnnouncementsFetcherDelegate
+
+    func announcementsFetchingFailed() {
+        self.setNetworkActivityIndicator(false)
+    }
+
+    func announcementsFetched(_ announcements: [Announcement]) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        self.setNetworkActivityIndicator(false)
+
+        self.tableViewDataSource.announcements = announcements
+        self.tableViewDelegate.announcements = announcements
+        self.tableView.reloadData()
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -177,13 +310,43 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDataSource : NSObject, UITableViewDataSource {
+
+    var announcements = [Announcement]()
+
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
+        return announcements.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
+
+        let cell = tableView.dequeueReusableCell(withIdentifier: &quot;Cell&quot;, for: indexPath)
+
+        let announcement = announcements[indexPath.row]
+        cell.textLabel!.text = announcement.title
+        return cell
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDelegate : NSObject, UITableViewDelegate {
+
+    var announcements = [Announcement]()
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let announcement = announcements[indexPath.row]
+        NotificationCenter.default.post(name: Notification.Name(&quot;AnnouncementTappedNotification&quot;), object: announcement) <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
index 7f2ad35060b..f7def8f097e 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/pages/v2iOS.html
@@ -96,7 +96,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/GrailsApi.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot;
+    static let version = &quot;2.0&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -116,7 +122,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcementPrimaryKey = announcement.primaryKey
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -133,7 +148,86 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate, AnnouncementFetcherDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    let fetcher = AnnouncementFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.fetcher.delegate = self
+        self.configureView()
+    }
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        }
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            self.configureView()
+        }
+    }
+
+    var announcementPrimaryKey: Int? {
+        didSet {
+            self.showActivityIndicator()
+            self.fetcher.fetchAnnouncement(self.announcementPrimaryKey!)
+        }
+    }
+
+    // MARK: - Private Methods
+    func showActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.startAnimating()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+
+    // Mark: - AnnouncementFetcherDelegate
+
+    func announcementFetchingFailed() {
+
+    }
+
+    func announcementFetched(_ announcement: Announcement) {
+        self.announcement = announcement
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -142,7 +236,42 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate: AnnouncementFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncement(_ primaryKey: Int) {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)/\(primaryKey)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+                return
+            }
+            if let announcement = self.builder.announcementFromJSON(data) {
+                if let delegate = self.delegate {
+                    delegate.announcementFetched(announcement)
+                }
+            } else {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -151,7 +280,20 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    func announcementFromJSON(_ data: Data?) -&gt; Announcement? {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        if let dict = json as? Dictionary&lt;String, AnyObject&gt; {
+            if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                let announcement = Announcement(primaryKey: primaryKey, title: title)
+                if let body = dict[&quot;body&quot;]  as? String {
+                    announcement.body = body
+                }
+                return announcement
+
+            }
+        }
+        return nil
+    }</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -160,7 +302,12 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementFetcherDelegate: class {
+
+    func announcementFetchingFailed()
+
+    func announcementFetched(_ announcement: Announcement)
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/single.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/single.html
index 07d2cb24617..352d709ec33 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/single.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/single.html
@@ -886,7 +886,16 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/Announcement.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">class Announcement {
+    let primaryKey: Int
+    let title: String
+    var body: String?
+
+    init(primaryKey: Int, title: String) {
+        self.primaryKey = primaryKey
+        self.title = title
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -906,7 +915,29 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementBuilder {
+
+    func announcementsFromJSON(_ data: Data?) -&gt; [Announcement] {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        var announcements = [Announcement]()
+        if let array = json as? [Any] {
+            for object in array {
+                if let dict = object as? Dictionary&lt;String, AnyObject&gt; {
+                    if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                        let announcement = Announcement(primaryKey: primaryKey, title: title)
+                        if let body = dict[&quot;body&quot;]  as? String {
+                            announcement.body = body
+                        }
+                        announcements.append(announcement)
+                    }
+                }
+            }
+        }
+        return announcements
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -926,7 +957,13 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/GrailsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot; <i class="conum" data-value="2"></i><b>(2)</b>
+    }
+    static let version = &quot;1.0&quot; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -960,7 +997,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementsFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate:AnnouncementsFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncements() {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementsFetchingFailed()
+                }
+                return
+            }
+            let announcements = self.builder.announcementsFromJSON(data)
+            if let delegate = self.delegate {
+                delegate.announcementsFetched(announcements)
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -977,7 +1044,12 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementsFetcherDelegate: class {
+
+    func announcementsFetchingFailed()
+
+    func announcementsFetched(_ announcements: [Announcement])
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -986,7 +1058,99 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class MasterViewController: UITableViewController, AnnouncementsFetcherDelegate {
+
+    var detailViewController: DetailViewController? = nil
+    var objects = [Any]()
+
+    var tableViewDataSource = AnnouncementsTableViewDataSource()
+    var tableViewDelegate = AnnouncementsTableViewDelegate()
+    let fetcher = AnnouncementsFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.dataSource = self.tableViewDataSource
+        self.tableView.delegate = self.tableViewDelegate
+        self.fetcher.delegate = self
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
+        super.viewWillAppear(animated)
+        self.registerNotifications()
+        self.fetchAnnouncements() <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        self.unregisterNotifications()
+    }
+
+    // MARK: - Notifications
+
+    func registerNotifications() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(self.announcementTapped),
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    func unregisterNotifications() {
+        NotificationCenter.default.removeObserver(
+            self,
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    // MARK: - Private Methods
+
+    @objc func announcementTapped(notification: NSNotification){
+
+        let announcement = notification.object as! Announcement
+        self.performSegue(withIdentifier: &quot;showDetail&quot;, sender: announcement)
+    }
+
+    func fetchAnnouncements() {
+        self.setNetworkActivityIndicator(true)
+        self.fetcher.fetchAnnouncements()
+    }
+
+    func setNetworkActivityIndicator(_ visible: Bool) {
+        UIApplication.shared.isNetworkActivityIndicatorVisible = visible
+    }
+
+    // MARK: - Segues
+
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }
+
+    // MARK: - AnnouncementsFetcherDelegate
+
+    func announcementsFetchingFailed() {
+        self.setNetworkActivityIndicator(false)
+    }
+
+    func announcementsFetched(_ announcements: [Announcement]) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        self.setNetworkActivityIndicator(false)
+
+        self.tableViewDataSource.announcements = announcements
+        self.tableViewDelegate.announcements = announcements
+        self.tableView.reloadData()
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1007,13 +1171,43 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDataSource : NSObject, UITableViewDataSource {
+
+    var announcements = [Announcement]()
+
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
+        return announcements.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
+
+        let cell = tableView.dequeueReusableCell(withIdentifier: &quot;Cell&quot;, for: indexPath)
+
+        let announcement = announcements[indexPath.row]
+        cell.textLabel!.text = announcement.title
+        return cell
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDelegate : NSObject, UITableViewDelegate {
+
+    var announcements = [Announcement]()
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let announcement = announcements[indexPath.row]
+        NotificationCenter.default.post(name: Notification.Name(&quot;AnnouncementTappedNotification&quot;), object: announcement) <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1044,7 +1238,15 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -1066,7 +1268,61 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        } else {
+            self.hideActivityIndicator()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view, typically from a nib.
+        self.configureView()
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            // Update the view.
+            self.configureView()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -1314,7 +1570,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/GrailsApi.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot;
+    static let version = &quot;2.0&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1334,7 +1596,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcementPrimaryKey = announcement.primaryKey
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -1351,7 +1622,86 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate, AnnouncementFetcherDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    let fetcher = AnnouncementFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.fetcher.delegate = self
+        self.configureView()
+    }
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        }
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            self.configureView()
+        }
+    }
+
+    var announcementPrimaryKey: Int? {
+        didSet {
+            self.showActivityIndicator()
+            self.fetcher.fetchAnnouncement(self.announcementPrimaryKey!)
+        }
+    }
+
+    // MARK: - Private Methods
+    func showActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.startAnimating()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+
+    // Mark: - AnnouncementFetcherDelegate
+
+    func announcementFetchingFailed() {
+
+    }
+
+    func announcementFetched(_ announcement: Announcement) {
+        self.announcement = announcement
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1360,7 +1710,42 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate: AnnouncementFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncement(_ primaryKey: Int) {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)/\(primaryKey)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+                return
+            }
+            if let announcement = self.builder.announcementFromJSON(data) {
+                if let delegate = self.delegate {
+                    delegate.announcementFetched(announcement)
+                }
+            } else {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1369,7 +1754,20 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    func announcementFromJSON(_ data: Data?) -&gt; Announcement? {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        if let dict = json as? Dictionary&lt;String, AnyObject&gt; {
+            if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                let announcement = Announcement(primaryKey: primaryKey, title: title)
+                if let body = dict[&quot;body&quot;]  as? String {
+                    announcement.body = body
+                }
+                return announcement
+
+            }
+        }
+        return nil
+    }</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -1378,7 +1776,12 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementFetcherDelegate: class {
+
+    func announcementFetchingFailed()
+
+    func announcementFetched(_ announcement: Announcement)
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/version2.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/version2.html
index 3f31d4a96bc..54a4e557b30 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/version2.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/version2.html
@@ -338,7 +338,13 @@ endpoint. The next functional test verifies that behaviour.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/GrailsApi.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot;
+    static let version = &quot;2.0&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot;
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -358,7 +364,16 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcementPrimaryKey = announcement.primaryKey
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -375,7 +390,86 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate, AnnouncementFetcherDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    let fetcher = AnnouncementFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.fetcher.delegate = self
+        self.configureView()
+    }
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        }
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            self.configureView()
+        }
+    }
+
+    var announcementPrimaryKey: Int? {
+        didSet {
+            self.showActivityIndicator()
+            self.fetcher.fetchAnnouncement(self.announcementPrimaryKey!)
+        }
+    }
+
+    // MARK: - Private Methods
+    func showActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.startAnimating()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+
+    // Mark: - AnnouncementFetcherDelegate
+
+    func announcementFetchingFailed() {
+
+    }
+
+    func announcementFetched(_ announcement: Announcement) {
+        self.announcement = announcement
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -384,7 +478,42 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate: AnnouncementFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncement(_ primaryKey: Int) {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)/\(primaryKey)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+                return
+            }
+            if let announcement = self.builder.announcementFromJSON(data) {
+                if let delegate = self.delegate {
+                    delegate.announcementFetched(announcement)
+                }
+            } else {
+                if let delegate = self.delegate {
+                    delegate.announcementFetchingFailed()
+                }
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -393,7 +522,20 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.m</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    func announcementFromJSON(_ data: Data?) -&gt; Announcement? {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        if let dict = json as? Dictionary&lt;String, AnyObject&gt; {
+            if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                let announcement = Announcement(primaryKey: primaryKey, title: title)
+                if let body = dict[&quot;body&quot;]  as? String {
+                    announcement.body = body
+                }
+                return announcement
+
+            }
+        }
+        return nil
+    }</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -402,7 +544,12 @@ in <em>MasterViewController</em> as illustrated below:</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v2/IntranetClient/AnnouncementFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementFetcherDelegate: class {
+
+    func announcementFetchingFailed()
+
+    func announcementFetched(_ announcement: Announcement)
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
index 0ff4a250a05..7d039857229 100644
--- a/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
+++ b/guides/building-an-ios-swift-client-powered-by-a-grails-backend/4/guide/writingTheiOSApp.html
@@ -148,7 +148,16 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/Announcement.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/Announcement.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">class Announcement {
+    let primaryKey: Int
+    let title: String
+    var body: String?
+
+    init(primaryKey: Int, title: String) {
+        self.primaryKey = primaryKey
+        self.title = title
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -168,7 +177,29 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-v1/IntranetClient/AnnouncementBuilder.h</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementBuilder.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementBuilder {
+
+    func announcementsFromJSON(_ data: Data?) -&gt; [Announcement] {
+        let json = try? JSONSerialization.jsonObject(with: data!, options: [])
+        var announcements = [Announcement]()
+        if let array = json as? [Any] {
+            for object in array {
+                if let dict = object as? Dictionary&lt;String, AnyObject&gt; {
+                    if let title = dict[&quot;title&quot;] as? String, let primaryKey = dict[&quot;id&quot;]  as? Int {
+                        let announcement = Announcement(primaryKey: primaryKey, title: title)
+                        if let body = dict[&quot;body&quot;]  as? String {
+                            announcement.body = body
+                        }
+                        announcements.append(announcement)
+                    }
+                }
+            }
+        }
+        return announcements
+    }
+}</code></pre>
 </div>
 </div>
 
@@ -188,7 +219,13 @@ announcements exposed by the Grails application.</p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/GrailsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/GrailsApi.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">struct GrailsApi {
+    static let serverUrl = &quot;http://192.168.1.40:8080&quot; <i class="conum" data-value="1"></i><b>(1)</b>
+    struct Announcements {
+        static let Path = &quot;announcements&quot; <i class="conum" data-value="2"></i><b>(2)</b>
+    }
+    static let version = &quot;1.0&quot; <i class="conum" data-value="3"></i><b>(3)</b>
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -222,7 +259,37 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcher.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import Foundation
+
+class AnnouncementsFetcher : NSObject, URLSessionDelegate {
+
+    weak var delegate:AnnouncementsFetcherDelegate?
+    let builder = AnnouncementBuilder()
+
+    func fetchAnnouncements() {
+        let url = URL(string: &quot;\(GrailsApi.serverUrl)/\(GrailsApi.Announcements.Path)&quot;)!
+        let req = NSMutableURLRequest(url:url)
+        req.setValue(GrailsApi.version, forHTTPHeaderField: &quot;Accept-Version&quot;) <i class="conum" data-value="1"></i><b>(1)</b>
+        let config = URLSessionConfiguration.default
+        let session = URLSession(configuration: config, delegate: self, delegateQueue: OperationQueue.main)
+
+        let task = session.dataTask(with: req as URLRequest) { (data, response, error) in
+            if error != nil {
+                if let delegate = self.delegate {
+                    delegate.announcementsFetchingFailed()
+                }
+                return
+            }
+            let announcements = self.builder.announcementsFromJSON(data)
+            if let delegate = self.delegate {
+                delegate.announcementsFetched(announcements)
+            }
+
+        }
+        task.resume()
+
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -239,7 +306,12 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsFetcherDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">protocol AnnouncementsFetcherDelegate: class {
+
+    func announcementsFetchingFailed()
+
+    func announcementsFetched(_ announcements: [Announcement])
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -248,7 +320,99 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class MasterViewController: UITableViewController, AnnouncementsFetcherDelegate {
+
+    var detailViewController: DetailViewController? = nil
+    var objects = [Any]()
+
+    var tableViewDataSource = AnnouncementsTableViewDataSource()
+    var tableViewDelegate = AnnouncementsTableViewDelegate()
+    let fetcher = AnnouncementsFetcher()
+
+    // MARK: - LifeCycle
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        self.tableView.dataSource = self.tableViewDataSource
+        self.tableView.delegate = self.tableViewDelegate
+        self.fetcher.delegate = self
+    }
+
+    override func viewWillAppear(_ animated: Bool) {
+        self.clearsSelectionOnViewWillAppear = self.splitViewController!.isCollapsed
+        super.viewWillAppear(animated)
+        self.registerNotifications()
+        self.fetchAnnouncements() <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+    override func viewWillDisappear(_ animated: Bool) {
+        super.viewWillDisappear(animated)
+        self.unregisterNotifications()
+    }
+
+    // MARK: - Notifications
+
+    func registerNotifications() {
+        NotificationCenter.default.addObserver(
+            self,
+            selector: #selector(self.announcementTapped),
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    func unregisterNotifications() {
+        NotificationCenter.default.removeObserver(
+            self,
+            name: Notification.Name(&quot;AnnouncementTappedNotification&quot;),
+            object: nil)
+    }
+
+    // MARK: - Private Methods
+
+    @objc func announcementTapped(notification: NSNotification){
+
+        let announcement = notification.object as! Announcement
+        self.performSegue(withIdentifier: &quot;showDetail&quot;, sender: announcement)
+    }
+
+    func fetchAnnouncements() {
+        self.setNetworkActivityIndicator(true)
+        self.fetcher.fetchAnnouncements()
+    }
+
+    func setNetworkActivityIndicator(_ visible: Bool) {
+        UIApplication.shared.isNetworkActivityIndicatorVisible = visible
+    }
+
+    // MARK: - Segues
+
+    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }
+    }
+
+    // MARK: - AnnouncementsFetcherDelegate
+
+    func announcementsFetchingFailed() {
+        self.setNetworkActivityIndicator(false)
+    }
+
+    func announcementsFetched(_ announcements: [Announcement]) {  <i class="conum" data-value="2"></i><b>(2)</b>
+        self.setNetworkActivityIndicator(false)
+
+        self.tableViewDataSource.announcements = announcements
+        self.tableViewDelegate.announcements = announcements
+        self.tableView.reloadData()
+    }
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -269,13 +433,43 @@ You may need to change the ip address to match your local machine.
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDataSource.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDataSource : NSObject, UITableViewDataSource {
+
+    var announcements = [Announcement]()
+
+
+    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -&gt; Int {
+        return announcements.count
+    }
+
+    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -&gt; UITableViewCell {
+
+        let cell = tableView.dequeueReusableCell(withIdentifier: &quot;Cell&quot;, for: indexPath)
+
+        let announcement = announcements[indexPath.row]
+        cell.textLabel!.text = announcement.title
+        return cell
+    }
+}</code></pre>
 </div>
 </div>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/AnnouncementsTableViewDelegate.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class AnnouncementsTableViewDelegate : NSObject, UITableViewDelegate {
+
+    var announcements = [Announcement]()
+
+    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
+        let announcement = announcements[indexPath.row]
+        NotificationCenter.default.post(name: Notification.Name(&quot;AnnouncementTappedNotification&quot;), object: announcement) <i class="conum" data-value="1"></i><b>(1)</b>
+    }
+
+}</code></pre>
 </div>
 </div>
 <div class="colist arabic">
@@ -306,7 +500,15 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/MasterViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/MasterViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
+        if segue.identifier == &quot;showDetail&quot; {
+            let controller = (segue.destination as! UINavigationController).topViewController as! DetailViewController
+            if let announcement = sender as? Announcement {
+                controller.announcement = announcement
+            }
+            controller.navigationItem.leftBarButtonItem = self.splitViewController?.displayModeButtonItem
+            controller.navigationItem.leftItemsSupplementBackButton = true
+        }</code></pre>
 </div>
 </div>
 <div class="imageblock">
@@ -328,7 +530,61 @@ we set the announcement property of <em>DetailViewController</em></p>
 <div class="listingblock">
 <div class="title">/complete-swift-ios-v1/IntranetClient/DetailViewController.swift</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="swift">link:{sourcedir}/../complete-swift-ios-v1/IntranetClient/DetailViewController.swift[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="swift">import UIKit
+
+class DetailViewController: UIViewController, UIWebViewDelegate {
+
+    @IBOutlet weak var titleLabel: UILabel!
+    @IBOutlet weak var webView: UIWebView!
+    @IBOutlet weak var activityIndicatorView: UIActivityIndicatorView!
+
+    func configureView() {
+        // Update the user interface for the detail item.
+        if let announcement = self.announcement {
+            if let label = self.titleLabel {
+                label.text = announcement.title
+            }
+            if let webView = self.webView, let body = announcement.body {
+                self.hideActivityIndicator()
+                webView.loadHTMLString(body, baseURL: nil)
+            } else {
+                self.hideActivityIndicator()
+            }
+        } else {
+            self.hideActivityIndicator()
+        }
+    }
+
+    func hideActivityIndicator() {
+        if let activityIndicatorView  = self.activityIndicatorView {
+            activityIndicatorView.stopAnimating()
+        }
+    }
+
+    override func viewDidLoad() {
+        super.viewDidLoad()
+        // Do any additional setup after loading the view, typically from a nib.
+        self.configureView()
+    }
+
+    var announcement: Announcement? {
+        didSet {
+            // Update the view.
+            self.configureView()
+        }
+    }
+
+
+    // MARK: - UIWebViewDelegate
+
+    func webViewDidFinishLoad(_ webView: UIWebView) {
+        self.hideActivityIndicator()
+    }
+
+    func webView(_ webView: UIWebView, didFailLoadWithError error: Error) {
+        self.hideActivityIndicator()
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/discriminator-per-tenant/4/guide/index.html b/guides/discriminator-per-tenant/4/guide/index.html
index d4ad0466a93..a496c66d1fa 100644
--- a/guides/discriminator-per-tenant/4/guide/index.html
+++ b/guides/discriminator-per-tenant/4/guide/index.html
@@ -548,7 +548,22 @@ to the two tenants supported by this application.</p>
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/ManufacturerService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/ManufacturerService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(Manufacturer)
+<span class="type">interface</span> ManufacturerService {
+
+    <span class="type">int</span> count()
+
+    Manufacturer save(<span class="predefined-type">String</span> name)
+
+    <span class="predefined-type">List</span>&lt;Manufacturer&gt; findAll()
+
+    Manufacturer findByName(<span class="predefined-type">String</span> name)
+
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
diff --git a/guides/discriminator-per-tenant/4/guide/pages/tenantSelection.html b/guides/discriminator-per-tenant/4/guide/pages/tenantSelection.html
index a5d7af8507d..0c3d3d4de9a 100644
--- a/guides/discriminator-per-tenant/4/guide/pages/tenantSelection.html
+++ b/guides/discriminator-per-tenant/4/guide/pages/tenantSelection.html
@@ -99,7 +99,22 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/ManufacturerService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/ManufacturerService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(Manufacturer)
+<span class="type">interface</span> ManufacturerService {
+
+    <span class="type">int</span> count()
+
+    Manufacturer save(<span class="predefined-type">String</span> name)
+
+    <span class="predefined-type">List</span>&lt;Manufacturer&gt; findAll()
+
+    Manufacturer findByName(<span class="predefined-type">String</span> name)
+
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
diff --git a/guides/discriminator-per-tenant/4/guide/single.html b/guides/discriminator-per-tenant/4/guide/single.html
index d4ad0466a93..a496c66d1fa 100644
--- a/guides/discriminator-per-tenant/4/guide/single.html
+++ b/guides/discriminator-per-tenant/4/guide/single.html
@@ -548,7 +548,22 @@ to the two tenants supported by this application.</p>
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/ManufacturerService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/ManufacturerService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(Manufacturer)
+<span class="type">interface</span> ManufacturerService {
+
+    <span class="type">int</span> count()
+
+    Manufacturer save(<span class="predefined-type">String</span> name)
+
+    <span class="predefined-type">List</span>&lt;Manufacturer&gt; findAll()
+
+    Manufacturer findByName(<span class="predefined-type">String</span> name)
+
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
diff --git a/guides/discriminator-per-tenant/4/guide/writingTheApp.html b/guides/discriminator-per-tenant/4/guide/writingTheApp.html
index 38e7a14d34e..117e3e4fb20 100644
--- a/guides/discriminator-per-tenant/4/guide/writingTheApp.html
+++ b/guides/discriminator-per-tenant/4/guide/writingTheApp.html
@@ -374,7 +374,22 @@ to the two tenants supported by this application.</p>
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/ManufacturerService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/ManufacturerService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(Manufacturer)
+<span class="type">interface</span> ManufacturerService {
+
+    <span class="type">int</span> count()
+
+    Manufacturer save(<span class="predefined-type">String</span> name)
+
+    <span class="predefined-type">List</span>&lt;Manufacturer&gt; findAll()
+
+    Manufacturer findByName(<span class="predefined-type">String</span> name)
+
+}</code></pre>
 </div>
 </div>
 <div class="paragraph">
diff --git a/guides/grails-basicauth/3/guide/index.html b/guides/grails-basicauth/3/guide/index.html
index b38fda38ebe..bcc7f8168f3 100644
--- a/guides/grails-basicauth/3/guide/index.html
+++ b/guides/grails-basicauth/3/guide/index.html
@@ -290,7 +290,7 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">compile <span class="string"><span class="delimiter">'</span><span class="content">org.grails.plugins:spring-security-core:3.2.1</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -337,7 +337,7 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/conf/application.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/conf/application.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">grails.plugin.springsecurity.useBasicAuth = <span class="predefined-constant">true</span></code></pre>
 </div>
 </div>
 
@@ -357,7 +357,39 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/grails/HomeController.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/controllers/example/grails/HomeController.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">groovy.transform.CompileStatic</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.SpringSecurityService</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.annotation.Secured</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.userdetails.GrailsUser</span>
+
+<span class="annotation">@CompileStatic</span>
+<span class="annotation">@Secured</span>(<span class="string"><span class="delimiter">'</span><span class="content">isAuthenticated()</span><span class="delimiter">'</span></span>)
+<span class="type">class</span> <span class="class">HomeController</span> {
+
+    <span class="directive">static</span> responseFormats = [<span class="string"><span class="delimiter">'</span><span class="content">json</span><span class="delimiter">'</span></span>]
+
+    SpringSecurityService springSecurityService
+
+    <span class="keyword">def</span> <span class="function">index</span>() {
+        [<span class="key">name</span>: loggedUsername()]
+    }
+
+    <span class="predefined-type">String</span> loggedUsername() {
+        <span class="keyword">if</span> ( springSecurityService.principal == <span class="predefined-constant">null</span> ) {
+            <span class="keyword">return</span> <span class="predefined-constant">null</span>
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> <span class="predefined-type">String</span> ) {
+            <span class="keyword">return</span> springSecurityService.principal
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> GrailsUser ) {
+            <span class="keyword">return</span> ((GrailsUser) springSecurityService.principal).username
+        }
+        <span class="predefined-constant">null</span>
+    }
+
+}</code></pre>
 </div>
 </div>
 
@@ -377,7 +409,13 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/views/home/index.gson</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/views/home/index.gson[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">model {
+    <span class="predefined-type">String</span> name
+}
+
+json {
+    username name
+}</code></pre>
 </div>
 </div>
 
@@ -404,7 +442,19 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/services/example/grails/UserDataService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/grails/UserDataService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(User)
+<span class="type">interface</span> UserDataService {
+
+    User save(<span class="predefined-type">String</span> username, <span class="predefined-type">String</span> password, <span class="type">boolean</span> enabled, <span class="type">boolean</span> accountExpired, <span class="type">boolean</span> accountLocked, <span class="type">boolean</span> passwordExpired)
+
+    <span class="type">void</span> delete(<span class="predefined-type">Serializable</span> id)
+
+    <span class="type">int</span> count()
+}</code></pre>
 </div>
 </div>
 
@@ -424,7 +474,46 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">src/integration-test/groovy/example/grails/HomeControllerSpec.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/src/integration-test/groovy/example/grails/HomeControllerSpec.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestBuilder</span>
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestResponse</span>
+<span class="keyword">import</span> <span class="include">grails.testing.mixin.integration.Integration</span>
+<span class="keyword">import</span> <span class="include">spock.lang.Specification</span>
+
+<span class="annotation">@Integration</span>
+<span class="type">class</span> <span class="class">HomeControllerSpec</span> <span class="directive">extends</span> Specification {
+
+    UserDataService userDataService
+
+    <span class="keyword">def</span> <span class="string"><span class="delimiter">&quot;</span><span class="content">verify basic auth is possible</span><span class="delimiter">&quot;</span></span>() {
+        <span class="key">given</span>:
+        RestBuilder rest = <span class="keyword">new</span> RestBuilder()
+        <span class="directive">final</span> <span class="predefined-type">String</span> username = <span class="string"><span class="delimiter">'</span><span class="content">sherlock</span><span class="delimiter">'</span></span>
+        <span class="directive">final</span> <span class="predefined-type">String</span> password = <span class="string"><span class="delimiter">'</span><span class="content">elementary</span><span class="delimiter">'</span></span>
+
+        <span class="key">when</span>:
+        User user = userDataService.save(username, password, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, )
+
+        <span class="key">then</span>:
+        userDataService.count() == old(userDataService.count()) + <span class="integer">1</span>
+
+        <span class="key">when</span>:
+        <span class="predefined-type">String</span> token = <span class="string"><span class="delimiter">&quot;</span><span class="inline"><span class="inline-delimiter">${</span>username<span class="inline-delimiter">}</span></span><span class="content">:</span><span class="inline"><span class="inline-delimiter">${</span>password<span class="inline-delimiter">}</span></span><span class="delimiter">&quot;</span></span>.encodeAsBase64()
+        RestResponse rsp = rest.get(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost:</span><span class="inline"><span class="inline-delimiter">${</span>serverPort<span class="inline-delimiter">}</span></span><span class="content">/home</span><span class="delimiter">&quot;</span></span>) {
+            auth(<span class="string"><span class="delimiter">&quot;</span><span class="content">Basic </span><span class="inline"><span class="inline-delimiter">$</span>token</span><span class="delimiter">&quot;</span></span>)
+        }
+
+        <span class="key">then</span>:
+        rsp.status == <span class="integer">200</span>
+
+        <span class="key">and</span>:
+        rsp.json.username == username
+
+        <span class="key">cleanup</span>:
+        userDataService?.delete(user?.id)
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/pages/controller.html b/guides/grails-basicauth/3/guide/pages/controller.html
index 7fe488ff0c3..ad875a03703 100644
--- a/guides/grails-basicauth/3/guide/pages/controller.html
+++ b/guides/grails-basicauth/3/guide/pages/controller.html
@@ -81,7 +81,39 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/grails/HomeController.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/controllers/example/grails/HomeController.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">groovy.transform.CompileStatic</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.SpringSecurityService</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.annotation.Secured</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.userdetails.GrailsUser</span>
+
+<span class="annotation">@CompileStatic</span>
+<span class="annotation">@Secured</span>(<span class="string"><span class="delimiter">'</span><span class="content">isAuthenticated()</span><span class="delimiter">'</span></span>)
+<span class="type">class</span> <span class="class">HomeController</span> {
+
+    <span class="directive">static</span> responseFormats = [<span class="string"><span class="delimiter">'</span><span class="content">json</span><span class="delimiter">'</span></span>]
+
+    SpringSecurityService springSecurityService
+
+    <span class="keyword">def</span> <span class="function">index</span>() {
+        [<span class="key">name</span>: loggedUsername()]
+    }
+
+    <span class="predefined-type">String</span> loggedUsername() {
+        <span class="keyword">if</span> ( springSecurityService.principal == <span class="predefined-constant">null</span> ) {
+            <span class="keyword">return</span> <span class="predefined-constant">null</span>
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> <span class="predefined-type">String</span> ) {
+            <span class="keyword">return</span> springSecurityService.principal
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> GrailsUser ) {
+            <span class="keyword">return</span> ((GrailsUser) springSecurityService.principal).username
+        }
+        <span class="predefined-constant">null</span>
+    }
+
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/pages/dependencies.html b/guides/grails-basicauth/3/guide/pages/dependencies.html
index a7af27d834f..f633c98635c 100644
--- a/guides/grails-basicauth/3/guide/pages/dependencies.html
+++ b/guides/grails-basicauth/3/guide/pages/dependencies.html
@@ -81,7 +81,7 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">compile <span class="string"><span class="delimiter">'</span><span class="content">org.grails.plugins:spring-security-core:3.2.1</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -128,7 +128,7 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/conf/application.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/conf/application.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">grails.plugin.springsecurity.useBasicAuth = <span class="predefined-constant">true</span></code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/pages/services.html b/guides/grails-basicauth/3/guide/pages/services.html
index 74c0067396f..981b5b9bd98 100644
--- a/guides/grails-basicauth/3/guide/pages/services.html
+++ b/guides/grails-basicauth/3/guide/pages/services.html
@@ -88,7 +88,19 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/services/example/grails/UserDataService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/grails/UserDataService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(User)
+<span class="type">interface</span> UserDataService {
+
+    User save(<span class="predefined-type">String</span> username, <span class="predefined-type">String</span> password, <span class="type">boolean</span> enabled, <span class="type">boolean</span> accountExpired, <span class="type">boolean</span> accountLocked, <span class="type">boolean</span> passwordExpired)
+
+    <span class="type">void</span> delete(<span class="predefined-type">Serializable</span> id)
+
+    <span class="type">int</span> count()
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/pages/test.html b/guides/grails-basicauth/3/guide/pages/test.html
index c14e97e57fd..4a6d330e1d9 100644
--- a/guides/grails-basicauth/3/guide/pages/test.html
+++ b/guides/grails-basicauth/3/guide/pages/test.html
@@ -81,7 +81,46 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">src/integration-test/groovy/example/grails/HomeControllerSpec.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/src/integration-test/groovy/example/grails/HomeControllerSpec.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestBuilder</span>
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestResponse</span>
+<span class="keyword">import</span> <span class="include">grails.testing.mixin.integration.Integration</span>
+<span class="keyword">import</span> <span class="include">spock.lang.Specification</span>
+
+<span class="annotation">@Integration</span>
+<span class="type">class</span> <span class="class">HomeControllerSpec</span> <span class="directive">extends</span> Specification {
+
+    UserDataService userDataService
+
+    <span class="keyword">def</span> <span class="string"><span class="delimiter">&quot;</span><span class="content">verify basic auth is possible</span><span class="delimiter">&quot;</span></span>() {
+        <span class="key">given</span>:
+        RestBuilder rest = <span class="keyword">new</span> RestBuilder()
+        <span class="directive">final</span> <span class="predefined-type">String</span> username = <span class="string"><span class="delimiter">'</span><span class="content">sherlock</span><span class="delimiter">'</span></span>
+        <span class="directive">final</span> <span class="predefined-type">String</span> password = <span class="string"><span class="delimiter">'</span><span class="content">elementary</span><span class="delimiter">'</span></span>
+
+        <span class="key">when</span>:
+        User user = userDataService.save(username, password, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, )
+
+        <span class="key">then</span>:
+        userDataService.count() == old(userDataService.count()) + <span class="integer">1</span>
+
+        <span class="key">when</span>:
+        <span class="predefined-type">String</span> token = <span class="string"><span class="delimiter">&quot;</span><span class="inline"><span class="inline-delimiter">${</span>username<span class="inline-delimiter">}</span></span><span class="content">:</span><span class="inline"><span class="inline-delimiter">${</span>password<span class="inline-delimiter">}</span></span><span class="delimiter">&quot;</span></span>.encodeAsBase64()
+        RestResponse rsp = rest.get(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost:</span><span class="inline"><span class="inline-delimiter">${</span>serverPort<span class="inline-delimiter">}</span></span><span class="content">/home</span><span class="delimiter">&quot;</span></span>) {
+            auth(<span class="string"><span class="delimiter">&quot;</span><span class="content">Basic </span><span class="inline"><span class="inline-delimiter">$</span>token</span><span class="delimiter">&quot;</span></span>)
+        }
+
+        <span class="key">then</span>:
+        rsp.status == <span class="integer">200</span>
+
+        <span class="key">and</span>:
+        rsp.json.username == username
+
+        <span class="key">cleanup</span>:
+        userDataService?.delete(user?.id)
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/pages/views.html b/guides/grails-basicauth/3/guide/pages/views.html
index 71fe817ba92..1aca49d7996 100644
--- a/guides/grails-basicauth/3/guide/pages/views.html
+++ b/guides/grails-basicauth/3/guide/pages/views.html
@@ -81,7 +81,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/views/home/index.gson</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/views/home/index.gson[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">model {
+    <span class="predefined-type">String</span> name
+}
+
+json {
+    username name
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/single.html b/guides/grails-basicauth/3/guide/single.html
index b38fda38ebe..bcc7f8168f3 100644
--- a/guides/grails-basicauth/3/guide/single.html
+++ b/guides/grails-basicauth/3/guide/single.html
@@ -290,7 +290,7 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">compile <span class="string"><span class="delimiter">'</span><span class="content">org.grails.plugins:spring-security-core:3.2.1</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -337,7 +337,7 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/conf/application.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/conf/application.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">grails.plugin.springsecurity.useBasicAuth = <span class="predefined-constant">true</span></code></pre>
 </div>
 </div>
 
@@ -357,7 +357,39 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/grails/HomeController.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/controllers/example/grails/HomeController.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">groovy.transform.CompileStatic</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.SpringSecurityService</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.annotation.Secured</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.userdetails.GrailsUser</span>
+
+<span class="annotation">@CompileStatic</span>
+<span class="annotation">@Secured</span>(<span class="string"><span class="delimiter">'</span><span class="content">isAuthenticated()</span><span class="delimiter">'</span></span>)
+<span class="type">class</span> <span class="class">HomeController</span> {
+
+    <span class="directive">static</span> responseFormats = [<span class="string"><span class="delimiter">'</span><span class="content">json</span><span class="delimiter">'</span></span>]
+
+    SpringSecurityService springSecurityService
+
+    <span class="keyword">def</span> <span class="function">index</span>() {
+        [<span class="key">name</span>: loggedUsername()]
+    }
+
+    <span class="predefined-type">String</span> loggedUsername() {
+        <span class="keyword">if</span> ( springSecurityService.principal == <span class="predefined-constant">null</span> ) {
+            <span class="keyword">return</span> <span class="predefined-constant">null</span>
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> <span class="predefined-type">String</span> ) {
+            <span class="keyword">return</span> springSecurityService.principal
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> GrailsUser ) {
+            <span class="keyword">return</span> ((GrailsUser) springSecurityService.principal).username
+        }
+        <span class="predefined-constant">null</span>
+    }
+
+}</code></pre>
 </div>
 </div>
 
@@ -377,7 +409,13 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/views/home/index.gson</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/views/home/index.gson[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">model {
+    <span class="predefined-type">String</span> name
+}
+
+json {
+    username name
+}</code></pre>
 </div>
 </div>
 
@@ -404,7 +442,19 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">grails-app/services/example/grails/UserDataService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/grails/UserDataService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(User)
+<span class="type">interface</span> UserDataService {
+
+    User save(<span class="predefined-type">String</span> username, <span class="predefined-type">String</span> password, <span class="type">boolean</span> enabled, <span class="type">boolean</span> accountExpired, <span class="type">boolean</span> accountLocked, <span class="type">boolean</span> passwordExpired)
+
+    <span class="type">void</span> delete(<span class="predefined-type">Serializable</span> id)
+
+    <span class="type">int</span> count()
+}</code></pre>
 </div>
 </div>
 
@@ -424,7 +474,46 @@ You can go right to the <strong>completed example</strong> if you <code>cd</code
 <div class="listingblock">
 <div class="title">src/integration-test/groovy/example/grails/HomeControllerSpec.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/src/integration-test/groovy/example/grails/HomeControllerSpec.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestBuilder</span>
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestResponse</span>
+<span class="keyword">import</span> <span class="include">grails.testing.mixin.integration.Integration</span>
+<span class="keyword">import</span> <span class="include">spock.lang.Specification</span>
+
+<span class="annotation">@Integration</span>
+<span class="type">class</span> <span class="class">HomeControllerSpec</span> <span class="directive">extends</span> Specification {
+
+    UserDataService userDataService
+
+    <span class="keyword">def</span> <span class="string"><span class="delimiter">&quot;</span><span class="content">verify basic auth is possible</span><span class="delimiter">&quot;</span></span>() {
+        <span class="key">given</span>:
+        RestBuilder rest = <span class="keyword">new</span> RestBuilder()
+        <span class="directive">final</span> <span class="predefined-type">String</span> username = <span class="string"><span class="delimiter">'</span><span class="content">sherlock</span><span class="delimiter">'</span></span>
+        <span class="directive">final</span> <span class="predefined-type">String</span> password = <span class="string"><span class="delimiter">'</span><span class="content">elementary</span><span class="delimiter">'</span></span>
+
+        <span class="key">when</span>:
+        User user = userDataService.save(username, password, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, )
+
+        <span class="key">then</span>:
+        userDataService.count() == old(userDataService.count()) + <span class="integer">1</span>
+
+        <span class="key">when</span>:
+        <span class="predefined-type">String</span> token = <span class="string"><span class="delimiter">&quot;</span><span class="inline"><span class="inline-delimiter">${</span>username<span class="inline-delimiter">}</span></span><span class="content">:</span><span class="inline"><span class="inline-delimiter">${</span>password<span class="inline-delimiter">}</span></span><span class="delimiter">&quot;</span></span>.encodeAsBase64()
+        RestResponse rsp = rest.get(<span class="string"><span class="delimiter">&quot;</span><span class="content">http://localhost:</span><span class="inline"><span class="inline-delimiter">${</span>serverPort<span class="inline-delimiter">}</span></span><span class="content">/home</span><span class="delimiter">&quot;</span></span>) {
+            auth(<span class="string"><span class="delimiter">&quot;</span><span class="content">Basic </span><span class="inline"><span class="inline-delimiter">$</span>token</span><span class="delimiter">&quot;</span></span>)
+        }
+
+        <span class="key">then</span>:
+        rsp.status == <span class="integer">200</span>
+
+        <span class="key">and</span>:
+        rsp.json.username == username
+
+        <span class="key">cleanup</span>:
+        userDataService?.delete(user?.id)
+    }
+}</code></pre>
 </div>
 </div>
 
diff --git a/guides/grails-basicauth/3/guide/writingTheApp.html b/guides/grails-basicauth/3/guide/writingTheApp.html
index 0589f4d99c8..922ae6c2873 100644
--- a/guides/grails-basicauth/3/guide/writingTheApp.html
+++ b/guides/grails-basicauth/3/guide/writingTheApp.html
@@ -121,7 +121,7 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">build.gradle</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/build.gradle[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">compile <span class="string"><span class="delimiter">'</span><span class="content">org.grails.plugins:spring-security-core:3.2.1</span><span class="delimiter">'</span></span></code></pre>
 </div>
 </div>
 <div class="paragraph">
@@ -168,7 +168,7 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/conf/application.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/conf/application.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">grails.plugin.springsecurity.useBasicAuth = <span class="predefined-constant">true</span></code></pre>
 </div>
 </div>
 
@@ -188,7 +188,39 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/controllers/example/grails/HomeController.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/controllers/example/grails/HomeController.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">groovy.transform.CompileStatic</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.SpringSecurityService</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.annotation.Secured</span>
+<span class="keyword">import</span> <span class="include">grails.plugin.springsecurity.userdetails.GrailsUser</span>
+
+<span class="annotation">@CompileStatic</span>
+<span class="annotation">@Secured</span>(<span class="string"><span class="delimiter">'</span><span class="content">isAuthenticated()</span><span class="delimiter">'</span></span>)
+<span class="type">class</span> <span class="class">HomeController</span> {
+
+    <span class="directive">static</span> responseFormats = [<span class="string"><span class="delimiter">'</span><span class="content">json</span><span class="delimiter">'</span></span>]
+
+    SpringSecurityService springSecurityService
+
+    <span class="keyword">def</span> <span class="function">index</span>() {
+        [<span class="key">name</span>: loggedUsername()]
+    }
+
+    <span class="predefined-type">String</span> loggedUsername() {
+        <span class="keyword">if</span> ( springSecurityService.principal == <span class="predefined-constant">null</span> ) {
+            <span class="keyword">return</span> <span class="predefined-constant">null</span>
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> <span class="predefined-type">String</span> ) {
+            <span class="keyword">return</span> springSecurityService.principal
+        }
+        <span class="keyword">if</span> ( springSecurityService.principal <span class="keyword">instanceof</span> GrailsUser ) {
+            <span class="keyword">return</span> ((GrailsUser) springSecurityService.principal).username
+        }
+        <span class="predefined-constant">null</span>
+    }
+
+}</code></pre>
 </div>
 </div>
 
@@ -208,7 +240,13 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/views/home/index.gson</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/views/home/index.gson[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy">model {
+    <span class="predefined-type">String</span> name
+}
+
+json {
+    username name
+}</code></pre>
 </div>
 </div>
 
@@ -235,7 +273,19 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">grails-app/services/example/grails/UserDataService.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/grails-app/services/example/grails/UserDataService.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.gorm.services.Service</span>
+
+<span class="annotation">@Service</span>(User)
+<span class="type">interface</span> UserDataService {
+
+    User save(<span class="predefined-type">String</span> username, <span class="predefined-type">String</span> password, <span class="type">boolean</span> enabled, <span class="type">boolean</span> accountExpired, <span class="type">boolean</span> accountLocked, <span class="type">boolean</span> passwordExpired)
+
+    <span class="type">void</span> delete(<span class="predefined-type">Serializable</span> id)
+
+    <span class="type">int</span> count()
+}</code></pre>
 </div>
 </div>
 
@@ -255,7 +305,46 @@ function addJsClass() {
 <div class="listingblock">
 <div class="title">src/integration-test/groovy/example/grails/HomeControllerSpec.groovy</div>
 <div class="content">
-<pre class="CodeRay highlight"><code data-lang="groovy"><span class="key">link</span>:..<span class="regexp"><span class="delimiter">/</span><span class="content">..</span><span class="delimiter">/</span></span>snippets/src/integration-test/groovy/example/grails/HomeControllerSpec.groovy[role=include]</code></pre>
+<pre class="CodeRay highlight"><code data-lang="groovy"><span class="keyword">package</span> example.grails
+
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestBuilder</span>
+<span class="keyword">import</span> <span class="include">grails.plugins.rest.client.RestResponse</span>
+<span class="keyword">import</span> <span class="include">grails.testing.mixin.integration.Integration</span>
+<span class="keyword">import</span> <span class="include">spock.lang.Specification</span>
+
+<span class="annotation">@Integration</span>
+<span class="type">class</span> <span class="class">HomeControllerSpec</span> <span class="directive">extends</span> Specification {
+
+    UserDataService userDataService
+
+    <span class="keyword">def</span> <span class="string"><span class="delimiter">&quot;</span><span class="content">verify basic auth is possible</span><span class="delimiter">&quot;</span></span>() {
+        <span class="key">given</span>:
+        RestBuilder rest = <span class="keyword">new</span> RestBuilder()
+        <span class="directive">final</span> <span class="predefined-type">String</span> username = <span class="string"><span class="delimiter">'</span><span class="content">sherlock</span><span class="delimiter">'</span></span>
+        <span class="directive">final</span> <span class="predefined-type">String</span> password = <span class="string"><span class="delimiter">'</span><span class="content">elementary</span><span class="delimiter">'</span></span>
+
+        <span class="key">when</span>:
+        User user = userDataService.save(username, password, <span class="predefined-constant">true</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, <span class="predefined-constant">false</span>, )
... 10052 lines suppressed ...