About swk

I am a computational linguist, teacher of computer science and above all a huge fan of LaTeX. I use LaTeX for everything, including things you never wanted to do with LaTeX. My latest love is lilypond, aka LaTeX for music. I'll post at irregular intervals about cool stuff, stupid hacks and annoying settings I want to remember for the future.

Typearea settings for a scrbook

Here are dirty hacks for page layout in LaTeX and a few useful standard settings.

I load the following document class:

\documentclass[bibliography=totoc,12pt,a4paper,headsepline]{scrbook} 

The option bibliography=totoc puts the bibliography into table of contents. The option 12pt sets normal font size to 12pt instead of the usual 11pt. This font size was a requirement for my thesis. The option a4paper sets DIN A4 paper (which should be the default anyway). The option headsepline adds a line below the header content on pages without a title.

A useful additional option may be oneside, which creates symmetric margins for one-sided print. Again, that was a requirement for the manuscript of my thesis. For the final print, I needed a normal two-sided print. A useful option there is titlepage=firstiscover, which gives equal margins for the first two pages (the book cover).

Usually you don’t want to tamper with the margins that LaTeX gives you. But in some cases, you may have specific guidelines that you need to adhere to. Or you have a fixed number of pages and run out of space, so you want smaller margins. Anyway, this is not recommended, I am just showing you how it works, because I can.

We have loaded the documentclass scrbook which is the KOMA-Script document class for an DIN A4 page book with a font size of 12pt. At that paper and font size, KOMA-Script uses a value of DIV=12 to calculate margins and text area sizes. The page has a width of 157.50mm and a height of 222.75mm for the text area. The top margin is 24.75mm and the inner margin 17.50mm. You can increase or decrease the margins by setting a different DIV value. So if you use the option DIV=13 for example, you will have a bigger text area (161mm wide instead of only 157mm). You can play around with the values until you find something you like. Here are the measurements for different DIV values for an DIN A4 page:

If you don’t find anything you like, you can set all values by hand with the geometry package. Use at your own peril. This is an example with a larger text height:

\usepackage[width=157.50mm,top=35mm,left=24mm]{geometry}  % gives textheight=226.36mm

When you play around with margins and text area settings, the package showframe is useful to see what you are doing:

\usepackage{showframe}

“Non-sciency” table-of-contents in a LaTeX book

One of my “customers” wanted a book that didn’t look so “sciency” (i.e., like LaTeX). In addition to the look of the chapter and sections headings (described in my last post), my “customers” wanted the table-of-contents to also look “non-sciency”. So this is what I did.

The package to use for manipulations of the table-of-contents is titletoc:

\usepackage{titletoc}

The entry for a chapter specifies that chapters are prefaced with the chapter label (which is “Teil X” in our case) and otherwise pretty standard:

\titlecontents{chapter}
    [3.2em] % left margin from the left page margin. % default 1.5em
    {\addvspace{1em}\usekomafont{title}} % global formatting of the entry.
    {\contentslabel{3.2em}}  % numbered entry
    {\hspace*{-1.3em}} % non-nubered entry
    {\titlerule*[.5pc]{}\contentspage}  % filler-page format

Sections are not numbered and otherwise rather standard, except for a few adjustments of spacing:

\titlecontents{section}
    [1em] % left margin from the left page margin.
    {} % global formatting of the entry.
    {} % numbered entry, default \contentslabel{2.3em}
    {} % non-nubered entry
    {~\titlerule*[.7pc]{.}\contentspage} % filler-page format

“Non-sciency” chapters and sections in a LaTeX book

One of my “customers” wanted a book that didn’t look so “sciency” (i.e., less like LaTeX). The first few tweaks (described in my last post) were more general, this one deals with the look of chapter and section headings.

I use the package titlesec for the task:

\usepackage{titlesec}

Each chapter should start on its own page. On top it will say “Teil X”, then a line, then the chapter name centered. At the bottom of the page a picture is included. This is the code for it:

\titleformat{\chapter} % command
[display] % shape: display, block, runin, hang (default)
{\bfseries\Large\itshape} % format
{\thechapter} % label
{0.5ex} % sep btw. label and title body
{\rule{\textwidth}{1pt} \vspace{1ex} \centering} % before-code
[{\vfill\includegraphics[width=\linewidth]{\Chapterimg}\pagebreak}] % after-code

The image for a chapter is set before each chapter with the custom-defined command Chapterimg:

\def\Chapterimg{img/chapterimage6}
\chapter{Einleitung}

A section is just the title in large bold font, no number in front of it:

\titleformat{\section} % command
[block] % shape
{\usekomafont{title}\large} % format
{}  % label
{0pt} % sep 
{} % before-code
[] % after-code

I also adjusted the spacing a bit:

\titlespacing{\section}{0pt}{1ex}{0pt} % less space for sections
\titlespacing{\subsection}{0pt}{0pt}{0pt} % subsection is like a paragraph

In a previous version of the book, the images were supposed to be placed next to the section headings. My attempt at doing that was to include the image in the “after-code” of the section format and add a bit of space at the right margin for it. It looked ok, but there were some issues with one-line vs. multi-line titles that I didn’t fix, because the images moved to the chapters instead.

[{\vspace{-3em}\hfill\includegraphics[width=4em]{\Chapterimg}\hspace{-5em}~}] % after-code
\titlespacing{\section}{0pt}{1ex}{0pt}[6em] % left margin / before / after / [right]

A “non-sciency” LaTeX book

One of my “customers” wanted a book that didn’t look so “sciency” (i.e., less like LaTeX). So here are a few tweaks to match their expectations.

Chapters should have letters as references with the prefix “Teil”:

\renewcommand{\thechapter}{Teil \Alph{chapter}}

Sections have the letter, a hyphen and the number:

\renewcommand*{\thesection}{\Alph{chapter}-\arabic{section}} 

Figures have no numbers, only the caption text below (using the package caption):

\usepackage{caption}
\captionsetup[figure]{labelformat=empty,textfont=footnotesize}
\renewcommand{\thefigure}{}

The first line of a paragraph is not indented. To compensate, the space between paragraphs is bigger:

\setlength\parindent{0pt}
\addtolength\parskip{4pt}

The header line of a page contains no section, but only the name of the chapter (using the package scrlayer-scrpage):

\usepackage{scrlayer-scrpage}
\clearpairofpagestyles % empty default header/footer markings
\automark[chapter]{chapter} % only chapter as mark
\ihead{\headmark} % inner margin has name of chapter
\ohead{\pagemark} % outer margin has page number

Compact lists in LaTeX

New environments that take up a lot less space than the original ones:

\newcommand{\backskip}{\vspace{-0.4\baselineskip}}
\newenvironment{compactitemize} % compact itemize list
{\backskip\begin{itemize}\itemsep0pt\parskip0pt}
{\end{itemize}\backskip}
\newenvironment{compactdescription} % compact description list
{\backskip\begin{itemize}\itemsep0pt\parskip0pt}
{\end{itemize}\backskip}
\newenvironment{compactenumerate} % compact enumerate list
{\backskip\begin{enumerate}\itemsep0pt\parskip0pt}
{\end{enumerate}\backskip}

A numbered environment for example sentences

I want an environment for example sentences where sentences are numbered and can be referenced. This is common in publications in the area of linguistics and there are a few packages that do the trick. But here is my own.

First, we need a counter that provides the number for the sentence:

\newcounter{mySentence}

We reset sentence counter for each chapter:

\@addtoreset{mySentence}{chapter}

We print the sentence number as (chapter.sentence):

\renewcommand*{\themySentence}{(\thechapter.\arabic{mySentence})}

Then we define an environment for one example sentence, where the number will be printed in the beginning of the line and then the sentence follows:

\newcommand{\backskip}{\vspace{-0.4\baselineskip}}
\newenvironment{examplesentence}
{% start env
\backskip%
\stepcounter{mySentence}%
\begin{enumerate} \small%
\renewcommand{\theenumi}{\thechapter.\arabic{mySentence}}%
\renewcommand{\labelenumi}{\themySentence}%
\itemsep0pt \parskip0pt%
\item
}
{% end env
\end{enumerate}
\backskip
}

Next is an environment for more than one example sentence. Here the sentence number will be printed in the beginning of the line and the individual sentences get an a., b., c., in front of them:

\newenvironment{examplesentences}
{% start env
\begin{examplesentence}%
\begin{enumerate} \itemsep0pt \parskip0pt%
\renewcommand{\theenumii}{\alph{enumii}}%
\renewcommand{\labelenumii}{\alph{enumii}.}%
}
{% end env
\end{enumerate}
\end{examplesentence}
}

Distribute updates from server to pool computers (hacky way)

This is the crowning achievement of my days at the MINT computer pool. Sadly, by the time I write this post, it will all be deleted. So here it is, archived for posterity.

The setting is a typical computer pool setting. 24 computers and one server. All computers load their home directories from the server (see here). Otherwise, each computer is totally independent. The idea is now, that updates to the pool computers can also be distributed from the server. So that I don’t have to sit down at each computer and execute a script which is a real pain. Again, a really common problem and many solutions exist – but I made my own, hacky, one.

Setting up the server side of things is easy. Basically, we create a few folders and put one shell script in the home of a special user called admin. There is a folder /home/admin/poolsetup/script into which we put a script poolupdate.sh. You can get the script from my wkutils github repository. This script goes through all files in another folder, /home/admin/poolsetup/updates, and executes any scripts it finds in there. It redirects the outputs of the execution into a log file in the folder /home/admin/poolsetup/logs. We can use this file to check what happened. And the update script uses the log file to avoid executing scripts twice. If a log file for a given script exists, we don’t execute the script again.

Because the home directories are loaded from the server, each pool computer will have access to files in the home directory of admin. We don’t have to do any copying to distribute the update script to the pool computers and any changes to the script will take effect right away.

So here are the commands for the server setup – basically just create the necessary folder structure with the correct permissions and put the update script there:

mkdir /home/admin/poolsetup/script
mkdir /home/admin/poolsetup/updates
mkdir /home/admin/poolsetup/logs
chmod o+rx /home/admin/poolsetup/script
chmod o+rx /home/admin/poolsetup/updates
chmod o+rwx /home/admin/poolsetup/logs
wget https://github.com/Kaffeedrache/wkutils/blob/master/admin/poolupdate.sh
mv poolupdate.sh /home/admin/poolsetup/script
chmod o+rx /home/admin/poolsetup/script/poolupdate.sh

On client side, we only have to make the computer execute the update script on a regular basis. We use cron and therefor call crontab which manages the cron jobs:

crontab -e

In the editor, we add these two lines:

00 17 * * 5 bash /home/admin/poolsetup/script/poolupdate.sh
@reboot bash -c "while [[ ! -d /home/admin/ ]] ; do sleep 5; done" ; bash /home/admin/poolsetup/script/poolupdate.sh

The first line will execute the update script every Friday at 5 PM. The second line will execute the script at every system start. We need the ugly loop with the sleep to ensure that the home directories have been mounted, before trying to access them.

So how does making an update work now? Write a script that does what you want to do. Put this script into the folder /home/admin/poolsetup/updates. When a pool computer starts up, it will execute the script. After that, look into the log folder and read the corresponding log to see what has happened. When all computers execute the update, usually you need to read only one log file and then check if all other log files have the same size. Done!

Access a server with an SSH key

Install ssh on the server:

apt-get install openssh-server

Generate a key pair (files id_rsa and id_rsa.pub) with a passphrase:

ssh-keygen

Edit the ssh configuration file:

vi /etc/ssh/sshd_config

In the file, make the following settings:

   PasswordAuthentication no
   PermitRootLogin without-password
   RSAAuthentication yes
   PubkeyAuthentication yes

Add the public key as an authorized key for root that can be used for login:

cat id_rsa.pub >> /root/.ssh/authorized_keys

That’s all for the server!

Now for the client. Copy the key pair into the folder ~/.ssh. Now you should be able to connect with:

ssh -i ~/.ssh/id_rsa root@server

Regular backup with rsync and cron

This is nothing new, just for me to remember. We use rsync and cron to make a backup of all home directories regularly. There will be a weekly backup that is readily accessible and a zipped monthly backup.

First, we need to install rsync (this is for Ubuntu, replace with the package manager of your choice):

apt-get install rsync

Then we need to create the directories where we want to save the backups. Here I am putting it into /media/backup for no particular reason, use any directory you like.

mkdir /media/backup/weekly
mkdir /media/backup/monthly

Next the command that actually copies the files:

rsync -a --exclude=".*/" --delete /home/ /media/backup/weekly

The command uses rsync, which is the tool for the job. We want to backup the complete folder home with all the directories contained in there. We exclude hidden files (starting with .) to avoid copying .cache and other temporary files. You may want to refine this setting for your case. The option --delete overwrites the files in the target directory /media/backup/weekly. So last week’s data will be overwritten with this week’s data when the backup runs. I’d suggest running this command directly to see what happens before proceeding with the automation.

Now that we know how to copy the data, we just need to execute this command regularly. This is done with cron via this command:

crontab -e

This opens an editor with all cron jobs that are currently set up. Add two lines for the backup:

00 18 * * 5 rsync -a --exclude=".*/" --delete /home/ /media/backup/weekly
00 6 1 * * tar -cjf /media/backup/monthly/monthly_$(date +%Y%m%d).tar.bz2 /media/backup/weekly/

The numbers in the beginning of each line give the minutes, hours, day, month and day of the week. The rest of each line is the command. The first line copies the data to /media/backup/weekly on every Friday afternoon (at 18:00). So we will always have a backup that is at most a week old. The second line is executed on every first day of the month at 6:00 and copies the data to /media/backup/monthly in a zipped form.

Load home directories from a server

The setting is the following: I have a pool of 24 computers and about 20 students who need to be able to login at any of the computers and access their data. Basically the normal setup of a computer pool. Of course there are many solutions for this problem (LDAP and so on), but of course it is more fun to create your own solution!

The basic idea is that the home directories are loaded from the server and overwrite the home directories of the clients. The accounts are created directly on each computer, but a user has the same user ID on every computer, so that the mapping of permissions works.

Now for the details. First the server. As a first step, install the NFS server package:

apt-get install nfs-kernel-server

Configure what should be exported. This is done in the file etc/exports:

vi /etc/exports

We want to export the folder /home/ and make it available for all computers in our pool (the subnet 1.22.333.* – of course that’s not the correct IP). So we add this line to the file:

/home/  1.22.333.0/255.255.255.0(rw,async)

We re-read the configuration to let the changes take effect:

exportfs -ra

Now we can check if the correct folder is exported:

exportfs -v

Finally, we create all student accounts on the server. This will also create a home directory for each one. We use fixed user IDs, so for example we will have hans with UID 1010, lisa with UID 1011, kim with UID 1012, and so on.

Now for the clients, where as a first step we need to install the NFS package for the client:

apt-get install nfs-common

Now we could mount the exported folder from the server by hand, but because we want to mount them permanently, we will use the global fstab file for this:

vi /etc/fstab

In this file, insert the following line (where 1.22.333.4 is the server IP):

1.22.333.4:/home/    /home/  nfs     rw,soft 0       0

Restart the computer for the changes to take effect. And finally, again, we need to create all student accounts on each computer and take care to assign the same UID.