How-to generate PDF from Markdown

Pandoc

The first tool you can use to convert a Markdown file to PDF is Pandoc.

To install Pandoc and all its dependencies on my Ubuntu 11.04, I used the following command:

$ aptitude install pandoc nbibtex texlive-latex-base texlive-latex-recommended texlive-latex-extra preview-latex-style dvipng texlive-fonts-recommended

Then I applied the PDF transformation on the README.md file from my openerp.buildout GitHub project:

$ wget https://raw.github.com/kdeldycke/openerp.buildout/master/README.md
$ markdown2pdf README.md -o readme-pandoc.pdf

The result is good, but not perfect. For example code blocks with long lines don’t break at the end of the page:

While trying to solve this issue, I stumble upon another tool…

Gimli

Gimli is an utility that was explicitly written with GitHub in mind.

Gimli is written in Ruby, so let’s install it the Ruby way:

$ aptitude install rubygems wkhtmltopdf
$ gem install gimli

Then we can convert our Markdown file to a PDF. The following will generate a README.pdf file in the current folder:

$ /var/lib/gems/1.8/bin/gimli -f ./README.md

The resulting PDF is really close to how GitHub renders Markdown content on its website. And it solve the bad code block style of Pandoc:

Nichrome Preview (and Behind the Scene) video

Featured

Two months ago (October 8th) I shot a video for Cool Cavemen. I haven’t talked about it on this blog yet, let’s fix this right now:

The song is Nichrome, which is a brand new song that will be available on Cool Cavemen’s upcoming album (to be released in 2012). This is the first time Nichrome is made public. The video is only a preview of the song: it only contains the first 2 minutes and the audio track is a demo, not the final studio version.

Demos are used not only for reference, but also for rehearsals when a band member is missing. That’s the case in this video: there is no bass player, but his parts are played in all musician’s headphones. Shooting the video in this playback setup is a huge advantage for me, as it removes all issues related to audio/video synchronizations and tempo deviations.

I shot with my Canon EOS 7D (1080p, 23.976 fps, 1/50s shutter speed) and a Tokina 11-16mm f/2.8 wide open. I used this lens over my 8mm f/3.5 Fish-Eye to save the distorting effects of the latter for others projects.

Shades of magenta were produced by 2 PAR-56 LED cans (controlled in DMX with QLC). I did not initially planned to bring them, but they were lying in the trunk of my car and I never filmed them, so I took the opportunity. Unfortunately, as you can see in the video, the frequency of the PWM that is driving the LEDs is not high enough and generate ugly flickers.

ISO was set to auto as the lighting conditions were really messy. A quick test in the darkest area of the room showed me that ISOs were pushed too high, increasing the noise too much. I avoided this issue by mounting an HDV-Z96 LED light with its CTO diffuser filter, and carefully set its light level (around 60%):

According EXIF data, ISO did not get over 2500 with this method, and was measured at 5000 in the darkest place. Average seems to be around 600. But take these numbers with a big grain of salt as I have no better sources than the .THM preview files generated by the camera for each .MOV clip.

Meta-data also tells me that the white balance was set to auto at 2900K but I remember having set it manually to keep consist images colors. Always according EXIF, color profile was set to standard.

Finally, I created the title cards in Gimp and edited the video in Kdenlive (on Kubuntu 11.04):

And two weeks after releasing Nichrome’s preview video, I edited another one with all left-overs. Here are the outtakes (which may not be as funny to you as for a French-speaking person, sorry):

GPG commands

  • Generate a key (interactive mode):
    gpg --gen-key
    
  • You can use the key generator in an unattended mode. Values in the example below are the same as the defaults proposed in the interactive mode above. Parameters in comments are there for reference:
    gpg --gen-key --batch <<EOF
    Key-Type: RSA
    Key-Length: 2048
    Subkey-Type: RSA
    Subkey-Length: 2048
    Expire-Date: 0
    Name-Real: Kevin
    # Name-Email: kevin@deldycke.com
    # Name-Comment: My auto-generated key
    # Passphrase: my_secret_passphrase
    EOF
    
  • List available keys for the current user:
    gpg --list-keys
    
  • Decrypt a file:
    gpg --decrypt archive.001.tar.gpg --output archive.001.tar
    
  • Same as above but for a collection of files:
    gpg --multifile --decrypt archive.*.tar.gpg
    

Bazaar commands

  • Check-out in the local openerp-server folder the 6.0 branch of the OpenERP server project from Launchpad:
    bzr branch lp:openobject-server/6.0 openerp-server
    
  • Same command as above, but fetch a particular revision:
    bzr branch lp:openobject-server/6.0 -r 3425 openerp-server
    
  • Get revision number of the local copy we sit in:
    bzr revno ./
    
  • Remove lock file on the current repository:
    bzr break-lock
    

PostgreSQL commands

  • Update the default configuration to allow direct authentication from the local machine:
    sed -i 's/^local\s\+all\s\+all\s\+ident/local all all trust/g' /etc/postgresql/8.4/main/pg_hba.conf
    
  • Same as above but for local IPv4 and IPv6 connexions:
    sed -i 's/^host\s\+all\s\+all\s\+\(.*\)\s\+md5/host all all \1 trust/g' /etc/postgresql/8.4/main/pg_hba.conf
    
  • List databases:
    psql --list -U kevin
    
  • Create a new kevin_db database with the kevin user:
    createdb -U kevin kevin_db
    
  • Remove the database we created above:
    dropdb kevin_db -U kevin
    
  • To connect to a particular database:
    psql -d database_id
    
  • Show us how a table of a specific database can be recreated:
    pg_dump my_database --schema-only --table=my_table
    
  • Dump a database in a compressed format:
    pg_dump my_database -v --format=c --file=/var/lib/postgresql/my_database-db-2011-12-19.dump
    
  • Restore a compressed dump:
    pg_restore -U my_user -d my_database /var/lib/postgresql/my_database-db-2011-12-19.dump
    
  • Import an SQL file to a database:
    psql --username kevin -d kevin_db < ./database_dump.sql
    
  • Search if kevin is a PostgreSQL user:
    sudo -u postgres psql --tuples-only --no-align --command "SELECT usename FROM pg_user;" | grep --quiet 'kevin' && echo 'User found !' || echo 'User not found !'
    
  • Set the owner of a database:
    ALTER DATABASE db_id OWNER TO user_id;
    
  • Set the owner of all tables from the MY_DB_ID database to MY_DB_USER (source):
    for tbl in `psql -qAt -c "SELECT tablename FROM pg_tables WHERE schemaname = 'public';" MY_DB_ID` ; do psql -c "ALTER TABLE $tbl OWNER TO MY_DB_USER" MY_DB_ID ; done
    
  • Same as above but for sequences and views:
    for tbl in `psql -qAt -c "SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema = 'public';" MY_DB_ID` ; do psql -c "ALTER TABLE $tbl OWNER TO MY_DB_USER" MY_DB_ID ; done
    for tbl in `psql -qAt -c "SELECT table_name FROM information_schema.views WHERE table_schema = 'public';" MY_DB_ID` ; do psql -c "ALTER TABLE $tbl OWNER TO MY_DB_USER" MY_DB_ID ; done
    
  • Remove from a table all rows older than a month:
    sudo -u postgres psql -d database_id  --command "DELETE FROM smile_log WHERE log_date > current_date - interval '1 month';"
    
  • Monitor queries being run in real time:
    watch -n 1 'sudo -u postgres psql --tuples-only --command "SELECT datname, procpid, date_trunc(\$\$second\$\$, age(current_timestamp, xact_start)), current_query FROM pg_stat_activity;"'
    
  • Disable all triggers of a table, excluding triggers that are used to implement foreign key constraints:
    ALTER TABLE table_id DISABLE TRIGGER ALL;
    
  • List all constraints of your database (source):
    SELECT tc.constraint_name,
    tc.constraint_type,
    tc.table_name,
    kcu.column_name,
    tc.is_deferrable,
    tc.initially_deferred,
    rc.match_option AS match_type,
    rc.update_rule AS on_update,
    rc.delete_rule AS on_delete,
    ccu.table_name AS references_table,
    ccu.column_name AS references_field
    FROM information_schema.table_constraints tc
    
    LEFT JOIN information_schema.key_column_usage kcu
    ON tc.constraint_catalog = kcu.constraint_catalog
    AND tc.constraint_schema = kcu.constraint_schema
    AND tc.constraint_name = kcu.constraint_name
    
    LEFT JOIN information_schema.referential_constraints rc
    ON tc.constraint_catalog = rc.constraint_catalog
    AND tc.constraint_schema = rc.constraint_schema
    AND tc.constraint_name = rc.constraint_name
    
    LEFT JOIN information_schema.constraint_column_usage ccu
    ON rc.unique_constraint_catalog = ccu.constraint_catalog
    AND rc.unique_constraint_schema = ccu.constraint_schema
    AND rc.unique_constraint_name = ccu.constraint_name
    
    WHERE lower(tc.constraint_type) in ('foreign key');
    
  • And finally, here is a list of great monitoring one-liners.

Installation Guide for a full-featured Debian server

Featured

Here is a collection of articles I wrote during the past year. Together they form a guide that will let you setup a full-featured Debian server. All of these tutorials are based on the recent work I did to setup my personal server on Debian Squeeze.

These articles are independent with each other, meaning you can pick the one your interested in to customize your server and ignore the others.

  1. Setup SMART monitoring tool for HDDs.
  2. Setup Nut to manage the UPS.
  3. Setup Duplicity and Amazon S3 for cloud-based backups.
  4. Setup Exim to relay mails via Gmail.
  5. Setup cron-apt to keep our distribution up to date.
  6. Add a fail2ban deamon.
  7. Setup Munin to monitor our machine.
  8. Basic setup of Nginx + PHP-FPM + MySQL web stack.
  9. Optimizing Nginx + PHP-FPM + MySQL for performances.
  10. Setup PHP APC op-code cache.
  11. Install haveged to get lots of entropy.
  12. Setup a WebDAVs server with Lighttpd.
  13. Setup Mailman + Nginx + Exim for mailing-lists.
  14. Mailman mailing-list migration and merging.