Everybody Loves Ringo Photobook

We have two dogs (and three cats, two hairless rats, a sweet water aquarium, a pond in the garden with koi, goldfish and a sturgeon, and five beehives), and both of them have instagram accounts: the chichuahua Ringo has @everybodylovesjuno and the whippet greyhound Juno has @everybodylovesringodog.

As a Sinterklaas present for my wife I created this 24-page 14 x 14 cm hard cover photo book on Albelli:

(Don’t wait for the loading spinner to finish, just click next: >)

RELX End Of Year Party

Click on an image to start a slideshow.

This year’s RELX End Of Year Party (that’s a party for all of RBI, Elsevier and LexisNexis in the Amsterdam location) was held at the KIT Royal Tropical Institute and this was the dresscode:

Come dressed as a magical forest creature: a fairy, an elf, a unicorn, or maybe a dragon?
Come as your favourite character from Middle Earth, Avatar or Sherwood fairy-tale forest.
Wrap yourself in lights, leaves and leprechaun hats and create your own mystical forest character.

It was fun!

On using code as illustration

This morning we had a team breakfast session in the recently redecorated Herman Boerhaave (*) meeting hall of our Millennium Tower.

Part of the decoration of the wall behind the projector screen was this bit of html:

Below I’ll explain why I’m certain that for every meeting I’ll have there I’ll be annoyed by it.

I’ve found the source of the code (“Here at HTML.am, you can find all things HTML - from HTML codes, HTML editors, HTML generators and more.”) and the complete snippet is this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<!-- Start Styles. Move the 'style' tags and everything between them to between the 'head' tags -->
<style type="text/css">
.myTable { width:400px;background-color:#eee;border-collapse:collapse; }
.myTable th { background-color:#000;color:white;width:50%; }
.myTable td, .myTable th { padding:5px;border:1px solid #000; }
</style>
<!-- End Styles -->
<table class="myTable">
<tr>
<th>Table Header</th><th>Table Header</th>
</tr>
<tr>
<td>Table cell 1</td><td>Table cell 2</td>
</tr>
<tr>
<td>Table cell 3</td><td>Table cell 4</td>
</tr>
</table>

What’s wrong with this code

  • The CSS is inline.
  • The CSS and HTML are not indented.
  • There’s no space between the properties and the values.
  • For such a short <style> declaration there’s no need for <!-- Start/End Styles --> comments.
  • The colors are not defined in a consistent way: a background-color is defined in hexadecimal (#000, which would be black as a named color) while the color is defined as the named color white.
  • The classname does not follow any CSS naming convention.
  • The table does not have a <thead> and tbody.

Here’s what I would have like to see on the wall

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
.c-table--rigidtwocolumn {
width: 400px;
background-color: #eee;
border-collapse: collapse;
}

.c-table--rigidtwocolumn th {
background-color: #000;
color: #fff;
width: 50%;
}

.c-table--rigidtwocolumn td, .c-table--rigidtwocolumn th {
padding: 5px;
border: 1px solid #000;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
<table class="c-table--rigidtwocolumn">
<thead>
<tr>
<th>Table Header</th>
<th>Table Header</th>
</tr>
</thead>
<tbody>
<tr>
<td>Table cell 1</td>
<td>Table cell 2</td>
</tr>
<tr>
<td>Table cell 3</td>
<td>Table cell 4</td>
</tr>
</tbody>
</table>

Why .c-table--rigidtwocolumn?

  • c-table is the component name
  • --rigidtwocolumn describes the modifier of the component: it’s a fixed width table that can only contain two columns of equal width

Here’s a fiddle if you want to improve my fix!

(*) About Herman Boerhaave

Simplex sigillum veri: ‘The simple is the sign of the true’

Herman Boerhaave was a Dutch botanist, chemist, Christian humanist, and physician of European fame. He is regarded as the founder of clinical teaching and of the modern academic hospital and is sometimes referred to as “the father of physiology,” along with Venetian physician Santorio Santorio (1561–1636). Boerhaave introduced the quantitative approach into medicine, along with his pupil Albrecht von Haller (1708–1777) and is best known for demonstrating the relation of symptoms to lesions. He was the first to isolate the chemical urea from urine. He was the first physician to put thermometer measurements to clinical practice. His motto was Simplex sigillum veri: ‘The simple is the sign of the true’. He is often hailed as the “Dutch Hippocrates”.

Source: https://en.wikipedia.org/wiki/Herman_Boerhaave

Now Playing: Van Morrison - Into The Mystic

The song has an easy groove, beginning with acoustic guitar and including isolated horn and string charts, as Morrison evokes a sailor’s pledge to come home from the sea to his lover and “rock [her] gypsy soul.” Typical for Morrison, however, the story line is sketchy and, in any case, less important than the mood. As a lyricist, Morrison is often less interested in using words for meaning than for sound, and that is the case here. He once said that his original title for the song was “Into the Misty,” and he may have intended a meaning such as “into the mist,” since the song refers to fog horns among other things nautical.

Source: https://www.allmusic.com/song/into-the-mystic-mt0004460692

Turning off ligatures - two letters that are joined - for your font

The font we’ll be using in Nextens starting with our next release has ligatures (“a ligature occurs where two or more letters are joined as a single glyph”) turned on by default. It’s a nice typographic effect, but for some words in Dutch it doesn’t work so well.

This is the default Lato:

This is Lato with ligatures turned off:

You can turn it off everywhere:

1
2
3
html {
font-feature-settings: "liga" 0;
}

or only for headings (where it’s more prominent):

1
2
3
h1, h2, h3, h4, h5, h6 {
font-feature-settings: "liga" 0;
}

Be careful when moving your TFS server across timezones

Our TFS server and two build servers were moved from the UK datacenter to the Amsterdam one this week, and a funny thing happened: I time-travelled into the future.

After the move I did a check-in to test if the migration was succesful: it was! However every check-in after that failed with:

TF54000: Cannot update data because the server clock may have been set incorrectly. Contact your Team Foundation Server Administrator.

After some googling I decided to have a look at the tbl_ChangeSet table. I ran

SELECT TOP 1 *
FROM tbl_ChangeSet
ORDER BY CreationDate DESC

and the result was a changeset one hour into the future! So when we tried to check-in changes to TFS it looked at the timestamp of the most recent changeset, compared it to timestamp of the new changeset, saw that it was older, and decided to throw an error that there must be a problem with the server time. I assume that sometime after my check-in the timezone of the server was updated.

Luckily after waiting for the time of the future changeset to arrive - one hour - we could check-in again.

Fix 'The underlying connection was closed' error in Invoke-RestMethod from PowerShell

When calling a url from PowerShell like this …

1
Invoke-RestMethod -Uri https://dashboarddelivery.nextens.nl/api/invalidate/

… fails with …

1
Invoke-RestMethod : The underlying connection was closed: An unexpected error occurred on a send.

… you should add this line to your script:

1
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12

(because PowerShell by default uses TLS 1.0 for web requests).

Building and deploying Hexo to an Azure App Service from Azure DevOps

This blog runs on the wonderful Hexo, a Markdown-based and NodeJS-powered blog framework. The code is stored in a project on Azure DevOps (https://***.visualstudio.com/) and the blog runs on an Azure App Service.

In this blog post I’ll show you how I build and deploy my blog to Azure.

Project and solution

My Hexo blog lives in an otherwise empty ASP.NET Web Application because I want to run the hexo generate command - that generates the static files that need to be deployed - via the Post-build event command line.

To do this right-click the Project, select Properties, go to Build Events and add the following in Post-build event command line:

hexo generate

This will also trigger the same command when you build the project in Visual Studio.

The Build

Get Sources

npm install

npm install hexo-cli -g

Command and arguments: install hexo-cli -g

Visual Studio Build

In the logs you should see the hexo generate PostBuildEvent being triggered:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
PostBuildEvent:
hexo generate
INFO Start processing
INFO Files loaded in 342 ms
INFO Generated: index.html
INFO Generated: about/index.html
INFO Generated: archives/index.html
INFO Generated: archives/2018/11/index.html
INFO Generated: fancybox/blank.gif
INFO Generated: tags/automate-everything/index.html
[...]
INFO Generated: css/images/IMG_20181012_140103.jpg
INFO 54 files generated in 1.07 s
Done Building Project "D:\a\3\s\Blog.csproj" (default targets).
Done Building Project "D:\a\3\s\Blog.sln" (default targets).

Build succeeded.

For this step I first tried to run hexo generate via npm too, as described in posts like this, but I could not get that to work…

Copy Files

Target Folder: $(Build.ArtifactStagingDirectory)

Publish Build Artifacts

The Release

The release is a standard Azure App Service Deploy:

Building and deploying fractal.build to Azure from Team Foundation Server

This year we started with creating a Design Language System for Nextens. It runs on Fractal, “a tool to help you build and document web component libraries, and then integrate them into your projects”. We use it to create and document the atoms, molecules and organisms that make up our components.

The site is deployed continuously to an App Service in Azure from our on-premise Microsoft Visual Studio Team Foundation Server 2017.3.1. This post documents how this is done.

web.config

In the source folder we have a web.config that fixes the MIME types of fonts so they load correctly in Azure, and which adds a rewrite rule that enables extension-less URLs in the documentation pages of Fractal.

The latter is needed because we have this setting in \gulp\fractal-setup.js:

1
fractal.web.set('builder.urls.ext', null); // default is '.html'

The content of web.config:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.web>
<compilation debug="true" targetFramework="4.0"/>
</system.web>
<system.webServer>
<httpProtocol>
<customHeaders>
<add name="Access-Control-Allow-Origin" value="*" />
</customHeaders>
</httpProtocol>
<staticContent>
<remove fileExtension=".svg" />
<remove fileExtension=".woff" />
<remove fileExtension=".woff2" />
<mimeMap fileExtension=".svg" mimeType="image/svg+xml" />
<mimeMap fileExtension=".woff" mimeType="application/x-font-woff" />
<mimeMap fileExtension=".woff2" mimeType="application/font-woff2" />
</staticContent>
<rewrite>
<rules>
<rule name="docs/pattern-overview">
<match url="(^docs|^components)(\/.+)+$"/>
<action type="Rewrite" url="{R:0}.html"/>
<conditions>
<add input="{URL}" pattern=".(html|svg|scss|css)$" negate="true"/>
</conditions>
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>

The web.config file is copied from the source folder to the public folder by a gulp task (gulp\gulp-tasks\copy.js):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/* global module */
module.exports = function (gulp, config, plugins, build_base) {
'use strict';

gulp.task('copy:js', function (done) {
gulp.src(config.src.js)
.pipe(plugins.plumber({ errorHandler: config.onError }))
.pipe(plugins.include())
.pipe(plugins.uglify())
.pipe(gulp.dest(config.build.js))

gulp.src(config.fractal.docsImages)
.pipe(gulp.dest(build_base + 'docs/'))

gulp.src(config.src.path + '*.*') // favicon.ico and web.config
.pipe(gulp.dest(build_base))

done();
});
};

The config.src.path is __dirname + '/source/'

The Build tasks

NPM install

To install the npm packages defined in your package.json file add an npm task with these settings:

  • The working folder should point to the directory that contains the package.json file.
  • The npm command to use is install

Install gulp –save-dev

To install the gulp npm package add an npm task with these settings:

  • npm command: install
  • arguments: gulp --save-dev

Install gulp-cli –save-dev

To install the gulp-cli npm package add an npm task with these settings:

  • npm command: install
  • arguments: gulp-cli --save-dev

Gulp build

To run the actual Gulp build task add a Gulp task with these settings:

  • Gulp File Path: the path to your gulpfile.js
  • Gulp Task(s): build
  • Advanced > Working Directory: the same as the working folder in the first two tasks
  • Advanced > gulp.js location: node_modules/gulp/bin/gulp.js

The log of this task should look something like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
##[section]Starting: gulp build
[...]
[00:44:44] Starting 'build'...
[...]
[00:45:41] Finished 'build:all' after 55 s
[00:45:41] Starting 'fractal:build'...
[?25l⚑ Exported 1 of 635 items
[...]
[?25l⚑ Exported 635 of 635 items
✔ Fractal build completed!
[00:51:17] Finished 'fractal:build' after 5.6 min
[00:51:17] Finished 'build' after 6.55 min
##[section]Finishing: gulp build

Publish Build Artifacts

Add a Publish Build Artifacts task with these settings:

Path to Publish

The path to publish is the folder named public created by the Gulp build.

1
$/Cumulus/Stitch-DLS/$(BranchName)/rbi-stitch/public

Artifact Name

1
drop

The Release

The release is done with an Azure App Service Deploy task.

Point the Package or folder to the public folder created by the build:
$(System.DefaultWorkingDirectory)/Dev05-Stitch/drop

The log of this task should look something like this:

1
2
3
4
5
6
Info: Updating file (*****\assets.html).
[...]
Info: Updating file (*****\themes\mandelbrot\js\mandelbrot.js.map).
Info: Updating file (*****\Web.config).
Total changes: 1211 (0 added, 0 deleted, 1211 updated, 0 parameters changed, 75632972 bytes copied)
Successfully deployed web package to App Service.