{"id":2861,"date":"2019-09-09T10:00:09","date_gmt":"2019-09-08T22:00:09","guid":{"rendered":"https:\/\/www.deltics.co.nz\/blog\/?p=2861"},"modified":"2019-09-22T09:59:44","modified_gmt":"2019-09-21T21:59:44","slug":"azure-devops-building-some-code","status":"publish","type":"post","link":"https:\/\/www.deltics.co.nz\/blog\/posts\/2861\/","title":{"rendered":"Azure DevOps &#8211; Building Some Code"},"content":{"rendered":"<span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>\n<p class=\"wp-block-paragraph\">After <a href=\"https:\/\/www.deltics.co.nz\/blog\/posts\/2659\">the previous post<\/a> we should have ourselves a build agent with everything we need to perform command line builds of Delphi code. But let&#8217;s make sure!<\/p>\n\n\n\n<!--more-->\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">The first thing we need is some code, so we&#8217;ll need a git repository in Azure DevOps.  Before we can get to that though, we need a <strong>Project<\/strong>.  In Azure DevOps, a project is a container for any number of repositories you may wish but also backlogs for managing work items relating to those repositories and much else besides.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Projects may be <strong>private<\/strong> or <strong>public<\/strong> and which you choose depends on your collaboration model.  Private repositories can still be used collaboratively but people need to be invited to join those projects.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">But it is not the aim of these posts to get into the details of Azure DevOps (maybe another time), so for our purposes we&#8217;ll create a private <strong>Hello Delphi<\/strong> project:<\/p>\n\n\n\n<p class=\"wp-block-paragraph\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"296\" class=\"wp-image-2863\" style=\"width: 1024px;\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?resize=640%2C296&#038;ssl=1\" alt=\"\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?w=1361&amp;ssl=1 1361w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?resize=300%2C139&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?resize=768%2C356&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?resize=1024%2C474&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?resize=380%2C176&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.11.56.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once created (it takes a few seconds) we can navigate to the project and its repositories.  Initially there is a single, default repository (named for the project) but it contains no code at this point.  The quickest and simplest way to get something into that repo is to add a <strong>README.MD<\/strong> and <strong>.gitignore<\/strong> directly from the Azure DevOps UI:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"354\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?resize=640%2C354&#038;ssl=1\" alt=\"\" class=\"wp-image-2864\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?resize=1024%2C566&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?resize=300%2C166&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?resize=768%2C425&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?resize=380%2C210&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?w=1362&amp;ssl=1 1362w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.18.17.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Here we <span style=\"text-decoration: underline;\">do<\/span> find some awareness of Delphi as a default <strong>.gitignore<\/strong> file is available!  \\o\/<\/p>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">Once we&#8217;ve initialised the repo we are presented with the contents of that repo (the <strong>README.MD<\/strong> and <strong>.gitignore<\/strong> we just created) and can now add additional files.  Adding folders is a bit trickier (even though it is offered as an option) because git repos do not track empty folders; to create a folder you actually need to create a file and specify a new path involving the new folder.  But that\u2019s not a problem right now as our next step is to create a simple Delphi project (i.e. dpr) to exercise our build agent with.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We could of course clone the repo to a machine and work there, pushing our changes to the Azure DevOps repo as we go, but everything we need to do for this exercise we can do directly from with Azure DevOps.<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"206\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?resize=640%2C206&#038;ssl=1\" alt=\"\" class=\"wp-image-2865\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?resize=1024%2C330&amp;ssl=1 1024w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?resize=300%2C97&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?resize=768%2C247&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?resize=380%2C122&amp;ssl=1 380w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?w=1364&amp;ssl=1 1364w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-09.26.19.png?w=1280&amp;ssl=1 1280w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">However you choose to do it, we just need two files:<\/p>\n\n\n\n<ol class=\"wp-block-list\"><li><strong>HelloDelphi.dpr<\/strong> &#8211; a simple Delphi project which we can compile on our build agent<\/li><li><strong>build.yml <\/strong>&#8211; a YAML build pipeline that describes the build job. (This can actually be named whatever we like)<\/li><\/ol>\n\n\n\n<p class=\"wp-block-paragraph\">After adding each file you are presented with a file editor to create some initial content for the file before it is committed to the repo.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">First, <strong>HelloDelphi.dpr<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-pascal\" data-line=\"\">\/\/ File: Hello Delphi \/ HelloDelphi.dpr\n\n{$APPTYPE CONSOLE}\n\nprogram HelloDelphi;\nbegin\n  WriteLn(&#039;Hello Delphi!&#039;);\nend.<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\">And then <strong>build.yml<\/strong>:<\/p>\n\n\n\n<pre class=\"wp-block-prismatic-blocks\"><code class=\"language-yaml\" data-line=\"\"># File: build.yml\n\ntrigger:\n- master\n\npool:\n  name: The Den\n  demands: Delphi.7\n\nsteps:\n- powershell: |\n    c:\\dcc\\7\\bin\\dcc32.exe HelloDelphi.dpr -Uc:\\dcc\\7\\lib -CC\n    if (Test-Path -path HelloDelphi.exe) {\n        .\\HelloDelphi.exe\n    }\n  displayName: Build and run tests (Delphi 7)<\/code><\/pre>\n\n\n\n<p class=\"wp-block-paragraph\"><a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/yaml-schema?view=azure-devops&amp;tabs=schema\">Full documentation of the YAML build format<\/a> is beyond the scope of these posts but is available <a href=\"https:\/\/docs.microsoft.com\/en-us\/azure\/devops\/pipelines\/yaml-schema?view=azure-devops&amp;tabs=schema\">from Microsoft<\/a>.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\"><strong>NOTE:<\/strong> <em>YAML can be an infuriating format.  It relies on whitespace and indentation to convey structure and meaning and errors can be very difficult to spot unless using a YAML aware editor, such as the online one provided by Azure DevOps itself.  Even then, an error highlighted in your YAML might be caused by a whitespace problem elsewhere in the file!<\/em><\/p>\n\n\n\n<p class=\"wp-block-paragraph\">For my build step I have chosen a <strong>powershell<\/strong> script but I could equally have used a simple <strong>cmd.exe<\/strong> based script by using <code class=\"\" data-line=\"\">- script<\/code> in place of <code class=\"\" data-line=\"\">- powershell<\/code> .&nbsp;<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In addition to the build script itself, there is some additional configuration that tells Azure DevOps how to work with this build:<\/p>\n\n\n\n<ul class=\"wp-block-list\"><li>The <code class=\"\" data-line=\"\">- trigger<\/code> identifies that the build is configured to be triggered by changes on the <strong>master<\/strong> branch.<\/li><\/ul>\n\n\n\n<ul class=\"wp-block-list\"><li>The <code class=\"\" data-line=\"\">- pool<\/code> identifies that this build is to run in the agent pool called <strong>The Den<\/strong> and requires an agent that has the capability <strong><code class=\"\" data-line=\"\">Delphi.7<\/code><\/strong>.<\/li><\/ul>\n\n\n\n<p class=\"wp-block-paragraph\">Remember, the user-defined capabilities I added to my agent identify which specific Delphi versions are available on the machine and the location in which they are to be found.  You will note however that in this script, the location of the Delphi 7 compiler is hard-coded.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Unfortunately I haven&#8217;t yet found a way to obtain the values of user-defined capabilities in a pipeline that doesn&#8217;t involve creating a custom task which is <em>way<\/em> beyond the scope of these posts.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">There is <a href=\"https:\/\/marketplace.visualstudio.com\/items?itemName=fernfrost.agent-capabilities\">a plug-in in the Visual Studio Marketplace<\/a> which purports to make these values available via environment variables but I haven&#8217;t yet succeeded in getting this to work (it just crashes my pipeline).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">I am using Delphi 7 for this initial test simply because it requires the least configuration of all the Delphi versions to get a simple build up and running but you should be able to adapt this to whatever version you need.  If you haven&#8217;t previously configured command line builds for later versions, be aware that things became significantly more complicated with support for platforms other than Windows, but it&#8217;s still not that difficult.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">In a later post we&#8217;ll see a much more comprehensive approach.<\/p>\n\n\n\n<p class=\"has-background has-very-light-gray-background-color wp-block-paragraph\">I anticipate that some will suggest I use MS Build but I haven\u2019t yet investigated whether MS Build can be successfully used with side-by-side Delphi installs without full IDE installation.  In any event, for this exercise this would be an unnecessary additional complication since at the very least it relies on IDE created configuration files.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Clearly a great deal more work is needed to turn this into something suitable for production use with real-world Delphi applications, but remember that the aim here is to test the basic ability of the agent to build with Delphi.  Keeping things simple will help us focus on that without getting bogged down in the details (which will come later).<\/p>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">At this point<strong> build.yml<\/strong> is just a file in our repo and isn&#8217;t doing anything for us.  To turn it into something useful we need to create a pipeline and associate this file with it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">To do this, we go to the <strong>Pipelines<\/strong> area of our <strong>Hello Delphi<\/strong> project.  Since we don\u2019t have any currently we are prompted to create our first one and choose to create a pipeline whose code is stored in <strong>Azure Repos Git<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"368\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-10.52.41.png?resize=640%2C368&#038;ssl=1\" alt=\"\" class=\"wp-image-2872\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-10.52.41.png?w=841&amp;ssl=1 841w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-10.52.41.png?resize=300%2C172&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-10.52.41.png?resize=768%2C441&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-10.52.41.png?resize=380%2C218&amp;ssl=1 380w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Following the prompts, we select the repo (there&#8217;s only the one we were just working with) and can then choose either to start with a <strong>Starter Pipeline<\/strong> (i.e. a new file with some <em>very<\/em> basic content which won\u2019t be of any use to us) or identify an existing YAML file.  This latter option is what we need since we just created the file we need (<strong>build.yml<\/strong>).<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once we have chosen the file, we are dropped into the pipeline editor (a basic text editor with some YAML and pipeline syntax smarts) where we can make some final tweaks and correct any of those pesky whitespace errors I mentioned.  But we should be good to go and can just run the pipeline.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">Once it completes (hopefully) successfully, you can then drill into the job details and should see something like this:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"515\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.13.16.png?resize=640%2C515&#038;ssl=1\" alt=\"\" class=\"wp-image-2873\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.13.16.png?w=964&amp;ssl=1 964w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.13.16.png?resize=300%2C241&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.13.16.png?resize=768%2C618&amp;ssl=1 768w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.13.16.png?resize=323%2C260&amp;ssl=1 323w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">Each of the steps in the job can be expanded to see more detail.  Most of these steps are boiler-plate operations performed by Azure DevOps to send work to the agent, including checking out the repo to provide the necessary files for the agent to work on.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">The step we&#8217;re most interested in is the middle one: <strong>Build and run tests (Delphi 7)<\/strong>.  This was the <code class=\"\" data-line=\"\">displayName<\/code> we specified for our build step so expanding this we should see the output from the <strong>powershell<\/strong> step in our <strong>build.yml<\/strong>:<\/p>\n\n\n\n<figure class=\"wp-block-image\"><img data-recalc-dims=\"1\" loading=\"lazy\" decoding=\"async\" width=\"640\" height=\"459\" src=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.16.34.png?resize=640%2C459&#038;ssl=1\" alt=\"\" class=\"wp-image-2874\" srcset=\"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.16.34.png?w=676&amp;ssl=1 676w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.16.34.png?resize=300%2C215&amp;ssl=1 300w, https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/Screen-Shot-2019-09-07-at-11.16.34.png?resize=362%2C260&amp;ssl=1 362w\" sizes=\"auto, (max-width: 640px) 100vw, 640px\" \/><\/figure>\n\n\n\n<p class=\"wp-block-paragraph\">And there we have it.<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">We can see that our simple script to run the compiler was indeed successful and that following compilation we identified the resulting <strong>exe<\/strong> file and ran it to obtain the <code class=\"\" data-line=\"\">Hello Delphi!<\/code> output to the console.<\/p>\n\n\n\n<p class=\"has-background has-light-green-cyan-background-color wp-block-paragraph\">I just said that you can drill into this detail once the job is completed, but in fact you can also view the output of a build as it happens, with logs sent in real-time even from the agent running on your machine to be viewed via the Azure DevOps UI live!<\/p>\n\n\n\n<p class=\"wp-block-paragraph\">So, I&#8217;ve established that my build agent is able to successfully compile my Delphi code, even though Azure DevOps knows nothing about Delphi (other than in providing a default <strong>.gitignore<\/strong> for my repos).<\/p>\n\n\n\n<p class=\"has-drop-cap wp-block-paragraph\">Next time we&#8217;ll skip ahead somewhat with a more comprehensive and sophisticated build script.  We&#8217;ll also do something more useful after a successful build: Executing some tests and capturing the results of those tests to obtain code quality metrics from Azure DevOps.<\/p>\n","protected":false},"excerpt":{"rendered":"<p><span class=\"span-reading-time rt-reading-time\" style=\"display: block;\"><span class=\"rt-label rt-prefix\">[Estimated Reading Time: <\/span> <span class=\"rt-time\"> 6<\/span> <span class=\"rt-label rt-postfix\">minutes]<\/span><\/span>In this post we create a (very!) simple project, build it using Delphi (7) and run it.  All with Azure DevOps.<\/p>\n","protected":false},"author":2,"featured_media":2862,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"_jetpack_newsletter_access":"","_jetpack_dont_email_post_to_subs":false,"_jetpack_newsletter_tier_id":0,"_jetpack_memberships_contains_paywalled_content":false,"_jetpack_feature_clip_id":0,"_jetpack_memberships_contains_paid_content":false,"footnotes":"","jetpack_publicize_message":"","jetpack_publicize_feature_enabled":true,"jetpack_social_post_already_shared":true,"jetpack_social_options":{"image_generator_settings":{"template":"highway","default_image_id":0,"font":"","enabled":false},"version":2},"jetpack_post_was_ever_published":false},"categories":[324,322,323,4,321],"tags":[325,326,251,292],"class_list":["post-2861","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-automation","category-azure-devops","category-ci-cd","category-delphi","category-devops","tag-azure","tag-azure-devops","tag-build-automation","tag-delphi"],"jetpack_publicize_connections":[],"jetpack_featured_media_url":"https:\/\/i0.wp.com\/www.deltics.co.nz\/blog\/wp-content\/uploads\/pipelines-hero-code-1024x256.jpg?fit=1024%2C256&ssl=1","jetpack_shortlink":"https:\/\/wp.me\/p1TKYv-K9","jetpack_sharing_enabled":true,"jetpack-related-posts":[],"_links":{"self":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2861","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/comments?post=2861"}],"version-history":[{"count":12,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2861\/revisions"}],"predecessor-version":[{"id":2906,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/posts\/2861\/revisions\/2906"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media\/2862"}],"wp:attachment":[{"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/media?parent=2861"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/categories?post=2861"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.deltics.co.nz\/blog\/wp-json\/wp\/v2\/tags?post=2861"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}