Posts categorized “Programming”


September 9, 2017
  Writing a Hexo Tag Plugin

In the process of migrating Daniel’s Weekly Devotions to Hexo, we ran into a problem that we felt sure a tag plugin could solve.

The Problem

Jekyll‘s Markdown parser follows the original one, where text within an HTML tag is not processed. This can be the desired behavior in many cases, as you could put what would otherwise be translated as Markdown between HTML tags, and the parser/renderer will leave it alone. One of the common features, used multiple times in most posts, are links to Scripture references and blocks of quoted text. We had an include to automate the links, but we needed a special class on the <blockquote> tag, which meant that all Scripture blockquotes could not use Markdown (or end up with “smartified” quotes and such; we had to use the HTML entities within these quotes.) We also included the verse numbers as superscripts within the quoted text; more tags.

It looked something like this… (the “ref” CSS class turns the text red)

1
2
3
4
5
6
7
8
<blockquote class="bible">
<p>
<sup>11</sup> &hellip;And Jesus said, <span class="ref">&ldquo;Neither do I condemn you;
go, and from now on sin no more.&rdquo;</span>
</p>
<cite>&mdash; <a href="https://www.biblegateway.com/passage/?search=John+8:11&amp;version=ESV"
title="Read John 8:11 (ESV) at Bible Gateway">John 8:11</a>b <em>(ESV)</em></cite>
</blockquote>

If you’ve ever edited Markdown, you’ll recognize how jarring all that HTML code is within the flow of the otherwise-regular text; and look at all those entities!

The Solution

We looked through at the Hexo Plugin List to find some examples, and began working towards writing a plugin to handle both the links (the part within the <cite> in the example above) as well as the entire blocks of quoted text. Some tags, like the {% codeblock %} tag, have a start tag and an end tag ({% endcodeblock %}); others, like the {% youtube %} tag, just pass arguments with the tag. (You can see all the default tags here.) Hexo passes two arguments to the tag plugin - the arguments within the (start) tag, plus the content (which is blank for tags that don’t have an end tag). The returned value from the plugin call is substituted in the document.

For generating a link, that is pretty easy; it could be an inline tag, and it’s just a matter of parsing the arguments and forming a link. For the quotes, we need to make sure that we include the content, and Hexo provides a way to run that content through the Markdown renderer. We are converging on a solution!

Hexo will pick up and execute any .js files in the scripts directory of the site as its generating it, so the first efforts were just local to that repo. The reference link looked something like this…

esv.js
1
2
3
4
5
6
7
8
9
hexo.extend.tag.register('esv', (args, content) => {
// option parsing with RegEx, similar to the way their tags do
let reference = arg.trim()
let urlReference = reference.split(' ').join('+')
return `<a href="https://www.biblegateway.com/passage/?search=${urlReference}&amp;version=${version}" `
+ `title="Read ${reference} (${version}) at Bible Gateway">${reference}</a>${extraText}${versionText}`
})

…which let the Markdown document go from…

1
2
<a href="https://www.biblegateway.com/passage/?search=John+8:11&amp;version=ESV"
title="Read John 8:11 (ESV) at Bible Gateway">John 8:11</a>b <em>(ESV)</em>

…to…

1
{% esv John 8:11 extra:b show-version %}

We refactored the link code to be version-agnostic and extracted it from the tag.register function so that we could reuse that for the blockquote citation. This made the local version of the blockquote look something like this:

bible.js
1
2
3
4
hexo.extend.tag.register('bible', (args, content) => {
let text = hexo.render.renderSync({ text: content, engine: 'markdown' })
return `<blockquote class="bible">${text}<cite>&mdash; ${generateRef(args)}</cite></blockquote>`
})

This means that the blockquote can support all of the arguments the inline reference did. We also switched out the marked Markdown processor for the markdown-it one, which lets us do superscripts by using the ^ character. Revisiting our example under “The Problem,” our Markdown source to generate the same blockquote is now:

1
2
3
4
{% bible John 8:11 extra:b show-version %}
^11^...And Jesus said, <span class="ref">"Neither do I condemn you; go, and from
now on sin no more."</span>
{% endbible %}

The Plugin

The plugin is available on npm, is fully tested, and its source is open. If you use Hexo, and wish to cite Scripture references in your posts with links where readers can see the text for themselves - enjoy!

Categorized under , ,
Tagged , , , ,


September 2, 2017
  Mapping Categories and Tags with Hexo

This blog moved today from Jekyll to Hexo (and it’s now open source as well). One of the final issues I had when wrapping up the conversion was how to handle categories and tags that do not necessarily have a slug that can be naturally derived from the name. Take the “C#” category, for example. The normal slug for that category would be c, which is an entirely different programming language; interestingly, “C++” will also normally get its slug as c.

Within Hexo’s default _config.yml file, there are two empty items named category_map and tag_map; their comments allude to a mapping, but I could not find what the proper syntax was for those items. We hopped onto the Hexo Gitter chat and asked the question, and someone pointed us to this issue. To define a mapping, create an item under either the category_map or tag_map top-level item. The maps for this site, as they currently are, look like this:

_config.yml
1
2
3
4
5
6
7
category_map:
C++: c-plus-plus
C#: c-sharp
.NET: dot-net
tag_map:
c#: c-sharp
.net: dot-net

As you can see by hovering over the links in the sidebar, “Programming > .NET > C#” ends up with a URL ending with /programming/dot-net/c-sharp/, which is exactly what we were looking for.

Categorized under , ,
Tagged , , , , ,


February 18, 2017
  Generating a Jekyll Site on Mercurial (Hg) Push

As we mentioned in our last post, we plan to share aspects of how we moved to Jekyll. This is the first of these posts.

Background

With a database-based solution, updating is easy; when the user updates content through the user interface, the new content is served when the page or post is requested. However, with a static site, an “update” is technically any change to the underlying files from which the site is generated. Typically, though, this is marked by source control commit and push to a master repository. GitHub Pages, the product for which Jekyll was developed, uses this as a flag to regenerate the site. We weren’t using GitHub*, though - we were using Mercurial (Hg) for our source code control, with the master repository on a different server than the one from which the site is served.

* There were a few reasons we did not wish to host our sites using GitHub, none of which are pertinent to how this works.

Options

With the need to regenerate the site after each site’s master repository receives a push, there were a few different options we considered.

  1. When a push occurs, regenerate the site on the Hg server, then use scp to delete the old files from and copy the new files to the web server.
  2. Set up a sandbox on the Hg server that updates and regnerates each time a push occurs, and run rsync on the web server to check for updates every so often.
  3. When a push occurs, notify the web server, and have it regenerate the site.

The first option has the potential to run afoul of SSH rate limits, plus has the potential to require much more data transfer than option 3. The second option had the advantage of running a process local to the Hg server, but would have required disk space utilization that we didn’t really need; and, as Jekyll regenerates all the pages in a site, rsync would have likely ended up transferring all the data for every update anyway, losing one of its benefits. The third option required Jekyll to be installed on the web server, and uses it for processing, potentially taking cycles that could be used to serve web pages.

Eventually, we decided to go with option 3.

Script All the Things

On the Hg server, in the master repository for each site, we put the following in .hg/hgrc (the following examples are for this site):

hgrc
1
2
[hooks]
incoming = /opt/jobs/notify.tech-blog.sh

…and then, notify.tech-blog.sh

notify.tech-blog.sh
1
2
#!/bin/bash
ssh user@web.server touch /opt/jobs/jekyll/.tech-blog

That is the only logic required on the Hg server. Now, over on the web server, we need logic to regenerate the site and make it live. Since we have multiple sites, we wrote a script that has a few variables, so it could be duplicated for other sites. The following is tech-blog.sh:

tech-blog.sh
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
33
##
## DJS Consulting Tech Blog Jekyll Build Script
##
## This will check out, build, and replace a Jekyll-generated site. Just update
## the parts under the "Env" heading for the specific site.
##
## Env
REPO=jekyll.tech-blog
DEST=/path/to/public/techblog
TRIGGER=.tech-blog
## /Env
cd /opt/jobs/jekyll
if [ -e $TRIGGER ]
then
rm $TRIGGER
## Check out the site and build it
hg clone ssh://user@hg.server/HgPath/$REPO $REPO
cd $REPO
jekyll build
## Copy it to the proper directory
cd _site
rm -r $DEST/*
cp -r * $DEST
## Clean up
cd ../..
rm -r $REPO
fi

This script isn’t perfect; it needs to check the exit code from the Jekyll build process before whacking the current site (and notifying for a failed build would be a nice addition). However, with Jekyll being the same on both development and production, and a single committer, this is fine for our purposes.

Finally, each script needs to be run to check for the presence of the semaphore (or TRIGGER, as the script calls it). The following cron definition will check every 4 minutes for a change.

crontab
1
*/4 * * * * /opt/jobs/jekyll/tech-blog.sh > /dev/null

Conclusion

Overall, we’re pleased with the results. The inter-server communication is light, only requiring one initiated ssh connection from each server, so we won’t run afoul of rate limits. With the work being done on the destination server, the amount of time where there are no files in the directory (between the rm -r $DEST/* and the time the cp -r * $DEST finishes) is very short; it would have been much longer if the directory were being repopulated across the network, or more complex if we added a staging area on the web server. Each piece can be run separately, and if we’ve committed a post with a future date, we can run the same touch command to make that post appear.

Next time, we’ll discuss our experiences converting a non-WordPress site.

Categorized under , ,
Tagged , , , , , , , , ,


August 4, 2014
  A Handy C# Async Utility Method

In the course of writing C# code utilizing the new (for 4.5.1) Task-based asynchronous programming, I’ve run across a couple of places where the await keyword either is not allowed (a catch block or a property accessor) or the async keyword greatly complicates the syntax (lambda expressions). I’ve found myself writing this method for two different projects, and so I thought I would drop this Q&D, more-comments-than-code utility method here for others to use if you see the need.

(UPDATE: This works well in console applications; it can cause deadlocks in desktop and web apps. Test before you rely on it.)

1
2
3
4
5
6
7
8
9
10
11
/// <summary>
/// Get the result of a task in contexts where the "await" keyword may be prohibited
/// </summary>
/// <typeparam name="T">The return type for the task</typeparam>
/// <param name="task">The task to be awaited</param>
/// <returns>The result of the task</returns>
public static T TaskResult<T>(Task<T> task)
{
Task.WaitAll(task);
return task.Result;
}

And, in places where you can’t do something like this…

ExampleClass.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/// <summary>
/// A horribly contrived example class
/// </summary>
/// <remarks>Don't ever structure your POCOs this way, unless EF is handling the navigation properties</remarks>
public class ExampleClass
{
/// <summary>
/// A contrived ID to a dependent entity
/// </summary>
public int ForeignKeyID { get; set; }
/// <summary>
/// The contrived dependent entity
/// </summary>
public DependentEntity DependentEntity
{
get
{
// Does not compile; can't use await without async, can't mark a property as async
return await Data.DependentEntities
.FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID);
}
}
}

…you can instead do this in that “DependentEntity” property…

1
2
3
4
5
6
7
8
9
10
11
/// <summary>
/// The contrived dependent entity
/// </summary>
public DependentEntity DependentEntity
{
get
{
return UtilClass.TaskResult<DependentEntity>(Data.DependentEntities
.FirstOrDefaultAsync(entity => entity.ID == ForeignKeyID));
}
}
Categorized under , ,
Tagged , ,


June 22, 2013
  Oracle SQL Developer 3.2 Debian Package

Oracle has released version 3.2 (.20.09) of their SQL Developer tool. They’re still releasing RPMs, so developers on Debian-based systems need to use alien to install it on their machines. We have done that, and have made this available for others to use as well. What makes this particular release of SQL Developer so great is that it now runs reliably under Java 1.7 - no more keeping a 1.6 JDK floating around just for SQL Developer!

The .deb package can be downloaded here, or you can browse current and previously posted packages in the “SQL Developer” directory of the Bit Badger Solutions Software Repository.

Categorized under , , ,
Tagged , , ,


July 1, 2012
  40/40 WordPress Plugin

The WordPress plugin for the 40/40 Prayer Vigil has just been published! You can download it from your plugin menu, or by visiting its home on the WordPress Plugin Directory.

The plugin provides a widget that utilizes the web service about which we previously wrote to display the prayer guide for each day. You can configure whether you want it to display 40 days or 40 hours; what language to retrieve; the translation version for the Scripture links displayed with each day’s guide; and the number of overlap days (it will display a “Coming Soon” entry before and a “Thanks for Praying” entry after). Use is pretty simple; just drop it into a widgetized area of your theme. It will probably look best with at least 200 horizontal pixels, although it will wrap to any sort of narrowness.

Version 2012.0 is the version that’s up there now. The Spanish translations of the options menu is not done yet, but you can specify Spanish prayer guides. Version 2012.1 will contain the localized options menu. If you run into any problems using it, you can submit issues against it at its WordPress Plugin Directory page.

Categorized under , , ,