Posts tagged "meta":

How I use :dbconnection in org files

In the post "Followup on secrets in my work notes" Magnus Therning mentions a feature in Org Babel I contributed to (in ob-sql.el, to be more precise).

You can see my old post for details about that feature, but basically, the patch allows one to use a :dbconnection header argument in a source block to reference a connection defined in sql-connection-alist.

The question in Magnus' post is a signal somebody is actually using this feature, so I am pleased. Perhaps I should also follow up, describing how I use this feature in my workflow. This will constitute another example of how to manage secrets.

I use Org, among other things, to keep work "lab notes" that usually contain SQL queries on different databases.

At work, pretty much all databases are Postgresql or Redshift, and I keep connection details in ~/.pgpass, following this format:

In other words, every DB definition is made of two lines: the first is a comment, with the name of the database (with no spaces); the second contains the actual connection details.

In my Emacs configuration, then, I have this function:

(defun get-connection-alist (filename)
  "Gets PG connections details from ~/.pgpass file (FILENAME)."
  (with-current-buffer (find-file-noselect filename)
        (let ((lines (split-string (buffer-string) "\n" t)))
          (when lines
            (cl-loop for (k v) in (seq-partition lines 2)
                  collect (cl-destructuring-bind (host port db user password)
                              (split-string v ":" nil)
                            `(,(replace-regexp-in-string "^#\s+" "" k)
                              (sql-product 'postgres)
                              (sql-port ,(string-to-number port))
                              (sql-server ,host)
                              (sql-user ,user)
                              (sql-database ,db)
                              (sql-password ,password))))))))

and

(setq sql-connection-alist (get-connection-alist "~/.pgpass"))

I use Emacs in daemon mode and it's not unusual Emacs to stay up for weeks, so I also have an automatic way to incorporate .pgpass changes, using filenotify.

(file-notify-add-watch
 "~/.pgpass" '(change)
 (lambda (evt)
   (setq sql-connection-alist
         (get-connection-alist "~/.pgpass"))))

Reactions and follow ups

The Hygieia Fountain in Hamburg

I recently spent a weekend in Hamburg to visit friends. While exploring the city my attention was caught, for some reason, by the fountain situated in the courtyard of the city hall, and the sculptures that surround it. It's called Hygieia Fountain.

×

Hygieia as the goddess of health and hygiene in Greek mythology and its surrounding figures represents the power and pureness of the water. It was built in remembrance of the cholera epidemic in 1892, the former technical purpose was air cooling in the city hall

1337

statshunters-country-de.png

According to Statshunters so far I covered a non-random number of squares in Germany.

A weekend in London

london.jpg

After many years since my last visit, I spent a long weekend in London. Among my various impressions, I note that I didn't touch any cash whatsoever for the entire stay. Even more: if it weren't for a guy in front of me at the cash register in a pub, who was paying with a banknote, I would've not seen any cash during my visit. It's possible this way one runs the risk of overspending, but nice.

Exporting content from org-roam to arbitrary org files

I adopted org-roam to collect and manage my personal notes. I also use Org for managing the pages of my personal website (this site). My notes are mostly personal, as I said, but sometimes I want to publish them on the website.

So far the process has been manual: when I had significant updates to publish I just copied text from one org file (in org-roam) to another. But I wanted something more systematic.

I therefore added this two functions in my Emacs configuration

(defun my/remove-org-roam-links (buffer-as-string)
  (replace-regexp-in-string
   "\\[\\[id:.*\\]\\[\\(.*\\)\\]\\]" "\\1" buffer-as-string))

(defun my/paste-org-roam-node (initial-input &key no-links)
  (interactive)
  (let* ((file (org-roam-node-file (org-roam-node-read initial-input)))
         (raw-buffer (with-current-buffer (find-file-noselect file)
                       (goto-char (point-min))
                       (buffer-string))))
    (if no-links (my/remove-org-roam-links raw-buffer)
      raw-buffer)))

Then I can use a snippet like this in the destination buffer

#+begin_src emacs-lisp :results value raw append
  (my/paste-org-roam-node "through" :no-links t)
#+end_src

And this appends to the file the contents of the original org-roam note (I happen to have a note titled "Through the Language Glass", so that 'through' is enough to identify a node), after stripping, if requested, the links to other notes.

There's still some manual work to do before one can post, but this solution is already an useful improvement.

TODO

  • [ ] the operation is not idempotent
  • [ ] org-roam-node-read still requires the user to hit return in the minibuffer to confirm the choice. I'd rather have no interaction after invoking the command by C-C C-C
  • [ ] after the note content is appended to the file, there's some clean up to do: removing unwanted metadata from the original buffer, and so on…
  • [ ] it seems there are problems with the management of footnotes, if present in the original note

Custom CSS for my website

My website is intentionally unadorned, but not because I don't like colors or typography. It's just I want the site to load as fast as possible, and I don't want to impose JS automatisms or othe shenanigans like these.

Actually, when I browse my pages myself, I use browser add-ons to apply a personalized CSS and even some JS facility. And I change the style often. Here how it currently looks like.

site-dark-light.png-thumb.jpg

And the respective CSS and JS I use with User JS and CSS Chrome extension to implement it.

https://stefanorodighiero.net/misc/personal.css

https://stefanorodighiero.net/misc/personal.js

Switching from stream to blog

I wanted to transform my stream for a long time, switching from a single .org file where I kept adding things, to a more appropriate blog structure, with individual posts, index, archive, tag pages, a feed and so on. Thanks to Org, it was relatively easy to use the original material to produce the files I then fed to org-static-blog.

Here the code I used (I just omitted a few service functions)

(defun split-org-file (input-file output-dir)
  "Split an .org file into separate files for each top-level entry.
INPUT-FILE is the path to the .org file.
OUTPUT-DIR is the directory where the separate files will be saved."
  (with-current-buffer (find-file-noselect input-file)
    (goto-char (point-min))
    (org-map-entries
     (lambda ()
       (let* ((entry-title (nth 4 (org-heading-components)))
              (tags (parse-tags-into-filetags
                     (nth 5 (org-heading-components))))
              (ts (get-timestamp-from-title entry-title))
              (entry-title-stripped (strip-entry-title entry-title))
              (output-file (expand-file-name
                            (format "%s.org" (dirify-string entry-title-stripped))
                            output-dir)))
         (let ((body (org-copy-subtree))
               (cleaned-body (with-temp-buffer
                               (insert (car kill-ring))
                               (goto-char (point-min))
                               (when (re-search-forward "^\\*+ \\(.*\\)$" nil t)
                                 (replace-match "" nil nil))
                               (buffer-string))))
           (with-temp-file output-file
             (insert (format "#+title: %s\n" entry-title-stripped)
                     (format "#+date: %s\n" (or ts "2000-01-01"))
                     (format "#+filetags: %s\n" (or tags ""))
                     "\n\n"
                     (format "%s" cleaned-body))))))
     "LEVEL=1")))

Venetogravel finisher stats

The organization of Venetogravel published the finisher stats for the 2024 edition. I grabbed this data and the datapoints from 2023 to plot some charts.

comparison-vg.png

"beach", "classic" and "lake" represent three different routes each participant could choose from, respectively ~400km (2800m total ascent), ~720km (4300m), ~400km (1800m). The editions of 2024 and 2023 presented the same choices, with the major difference that the direction of the routes was reversed. 2024's edition had also a new 200km (2800m) option which I didn't analyze.

I was interested to see if the median finisher time (indicated by the dashed line in the charts) would change, which I intended as a possible answer to the question "Would reversing the direction make the routes easier or harder?".

Data show that for "classic" and "beach" it didn't change, but the value is significantly higher for 2024 for the Lake route. (I, by the way, completed the Lake route in 53 hours and 16 minutes).

Not sure how to explain that. It's true the weather was worst in 2024, and I know several cyclists (including me) were blocked by a storm on Sunday, but that lasted only a couple of hours, not enough to explain the significant increase in median time.

Perhaps the population of cyclists that chose the Lake route was made of less experienced athletes, that had to take more time to complete it. Not sure.


How I made the charts

First I load and transform the files I obtained from the website:

classic2023 <- processfile("2023/data/classic.txt", "classic", 2023)
beach2023 <- processfile("2023/data/beach.txt", "beach", 2023)
lake2023 <- processfile("2023/data/lake.txt", "lake", 2023)

classic2024 <- processfile("2024/data/classic.txt", "classic", 2024)
beach2024 <- processfile("2024/data/beach.txt", "beach", 2024)
lake2024 <- processfile("2024/data/lake.txt", "lake", 2024)

here the body of processfile:

convert_elapsed_time_to_minutes <- function(elapsed_time_str) {
  time_parts <- str_split(elapsed_time_str, ":")[[1]]
  hours <- as.integer(time_parts[1])
  minutes <- as.integer(time_parts[2])
  total_minutes <- (hours * 60) + minutes
  result <- total_minutes
}

processfile = function(filepath, track, year) {
  df <- read.table(
    text=gsub(" – ", "\t", readLines(filepath)),
    sep="\t"
  )

  names(df) <- c("country", "name", "elapsed_time")

  return(df
         %>% rowwise()
         %>% mutate(elapsed_time_minutes = convert_elapsed_time_to_minutes(elapsed_time))
         %>% mutate(track = track)
         %>% mutate(year = year)
         %>% filter(elapsed_time_minutes > 0)
         %>% filter(elapsed_time_minutes < 10000) # filter outliers
         %>% select(country, track, year, elapsed_time_minutes)
  )
}

Then we put together these dataframes, and compute some aggregated stats

data <- bind_rows(classic2023, beach2023, lake2023,
                  classic2024, beach2024, lake2024)

data_medians <- data %>% group_by(year, track) %>% summarize(x=median(elapsed_time_minutes))

data_count <- data %>% group_by(year, track) %>% summarize(x=n())

We're ready to produce the chart using ggplot:

x_labels <- function(m) {
  res <- round(m / 60, 2)
  paste(res, 'h',sep = "")
}

ggplot(data, aes(x=elapsed_time_minutes, color=track)) +
  geom_histogram(binwidth = 60) +
  facet_grid(cols=vars(track), rows = vars(year)) +
  geom_vline(data = data_medians, aes(xintercept = x),
             linetype="dashed") +
  geom_text(
    data=data_medians,
    aes(x=x, label=x_labels(x), y=25),
    size = 4,
    nudge_x=+1000,
    color = 'black'
  ) +
  geom_text(
    data=data_count,
    aes(x=0, label=paste("# finisher:", x), y=35),
    size = 4,
    nudge_x=1500,
    color = 'black'
  ) +
  scale_x_continuous(breaks=c(60*24, 60*48, 60*72, 60*48*2, 60*24*5),
                     label=x_labels) +
  xlab("Tempo totale") +
  ylab("Numero di finisher") +
  theme_solarized() +
  theme(
    legend.position = "none",
    axis.title = element_blank(),
    axis.line.x = element_line(linewidth=.8),
    axis.ticks.x = element_line(linewidth = .8) ,
    axis.ticks.length.x = unit(.5, "cm"),
    panel.border = element_blank(),
    panel.grid = element_blank(),
    plot.title = element_text(face="bold", size=21)
  ) +
  ggtitle("Venetogravel: confronto distribuzione tempi finisher")

Using Clerk to plan bikepacking events

I have been experimenting with Clerk to build a tool I can use to study different strategies for Venetogravel 2024. Inputing parameters such as the distance I have to cover, the average speed I think I can maintain during the event, and how I intend to distribute the effort over several days, I can obtain a diagram. It's a work in progress, here what I got so far:

(def plan-start-19
{:description "Starting on April 19th"
 :daily-plans [{:label "Day 1"
                :activities [{:start "15:00" :length 6 :type :ride}]}
               {:label "Day 2"
                :activities [{:start "07:00" :length 5 :type :ride}
                             {:start "17:00" :length 3 :type :ride}]}
               {:label "Day 3"
                :activities [{:start "08:00" :length 6 :type :ride}]}]})

which results in

vg24-plan.png

To do:

Bikepacking updates

I only managed two overnighters during this season, but I learned something on how to pack, reaching a nice setup for my kit.

PXL_20230820_060950325-thumb.jpg

The setup is now more compact and feels more comfortable.

The front bag contains the sleeping bag (15 ⁰C) and both the tent layers (Naturhike Cloudup 2). I didn't think it was possible, but it was just a matter of squeezing (and believing) harder. Also, not using compression bags helps, because this way the material is more free to occupy all available space.

This makes the front bag slightly wider, so I had to add spacers to keep it clear of the levers.

I added an Ortlieb accessory bag on the front, where I put food and some kitchen tools (nothing particular, a collapsible bowl, sporks, … stuff like that)

The saddle bag is much smaller and shorter, which makes the bike easier to handle. It now contains just the mat, the tent base layer, stove + pot (another new addition to my kit), and clothes.

I am quite satisfied with the results. One thing I have to learn is how to re-pack things so that dirty or slightly soggy clothes don't ruin other clean items; this would allow me to do longer journeys.

Org-roam

I started experimenting with org-roam (v2, with org-roam-ui to have an idea of the progress). Still not entirely clear to me, but I will continue.

Mühlensee

IMG_20210501_114837-thumb.jpg

Biking, December update

goal2020-20210102.png
veloviewer-square-20210102.png

Biking, November update

goal2020-20201204.png
veloviewer-square-20201204.png

Biking, October update

goal2020-20201102.png
veloviewer-square-20201102.png

Biking, September update

goal2020-20201001.png
veloviewer-square-20201001.png

Blankenfelde

IMG_20200906_150800-thumb.jpg

Biking, July update

goal2020-20200801.png
veloviewer-square-20200801.png
veloviewer-square-20200801-2.png

Biking, June update

Done almost nothing (bad weather, bad mood)

goal2020-20200701.png
veloviewer-square-20200701.png

Biking, May update

goal2020-20200601.png
veloviewer-square-20200601.png

First (metric) century

IMG_20200517_095740_small.jpg

A bit above 100km in a single ride.

Biking, April update

goal2020-20200501.png
veloviewer-square-20200501.png

Biking, March update

Started well. Abrupt stop: riding in the midst of COVID19 related restrictions didn't feel right.

goal2020-20200401.png
veloviewer-square-20200401.png

Biking, February update

Not very exciting (bad weather and broken glasses)

goal2020-20200301.png
veloviewer-square-20200301.png

Biking, January update

Here some stats about January.

goal2020-20200201.png

And here Veloviewer's map update. Max square still 3x3, but I covered more territory.

veloviewer-square-20200201.png

Books I finished in 2019

Veloviewer stats

One of the fun parts of riding a bike is generating stats. Using Veloviewer (via Strava), for example, one can compute the max cluster size of his activities. Mine is 3x3, at the moment.

veloviewer-square-20200104.png

Plans for 2020

I don't particularly like the plans-for-next-year literary genre, but I imagine it will be fun to read this at this very same time next year: a memento of what my focus was. Anyway, here what I'd like to start, stop and continue doing next year.

A view on the river Havel

IMG_20190728_110022-PANO-thumb.jpg

Changing style of Emacs' tooltips

It seems obvious now that I figured it out.

Some parts of Emacs GUI are not configurable through faces (obvious). My Emacs is compiled with GTK 3.0, so it uses that library to render some of the elements of the GUI (even more obvious). Tooltips are among those elements. So, in order to change their style, I need to intervene on the configuration of GTK. For example, I had this:

tooltip-dark.png

Creating a file ~/.config/gtk-3.0/gtk.css:

@define-color tooltip_bg_color #fff8dc;
@define-color tooltip_fg_color Black;

and restarting Emacs, I obtain this:

tooltip-light.png

A patch for Org Babel

Org-babel allows SQL snippets to be run on a database connection that can be specified in the source block header using parameters such as :dbhost, :dbuser, :dbpassword and so forth.

This is very useful, but I'd also like to be able to use symbolic references to connections defined elsewhere, so that for example one does not have to specify the password every time, interactively or, worse, in the .org file itself.

I am also a user of sql.el, that provides a custom variable sql-connection-alist, where users can define a mapping between connection names and connection details.

The patch I submitted extends the behavior of org-babel-execute:sql so that it's possible to specify a new param :dbconnection containing a connection name, used for looking up sql-connection-alist.

Bürgerpark Pankow

is conveniently close to home (the picture was not taken in the park but just outside it, on my way back)

IMG_20190127_111318-thumb.jpg

Books batch

IMG_20190120_104656-thumb.jpg

Fruit

Today I said: "Cherries are the best fruit with the worst user interface". I love how they taste, but I'm always afraid to choke or break a teeth on the core, I find it annoying to dispose of the petioles, and so on. A colleague replied: "There's a XKCD for that! And he disagrees!". Indeed there is one!

PyData Berlin 2018

First Python conference I attend.

The venue is in the complex of Charité – Universitätsmedizin Berlin: Forum 3 is a nice building and has also some space outdoors (fortunately the conference days were blessed by sun and a nice temperature).

First experiences with Python

At the new job I use Python for my programming tasks. Currently developing some data related stuff (ETL and reporting) and a web service, trying to organize the stuff I write so that it can be used by other members of the team for other projects. I will register a few impressions:

Update

Speaking of great tools in the Python ecosystem, I just discovered Jupyter received the ACM Software System Award. Congratulations!

eyebrowse

I started using eyebrowse more systematically. I tend to have multiple frames scattered around my xmonad workspaces, but I usually also have a workspace exclusively devoted to a fullscreen Emacs frame, and there I usually work on different projects, that require different windows configurations. So eyebrowse is useful. To be able to switch more confortably from a configuration to another, I added this little piece of code to my setup:

(loop for i from 1 upto 9
      do (define-key eyebrowse-mode-map
           (kbd (format "M-%d" i))
           `(lambda ()
              (interactive)
              (eyebrowse-switch-to-window-config ,i))))

Code to read

I opened a new repository on github. It's called code-to-read, an attempt to collect and organize links to code bases particularly good for a human to read.

Pocket Perl ebook

The publisher released an ebook version of my book.

Haskell Day in Rome

haskell-day-rome-2017-group-thumb.jpg haskell-day-rome-2017-room-thumb.jpg

Yesterday I spent the entire day in Rome to attend another Haskell meeting. It's been quite a productive and interesting event: as usual, instead of talks we had impromptu groups engaged in different practical projects. Yesterday, the majority of people followed a beginners course. In my case, I showed my Wiz project to some more experienced programmers, receiving a great deal of observations, questions and suggestions. Other remarks: I saw a "Frankenpad" and learned some details about it; I showed my mechanical keyboards to other aficionados; I unexpectedly received a bottle of Rohrer & Klingner Leipziger Schwarz fountain pen ink (thank you!).

"The right thing should be easier to do"

I register here a series of tweets I already posted, for further ruminations.

One nice thing about Lisp and image based dev environments is that they make the act of exploring easier and more frictionless. This means producing something working is easier, when you're learning a new API or technology. On the other hand they make easier also to transform a crack-fueled idea into something deceitfully working, especially if you don't know well the domain. Thus breaking the rule "Right things should be easier to do", I guess.

August 2017

I spent the entire month in Berlin, half telecommuting, half being my summer vacations. So, I had some free time I spent in many ways, in particular:

The Swapper

swapper.png

Decided to download a new game from Steam, The Swapper. Interesting game mechanic, and daunting sci-fi setting.

When did you start using Emacs?

When did you start using Emacs?

Noticed this Reddit thread in one of Sacha Chua's Emacs News posts, and wondered what I could answer.

~/.emacs.d (master) $ git log --reverse --pretty=format:%ai | head -n 1
2014-05-23 10:29:04 +0200

I didn't realize it's been 3 years already since I started using Emacs.

Wacom tablet

Quite surprisingly, the rotation property is a property of the stylus and the eraser, not of the pad.

$ xsetwacom --set "Wacom Bamboo 16FG 4x5 Pen stylus" Rotate half
$ xsetwacom --set "Wacom Bamboo 16FG 4x5 Pen eraser" Rotate half

Games

I've been playing more than the usual, recently:

xmonad + Libreoffice problems

Apparently I fixed the pesky problems I had with xmonad + Libreoffice.

xmonad-patch.png

Mac OS X -> Linux

In other news, I completely switched from Mac OS X to Linux.

Status update

Some days off, not very much done. Somehow relevant in the context of this stream:

New site structure

I just published a restructuring of my website. Content is more or less the same. Main difference is I ditched the blog: I discovered blogging (I mean, organizing the stuff I publish as distinct articles ordered in time) is not for me. I'm more comfortable dedicating a page to each project I'm following, and keep updating the page as the project proceeds.

Ditching the blog also means I'm now using one tool only for all the editing and publishing.

Things to do:

Switched to Ubuntu Xenial Xerus

Better hardware support with less work for me (the Broadcom Wifi chip has been recognized with no problems).

Yay! New laptop

Now some work to make it work like I want (it comes with Windows 10 installed but I want a GNU/Linux system on it. So far I've only tried a live distro to check hardware support. As I expected, it's going to need some work to make the wifi chipset work properly).

Update

Linux installed. First update from the new environment!

Spoiled by xmonad

I'm doing some experiments with xmonad and I particularly like its mod-Space key combination to switch the window layout in a workspace. Is there something similar for Emacs?

This is similar to what I want: ThreeWindows

Update <2015-11-15 Sun 11:51>

I ended up doing this (the entire code is here: larsen-functions.el)

(defvar *larsen/split-layout-type* t)

(defun toggle-split-layout ()
  (interactive)
  (progn (change-split-type-2 *larsen/split-layout-type*)
         (if *larsen/split-layout-type*
             (setq *larsen/split-layout-type* nil)
           (setq *larsen/split-layout-type* t))))

(global-set-key (kbd "M-<f1>") 'toggle-split-layout)

the interview with Oliver Charles

the interview with Oliver Charles

Software I'm looking for

Software I'm looking for

Trying to configure ox-rss.el

I'm trying to properly configure ox-rss.el to produce a feed for this stream.

TMK firmware

Trying the tmk firmare on the Atreus. The feature list is very interesting, but it's not clear to me if it's all appliable to the specific hardware I'm using.

Double feature keyboard review

Double feature keyboard review

Basic setup

Basic stream setup done.

Anachronistic computing

Yay! The laptop I recently bought for a ridiculously low price is eventually working like I want.

x32.png First its characteristics:

CPU Intel Pentium M (Dothan)
RAM 512MB
HDD 40GB 2.5" PATA
Display 12.1" TFT with 1024x768 resolution

It is a IBM Thinkpad X32. A good news is it sports one of the best keyboards one can find on a laptop (and I was lucky enough to find the GB layout). I found it at an electronic fair I recently visited, and grabbed it without much thinking from the pile (literally) where it layed together with some of its twins.

I think it's remarkable that such an old piece of hardware can be a perfectly usable machine (at least for the way I'm used to work). All it takes is some attention to the software one chooses to install:

2011 in books

Essays/Computer science/$work stuff

In 2011 I started my adventures in the perilous lands of bigdata, so I've begun harvesting literature on the subject. Extremely interesting and relatively young field. I have an almost finished review of "Data Analysis with Open Source Tools" which I hope to publish soon.

Novels

My first encounter with Douglas Coupland. I particularly liked Microserfs, that somehow seemed to be speaking directly to me. Perhaps not for everybody.

Five minutes after Games of Thrones s01e01 I realized I couldn't wait an entire week to know the rest of the story. Still entertaining, after ~3000 pages and already in the fourth book.

I'm a hardcore Neal Stephenson fan. I also have Anathem in my stack, but I decided to read Reamde first, because it seemed less dense. It was, and also more fast-paced than usual.

Kindle first impressions

I just unboxed my Kindle. I played with it for a few hours only, but I'm satisfied with the choice so far.

First of all, to the zealots that may happen to read this article and feel compelled to whine on "scent of paper" and other oddities: I'm not planning the disposal of all my "real" books, neither I'm considering buying only digital contents from now on.

I decided to buy an ebook reader because I wanted to see on my own what can be done with this technology, which I consider immature and yet to be completely exploited.  I think I am an early adopter, even if Amazon Kindle and its competitors hit the market several years ago.

Also, I think having an ebook reader is nowadays the most practical solution to the eternal problem "What books should I bring with me during the journey?". Being able to answer "All!" is a wild dream that comes true (but I understand this can be a problem as well).

Anyway, here a few impressions from a very very beginner.

Other posts