Science bootstrap glyph icons

I’m starting a new repository on GitHub which will be an svg based set of scientific icons.

This is just the start of making some free to use (CC-BY-SA 4.0), science based icons that will be compiled into a web font (ttf, oeff, svg etc) and provide a css file to easy drop in placement into many websites in the science fields.

A lot of the icons are meant as inaccurate depictions. The goal is to convey the general idea behind the button or status without having to have every proton in the right place.

If you’d like to help, there are instructions on the github page for contributions.

GPG with Confirmation

I got tired of Evolution email client giving me those horrid error messages when ever I try to email someone who’s key isn’t in my current list of keys.

The design of this is appallingly bad. It discourages the use of GPG rather than encouraging the importing of keys and it makes no mention of helping you acquire keys if possible. It also allows for no additional or optional footer to explain to the recipient that their message couldn’t be encrypted because they don’t use GPG.

While I couldn’t do much about the later, without hacking on the evolution codebase directly. I did do a bit of hacking on the former with a gpg middlware. Yes, when I say hack, I mean HACK. A dangerous and potentially devastating way of wrapping the gpg binary with my own python script that could intercept the evolution call and do work to search, display and add keys to encourage the use of encryption overall.

The design was simple. When we are asked to encrypt for a person who we don’t have the keys for, we do a search. The results are shown in a GUI to the user and they can select a key to use. This then is added to the key ring and used to encrypt the email.

This setup allows for experimentation with user prompting and workflow. It’s not something I would recommend be installed on user’s computers. But for designers and developers, this sort of match-stick making is a valuable platform to build, try, test and rebuild quickly.

I use zenity for the user interface. This is a Gtk command line tool that lets you launch a window from the command line and the interface is good enough to support photos in lists and returning which item was selected. Very cool.

Bellow you will find the script I created for this hack, this is saved to /usr/bin/gpg and gpg is moved to gpg.orig:

#!/usr/bin/python
#
# Wrap the gpg command to provide evolution with a bit of extra functionality
# This is certainly a hack and you should feel very bad about using it.
#
# Public Domain, Authored by Martin Owens  2016
#
import os
import sys
import atexit

from collections import defaultdict
from subprocess import Popen, PIPE, call
from tempfile import mkdtemp, mktemp
from datetime import date
from shutil import rmtree

to_date = lambda d: date(*[int(p) for p in d.split('-')])


class GPG(object):
    keyserver = 'hkp://pgp.mit.edu'
    remote_commands = ['--search-keys', '--recv-keys']

    def __init__(self, cmd='/usr/bin/gpg', local=False):
        self.command = cmd
        self.photos = []
        self.local = local
        self.homedir = mkdtemp() if local else None
        atexit.register(self.at_exit)

    def at_exit(self):
        """Remove any temporary files and cleanup"""
        # Clean up any used local home directory (only if it's local)
        if self.local and self.homedir and os.path.isdir(self.homedir):
            rmtree(self.homedir)

        # Clean up any downloaded photo-ids
        for photo in self.photos:
            if os.path.isfile(photo):
                os.unlink(photo)
            try:
                os.rmdir(os.path.dirname(photo))
            except OSError:
                pass

    def __call__(self, *args):
        """Call gpg command for result"""
        # Add key server if required
        if any([cmd in args for cmd in self.remote_commands]):
            args = ('--keyserver', self.keyserver) + args
        if self.homedir:
            args = ('--homedir', self.homedir) + args

        command = Popen([self.command, '--batch'] + list(args), stdout=PIPE)
        (out, err) = command.communicate()
        self.status = command.returncode
        return out

    def list_keys(self, *keys, **options):
        """Returns a list of keys (with photos if needed)"""
        with_photos = options.get('photos', False)
        args = ()
        if with_photos:
            args += ('--list-options', 'show-photos',
                     '--photo-viewer', 'echo PHOTO:%I')
        out = self(*(args + ('--list-keys',) + keys))

        # Processing the output with this parser
        units = []
        current = defaultdict(list)
        for line in out.split('\n'):
            if not line.strip():
                # We should always output entries if they have a uid and key
                if current and 'uid' in current and 'key' in current:
                    # But ignore revoked keys if revoked option is True
                    if not (current.get('revoked', False) and options.get('revoked', False)):
                        units.append(dict(current))

                current = defaultdict(list)

            elif line.startswith('PHOTO:'):
                current['photo'] = line.split(':', 1)[-1]
                self.photos.append(current['photo'])
            elif ' of size ' in line:
                continue
            elif '   ' in line:
                (kind, line) = line.split('   ', 1)
                if kind == 'pub':
                    current['expires'] = False
                    current['revoked'] = False

                    if '[' in line:
                        (line, mod) = line.strip().split('[', 1)
                        (mod, _) = mod.split(']', 1)
                        if ': ' in mod:
                            (mod, edited) = mod.split(': ', 1)
                            current[mod] = to_date(edited)

                    (key, created) = line.split(' ', 1)
                    current['created'] = to_date(created)
                    (current['bits'], current['key']) = key.split('/', 1)
                elif kind in ('uid', 'sub'):
                    current[kind].append(line.strip())
                else:
                    current[kind] = line.strip()

        return units

    @property
    def default_photo(self):
        if not hasattr(self, '_photo'):
            self._photo = mktemp('.svg')
            with open(self._photo, 'w') as fhl:
                fhl.write("""
  
""")
            self.photos.append(self._photo)
        return self._photo

    def recieve_keys(self, *keys, **options):
        """Present the opotunity to add the key to the user:
         
        Returns
          - True if the key was already or is now imported.
          - False if keys were available but the user canceled.
          - None if no keys were found within the search.

        """
        keys = self.search_keys(*keys)
        if not keys:
            return None # User doesn't have GPG

        # Always use a temporary gpg home to review keys
        gpg = GPG(cmd=self.command, local=True) if not self.local else self

        # B. Import each of the keys
        gpg('--recv-keys', *zip(*keys)[0])

        # C. List keys (with photo options)
        choices = []
        for key in gpg.list_keys(photos=True):
            choices.append(key.get('photo', self.default_photo))
            choices.append('\n'.join(key['uid']))
            choices.append(key['key'])
            choices.append(str(key['expires']))

        if len(choices) / 4 == 1:
            title = "Can I use this GPG key to encrypt for this user?"
        else:
            title = "Please select the GPG key to use for encryption"

        # Show using gtk zenity (easier than gtk3 directly)
        p = Popen(['zenity',
            '--width', '900', '--height', '700', '--title', title,
            '--list', '--imagelist', '--print-column', '3',
              '--column', 'Photo ID',
              '--column', 'ID',
              '--column', 'Key',
              '--column', 'Expires',
            ] + choices, stdout=PIPE, stderr=PIPE)

        # Returncode is generated after communicate!
        key = p.communicate()[0].strip()

        # Select the default first key if one choice.
        # (person pressed ok without looking)
        if not key and len(choices) == 4:
            key = choices[2]

        if p.returncode != 0:
            # Cancel was pressed
            return False

        # E. Import the selected key
        self('--recv-keys', key)
        return self.status == 0

    def is_key_available(self, search):
        """Return False if the email is not found in the local key list"""
        self('--list-keys', search)
        if self.status == 2: # Keys not found
            return False
        # We return true, even if gpg returned some other kind of error
        # Because this prevents us running more commands to a broken gpg
        return True

    def search_keys(self, *keys):
        """Returns a list of (key_id, info) tuples from a search"""
        out = self('--search-keys', *keys)
        found = []
        prev = []
        for line in out.split("\n"):
            if line.startswith('gpg:'):
                continue
            if 'created:' in line:
                key_id = line.split('key ')[-1].split(',')[0]
                if '(revoked)' not in line:
                    found.append((key_id, prev))
                prev = []
            else:
                prev.append(line)
        return found


if __name__ == '__main__':
    cmd = sys.argv[0] + '.orig'
    if not os.path.isfile(cmd):
        sys.stderr.write("Can't find pass-through command '%s'\n" % args[0])
        sys.exit(-13)

    args = [cmd] + sys.argv[1:]
    # Check to see if call is from an application
    if 'GIO_LAUNCHED_DESKTOP_FILE' in os.environ:
        # We use our moved gpg command file
        gpg = GPG(cmd=cmd)
        # Check if we've got a missing key during an encryption, we get the
        # very next argument after a -r or -R argument (which should be
        # the email address)
        for recipient in [args[i+1] for (i, v) in enumerate(args) if v in ('-r', '-R')]:
            # Only check email addresses
            if '@' in recipient:
                if not gpg.is_key_available(recipient):
                    if gpg.recieve_keys(recipient) is None:
                        pass
                        # We can add a footer to the message here explaining GPG
                        # We can't do this, evolution will wrap it all up in a
                        # message structure.
                        #msg = sys.stdin.read()
                        #if msg:
                        #    msg += GPG_TRIED_FOOTER
                        #sys.stdout.write(msg)
                        #sys.exit(0)

    # We call and do not PIPE anything (pass-through)
    try:
        sys.exit(call(args))
    except KeyboardInterrupt:
        sys.exit(-14)

Review: goodnight Sweetheart

I’ve just watched the special for goodnight sweetheart (BBC Sept 2nd 2016). Goodnight Sweetheart was a sitcom/drama back in the 90s about a tv repairman (Garry) who finds a portal back to the 1940s during the world war London Blitz. This deeply flawed time traveler then flits back and forth between the 1990s and the 1940s with a woman in each era.

The show was and still is, very well written. The jokes are masterfully done and I appreciate how much the show dovetailed the two times.

** Spoilers below, but I think spoilers add to the experience **

The part I always found fascinating is the time travel stories. There’s one episode where he has to stop pearl harbor attacks, he fails, goes back to the 90s to discover everything changed. Apparently in his universe he was able to stop the attacks by pretending to be a British spy. There’s another where he finds a portal back to the 1800s by going the wrong way round and discovers that Jack the ripper is actually a time traveler from the 1940s.

So this is a sci-fi and a comedy. But it’s also a drama. The snarky biting tension between his wife Evon and him as his marriage falls apart, the pressure on his friend Ron who’s business and life is ruined by Gary’s self centered story. It’s the best possible balance and the three way split between funny, interesting and serious reminds me a lot of Back to the Future; where some quite complex (for mainstream) time travel is the backdrop for some funny shenanigans. The only difference is that Goodnight Sweetheart has more time over six seasons to develop and the drama is a lot more serious when it’s there.

I’m writing this so my friends in the USA can find themselves a copy and see if they like it too. It’s an off-brand British sci-fi of the best kind. Something I wish we did more of to be honest. But hopefully this series has enough seasons to really binge watch.

The new special which caused this blog entry was excellent. Although it’s not a good idea to watch it without having seen the original series. In fact the show should be watched in order as there’s a lot of layers that build on each other as the show progresses and even the jokes and often back references. For example Gary playing music from the Beatles during the war, and then everyone believing that the famous band stole all their hits from Gary.

It was very funny seeing Gary, who often would be the one to be ‘in-on-the-joke’ with regard to technology and time travel, be thrown into 2016, where he’s been missing for 17 years. He tries to use a public phone box, but they’re all not-phones (the gags are great). No one responds to him because they’re all on their phones and there’s just a ton of jokes at the expense of how things have changed since the 1999. The Adel song was quite sweet actually, it’s hard to imagine Gary learned the song in a single car ride, but I’ll forgive it because it fits so well for what he’s been through.

Well, if you’re interested in the show. Check it out now! and let me know in the comments what you thought.

What is Art? is code Art?

The musings of today’s Thought for Today on BBc Radio Four are often interesting perspectives that drive at something both personal and social. Today’s subject was the concept of modern art, it’s valuation and the way in which artists invest in the art while knowing little about it.

This got me thinking about code. You see code is something that requires an imense amount of creative thinking. Not just problem solving and puzzle mastery; but down right honest to god design and humble craftsmanship to boot. A piece of code must be more than just functional for the user, it must be maintainable in an ever changing world.

This requires that the code be readable and possibly even attractive to potential maintainers as a learning exercise. The best code is obvious where is can be and smartly presented where it needs to be clever. It must deliver it’s cleverness carefully and in reasonable chunks, much like a classical lesson in latin or a course of antibiotics. The code needs to cozy up to the reader and be as familiar with it’s patterns, syntax choices and variable naming conventions as a well worn pair of slippers.

Start using single letter names, odd abbreviations or inventing undocumented artifice and you’ll lose the audience. You’ll alienate the future from your comfortable seat in the past with a smug sense of converse hindsight. The arrogant developer assumes all things are known in the future and all maintainers are themselves or someone very much like themselves. And the trouble with people is, no matter how many you know, there’s always one strange outliers you’ve never met and one day they’ll be looking at your code thinking to themselves that you must have been enjoying your legal high quite a lot on the day you wrote /this/.

So what is art and how does it fit into this whole “understandable code” thought?

I’m not going to pretend there’s not seven billion ways to define art. But I believe art to be “the intentional communication through emotional language”. This means I consider stand up comics to be artists, I consider Fox news to be an arts show and music like rap to be one of the most powerful forms of art around today. But art can be bad like Fox, art can be good like Banksy and that doesn’t detract from it’s medium.

Art can be a failure when it fails to deliver the intended emotions like most modern visual art (to the general population anyway). We can feel disappointed in politicians for failing to be concise and factual, while at the same time marveling at their artistry for using their home spun bull shit to evoke the emotions they want in their audience. It’s wonderfully successful art, and a terrible education for the public. Not that art needs to be true, or that it needs to not be true of course.

Code in this narrowed definition of art, can be art. Sure as above we really want code to be artful as in crafted well; but we also could have code that intends to and successfully delivers an emotion. It has two ways. The usual way is that the code runs a game or some other intended visual art say. It’s the mechanism by which art is delivered and the code in there is part of the whole art.

I remember the radio head “Big Ideas” video that uses a specrum and hard disk array. That delivers art through it’s code is some interesting ways.

But I think most interesting to developers is how their emotions can be engaged by just reading code and repositories. I think source code poetry is a pretty well established way of making art out of code and I really enjoy reading some of it and running it. There are code flowers and other clever mechanisms that evoke wonder and joy as they are compiled and run.

But what of every day code. I think all our code evokes some emotion in those that have to read it and fix it. Mostly this is frustration and annoyance that you didn’t write it in a way more comforting to the reader. But there’s got to be scope here for making functional code that’s beautiful, interesting, passionate, lovely, hateful or just plain fun.

And not just for the user.

What do you think? Can your code be art?