Mimsy Were the Borogoves

Two search bookmarklets for Django—Tuesday, August 19th, 2014

I run this site through a Django CMS. I often find myself looking for the most recent pages. Now, by default, the most recently edited pages show up at the top, and of course I can link a URL that specifically orders by when pages were added, but there is no way to limit it just to, say, the pages I’ve created this month. Even when I create only a few pages a month, which is normal, those views will still show, in my case, the hundred most recent pages. I’m not aware of a query parameter that will limit the number of results, nor of a query parameter that will only show within the last x days of a date field.

It is possible to show only a single month, but not to show only the current month. Any such bookmark will be out of date once the next month comes around. A JavaScript bookmarklet, however, can do this:

  • javascript:today=new%20Date();recentURL='https://django.localhost/admin/cms/page/?created__month='+(today.getMonth()+1)+'&created__year='+today.getFullYear();window.location=recentURL;

I also find myself going to the main list of pages and then doing a search. A bookmarklet can go directly to the search:

  • javascript:searchTerm=window.prompt('Search%20for?');searchURL='https://django.localhost/admin/cms/page/?q='+searchTerm;window.location=searchURL;

This will prompt for the search term and then construct a search URL with that term. It does not specifically encode the term, but I’ve tested it in Safari, Firefox, and Chrome and it works.

BASIC video decoder ring—Sunday, August 10th, 2014

I’ve been fooling around with BASIC a bit after getting HotPaw BASIC for iOS. First things were getting Mastermind (80 Microcomputing, October 1981, p. 122) and the infamous Super Star Trek BASIC programs working. I can now use my 64-gigabyte iPad 2 as a 1978 TRS-80 Model I.

One of the things I always had in mind back in the day but never got around to1 was a cipher decoder assistant. Over time, a cipher decoder seemed more and more pointless—who uses ciphers in the age of public keys?

Here’s a simple encipher program in Python for Editorial:

  • #coding: utf-8
  • import workflow
  • from random import shuffle
  • from string import ascii_lowercase
  • originalText = workflow.get_input().lower()
  • letters = list(ascii_lowercase)
  • cipher = list(ascii_lowercase)
  • shuffle(cipher)
  • cipher = dict(zip(letters, cipher))
  • cipheredText = ''
  • for letter in list(originalText):
  • if letter in cipher:
  • cipheredText = cipheredText + cipher[letter]
  • else:
  • cipheredText = cipheredText + letter
  • workflow.set_output(cipheredText)

This will shuffle the letters of the alphabet and use the new shuffling as the cipher. This puts it one step above a video decoder ring, which only had 25 possible ciphers.

The BASIC code acts as it would on any old computer of the era. It waits for text commands and prints out the currently-guessed cipher letter by letter and then the currently-guessed deciphered text.

HotPaw Basic on iOS—Sunday, July 13th, 2014

While looking at Chipmunk Basic yesterday, I noticed that Ron Nicholson also has a BASIC for iOS, HotPaw Basic. I’m not sure how useful it is, but it’s insanely fun. It appears to be based off of the Chipmunk code, and so works similarly. It also includes functions for accessing the touchscreen, the accelerometer, and the GPS location.

This is very simple code for drawing random circles wherever you’re touching the screen.

Compared to the other programming environment I have on my iPad, Pythonista, the built-in editor is archaic. It’s one-line-at-a-time editing pretty much just like I remember it from the early eighties—but even toward the late eighties, I was using a full-screen BASIC editor on OS-9. This is more like the old interactive BASICs where you replaced a line by retyping that line number; you can also edit a line by typing “edit” and the line’s number.

Type just the line’s number to delete that line.

Just like in the old days, it is very easy to program an endless loop; however, even these tiny computers we carry in our pockets are so fast that an endless loop can be impossible to break out of. My initial circles program just drew random circles at random locations on the screen; it locked up HotPaw Basic—the Stop button failed to work. Unlike the old days, however, one rogue program is less likely to lock up the entire system. The iPad itself experienced no slow-down and I was able to easily exit HotPaw Basic and restart it.

HotPaw automatically saves your current program in “tmp.bas”. You can also save it using the “save” command, load new ones using the “load” command, and view all programs using “dir”.

It does not support iCloud, which means that programs written on the iPad do not automatically transfer to the iPhone or other devices.

If you’re one of those people who look back fondly on BASIC, or if you have some BASIC programs you’d like to run on your iPhone or iPad, take a look at it. Most of the other BASIC languages I’m seeing on the app store are recreations of specific computers of the past, such as Commodore BASIC, or don’t even look like BASIC any more. Chipmunk Basic, while hardly modern, has been and continues to be updated for use today.

Apple goes to the Swift—Saturday, June 7th, 2014
photo for Swift Apple

The race may not always go to the swift, but that is the way to place your bets.

The most exciting part of the WWDC keynote last Monday wasn‘t the new operating systems for the Macintosh and iDevices. It was the announcement of the new Swift programming language for MacOS and iOS. A new programming language is my equivalent of “one more thing…”

It took a few seconds for the Swift Language Guide to appear on the iBookstore after the announcement, but the reference makes me even more excited. Swift appears to combine some of the best features of Objective-C/C++ and Python.1

The book, which is also available online, hooked me. I have not yet programmed in Swift, but I’m going to, and soon. I dabbled in iOS app creation for work, but so far all of my personal iPhone/iPad apps have been XHTML5. Swift makes me want to find some use for it.

It’s pretty rare for me to read a programming book all the way through; good ones, like the Swift book, make me want to hit the keyboard. In this case, even though I don’t have access to my iMac, I still wanted to, and did, finish the guide.

Swift will definitely be familiar to Python programmers. For example, it contains the for…in control statement that I first saw in Python.

In addition to the traditional for-condition-increment loop found in C, Swift adds a for-in loop that makes it easy to iterate over arrays, dictionaries, ranges, strings, and other sequences.

Swift contains both a while and a while… do loop, as does C++. It also includes C++’s switch statement, however, there are major differences:

The cases of a switch statement do not “fall through” to the next case in Swift, avoiding common C errors caused by missing break statements.

You can specify that any particular case does fall through, but that’s not the default.

A switch statement must handle all possible cases or the code will not compile. This is especially useful for enumeration types.

…a switch statement must be exhaustive when considering an enumeration’s members. If the case for .West is omitted, this code does not compile, because it does not consider the complete list of CompassPoint members. Requiring exhaustiveness ensures that enumeration members are not accidentally omitted.

Timeout class with retry in Python—Wednesday, April 16th, 2014

In Paramiko, the SSHClient’s connect method has a timeout parameter, but it rarely causes a timeout in some common instances. Since moving from San Diego’s Cox Cable to Round Rock’s Time-Warner, I’ve been seeing stuck connections much more often.

The fix appears to be to use signals: set an alarm before running the line/function that might get stuck, and then remove the alarm afterward. If the alarm has time to go off, it will generate an exception that can then be handled.

Since the inability to connect or fail to connect appears to be extremely random, I decided to combine it with the option to retry the connection:

[toggle code]

  • import signal
  • class TimeoutError(Exception):
    • pass
  • #Paramiko timeout does not work often, if at all
  • # So create a timeout class
  • class Timer(object):
    • def __init__(self, function=None, seconds=30, tries=3, errorMessage='Timeout'):
      • self.seconds = seconds
      • self.tryLimit = tries
      • self.tries = 1
      • self.function = function
      • self.errorMessage = errorMessage
    • def act(self):
      • signal.signal(signal.SIGALRM, self.handleTimeout)
      • signal.alarm(self.seconds)
      • self.function()
      • signal.alarm(0)
    • def handleTimeout(self, signum, frame):
      • if self.tries >= self.tryLimit:
        • raise TimeoutError(self.errorMessage)
      • else:
        • print 'Timed out on try', self.tries, self.errorMessage
        • self.tries = self.tries + 1
        • self.act()
        • print 'Succeeded on try', self.tries

The first class, a subclass of Exception, doesn’t do anything except give us an appropriately-named exception. The second class will raise that exception if the passed function does not complete before the given number of seconds.

First, instantiate the timer; then run the “act” method. If it times out, it will (by default) try again twice; that is, it will try three times. The function is retried simply by calling the act method again.

For example:

Updated Inkscape extension—Saturday, March 15th, 2014

I noticed on the Inkscape forum that a couple of parts of this tutorial are out of date.

First, the line that includes “/Applications/Inkscape.app/Contents/Resources/extensions” is no longer necessary. The path is now known to all extensions, and by removing this line you can make your extensions more portable. For one thing, you no longer have to worry about the location of the Inkscape app.

Second, the .inx files are now full-fledged XML. This means that they need a real declaration at the top. Replace the “inkscape-extension” root element with:

  • <?xml version="1.0" encoding="UTF-8"?>
  • <inkscape-extension xmlns="http://www.inkscape.org/namespace/inkscape/extension">

This makes the full code:

[toggle code]

  • #!/usr/bin/python
  • import copy
  • import inkex, simpletransform
  • class DuplicateMultiple(inkex.Effect):
    • def __init__(self):
      • inkex.Effect.__init__(self)
      • self.OptionParser.add_option('-n', '--number-of-copies', action='store', type='int', dest='number', default=2, help='How many copies would you like?')
      • self.OptionParser.add_option('-x', '--horizontal', action='store', type='float', dest='horizontal', default=0, help='Horizontal distance?')
      • self.OptionParser.add_option('-y', '--vertical', action='store', type='float', dest='vertical', default=0, help='Vertical distance?')
    • def effect(self):
      • transformation = 'translate(' + str(self.options.horizontal) + ', ' + str(self.options.vertical) + ')'
      • transform = simpletransform.parseTransform(transformation)
      • if self.selected:
        • for id, node in self.selected.iteritems():
          • counter = self.options.number
          • while counter > 0:
            • newNode = copy.deepcopy(node)
            • #newNode.set('style', 'fill:none;stroke:#ff0000;stroke-width:2px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1')
            • simpletransform.applyTransformToNode(transform, newNode)
            • self.current_layer.append(newNode)
            • counter = counter - 1
            • node = newNode
      • #inkex.debug(newNode.attrib)
  • effect = DuplicateMultiple()
  • effect.affect()

And the full .inx file:

Pipe viewer command-line progress report—Wednesday, November 6th, 2013

I’m sitting here waiting for a two and a half gigabyte MySQL dump file to make its way to the Amazon Cloud and basically the only way I have to monitor its progress is opening up a Sequel Pro window and wait for new databases to show up.

I thought I’d do a search on MySQL dump progress reports, and I found a neat little utility called pipe viewer that really ought to be standard on Mac OS X and Linux.

  • pv Y2013M11D06.sql | wc
  • 2.47GiB 0:00:11 [ 212MiB/s] [========================================================================>] 100%
  • 98159 122143517 2648450403

It took about 11 seconds to complete, and as it completed the progress bar made its way across the window.

Note that I don’t have MacPorts or HomeBrew installed; a simple ./configure and make worked fine.

File this under: Why did I not already know about this!

Nisus HTML script now handles floating content—Saturday, September 28th, 2013

My Nisus simple HTML publish script now handles floating images and floating text boxes. This means that floating images are no longer lost, and neither are tables or other text inside of floating text boxes.

This was made possible by several new features in Nisus’s macro language. For images, the script no longer has to extract the image from RTF. Selections have an enclosedInlineImages and an enclosedFloatingContents method, making it simple enough to grab any images in a selection:

[toggle code]

  • $currentSelection = $thisDocument.textSelection
  • #are there any images?
  • $images = $currentSelection.enclosedInlineImages
  • If $images
    • ForEach $image in $images
      • SaveImage($image)
    • End
  • End
  • $floats = $currentSelection.enclosedFloatingContents
  • If $floats
    • ForEach $float in $floats
      • If $float.isImage
        • SaveImage($float.image)
      • End
    • End
  • End

And images themselves are now objects with properties and methods, including the ability to write themselves out to a file:

[toggle code]

  • Define Command SaveImage($image, $imageFolder)
    • File.createFolderWithPath $imageFolder
    • $imagePath = $image.writeWebImageToFolderAtPath $imageFolder
    • $imageFileName = $imagePath.lastFilePathComponent
    • $imageName = $imageFileName
    • Begin Perl
      • use URI::Escape;
      • $imageFileName = uri_escape($imageFileName);
    • End
    • $imageHTML = "<img src=\"images/$imageFileName\" alt=\"$imageName\" />"
    • return $imageHTML
  • End

The writeWebImageToFolderAtPath ensures that the image is in a standard web format, regardless of its format in the document. This means that embedded PDFs and EPS images will be written to a more standard format, currently JPEG.

The ability to define commands contributed heavily to the main improvement of this version. It allowed me to separate out the code that handles text conversions, which in turn allowed me to call it both for text in the normal document flow and on text in floating text boxes.

Older posts.