Skip to content

Latest commit

 

History

History
1029 lines (808 loc) · 30.3 KB

blog.org

File metadata and controls

1029 lines (808 loc) · 30.3 KB

Pages

Chirps

<2018-04-09 Mon>

I started toying with overtone, a music instrument written in Clojure. My intention is to be able to generate a simple metronome, some drones, along with scales.

<2018-03-23 Fri 17:53>

How long should you wait with an eye twitch before seeing your doctor?

<2018-03-21 Wed 18:27>

I’m looking forward to the PDX Emacs meetup tonight. I’ll be sharing my ox-hugo setup.

<2018-03-20 Tue>

Taco 🌮 tuesday. 🌮

<2018-03-19 Mon 21:13>

I remember back when I had never used emacs. I did try once, but became frustrated as I didn’t know how to exit (C-x C-s OR M-x save-buffers-kill-emacs). But now, I rarely ever want to leave.

Posts

Lad’s guide to elisp

What’s in a name?

Once thing we can all appreciate is naming things. The name stands in the place for an individual, a place, etc. Some names are so powerful they must never be uttered.

The point is that names represent, well, anything we can imagine. In terms of e-lisp programming, a synonym for ‘name’ is ’symbol’.

Ada
John

John and Ada are symbols for something, whatever you’d like.

What if your ‘something’, was nothing? Imagine asking a stranger “Excuse me, Where is Ada?”. They might reply with a shrug or blank stare. They don’t know who Ada is; “Ada” means nothing to them.

In elisp lingo, the symbol ‘Ada’ has no associated value. If we asked the computer about Ada, it would reply with this message:

Symbol’s value as variable is void: Ada

Ada means nothing to the computer which is actually rather sad, but it’s fine. Here’s some symbols you and the computer recognize:

+  -  *  /

Imagine asking a close friend to sum some numbers, how would you ask?

"Hey John, what's the sum of 42 and 24?"

OR

"Hey, John, what is 42 plus 24?"

Maybe you’re in a library so you have to write it on a 3x5. Which way is correct?

sum of 42 and 24
42 plus 24

Maybe you only know how to use math symbols and numbers. What’s the difference?

+ 42 24
42 + 24

The plus symbol moves!

The first example uses prefix notation while second uses infix notation.

The computer uses this prefix notation, so let’s ask it. We would write:

(+ 42 24)

I added parenthesis because that’s tells the computer to start the addition program or rather function. Without the parenthesis it won’t work.

	|--|-- OPERANDS
   (+ 42 24)
    |
    - OPERATOR

The same concept works for any other operator.

LISPENGLISH
(- 42 24)subtract 24 from 42
(* 42 24)the product of 42 and 24
(/ 42 24)42 divided by 24

Hold on, though! We were talking about names, how’d we get to math, where’s Ada?

Easy. To the computer, these are symbols:

+ - * /

And you now know that symbols are names. And names can have arbitrary meanings or values. The computer is like us, not exactly, but it does know about math, because math is important for so many people.

But, the computer doesn’t know anything about Ada or John like this (mind your parenthese):

(Ada)
(John)

It responds with this:

Symbol’s function definition is void: Ada
Symbol’s function definition is void: John

The symbol’s function definition is absolutely nothing. The computer has no definition, no value, no behavior for the symbols Ada and John.

Variables vs Functions

To the computer, a symbol can have certain kinds of meanings or values associated with it. One kind is a variable and another kind is a function.

  • Read: What is a Symbol, What is a Function, and What are Variables
    TermDefinition
    SymbolAn object with a unique name.
    VariableA name used in a program to stand for a value. In Lisp, each variable is represented by a Lisp symbol (see Symbols). The use of a symbol as a variable is independent of its use as a function name.
    FunctionA rule for carrying out a computation given input values called arguments. it is an object which can optionally be associated with a symbol.

Moving on

Don’t worry if you are confused. The ideas presented will be fundamental to everything else in the guide; it will become natural as we proceed to commune with the machine.

So far we have explored computing simple math by using prefix notation and math symbols (names). We also discovered that names are associated with variables and functions. And so, we can determine that to the computer, the math symbols we used are just names associated with algebraic functions.

For now, we’ll leave Ada and John behind and turn to our dead friend George who is working on putting together a shopping list.

Data

  • symbols
  • strings
  • numbers
  • true
  • false

Naming

  • defun
  • setq
  • defvar
  • defconst

Combining lists

  • cons

Deconstructing lists

  • car
  • cdr

Equality

Infinite Bash History with Git

My goal is to start keep a log of commands over a long period. It seems useful to me. I’ve come up with a strategy for one machine, but I’d like to replicate it to others eventually. So, how?

  • Configure Bash to store commands
  • Configure Git repo
  • Create a script to copy the history file into the repo and commit
  • Configure a timer

Configure Bash to store history forever.

I found a helpful post describing the bash configuration you’d need for infinite history.

## Place this in ~/.bashrc
HISTTIMEFORMAT='%F %T '
HISTFILESIZE=-1
HISTSIZE=-1
HISTCONTROL=ignoredups
HISTIGNORE=?:??
shopt -s histappend                 # append to history, don't overwrite it
# attempt to save all lines of a multiple-line command in the same history entry
shopt -s cmdhist
# save multi-line commands to the history with embedded newlines
shopt -s lithist

Initialize the git repository

mkdir -p $HOME/bash-infinity/$USER@$HOSTNAME/
cd bash-infinity
git init

Sync and commit

cp $HISTFILE $HOME/bash-infinity/$USER@$HOSTNAME/
git add .
git commit -m "initial bash infinity"

Put it on a timer

Modify the crontab file with:

crontab -e

Add this to your crontab:

Modify crontab

This cronjob is configured to run every hour.

* */1 * * * HISTFILE=/home/$USER/.bash_history /usr/local/bin/bash-infinity.sh

Bash-infinity.sh

#!/bin/bash 
## Place in: /usr/local/bin/bash-infinity.sh

# Bash doesn't load HISTFILE by default. You must supply it manually.
if ! [ -v HISTFILE ]; then
    echo "No HISTFILE environment variable set. exiting."
    exit 1
fi    

if ! [ -d "$HOME/bash-infinity/$USER@$HOSTNAME" ]; then
  mkdir -p $HOME/bash-infinity/$USER@$HOSTNAME/
fi

cd $HOME/bash-infinity

if ! [ -d "$HOME/bash-infinity/.git" ]; then
  git init
fi

cp $HISTFILE $HOME/bash-infinity/$USER@$HOSTNAME/

git add $USER@$HOSTNAME

git commit -m "update bash infinity" -- $USER@$HOSTNAME
chmod +x /usr/local/bin/bash-infinity.sh

Blogging with Hugo and OX-Hugo

Part 1: Blog Setup

Download Hugo

pacman -S hugo

Initialize Project

hugo new site test-blog
cd test-blog
git init

Download a Theme (YMMV)

This seems like a clean, simple theme.

You can use a submodule like this:
git submodule add https://github.com/goodroot/hugo-classic.git themes/hugo-classic

OR

Or you can just clone it
mkdir themes/
git clone git@github.com:goodroot/hugo-classic.git themes/hugo-classic

Copy the necessary files from the theme

Warning: This will destroy your config.toml file, so, optionally back yours up.

cp -r themes/hugo-classic/exampleSite/* .

Part 2: Emacs/Org-Mode/OX-Hugo integration

Installing ox-hugo

Add the following to your .emacs or ~/.emacs.d/init.el file.

(use-package ox-hugo :ensure t :after ox)

Configuring Ox-hugo

Create a new org-mode file to represent your blog. This file should live in the root of the blog.

touch blog.org

Create your blog content in org-mode

Here’s a starter template for the blog.org file:

#+HUGO_BASE_DIR: .
* Pages
  :PROPERTIES:
  :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :noauthor true :nocomment true :nodate true :nopaging true :noread true
  :EXPORT_HUGO_MENU: :menu main
  :EXPORT_HUGO_TITLE: hmm
  :EXPORT_HUGO_SECTION: pages
  :EXPORT_HUGO_WEIGHT: auto
  :END:
** About Page
   :PROPERTIES:
   :EXPORT_FILE_NAME: about
   :END:
This is my about page.
* Posts
  :PROPERTIES:
  # :EXPORT_HUGO_CUSTOM_FRONT_MATTER: :noauthor true :nocomment true :nodate true :nopaging true :noread true
  :EXPORT_HUGO_MENU: :menu main
  :EXPORT_HUGO_SECTION: posts
  :EXPORT_HUGO_WEIGHT: auto
  :END:
** First Post
   :PROPERTIES:
   :EXPORT_FILE_NAME: some-file-name
   :EXPORT_DATE: <2018-03-19 Mon 22:08>
   :EXPORT_HUGO_DRAFT: true
   :END:

Export your content to hugo with ox-hugo

When editing the blog.org file, export it through org-export-dispatch:

This will export all the content from the blog.org file into the hugo project.

C-c C-e H A

Sometimes you just want to export one post/page (aka subtree in org-mode terms):

C-c C-e H H

Start the Server

At this point, you

hugo server -D

Extras

MathJax

If you’d like to have nice equation support, check this link: https://ox-hugo.scripter.co/doc/equations/

Here’s an example of a LaTeX formatted equation: \( E = -J ∑i=1^N s_i si+1 \)

Add this to the footer.html to get MathJax support:

<script type="text/x-mathjax-config">
 MathJax.Hub.Config({
     displayAlign: "center",
     displayIndent: "0em",

     "HTML-CSS": { scale: 100,
                   linebreaks: { automatic: "false" },
                   webFont: "TeX"
     },
     SVG: {scale: 100,
           linebreaks: { automatic: "false" },
           font: "TeX"},
     NativeMML: {scale: 100},
     TeX: { equationNumbers: {autoNumber: "AMS"},
            MultLineWidth: "85%",
            TagSide: "right",
            TagIndent: ".8em"
     }
 });
</script>
<!-- https://gohugo.io/content-management/formats/#mathjax-with-hugo -->
<script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-AMS_HTML"></script>
<!-- <script src="https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.1/MathJax.js?config=TeX-MML-AM_CHTML"></script> -->

Emacs and Tramp

/su: or /sudo: on remote hosts with emacs

C-x C-f /ssh:you@remotehost|sudo:remotehost:/path/to/file <RET>

Cartesian Product

A question came up about how to compute the cross-product of sets. Take this example, we want to turn this:

((chocolate strawberry) (sprinkle oreo))

Into this:

((chocolate sprinkle) (chocolate oreo) (strawberry sprinkle) (strawberry oreo))

Take some time to think about you might solve it.

Okay, now that you’ve thought some about it let’s look at one solution. Shout out to capablemonkey on Github for providing the code.

;; https://gist.github.com/capablemonkey/4133438ba7043af94691a2b54d997e8b
(defun cartesian-product (a b)
  (mapcan
    (lambda (item-from-a)
      (mapcar
        (lambda (item-from-b)
          (if (listp item-from-a)
            (append item-from-a (list item-from-b))
            (list item-from-a item-from-b)))
        b))
    a))

Each function shown above has a definition following so you can understand what’s going on after studying a bit.

Let’s look at `mapcan`.

mapcan :: mapcan is like mapcar, except that the results of applying function are combined into a list by the use of nconc rather than list.

nconc (called from within mapcan) :: Returns a list that is the concatenation of lists. If no lists are supplied, (nconc) returns nil.

Here’s an example that hopefully clears up nconc.

(nconc '(1) nil '(2) nil) ;;=> (1 2)

lambda :: the result of evaluating the lambda expression is the expression itself. The lambda expression may then be treated as a function, i.e., stored as the function value of a symbol, passed to ‘mapcar’, etc.

(mapcan
 (lambda (item-from-a)
   ...
   )
 a)

Then we use *mapcar*

mapcar :: mapcar operates on successive elements of the lists. function is applied to the first element of each list, then to the second element of each list, and so on. The iteration terminates when the shortest list runs out, and excess elements in other lists are ignored. The value returned by mapcar is a list of the results of successive calls to function.

(mapcar

(lambda (item-from-b)
  ...
)
b)

For each item-from-b, we ask if item-from-a is a list. If so, append item-from-b onto item-from-a. Otherwise, make a list with item-from-a and item-from-b.

listp :: Return t if OBJECT is a list, that is, a cons cell or nil. Otherwise, return nil.

append :: Concatenate all the arguments and make the result a list.

list :: Return a newly created list with specified arguments as elements. Any number of arguments, even zero arguments, are allowed.

(if (listp item-from-a)
            (append item-from-a (list item-from-b))
            (list item-from-a item-from-b))

Let’s try an example:

(cartesian-product '(a b) '(c d)) 
((a c) (a d) (b c) (b d))

We can support any number of lists by leveraging the reduce function.

(reduce #'cartesian-product '((chocolate strawberry) (sprinkle oreo) (smoothie cake)))
((chocolate sprinkle smoothie) 
 (chocolate sprinkle cake) 
 (chocolate oreo smoothie) 
 (chocolate oreo cake) 
 (strawberry sprinkle smoothie) 
 (strawberry sprinkle cake) 
 (strawberry oreo smoothie) 
 (strawberry oreo cake))

LISP provides lots of useful tools that when put together become very delicious. I mean, powerful.

Tracking unorganized time

Have you heard of org-mode? It has markdown like capabilities with additional features such as time tracking and a calendar. And a lot more!

I’m thinking about tracking unorganized time within GNU Emacs. In org-mode this is a task called “Tracking unorganized time”. It’s a task for tracking empty time; the time when I’m not tracking other stuff:

* Tracking unorganized time
:PROPERTIES:
:ID: empty-time-tracker
:END:

My idea is that by logging untracked time, I’ll be able to better determine where I can improve. I find that setting a timer can be a good motivator. So, why not a timer for untracked time, too? Just maybe it will motivate me by reminding me it’s always ticking, that I should do something more productive – and log it.

Programming a function to clock in

(org-id-find "empty-time-tracker")

org-id-find is an autoloaded compiled Lisp function in ‘org-id.el’.

(org-id-find ID &optional MARKERP)

Return the location of the entry with the id ID. The return value is a cons cell (file-name . position), or nil if there is no entry with that ID. With optional argument MARKERP, return the position as a new marker.

Programatic clock in like this:

(org-clock-in "empty-time-tracker")

org-clock-in is an interactive autoloaded compiled Lisp function in ‘org-clock.el’.

It is bound to C-c C-x TAB, <menu-bar> <Org> <Logging work> <Clock in>.

(org-clock-in &optional SELECT START-TIME)

Start the clock on the current item.

If necessary, clock-out of the currently active clock.

With a ‘C-u’ prefix argument SELECT, offer a list of recently clocked tasks to clock into.

When SELECT is ‘C-u C-u’, clock into the current task and mark it as the default task, a special task that will always be offered in the clocking selection, associated with the letter ‘d’.

When SELECT is ‘C-u C-u C-u’, clock in by using the last clock-out time as the start time. See ‘org-clock-continuously’ to make this the default behavior.

Which yields a running clock on the given task ID. For example:

* Tracking unorganized time
:PROPERTIES:
:ID: empty-time-tracker
:END:
:LOGBOOK:
CLOCK: [2018-04-09 Mon 18:38]--[2018-04-09 Mon 19:02] =>  0:24
:END:

Here’s what I came up with in a function:

(lambda ()
  (if (not (org-clocking-p))
    (org-with-point-at (org-id-find "empty-time-tracker" 'marker)
      (org-clock-in "empty-time-tracker"))))

org-clocking-p is a compiled Lisp function in ‘org-clock.el’.

(org-clocking-p)

Return t when clocking a task.

org-with-point-at is a Lisp macro in ‘org-macs.el’.

(org-with-point-at POM &rest BODY)

Move to buffer and point of point-or-marker POM for the duration of BODY.

Putting it on a timer

Every 30 minutes the code asks whether another task is currently being clocked.

When no other task is being clocked, the code starts clocking the “empty-time-tracker” task.

(run-with-timer 0 (* 30 60)
  (lambda ()
    (if (not (org-clocking-p))
      (org-with-point-at (org-id-find "empty-time-tracker" 'marker)
	(org-clock-in "empty-time-tracker")))))

run-with-timer is an interactive compiled Lisp function in ‘timer.el’.

(run-with-timer SECS REPEAT FUNCTION &rest ARGS)

Perform an action after a delay of SECS seconds. Repeat the action every REPEAT seconds, if REPEAT is non-nil. SECS and REPEAT may be integers or floating point numbers. The action is to call FUNCTION with arguments ARGS.

This function returns a timer object which you can use in ‘cancel-timer’.

Gotchyas

You will need to define `org-agenda-files` because `org-find-id` uses that value to find tasks. For example:

(setq org-agenda-files '("~/tasks.org" "~/path/to/another.org"))

Copy pasta

Here’s a slightly cleaner version suitable for your init.el or ~/.emacs file:

(require 'org)
(require 'org-clock)

(defvar ld/unorganized-time-id "empty-time-tracker")
(defun ld/clock-in-unorganized-time ()
  (interactive)
  (if (not (org-clocking-p))
      (org-with-point-at (org-id-find ld/unorganized-time-id 'marker)
	(org-clock-in ld/unorganized-time-id))))
(run-with-timer 0 (* 30 60) 'ld/clock-in-unorganized-time) ;; every half hour.

References

Emacs extension: eval-in-repl

It’s feels very fast to evaluate expressions in GNU Emacs with `C-x C-e`. It would be nice to evaluate bash expressions with such speed. Enter eval-in-repl.

First, add this snippet to the config file:

(use-package eval-in-repl :ensure t
  :config
  (define-key sh-mode-map (kbd "<C-return>") 'eir-eval-in-shell))

Now, open a shell script or a new “.sh” file. This should activate the `sh-mode`. Then, press `C-return` while a shell expression is under the cursor.

The package supports other language as well. For now, I’ll just try bash.

Building musical scales

The code below was an exploration in building musical scales based on intervals within the chromatic scale.

One interesting aspect is the cycling of the chromatic scale on each recursive function call. Append is used to combine the last note in the chromatic scale with a fresh chromatic scale. This makes the chromatic scale rotate infinitely.

 (setq chromatic-scale '(C C\# D D\# E F F\# G G\# A A\# B))
 (setq scale-data '((scales (has-sharps (C C\# D D\# E F F\# G G\# A A\# B))
			     (has-flats (C Db D Eb E F Gb G Ab A Bb B))
			     (no-flats (C nil D nil E F nil G nil A nil B))
			     (pentatonic-major
			      (no-flats (C F G))
			      (has-flats (Eb Bb Gb Ab))
			      (has-sharps (C\# D D\# E F\# G\# A A\# B)))
			     (pentatonic-minor
			      (no-flats (D E A))
			      (has-flats (C D F G))
			      (has-sharps (A\# B C\# D\# F\# G\#)))
			     (major
			      (no-flats (C))
			      (has-flats (Gb Db Ab Eb Bb F))
			      (has-sharps (C\# G G\# D D\# A A\# E B F\#)))
			     (minor
			      (no-flats (A))
			      (has-flats (Eb Bb F C G D))
			      (has-sharps (A\# D\# E B F\# C\# G\#))))
		     (intervals (major (r w w h w w w h))
				(minor (r w h w w h w w))
				(pentatonic-minor (r wh w w wh))
				(pentatonic-major (r w w wh w)))))

 (defun find-nested (l s)
   (when l
     (cond
      ((eq (car l) s) s)
      (t
	(cond
	 ((atom (car l)) (find-nested (cdr l) s))
	 ((listp (car l)) (find-nested (append (car l) (cdr l)) s)))))))

 (defun determine-notation-helper (list key)
   (when list
     (if (find-nested (car list) key)
	  (car (car list))
	(determine-notation-helper (cdr list) key))))

 (defun determine-notation (key scale-type)
   (determine-notation-helper (cdr (assoc scale-type (assoc 'scales scale-data))) key))

 (defun make-chromatic-scale (key scale-type)
   (let ((new-scale-type (determine-notation key scale-type)))
     (let ((scale (set-scale (car (cdr (assoc new-scale-type (assoc 'scales scale-data)))) key)))
	scale)))

 (defun set-scale (base-scale key)
   (cond
    ((eq key (car base-scale)) base-scale)
    (t (set-scale (append (cdr base-scale) (list (car base-scale))) key))))

 (defun play-scale (key scale-type)
   (play-scale-helper (make-chromatic-scale key scale-type)
		       (make-chromatic-scale key scale-type)
		       (car (cdr (assoc scale-type (assoc 'intervals scale-data))))
		       key))

 (defun play-scale-helper (base-scale my-chromatic-scale intervals key)
   (when intervals
     (cond
      ((eq (car intervals) 'r)
	(cons (car (set-scale base-scale key))
	      (play-scale-helper
	       base-scale
	       (set-scale base-scale key) (cdr intervals) key)))
      ((eq (car intervals) 'wh)
	(cond
	 ((null (car (cdr (cdr (cdr my-chromatic-scale)))))
	  (play-scale-helper base-scale
			     (append
			      my-chromatic-scale
			      (set-scale base-scale key)) intervals key))

	 (t (cons (car (cdr (cdr (cdr my-chromatic-scale))))
		  (play-scale-helper
		   base-scale
		   (cdr (cdr (cdr my-chromatic-scale)))
		   (cdr intervals) key)))))
      ((eq (car intervals) 'w)
	(cond
	 ((null (car (cdr (cdr my-chromatic-scale))))
	  (play-scale-helper base-scale
			     (append
			      my-chromatic-scale
			      (set-scale base-scale key)) intervals key))

	 (t (cons (car (cdr (cdr my-chromatic-scale)))
		  (play-scale-helper
		   base-scale
		   (cdr (cdr my-chromatic-scale))
		   (cdr intervals) key)))))
      ((eq (car intervals) 'h)
	(cond
	 ((null (car (cdr my-chromatic-scale)))
	  (play-scale-helper base-scale (append
					 my-chromatic-scale
					 (set-scale base-scale key)) intervals key))
	 (t (cons (car (cdr my-chromatic-scale))
		  (play-scale-helper base-scale (cdr my-chromatic-scale) (cdr intervals) key) )))))))

 (defun major-scale (key)
   (play-scale key 'major))

 (defun minor-scale (key)
   (play-scale key 'minor))

 (defun pentatonic-minor-scale (key)
   (play-scale key 'pentatonic-minor))

 (defun pentatonic-major-scale (key)
   (play-scale key 'pentatonic-major))

We can generate a list of the major scales by applying the major-scale function each notes in the chromatic scale.

Major Scale

(mapcar #'major-scale chromatic-scale)
CDEFGABC
C#D#FF#G#A#CC#
DEF#GABC#D
D#FGG#A#CDD#
EF#G#ABC#D#E
FGABbCDEF
F#G#A#BC#D#FF#
GABCDEF#G
G#A#CC#D#FGG#
ABC#DEF#G#A
A#CDD#FGAA#
BC#D#EF#G#A#B

Or we can generate the minor scales using the same technique:

Minor Scale

(mapcar #'minor-scale chromatic-scale)
CDEbFGAbBbC
C#D#EF#G#ABC#
DEFGABbCD
D#FF#G#A#BC#D#
EF#GABCDE
FGAbBbCDbEbF
F#G#ABC#DEF#
GABbCDEbFG
G#A#BC#D#EF#G#
ABCDEFGA
A#CC#D#FF#G#A#
BC#DEF#GAB

Pentatonic Minor Scale

(mapcar #'pentatonic-minor-scale chromatic-scale)
CEbFGBb
C#EF#G#B
DFGAC
D#F#G#A#C#
EGABD
FAbBbCEb
F#ABC#E
GBbCDF
G#BC#D#F#
ACDEG
A#C#D#FG#
BDEF#A

Pentatonic Major Scale

(mapcar #'pentatonic-major-scale chromatic-scale)
CDEGA
C#D#FG#A#
DEF#AB
D#FGA#C
EF#G#BC#
FGACD
F#G#A#C#D#
GABDE
G#A#CD#F
ABC#EF#
A#CDFG
BC#D#F#G#