December 2015

Monthly review: November 2015

December 2, 2015 - Categories: monthly, review

Lots of coding this month, and lots of tech-related blog posts. =)

Consulting-wise, I’ve been learning a lot about NodeJS and Angular. I’ve been refining the internal command-line scraping tools and dealing with new requirements. I’ve also been working on a mobile prototype that uses ng-touch and a few other niceties. I’ve been making good use of the Q library for promises, too. Good thing I spent some time last month learning more about asynchronous programming.

The Emacs News series I’ve been publishing every Monday was well-received, and I’m gradually creating little tools to make it easier to summarize the news from various sources. I’ve also been using it to queue up some tweets for @emacs, so there’s regular activity over there. We had a fun Emacs Hangout, and I’ve scheduled another one for next month.

I’m glad I came across the poster for the Toronto Public Library hackathon. It was a good opportunity to learn about neat things you can do with the library’s web interface and data. They’ve posted a recap, and I’ve also braindumped a bunch of notes on the hack I made for visualizing search results by branch. Boggle of boggles, my userscript still works. =D

I’ve been thinking about how I want to use my time during this phase of the experiment, since I have more energy these days. Spending more time consulting means building up useful skills and prototyping cool stuff that my clients find helpful, so that’s good. It’s also good to take some time to explore other interests and skills, and to prepare for what’s likely to come up. Playing it by ear seems to be the way to go. I keep a long list of little ideas to work on for consulting, and I’ve been cleaning up my Org Mode agenda files to make it easier to see the personal stuff I want to work on. Since the weather is nice today, I’ll go for a walk to the library. Maybe I’ll do some sewing this afternoon.

Also, I filed my business taxes. The dry-run I did last month paid off. All I had to do was update the numbers and double-check my calculations. Yay! I might actually be getting the hang of this. I’ve taken more notes, so next year should be even easier.

I’m back to dual-booting Linux, hooray! I’m still figuring out parts of my new workflow. I think I’ll get it all sorted out over the next few weeks. I’ll probably still boot into Windows for things like Quickbooks and TurboTax (unless I feel like manually crunching the numbers for business taxes – wouldn’t that be something!), but everything else seems to be just fine.

Still feeling pretty much in hermit-mode, although I did make it out to a few low-key things. Next month is probably going to be complicated, but we’ll see.

In December, I’m looking forward to catching up on the cool things that have been going on in the Linux world since the last time I checked. I’d like to document and automate more of my processes, too, in preparation for possible fuzziness. Onward!

2015-12-02a November 2015 -- index card #journal #monthly #review

output

Blog posts

Sketches

Daily sketches: 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 27 29 30

Time

Category Last month % This month Avg h per week Delta (h/wk)
Business – Build 3.2 5.5 9 3.9
Discretionary – Play 6.9 8.9 15 3.4
Unpaid work 6.3 7.9 13 2.7
Discretionary – Social 0 0.6 1 1.0
Discretionary – Family 2.6 3.1 5 0.8
Sleep 37.4 37.9 64 0.8
Business – Connect 1.1 1.5 3 0.7
Business – Earn 11.2 10.7 18 -0.8
Discretionary – Productive 11.2 7.5 13 -6.2
Personal 20.0 16.2 27 -6.4

Huh. More drawing, more Borderlands, more cooking, actually a little
less consulting, and less time on personal projects and routines. More
time on coding, though. Didn’t expect that. Two and a half days is
still more consulting than the one-day-a-week pace I’d been keeping
before this recent intensification, anyway. Anyway, time still feels
pretty good, so I’ll carry on.

Making my to-do list more detailed; process versus outcome

December 5, 2015 - Categories: emacs, org, productivity

Some time ago, I wrote some code to make it easier for me to update my web-based Quantified Awesome time logs from Org Mode in Emacs, clocking into specific tasks or quickly selecting routine tasks with a few keyboard shortcuts. I’ve been refining my/org-clock-in-and-track, my/org-clock-in-and-track-by-name, and defhydra my/quantified-hydra, and I’ve been getting used to the new workflow. The more I smooth out the workflow, the more possibilities open up. Because I’ve set it up to prompt me for a time estimate before I start a task, I can see a running clock and timer in my modeline, and Emacs lets me know if I’m running over my estimate. Come to think of it, this makes it even easier to track at the detailed task level than to track at just the medium-level categories available through my web or mobile shortcuts. (If you’re curious about the Emacs Lisp code, you can check out my Emacs configuration.)

I’ve also been sorting out my workflow for quickly adding tasks. C-c r t (org-capture, with the t template I defined in org-capture-templates) displays a buffer where I can type in the task information and set a time estimate. From there, I can file it under the appropriate project with C-c C-w (org-refile), or maybe schedule it with C-c C-s (org-schedule).

Since both creating and tracking tasks are now easier, I’ve been gradually adding small, routine tasks to my task list. This includes household tasks such as vacuuming and quick computer-based tasks such as checking for replies to @emacs. These tasks are in my routines.org file or tagged with the :routine: tag, so I can sort them in my Org agenda view or filter them out if I want.

It might be interesting to bring that data from Emacs to my mobile phone, but it’s not particularly important at the moment. I’m usually home, so I can just check my org-agenda throughout the day. If I’m out for some errands, my errand list is short enough to remember (or quickly note somewhere), and I can use my phone to quickly jot short notes to add to my to-do list when I get back.

The next step for that workflow would probably be to improve my views of unscheduled tasks, choosing new things to work on based on their time estimates, contexts, or projects. I already have a few org-agenda-custom-commands for these, although I still need to tweak them so that they feel like they make sense. Project navigation works out pretty well, though, and it’ll get better as I gradually clean up my Org files.

It feels a little odd to use my to-do list this much throughout the day, compared to the less-structured approach of deciding at each moment. The day feels less leisurely and expansive. Still, there’s a certain satisfaction in crossing things off and knowing I’m taking care of the little things. I’ll find a new balance between the number of items on my list and the time I want to use to follow the butterflies of my interest or energy. Maybe I’ll use tags or priorities to highlight energizing tasks, the dessert tasks to my vegetable tasks. (Ooh, I wonder how I can get different colours in my org-agenda.) In the meantime, I think that fleshing out my to-do list even more – capturing the little routines that might get forgotten if I get more fuzzy-brained or distracted – may help me in the long run.

I think one of the things about working with a list of small, varied tasks is that there’s less of that feeling of accomplishing a big, non-routine chunk. One way I can work around this is to pick a dessert-y project focus for the morning and finish several tasks related to it, before getting through the rest of the routine tasks. There’s also a different approach: focusing on the process instead of the outcome, cultivating the satisfaction of steady progress instead of the exhilaration of a win. If I keep on improving my workflow for managing tasks, ideas, and reviews, I think it will pay off even as circumstances change.

2015-12-04e Process versus outcome -- index card #productivity #mindset #perspective #stoicism #philosophy

2015-12-04c Preparing for steady progress -- index card #productivity #fuzzy #preparation

Weekly review: Week ending December 4, 2015

December 5, 2015 - Categories: review, weekly

After experimenting with Krita to see if it could handle my simple sketchnoting needs, I shifted to dual-booting Linux last weekend instead of being only on Windows. It’s been fun so far! I’ve been able to move most of my workflows over, although I think I’ll still keep my Windows partition for things like Quickbooks and TurboTax. (Until I get up the confidence to do my corporate taxes by hand, maybe.) I’ve slowly been accumulating little scripts to make my life easier, and I should post them on Github at some point. It’s so nice to be able to script things properly again!

I’ve also been playing around with more detailed task lists. Recognition is easier than recall, so having a more fleshed-out task list makes sense especially during fuzzy-brained times. Over the next few weeks, I’ll probably figure out a good way to make sense of these granular tasks during my weekly and monthly reviews. We’ll see!

It’s been an excellent week for geeking around. =)

2015-12-05a Week ending 2015-12-04 -- index card #journal #weekly

output

Blog posts

Sketches

Focus areas and time review

  • Business (27.6h – 16%)
    • Earn (12.2h – 44% of Business)
      • ☑ Update data extract
      • ☑ Reupload to B
      • ☑ Scrape avatars
      • ☐ Use scraped avatars
      • ☐ Earn: E1: 1-2 days of consulting
    • Build (14.4h – 52% of Business)
      • Drawing (2.3h)
      • Paperwork (0.3h)
        • ☑ Back up laptop files
    • Connect (0.9h – 3% of Business)
  • Relationships (7.9h – 4%)
    • ☑ Buy stuff
    • ☑ Go to Jen’s thing
    • ☑ Meet M
    • ☑ Call to check on U
    • ☑ Write letter and package gift
    • ☑ Check with W- about JordiGH
    • ☑ Copy insurance information
  • Discretionary – Productive (18.0h – 10%)
    • Emacs (7.7h – 4% of all)
      • ☑ Investigate org toc local section
      • ☑ Do another Emacs News review
      • ☑ Make a fill-in drill based on an Org table
      • ☑ Make invoice template in Org Mode
      • ☑ Look into org-agenda-sorting-strategy and tag-up
      • ☑ Update patch based on feedback
      • ☑ Sort out stylus clicks in Emacs
      • ☐ Add layer resize as a button to Emacs
      • ☐ Announce Hangout
      • ☐ Do another Emacs News review
      • ☐ Debug Emacs crashes
    • Linux stuff
      • ☑ Sort out my wireless issues
      • ☑ Figure out Evernote
      • ☑ Replace flickr.bat
      • ☑ Figure out Dropbox
      • ☑ Mount with Truecrypt
      • ☑ Set up screen rotation
      • ☑ Set up server backup partition and space
      • ☑ Back up Flickr files somewhere
      • ☑ Clean up old WordPress sites on the server
      • ☑ Back up etckeeper with git
      • ☑ Look into automating krita
      • ☑ Explore Krita interface – automate resizing a layer
      • ☑ Learn about Klipper clipboard actions
      • ☑ Get headphones working
      • ☑ Generate gpg key with expiration date
      • ☑ Automate addition of output.png
      • ☑ Swap previous/next and pageup/pagedown buttons
      • ☑ Set up a GPG-encrypted file with one-time passcodes
      • ☑ Set up zshrc prompt
      • ☑ Figure out a better mail solution that synchronizes with Google’s inbox
      • ☑ Upgrade to 15.10
      • ☑ Look into Chrome + emacsclient integration
      • ☑ Fix flickr-upload.js
      • ☑ Fix org-protocol on KDE – port field was empty
      • ☑ Re-memorize declensions
      • ☑ Figure out wacom settings for KDE5
      • ☑ Set up znc
      • ☑ Look into hibernation
      • ☑ Port over growth-projections.xlsx
      • ☐ Review, organize, and document my backups
    • Sewing (3.5h)
      • ☑ Order more Kam snaps
      • ☑ Look for fabric
      • ☑ Sew wrap dress
      • ☑ Wash new fabric
      • ☑ Analyze fabric costs
      • ☐ Sew two more covers
    • Writing (5.8h)
    • ☑ Re-memorize declensions
  • Discretionary – Play (4.0h – 2%)
  • Personal routines (29.6h – 17%)
  • Unpaid work (22.2h – 13%)
  • Sleep (58.6h – 34% – average of 8.4 per day)

2015-12-07 Emacs News

December 7, 2015 - Categories: emacs, emacs-news

Links from reddit.com/r/emacs, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel.

Past Emacs News round-ups

Scripting and the Toronto Public Library’s movie collection

December 9, 2015 - Categories: geek

We hardly ever watch movies in the theatre now, since we prefer watching movies with subtitles and the ability to pause. Fortunately, the Toronto Public Library has a frequently updated collection of DVDs. The best time to grab a movie is when it’s a new release, since DVDs that have been in heavy circulation can get pretty scratched up from use. However, newly released movies can’t be reserved. You need to find them at the library branches they’re assigned to, and then you can borrow them for seven days. You can check the status of each movie online to see if it’s in the library or when it’s due to be returned.

Since there are quite a few movies on our watch list, quite a few library branches we can walk to, and some time flexibility as to when to go, checking all those combinations is tedious. I wrote a script that takes a list of branches and a list of movie URLs, checks the status of each, and displays a table sorted by availability and location. My code gives me a list like this:

In Library Annette Street Mad Max Fury Road M 10-8:30 T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
In Library Bloor/Gladstone Inside Out M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5 Sun 1:30-5
In Library Bloor/Gladstone Match M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5 Sun 1:30-5
In Library Jane/Dundas Avengers: Age of Ultron M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library Jane/Dundas Ant-Man M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library Jane/Dundas Mad Max Fury Road M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library Jane/Dundas Minions M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library Perth/Dupont Chappie T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
In Library Runnymede Ant-Man M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library Runnymede Minions M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5
In Library St. Clair/Silverthorn Kingsman: the Secret Service T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
In Library St. Clair/Silverthorn Mad Max Fury Road T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
In Library Swansea Memorial Ant-Man T 10-6 W 1-8 Th 10-6 Sat 10-5
In Library Swansea Memorial Chappie T 10-6 W 1-8 Th 10-6 Sat 10-5
In Library Swansea Memorial Kingsman: the Secret Service T 10-6 W 1-8 Th 10-6 Sat 10-5
In Library Swansea Memorial Kingsman: the Secret Service T 10-6 W 1-8 Th 10-6 Sat 10-5
In Library Swansea Memorial Mad Max Fury Road T 10-6 W 1-8 Th 10-6 Sat 10-5
In Library Swansea Memorial Minions T 10-6 W 1-8 Th 10-6 Sat 10-5
2015-12-08 Perth/Dupont Terminator Genisys T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
2015-12-08 Perth/Dupont Mad Max Fury Road T 12:30-8:30 W 10-6 Th 12:30-8:30 F 10-6 Sat 9-5
2015-12-09 Swansea Memorial Avengers: Age of Ultron T 10-6 W 1-8 Th 10-6 Sat 10-5

… many more rows omitted. =)

With this data, I can decide that Swansea Memorial has a bunch of things I might want to check out, and pick that as the destination for my walk. Sure, there’s a chance that someone else might check out the movies before I get there (although I can minimize that by getting to the library as soon as it opens), or that the video has been misfiled or misplaced, but overall, the system tends to work fine.

It’s easy for me to send the output to myself by email, too. I just select the part of the table I care about and use Emacs’ M-x shell-command-on-region (M-|) to mail it to myself with the command mail -s "Videos to check out" [email protected].

The first time I ran my script, I ended up going to Perth/Dupont to pick up seven movies in addition to the two I picked up from Annette Library. Many of the movies had been returned but not yet shelved, so the librarian retrieved them from his bin and gave them to me. When I got back, W- looked at the stack of DVDs by the television and said, “You know that’s around 18 hours of viewing, right?” It’ll be fine for background watching. =)

Little things like this make me glad that I can write scripts and other tiny tools to make my life better. Anything that involves multiple steps or combining information from multiple sources might be simpler with a script. I wrote this script as a command-line tool with NodeJS, since I’m comfortable with the HTML request and parsing libraries available there.

Anyway, here’s the code, in case you want to build on the idea. Have fun!

/* Shows you which videos are available at which libraries.

   Input: A json filename, which should be a hash of the form:
   {"branches": {"Branch name": "Additional branch details (ex: hours)", ...},
   "videos": [{"Title": "URL to library page"}, ...]}.

   Example: {
   "branches": {
   "Runnymede": "M 9-8:30 T 9-8:30 W 9-8:30 Th 9-8:30 F 9-5 Sat 9-5"
   },
   "videos": [
   {"title": "Avengers: Age of Ultron", "url": "http://www.torontopubliclibrary.ca/detail.jsp?Entt=RDM3350205&R=3350205"}
   ]}

   Output:
   Status,Branch,Title,Branch notes
*/

var rp = require('request-promise');
var moment = require('moment');
var async = require('async');
var cheerio = require('cheerio');
var q = require('q');
var csv = require('fast-csv');
var fs = require('fs');

if (process.argv.length < 3) {
  console.log('Please specify the JSON file to read the branches and videos from.');
  process.exit(1);
}

var config = JSON.parse(fs.readFileSync(process.argv[2]));
var branches = config.branches;
var videos = config.videos;

/*
  Returns a promise that will resolve with an array of [status,
  branch, movie, info], where status is either the next due date, "In
  Library", etc. */
function checkStatus(branches, movie) {
  var url = movie.url;
  var matches = url.match(/R=([0-9]+)/);
  return rp.get(
    'http://www.torontopubliclibrary.ca/components/elem_bib-branch-holdings.jspf?print=&numberCopies=1&itemId='
      + matches[1]).then(function(a) {
        var $ = cheerio.load(a);
        var results = [];
        var lastBranch = '';              
        $('tr.notranslate').each(function() {
          var row = $(this);
          var cells = row.find('td');
          var branch = $(cells[0]).text().replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, '');
          var due = $(cells[2]).text().replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, '');
          var status = $(cells[3]).text().replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, '');
          if (branch) { lastBranch = branch; }
          else { branch = lastBranch; }
          if (branches[branch]) {
            if (status == 'On loan' && (matches = due.match(/Due: (.*)/))) {
              status = moment(matches[1], 'DD/MM/YYYY').format('YYYY-MM-DD');
            }
            if (status != 'Not Available - Search in Progress') {
              results.push([status, branch, movie.title, branches[branch]]);
            }
          }
        });
        return results;
      });
}

function checkAllVideos(branches, videos) {
  var results = [];
  var p = q.defer();
  async.eachLimit(videos, 5, function(video, callback) {
    checkStatus(branches, video).then(function(result) {
      results = results.concat(result);
      callback();
    });
  }, function(err) {
    p.resolve(results.sort(function(a, b) {
      if (a[0] == 'In Library') {
        if (b[0] == 'In Library') {
          if (a[1] < b[1]) return -1;
          if (a[1] > b[1]) return 1;
          if (a[2] < b[2]) return -1;
          if (a[2] > b[2]) return 1;
          return 0;
        } else {
          return -1;
        }
      }
      if (b[0] == 'In Library') { return 1; }
      if (a[0] < b[0]) { return -1; }
      if (a[0] > b[0]) { return 1; }
      return 0;
    }));
  });
  return p.promise;
}

checkAllVideos(branches, videos).then(function(result) {
  csv.writeToString(result, {}, function(err, data) {
    console.log(data);
  });
});

P.S. Okay, I’m really tempted to walk over to Swansea Memorial, but W- reminds me that we’ve got a lot of movies already waiting to be watched. So I’ll probably just walk to the supermarket, but I’m looking forward to running this script once we get through our backlog of videos!

2015-12-10 Emacs Chat: John Wiegley on maintaining Emacs and how you can help

December 10, 2015 - Categories: emacs, Emacs Chat
These are the bugs that have the “easy” keyword. Note that some of them are because of the package or mode name. =)

John Wiegley shared how he uses Gnus and Org to help him with the volume of Emacs-related information, and how people can get started with Emacs development.

  • 0:02 Gnus for mail and news
  • 0:04 Organizing groups by topic
  • 0:05 Adaptive scoring and prioritization
  • 0:09 Setup for mail: Gmail, Fetchmail, Dovecot, Gnus
  • 0:11 Time: 1-2 hours a day
  • 0:13 Community-building
  • 0:15 Using Org to keep track of initiatives
  • 0:19 Reading bug reports in Gnus
  • 0:22 How people can help: tests, documentation, reviewing bugs
  • 0:24 Coverage
  • 0:33 Efficiency, benchmarks
  • 0:40 Magit, Projectile, Flycheck
  • 0:45 Following up on emacs-devel topics: IDEs, APIs, lexical binding, Guile, etc.

You can e-mail John Wiegley at [email protected]. The emacs-devel mailing list is at https://lists.gnu.org/mailman/listinfo/emacs-devel.

Event page on Google+
Ogg Vorbis (audio only)
MP3 (audio only)

View the full blog post for the transcript. Thanks to Phil Hudson for volunteering to transcribe this!

(more…)

Weekly review: Week ending December 11, 2015

December 12, 2015 - Categories: review, weekly

Slow week, down with a bad cold. Still managed to keep things together long enough to have a good chat with John Wiegley and post notes from that. I’ll catch up on consulting next week.

2015-12-12a Week ending 2015-12-11 -- index card #journal #weekly output

Blog posts

Sketches

Focus areas and time review

  • Business (12.1h – 7%)
    • Earn (3.4h – 28% of Business)
      • ☑ Use scraped avatars
      • ☐ Earn: E1: 1-2 days of consulting
    • Build (8.1h – 66% of Business)
      • Drawing (4.3h)
      • Paperwork (0.4h)
    • Connect (0.6h – 5% of Business)
  • Relationships (7.1h – 4%)
    • ☐ Bake a pie or something like that
  • Discretionary – Productive (17.0h – 10%)
    • Emacs (4.8h – 2% of all)
      • ☑ Add layer resize as a button to Emacs
      • ☑ Set up org-gcal
      • ☑ Learn how to fix commits in magit
      • ☑ Read patches to get the hang of things
      • ☑ Do another Emacs News review
      • ☑ Update patch based on Aaron’s feedback
      • ☑ Announce johnw/sachac EmacsCast
      • ☑ Set up for chat with John Wiegley
      • ☑ Chat with John Wiegley about Emacs maintainership etc.
      • ☐ Do another Emacs News review
    • ☑ Set up clamav for scanning
    • ☑ Review, organize, and document my backups
    • ☑ Set up printer
    • ☑ Document backups
    • ☑ Review top-level Dropbox directories and trim as needed
    • ☑ Consider shifting my TFSA to investments
    • ☑ Organize my Org files
    • ☑ Write a script for stalking library videos
    • Sewing (5.0h)
    • Writing (3.7h)
  • Discretionary – Play (8.9h – 5%)
  • Personal routines (30.9h – 18%)
  • Unpaid work (15.9h – 9%)
  • Sleep (76.0h – 45% – average of 10.9 per day)

2015-12-14 Emacs News

December 14, 2015 - Categories: emacs, emacs-news

Links from reddit.com/r/emacs, /r/orgmode, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel.

Past Emacs News round-ups

Scan ~/bin and turn the scripts into Emacs commands

December 14, 2015 - Categories: emacs

I want to automate little things on my computer so that I don’t have to look up command lines or stitch together different applications. Many of these things make sense to turn into shell scripts. That way, I can call them from other programs and assign keyboard shortcuts to them. Still, I spend most of my computer time in Emacs, and I don’t want to think about whether I’ve defined a command in Emacs Lisp or in a shell script. Besides, I like the way Helm lets me type parts of commands in order to select and call them.

Emacs Lisp allows you to define a macro that results in Emacs Lisp code. In this case, I want to define interactive functions so I can call them with M-x. In case I decide to call them from Emacs Lisp, such as (my/shell/rotate-screen "left"), I want to be able to pass arguments. I’m also using dash.el to provide functions like -filter and -not, although I could rewrite this to just use the standard Emacs Lisp functions.

Here’s the code that scans a given directory for executable files and creates interactive functions, and some code that calls it for my ~/bin directory.

(defmacro my/convert-shell-scripts-to-interactive-commands (directory)
  "Make the shell scripts in DIRECTORY available as interactive commands."
  (cons 'progn
          (-map
           (lambda (filename)
             (let ((function-name (intern (concat "my/shell/" (file-name-nondirectory filename)))))
               `(defun ,function-name (&rest args)
                  (interactive)
                  (apply 'call-process ,filename nil nil nil args))))
           (-filter (-not #'file-directory-p)
                    (-filter #'file-executable-p (directory-files directory t))))))

(my/convert-shell-scripts-to-interactive-commands "~/bin")

Let’s see how that goes!

Scripting and the grocery store flyer

December 18, 2015 - Categories: geek

We plan the week’s meals around the grocery store flyers, taking advantage of what’s on sale (chicken, ground beef, etc.) and stocking up when the opportunity presents itself (for example, diced tomatoes or cream of mushroom soup).

The flyers are usually delivered on Thursdays. We do most of our grocery shopping at No Frills because it’s convenient and almost always a good price, but sometimes we’ll go to Freshco or Metro if there’s a particularly good sale. I might flip through the other flyers if we’re looking for something in particular, but most of the time, we just toss them out. I’d love to opt out of paper flyers, but that doesn’t seem to be an option in our neighbourhood.

It doesn’t take a lot of time to review the flyers, but I figured it would be fun to write a script that highlights specific items for us. Now I have a script that parses the output of the No Frills accessible flyer to create a table like this:

Y Clementines 2.47 2 lb bag product of Spain $2.47
Y Smithfield Bacon 3.97 500 g selected varieties $3.97
Y Thomas’ Cinnamon Raisin Bread 2.5 675 g or Weston Kaisers 12’s selected varieties $5.00 or $2.50 ea.
Y Unico Tomatoes 0.97 796 mL or Beans 540 mL selected varieties $0.97
Fresh Boneless Skinless Chicken Breast 3.33 2.78 BIG Pack!™ DECEMBER 18TH – 24TH ONLY! $3.33 lb/$7.34/kg save $2.78/lb
Purex 3.97 2.02 2.03 L $3.97 save $2.02
Frozen Steelhead Trout Fillets 5.97 2.0 filets de truite $5.97 lb/$13.16/kg save $2.00/lb
Heinz Tomato Juice 0.97 1.52 1.36 L selected varieties $0.97 save $1.52
Nestlé Multi-Pack Chocolate or Bagged Chocolate 2.88 0.61 45-246 g selected varieties $2.88 save 61¢
Source 4.97 0.5 16 x 100 g selected varieties $4.97 save 50 ¢
Franco Gravy 0.67 0.32 284 mL selected varieties $0.67 save 32¢
Ocean Spray Cranberry Sauce 1.67 0.32 348 mL whole or jellied $1.67 save 32¢
10 lb Bag Yellow Potatoes, 5 lb Bag Carrots or 10 lb Bag Yellow Cooking Onions 1.87 product of Ontario, Canada no. 1 grade or 5 lb Bag Rutabaga product of Canada, no. 1 grade $1.87
Betty Crocker Hamburger Helper 1.5 158-255 g or Mashed or Scallop Potatoes 141-215 g selected varieties $3.00 or $1.50 ea.
Blackberries 1.25 6 oz product of U.S.A. or Mexico DECEMBER 18TH – 24TH ONLY! 4/$5.00 or $1.25 ea.

(more lines omitted)

The table is sorted by whether the item name matches one of the things we usually buy (first column: Y), then how much the sale is for, and then the name of the item. Over time, I’ll add more things to the priority list, and the script will get smarter and smarter.

I can use Org commands to move the rows up or down or remove the rows I’m not interested in. Then I can take the second column of the script’s output with Emacs’ copy-rectangle-as-kill command (C-x r M-w), and paste it into OurGroceries‘ import dialog. That builds a shopping list that’s sorted by the aisles I’ve previously set up, and this list is synchronized with our phones.

I’ve added the script to https://github.com/sachac/scripts/blob/master/check-grocery-flyer.js, so you can check there for updates. The flyer URL and the list of staples are defined in a separate configuration file that I haven’t included in the repository, but you can probably come up with your own if you want to adapt the idea. =)

Here’s the source, just in case:

#!/usr/bin/env node

/*
  Creates a prioritized list based on the flyers, like this:

Y Clementines 2.47    2 lb bag product of Spain $2.47
Y Smithfield Bacon  3.97    500 g selected varieties $3.97
Y Thomas' Cinnamon Raisin Bread 2.50    675 g or Weston Kaisers 12's selected varieties $5.00 or $2.50 ea.
Y Unico Tomatoes  0.97    796 mL or Beans 540 mL selected varieties $0.97
  Fresh Boneless Skinless Chicken Breast  3.33  2.78  BIG Pack!™ DECEMBER 18TH - 24TH ONLY! $3.33 lb/$7.34/kg save $2.78/lb
  Purex 3.97  2.02  2.03 L $3.97 save $2.02
  Frozen Steelhead Trout Fillets  5.97  2.00  filets de truite $5.97 lb/$13.16/kg save $2.00/lb
  Heinz Tomato Juice  0.97  1.52  1.36 L selected varieties $0.97 save $1.52
  Nestlé Multi-Pack Chocolate or Bagged Chocolate 2.88  0.61  45-246 g selected varieties $2.88 save 61¢
  ...
  */

var rp = require('request-promise');
var cheerio = require('cheerio');
var homeDir = require('home-dir');
var config = require(homeDir() + '/.secret');
var staples = config.grocery.staples; // array of lower-case text to match against flyer items
var flyerURL = config.grocery.flyerURL; // accessible URL

function parseValue(details) {
  var matches;
  var price;
  if ((matches = details.match(/\$([\.0-9]+)( |&nbsp;)+(ea|lb|\/kg)/i))) {
    price = matches[1];
  }
  else if ((matches = details.match(/\$([\.0-9]+)/i))) {
    price = matches[1];
  }
  else if ((matches = details.match(/([0-9]+) *¢/))) {
    price = parseInt(matches[1]) / 100.0;
  }
  return price;
}

function getFlyer(url) {
  return rp.get(url).then(function(response) {
    var $ = cheerio.load(response);
    var results = [];
    $('table[colspan="2"]').each(function() {
      var cells = $(this).find('td');
      // $0.67  or  2/$3.00 or $1.25ea
      var item = $(cells[0]).text().replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, '');
      var details = $(cells[1]).text().replace(/([ \t\r\n\u00a0\u0000]|&nbsp;)+/g, ' ').replace(/^[ \t\r\n]+|[ \t\r\n]+$/g, '');
      var matches;
      var save = '';
      var price = parseValue(details);
      details = details.replace(/ \/ [^A-Z$]+/, ' ');
      if (details.match(/To Our Valued Customers/)) {
        details = details.replace(/To Our Valued Customers.*/, 'DELAYED');
      }
      if ((matches = details.match(/save .*/))) {
        save = parseValue(matches[0]);
      }
      results.push({item: item,
                    details: details,
                    price: price,
                    save: save});
    });
    return results;
  });
}

function prioritizeFlyer(data) {
  for (var i = 0; i < data.length; i++) {
    var name = data[i].item.toLowerCase();
    for (var j = 0; j < staples.length; j++) {
      if (name.match(staples[j])) {
        data[i].priority = true;
      }
    }
  }
  return data.sort(function(a, b) {
    if (a.priority && !b.priority) return -1;
    if (!a.priority && b.priority) return 1;
    if (a.save > b.save) return -1;
    if (a.save < b.save) return 1;
    if (a.item < b.item) return -1;
    if (a.item > b.item) return 1;
  });
}

function displayFlyerData(data) {
  for (var i = 0; i < data.length; i++) {
    var o = data[i];
    console.log((o.priority ? 'Y' : '') + '\t' + o.item + "\t" + o.price + "\t" + o.save + "\t" + o.details);
  }
}

getFlyer(flyerURL).then(prioritizeFlyer).then(displayFlyerData);

I’ll check next week to see if the accessible flyer URL changes each time, or if I can determine the correct publication ID by going to a stable URL. Anyway, this was fun to write!

Weekly review: Week ending December 18, 2015

December 19, 2015 - Categories: review, weekly

Slow and fuzzy-brained over the weekend due to a bad cold, but W- and J- kept the house in order. They even made General Tsao’s Chicken, which is quite labour-intensive. We watched a few of the new DVDs I picked up during my library raids, too.

I think I’m mostly over the cold now. It was a good opportunity to update what I can do with different energy levels (see all my fuzzy-brain-related sketches). I think it’s mostly about keeping my expectations low, and investing in processes and goodwill during non-fuzzy-brain periods. W- caught the cold from me. He’s dealing with it far better than I did, but still, it’s good to take things easy. My turn to pick up the slack!

Now that I’m on a proper operating system, I’ve been having fun writing little command-line scripts to automate bits and pieces of my life. I’m looking forward to building more of these pieces and gradually bringing them together. =) I should probably learn more about PhantomJS and CoffeeScript, too…

2015-12-19a Week ending 2015-12-18 -- index card #journal #weekly output

Blog posts

Sketches

Focus areas and time review

  • Business (16.4h – 9%)
    • Earn (7.5h – 45% of Business)
    • Build (5.5h – 33% of Business)
      • Drawing (2.9h)
      • Paperwork (0.1h)
    • Connect (3.4h – 20% of Business)
      • ☑ Reflect on Quantified Self questions from Christina
      • ☑ Talk to Christina about Quantified Self
  • Relationships (4.7h – 2%)
  • Discretionary – Productive (15.3h – 9%)
    • Emacs (2.0h – 1% of all)
      • ☑ Do another Emacs News review
      • ☑ Announce Hangout
      • ☑ Follow up on org-protocol patch
      • ☑ Doublecheck that the Yeti microphone works
      • ☑ Set up capture template for energy
      • ☐ Host Emacs Hangout
      • ☐ Do another Emacs News review
    • Sewing (5.8h)
      • ☑ Sew two more covers
      • ☑ Peasant top
    • Writing (3.8h)
    • ☑ Write a script to parse the flyer
    • ☑ Make a script that shows me walking and transit times
    • ☑ Script importing items into my grocery list
    • ☑ Make a list of things that are good to do when fuzzy-brained
  • Discretionary – Play (17.3h – 10%)
  • Personal routines (28.6h – 17%)
  • Unpaid work (16.4h – 9%)
    • ☑ Tidy up extra room
  • Sleep (69.2h – 41% – average of 9.9 per day)

2015-12-21 Emacs News

December 21, 2015 - Categories: emacs, emacs-news

Links from reddit.com/r/emacs, /r/orgmode, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel.

Past Emacs News round-ups

2015-12-21 Emacs Hangout

December 21, 2015 - Categories: emacs
Update 2015-12-25: Added link about multiple e-mail accounts in Gnus

Embarrassing technical issues, but fortunately, people are awesome and patient! =) Skip to about 0:07 or 0:12 or something if you want to get to the conversation part.

Text chat:

Also, codingquark’s link: http://codingquark.com/multiple-email-accounts-in-gnus/

Event page

Timestamps very fuzzy because of stress =)

  • Awkwardness by myself (turns out I had to change a setting to let other people join)
  • 0:07 Okay, other people joining, whew! warning: echo
  • 0:12 Gnus
  • 0:17 Meeting other Emacs geeks
  • 0:25 Mail splitting
  • 0:30 Asana to Org
  • 0:33 Literate programming
  • 0:36 Org Mode tables and Emacs Lisp functions
  • 0:45 edebug
  • 0:48 GnuPG
  • 0:52 macros
  • 1:00 smartparens / paredit
  • 1:06 flashcards
  • 1:18 narrow
  • 1:20 switching buffers

The audio is offset by about 7 minutes from the timestamps above, so you don’t have to listen to my panicking. =) MP3, OGG

See http://sachachua.com/blog/tag/emacs-hangout for more info, including where to find upcoming hangouts.

What’s worth making?

December 23, 2015 - Categories: sewing

I’ve been thinking about what’s worth making and what’s worth buying. Sometimes it’s cheaper to buy finished products used (or even new) than to buy the raw materials to make my own, especially in terms of common clothes and accessories. On the other hand, there are benefits to using and developing my DIY skills, such as cooking and sewing (and maybe eventually woodworking again).

Thinking about my considerations for that make vs. buy decision can help me improve those decisions. If I can make that “make” decision better, I can benefit from improved skills, more satisfaction, and possible savings. If I can make that “buy” decision better, I can take advantage of the capabilities of industries. Here are some factors that nudge me towards making things instead of buying them.

When something is much more expensive to buy than to make: Considering the quantities I use, the characteristics I want, and the cost of raw materials and time, it can be much cheaper to make things than to buy them. Cooking generally falls into this category. Sometimes sewing does too, especially if I can use fabric from sales or the thrift store.

When I want to adjust for personal fit, taste, or needs: It’s been nice to enjoy our favourite meals without being limited to what’s offered in restaurants. I also like being able to make several copies of simple blouses that fit me well in colours and fabrics that appeal to me, instead of trawling through stores to find the intersections of fit, style, fabric, colour/pattern, and price.

For that extra bit of satisfaction: I feel a little more satisfied when I enjoy something I’ve made compared to something I’ve simply bought. I’ve noticed this with the clothes I wear and the meals I make, and I’m looking forward to enjoying this even more as I learn how to make accessories.

When something is difficult to find: It’s often hard to find the things I want in store. Sometimes even online searching can be a hassle, especially with international shipping.

Independence from market trends and frustrating shopping experiences: Along those lines, it’s nice to be able to skip noisy malls and arbitrary trends.

Conversation starters and identity signallers: There’s a less of this because I don’t usually pay extra for novelty prints (well, aside from that Marvel comics one! =) ). I don’t feel the need to wear my geekiness on my sleeve – it usually comes out pretty quickly in conversation anyway. Still, it’s fun to infuse a little bit of personality into the things I make, like adding a cat-shaped pocket to a peasant blouse or making things that match each other. Who knows, maybe it will lead to interesting conversations with other crafters.

Convenience, not having to search: A well-stocked pantry lets us make something we like without having to look for a restaurant that’s open with the kind of food we might want to eat at the moment. Likewise, I want to eventually develop an organized stash of flexible, easy-to-coordinate fabric so that I can make things as needed (ex: apparel cotton, flannel, lining, knit, PUL). I haven’t quite sorted out my system yet, and I tend to do things in single colours/patterns because I’m not confident about coordinating. Someday, though!

Gifts: I’m pretty meh about giving and receiving gifts. It’s better when things are consumable or home-made, or preferably both. =)

Developing skills and appreciation: The more I make things, the more I learn about how things are constructed. This helps me appreciate the things around me, and it might even help me make those buying decisions more effectively.

Fuel for thinking/writing/sharing: Experiments in making things can often be turned into blog posts and ideas.

Ethical considerations: Although manufacturing can be good for the economic growth of developing countries, I’m not too comfortable with ethical issues in factories for clothing or other consumer goods. Besides, I like the waste reduction of repurposing things that might otherwise be trashed or turned into rags.

The intrinsic enjoyment of the activity: Cooking is fun, especially when W- and I cook together. Sewing is starting to be pretty fun too. It has its frustrating moments, but I’m starting to build up a good stash of “Look! This actually works!” memories.

In terms of decisions to buy instead of make:

  • There are things I definitely don’t have the skills or materials to make, so that’s an easy “buy” decision.
  • If I could make it, but it’s much cheaper and easier to buy things, then I might put off making them.
  • I tend to put off buying things if I know I can buy them inexpensively on short notice. I’ll wait until I have a clear need for them, since it’s often better to make do than to have more than we need.
  • I’ll buy in advance if I have a clear idea of our usage, or if there’s a good enough sale that I’m comfortable with the trade-offs.

Sometimes I also consider the question: “What else could I be doing with this energy, time, and money?” My life is pretty flexible at the moment, so it’s usually a choice of:

  • doing more consulting: good for building up skills and savings, but can be too tempting compared to the long-term value of other activities
  • doing something else in the real world: other DIY things, taking care of chores/errands/exercise
  • coding or learning something intangible: automating parts of my life, developing skills
  • thinking/drawing/writing about stuff: good for understanding, remembering, and connecting

There’s time enough for a little bit of everything, so I don’t worry too much about the decisions moment by moment. Still, it’s nice to be clear about the factors to consider so that I can recognize them more easily when they come up. =)

Based on our enjoyment of DIY videos on YouTube, I think I’ll enjoy a life that’s tilted even more towards making things. It would be awesome to be able to think spatially and draft my own patterns, and maybe get more into laser cutting, 3D-printing, and woodworking too.

We’ll see how things go!

Weekly review: Week ending December 25, 2015

December 26, 2015 - Categories: review, weekly

This week was more of a social one. My parents, sisters, and their families are in California for a vacation, so I called to say hi. We also hosted a houseguest I know from the Emacs community, and that worked out okay too. I ran into a few technical issues when hosting an Emacs Hangout, but fortunately we managed to get those sorted out.

A light week in terms of work – it was a little difficult to concentrate – but otherwise okay. More progress on various projects, yay! I’ve been taking advantage of small chunks of concentration time to automate or research various bits for my setup, so we’ll see if that pays off.

Looking forward to doing my year-end reviews this coming week. It’s been an odd year, but maybe it will make more sense when I look back. =)

2015-12-26a Week ending 2015-12-25 -- index card #journal #weekly

output

Blog posts

Sketches

Focus areas and time review

  • Business (13.1h – 7%)
    • Earn (4.7h – 36% of Business)
      • ☐ Earn: E1: 1-2 days of consulting
      • ☐ Prepare invoice
    • Build (7.0h – 53% of Business)
      • Drawing (3.1h)
      • Paperwork (0.0h)
    • Connect (1.4h – 10% of Business)
  • Relationships (17.5h – 10%)
    • ☑ Copy gear research to Evernote
  • Discretionary – Productive (13.6h – 8%)
    • Emacs (5.9h – 3% of all)
      • ☑ Do another Emacs News review
      • ☑ Make a list of recent Reddit links
      • ☑ Update org-protocol patch based on feedback
      • ☑ 2015-12-21 Emacs Hangout
      • ☑ Correctly link to package based on source – yes, ELPA does actually add packages
      • ☑ Refile and jump
      • ☑ Add an insert-link protocol
      • ☐ Do another Emacs News review
    • Preparation and automation
      • ☑ Anticipate a worst-case scenario and write down ways to mitigate it
      • ☑ Update script to renew library items
      • ☑ Write a user script for quickly displaying the status of library videos
      • ☑ Set up bitlbee
      • ☑ Fix gpg agent issue
      • ☑ Organize business tax information so that I have all my notes handy for next year
      • ☑ Explore fluxbox
      • ☑ Investigate kde baloo error with watches
      • ☑ Figure out if it’s the new Plasma or something else that’s jittering my X refresh
      • ☑ Find my Twiddler and set that up again
    • Sewing (2.1h)
    • Writing (3.9h)
      • ☑ Check out love languages thing
  • Discretionary – Play (14.0h – 8%)
  • Personal routines (34.5h – 20%)
  • Unpaid work (19.0h – 11%)
  • Sleep (56.3h – 33% – average of 8.0 per day)

2015-12-28 Emacs News

December 28, 2015 - Categories: emacs, emacs-news

Links from reddit.com/r/emacs, /r/orgmode, Hacker News, planet.emacsen.org, Youtube, the Emacs commit log, the changes to the Emacs NEWS file, and emacs-devel.

Past Emacs News round-ups

Learning about patchwork and sewing

December 28, 2015 - Categories: sewing

I’ve been looking into patchwork and quilting as a way to reuse scraps of fabric left over from sewing. That way, I don’t end up stashing stray odd-cuts forever, and I don’t feel guilty about trashing or donating material. (There are only so many zippered pouches I need in my life!) I can cut as many standard-size pieces as I can, and then store those in a more organized way.

I wanted to start pretty small: 4″x4″ squares (3.5″ after sewing with 1/4″ seam allowances), maybe 11×11 squares for a finished size of 38.5″ square. I still have lots of scraps to cut up, but I figured I’d give it a try first before committing the rest of my stash. Make a prototype, see what it’s like, maybe turn it into something for the cats or something to drape…

I counted the squares I cut from some fabric I had lying around, and assigned one-character labels for them. I stopped after I cut a little over 121 squares (11×11).

A red gingham 12
b black gingham 38
m marvel 6
D beige 11
B white crosses 56

Time to plan! I created a dot grid (in Emacs, naturally) and began filling it in with characters, like so:

B.B.B.B.B.B
...........
B.........B
...........
B.........B
...........
B.........B
...........
B.........B
...........
B.B.B.B.B.B

At first, I tried to keep track of the number of squares manually, but that got annoying to update as I tweaked the layout. By the time I got to something like this:

BbBbBbBbBbB
bBbBbBbBbBb
BbBABABABbB
bBABDBDBABb
BbBDmbmDBbB
bBABDmDBABb
BbBDmbmDBbB
bBABDBDBABb
BbBABABABbB
bBbBbBbBbBb
BbBbBbBbBbB

… I found this code to be really helpful for making sure I hadn’t put in more of one character than I had, and to show me which ones I still had left.

(let ((totals
       (mapcar (lambda (x) (cons (char-to-string (car x)) (length (cdr x))))
               (-group-by 'identity (string-to-list (replace-regexp-in-string "\n" "" data))))))
  (mapcar (lambda (x) (append (list (assoc-default (car x) totals)
                                    (- (elt x 2) (assoc-default (car x) totals)))
                              x)) squares))

The first column has the number of squares used in the design. The second column has the number of squares left. The remaining columns were copied from the original table.

12 0 A red gingham 12
38 0 b black gingham 38
5 1 m marvel 6
10 1 D beige 11
56 0 B white crosses 56

After lots of sewing and pressing, I ended up with something that looked reasonably like a patchwork quilt. It was actually pretty relaxing to sew once I got the hang of arranging things, since it just used straight lines. I unpicked two seams after stitching them incorrectly. The rest of the seams turned out okay.

2015-12-28 17.16.17

In retrospect, maybe I shouldn’t have included two strong black-and-white prints. This one feels a little like an optical illusion, and it’s not that restful to look at it in full. I probably won’t be using it as a wall hanging, but it might be nice to use it to dress up one of the cat beds. I could skip the batting, buy a cotton or flannel sheet from the thrift store for use as backing, and then quilt it for practice. Skipping the batting this time around might let me get away without setting up a walking foot, too.

I still have tons to learn about dealing with colours and prints. Maybe I can learn faster with smaller blocks. I’ll probably cut more 4″ squares since that’s a convenient size for my grid ruler, and maybe 2.5″ or 2″ if there are leftover scraps that won’t fit. Then I’ll organize them by value and colour and see what I can make. I can turn them into shopping bags, since our current collection is starting to wear out. We’ll see how that goes!