22 Jan 2014

Syntax highlighting for source code on Blogger 2: highlight.js

After using the excellent SyntaxHighlighter by Alex Gorbatchev for a while (see this post), I decided it was time for a change, and tried highlight.js. Here's how to set it up to work with a Blogger blog:
  1.  On your blog's dashboard, click Template and then Edit HTML. You'll get a warning that says that you may mess up your blog, but since you're an ace programmer anyway, you don't mind much and you click Proceed.
  2. Find the closing </head> tag and right above it, paste the following:
    
    <!--SYNTAX HIGHLIGHTER BEGINS-->
    <link href='http://yandex.st/highlightjs/8.0/styles/default.min.css' rel='stylesheet'/>
    <script src='http://yandex.st/highlightjs/8.0/highlight.min.js'></script>
    <script>hljs.initHighlightingOnLoad();</script>
    <!--SYNTAX HIGHLIGHTER ENDS-->
    
  3. Click Save.
  4. Now, to use the syntax hightlighting in your Blogger post, click HTML in the Edit Post window, and write code like this (the example is for HTML code - notice the &lt; instead of < to prevent issues):
    
    <pre><code>
    &lt;input type="Submit" value="Submit" />
    </code></pre>
    
    to get this in the resulting post:
    
    <input type="Submit" value="Submit" />
    

That's all!

Update: to get the horizontal scrollbar if the lines are too long to fit, add the following after the <link> line above:


<style type="text/css">
.hljs {
  overflow-x: auto;
}
</style>

20 Jan 2014

Getting a date's week number in JavaScript

JavaScript's Date object doesn't seem to have a built-in function to get the week number of a date. There are many JS libraries that do have support for this, but I needed to get the week number in an environment where including libraries is awkward (in a TiddlyWiki 5 macro, if you really want to know). So I decided to make my own function.

A search on StackOverflow revealed plenty of ways to do this, but they all seemed to use date subtractions based on the fact that a date is represented internally as the number of milliseconds since 1 January 1970. To me that fact feels like an internal implementation detail, so I don't really like to use it. Also, I don't (want to) know how things like leap seconds would influence the reliability of these subtractions. No choice then but to reinvent the wheel and come up with my own algorithm and implementation.

The ISO 8601 standard says that week 1 of a year is the first week with a Thursday in that year. Based on that, I came up with the following "algorithm":

  1. Given a date d, adapt this date to Thursday of the same week.
  2. Subtract 1 week from this date and repeat this until the result is in the previous year.
  3. The week number for date d is the number of subtractions needed in the previous step to get to the previous year.
This surely isn't the fastest way to do it, but it takes a maximum of 53 subtractions, so it does have constant time complexity. Note that it does use subtractions, so we might end up using those milliseconds again, except that subtracting days can also be done by using the fact that JavaScript's setDate function has a kind of "underflow" protection: if 0 or a negative value is passed, it adapts the date to the correct month. So we can delegate the subtractions to an internal JS function and assume that it works well.

All these considerations led me to the following JavaScript function. Please let me know if there are any flaws anywhere in the function, or in the considerations.


function getWeekNumber(date) {
  var addDays = 0, dayOfWeek = date.getDay(), 
    modifiedDate = new Date(date);
  // move to Thursday in same week as date
  if (dayOfWeek == 0) {
    addDays = -3;
  }
  else {
    addDays = 4 - dayOfWeek;
  }
  modifiedDate.setDate(modifiedDate.getDate() + addDays);
   
  // count weeks going back in time one week at a time
  // until we reach previous year
  var year = modifiedDate.getFullYear(), weekCount = 0;
  do {
    modifiedDate.setDate(modifiedDate.getDate() - 7);
    weekCount++;
  } while (modifiedDate.getFullYear() == year);
  return weekCount;
}

Note: the code assumes weeks start on Mondays. In some countries (and in JavaScript) weeks start on Sundays, so there the first if statement would not be needed.

Since we're on a web page, let's test the function:

Today we are in week

17 Jan 2014

Mounting a HiDrive in Ubuntu

Accessing a (free) Strato HiDrive as a regular filesystem in Ubuntu is possible, though not completely trivial to set up. Here is what I had to do to get it running:
  1. I chose the WebDAV protocol to access my HiDrive (another option would be sftp, but only if you have a paid account). For this, some packages needed to be installed:
    
    sudo apt-get install davfs2
    sudo apt-get install ca-certificates
    
  2. I wanted to mount and use the HiDrive as a normal Ubuntu user, not as root. For this, the davfs2 package needed some tuning. I performed the following command:
    
    sudo dpkg-reconfigure davfs2
    
    and I answered "Yes" when it asked "Should unprivileged users be allowed to mount WebDAV resources?".
  3. Also, I needed to add myself (my Ubuntu username being penguin) to the davfs2 group:
    
    sudo usermod -a -G davfs2 penguin
    
  4. I created the mountpoint and made sure it would be accessible for a regular Ubuntu user:
    
    sudo mkdir /hidrive
    sudo chmod 777 /hidrive
    
  5. To configure the mountpoint, I edited /etc/fstab:
    
    sudo vi /etc/fstab
    
    and added the following entry:
    
    https://webdav.hidrive.strato.com/  /hidrive  davfs  user,noauto  0  0
    
For most Ubuntu users, this would be enough and the HiDrive could be mounted by this command (notice the absence of "sudo"):

mount /hidrive
However, this gave me an error that said:
/sbin/mount.davfs: / is the home directory of user abc.
You can't mount into another users home directory
A web search showed that some people got a similar message, only for user "kernoops". This could then be solved by adding kernoops to the ignore_home entry in the file /etc/davfs2/davfs2.conf. "kernoops" seems to be present already in most Ubuntus, but this abc user was not. I think in my case there was some kind of user/group id conflict caused by the YP/NIS server where this abc user was defined. Anyway, adding also abc to that line solved my problem:

sudo vi /etc/davfs2/davfs2.conf
ignore_home       kernoops,distccd,abc