Saturday, October 6, 2012

Gmail RTM Bookmarklet

I am evaluating the Remember The Milk task management system.  They have a bookmarklet that does not provide (as of 2012-10-06) a way to record the URL of the page the task was added from.  I played around with the mobile versions of the bookmarklet posted to Using the mobile Add as a generic Quick Add tool including all fields forum thread and could not get it to work. So I based my own on a modified copy of the original Gmail This! bookmarklet and edited it to create a message body with the fields I needed, including the URL off the current web page.

This bookmarklet opens up a new Gmail compose window and adds the required info to the body of the message. It appends a note for both the document title and the current selection. You can then manually add additional text into that note which is typically what I need to do to provide extra info about the task.

I left the Due field blank, as I know I will have to type that in anyhow. This is different from what the standard RTM bookmarklet as it expects you to highlight text of a date and/or time as the Due date.

This is just GMail compose window, so there is no auto-completion of existing Tags, which is something the original bookmarklet does that mine does not. I don't miss that much as I know what my tags are, which are kept to be short names.

Here is the bookmarklet text:

java_script:popw='';Q='';rtmMail='CHANGE_THIS';x=document;y=window;if(x.selection)%20{Q=x.selection.createRange().text;}else%20if%20(y.getSelection)%20{Q=y.getSelection();}else%20if%20(x.getSelection)%20{Q=x.getSelection();}popw=y.open('https://mail.google.com/mail?view=cm&tf=0&to='+encodeURIComponent(rtmMail)+'&su='+encodeURIComponent(document.title)+'&body='+encodeURIComponent('T: '+Q+'\n')+encodeURIComponent('D: \n')+encodeURIComponent('U: '+location.href)+encodeURIComponent("\n---\n"+document.title+"\n"+Q+"\n"),'gmailForm','scrollbars=yes,width=680,height=510,top=175,left=75,status=no,resizable=yes');if%20(!document.all)%20T%20=%20setTimeout('popw.focus()',50);void(0);

How to install:
  1. Select the text above and copy it to the clipboard (CTRL-C typically).
  2. Right mouse click on the Firefox toolbar, and select New Bookmark.
  3. Select the Link field, and paste the link text (CTRL-V typically).
  4. Remove the underscore character from "java_script".
  5. Change the "CHANGE_THIS" in the pasted text of the bookmarklet to be your Inbox Email Address (see How to). 
  6. Change the Name field to be GMail RTM.
  7. Click Save.
To use, highlight a part of a web page, and click the GMail RTM button on your toolbar.  Make any required changes and click Send.

(The platform and browser version I used: 32-bit Firefox 15.0.1 running on 64-bit Debian Linux (Testing).)

Sunday, May 27, 2012

Raspberry Transplanting Procedure

Overview


Below is the procedure I followed to transplant raspberries. This is a consolidation of various sources I found on the web (links are included). Primary sources were posts on http://ehow.com.

Equipment needed:

  • Garden gloves sturdy enough to deal with thorny raspberries.
  • Hand shovel or similar.
  • Garden shears for cutting the suckers roots.
  • Garden stakes for locating where the holes will go.
  • Tape measure to measure off the distances.

Procedure

  • When to transplant: This should be done in the 2nd year after the plant has grown. Transplant raspberry volunteers in April and May (see volunteer plants). Dig them up and move them when they have just begun to leaf out, with a few small leaves emerging. If possible, transplant during overcast weather, at the beginning of an overcast period, so the transplant will get 2 or 3 days to develop roots before the sun comes out. If transplanting during the summer months, use a sun shade for several weeks to provide the plant with reduced sunlight.
  • Locate the destination holes for the transplants (Select a full-sun location) by marking them with some stakes. Make the line east to west to maximize sun exposure during the summer. Space holes 3 feet apart to prevent the spread of disease, and rows 8 to 12 feet apart (note that one web page said spread them 2 feet apart). Destroy any perennial weeds growing near the destination holes including any wild raspberry or blackberry plants, because they can spread disease to your plants.
  • After the first frost, in early spring, identify the healthiest red raspberry plant from which to draw suckers. Look around the base of the mother plant for suckers (choose strong suckers with healthy roots), which are also known as daughter plants: find the off shoots from your main plant or plants that are popping up from the soil around the main plant. Put garden gloves on, because you will be working around the red raspberry's thorny canes. Use garden shears to snip roots that connect the daughter plant to the mother plant (It may be necessary to scoop some of the dirt away to find the root of the plant). Be careful to preserve a soil ball around the daughter plant's root system. When you find the roots, dig the plant out from that point. As you will see, some of the roots are actually part of your main plant. Go ahead and dig or cut away from those roots, as it will not harm your plants.
  • Be sure to loosen the soil around and under the raspberry sucker to remove it from the ground with its roots attached. Raspberry roots are shallow, growing no deeper than 10 inches. If you drive your spade into the ground to a depth of 1 foot, you should be able to take the baby bush out completely with its roots.
  • Dig out transplant candidates after the last spring frost and submerge their roots immediately in a bucket of water to keep the roots from drying out (but only if you are not going to transplant them immediately).
  • Take care to remove all old canes from bushes to be transplanted.
  • Plant one raspberry seedling per hole.
  • In the destination holes, insure to dig holes as deep as the daughter roots, and twice as wide as they are deep. Insure that the holes are large enough so that roots will not be crowded and an inch or two deeper than roots were growing previously (see also Set plant in a hole).
  • Fill holes with water and let them drain halfway down.
  • Use a shovel to tamp down the soil over the top of the newly transplanted red raspberry plant, being sure to cover roots. This is so that any water remaining in the hole will not leave a dry air-space when it drains out.
  • Trim all canes to 6 to 8 inches long (new small plants created by tipping can remain untrimmed). The reason is because "trimming back transplants may result in decreased fruiting the first year but will pay dividends in healthy growth". Check again that plants are solidly tamped in (i.e., do not leave dry air-spaces). (An alternative is to snip off two-thirds of the cane with garden shears to help encourage root development. Provide one inch of water. Consider planting at night to help the plant adapt to its new location.)
  • Keep soil consistently moist for at least a week, to help roots establish in new soil. Continue keeping soil moist during any dry spells until plants show solid new growth.
  • Do not immediately stake new plants; they must be trimmed and allowed to grow new canes first. In fact, since they do best with a trellis system, do the instructions in installing a trellis during the summer, or after the plants grow a bit.

Tips & Warnings

  • Your transplant should begin producing berries the following summer.
  • To help maintain moisture, reduce weeds and protect against the harshness of winter, maintain six inches of mulch around your transplant year round.  I ended up using lawn grass cuttings piled up high enough so that the suckers and other weeds cannot grow (just let the yard trimmings decompose around the plant which I believe will act as fertilizer for the raspberry bush).
  • Trimming back transplants may result in decreased fruiting the first year but will pay dividends in healthy growth.
  • The University of Maine recommends installing a trellis to support raspberry canes (They do best with a trellis system). Providing a place for the canes to climb reduces disease, improves fruit quality, and makes it easier to harvest the berries.

Saturday, May 19, 2012

Batch Image Resizing from the GIMP command-line

The following TinyScheme (Script-Fu) script resizes one or more image files as specified with a file glob, and writes the resized image files into an output directory:

(define (scale-to-max-fileglob
         file-pattern
         out-dir
         newmax
         )
  (let* ((filelist (cadr (file-glob file-pattern 1))))
    (while (not (null? filelist))
      (let* ((in-file (car filelist))
             (image (car (gimp-file-load RUN-NONINTERACTIVE in-file in-file)))
             (drawable (car (gimp-image-get-active-drawable image)))
             (old-width (car (gimp-image-width image)))
             (old-height (car (gimp-image-height image)))
             (old-max (max old-width old-height))
             (new-width (round (/ (* old-width newmax) old-max)))
             (new-height (round (/ (* old-height newmax) old-max))))
        ;; http://tinyurl.com/7bvura2 states "... because saving undo
        ;; steps can be time and memory intensive" and so we don't
        ;; care about undo operations for batch runs:
        (gimp-image-undo-disable image)
        (gimp-image-scale image new-width new-height)
        (let ((out-file
               (string-append out-dir
                              ;; Insert a slash character if
                              ;; not already at the tail-end
                              ;; of out-dir:
                              (if (char=? #\/ (car (last (string->list out-dir))))
                                  ""
                                  "/")
                              ;; Take the basename of in-file which may be a fully-qualified path:
                              (car (last (strbreakup in-file "/"))))))
          ;; The print function does not show output on standard
          ;; output, so use gimp-message instead:
          (gimp-message (string-append "   scale-to-max-fileglob: scaling "
                                       in-file " into " out-file
                                       " with these dimensions: "
                                       (number->string new-width) "x" (number->string new-height)))
          (gimp-file-save RUN-NONINTERACTIVE image drawable out-file out-file))
        (gimp-image-delete image))
      (set! filelist (cdr filelist)))))

Store this into ~/.gimp-2.6/scripts/batch-resize.scm and the definition of scale-to-max-fileglob will load into all future gimp sessions.


Example run: This was executed using GIMP 2.6 on a 64-bit Debian Linux machine.  The "script-fu-Warning" is coming from the gimp-message function:



user@somehost:/tmp/images_dir$ time gimp -i -b '(begin (scale-to-max-fileglob "*.jpg" "outdir" 1000) (gimp-quit 0))'

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-43-42_676.jpg into outdir/2012-05-19_16-43-42_676.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-44-35_210.jpg into outdir/2012-05-19_16-44-35_210.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-21_785.jpg into outdir/2012-05-19_16-41-21_785.jpg with these dimensions: 1000x562

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-44-02_760.jpg into outdir/2012-05-19_16-44-02_760.jpg with these dimensions: 1000x562

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-45-34_771.jpg into outdir/2012-05-19_16-45-34_771.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-43-15_141.jpg into outdir/2012-05-19_16-43-15_141.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-39_886.jpg into outdir/2012-05-19_16-42-39_886.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-45-13_128.jpg into outdir/2012-05-19_16-45-13_128.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-52_376.jpg into outdir/2012-05-19_16-42-52_376.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-49_429.jpg into outdir/2012-05-19_16-41-49_429.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-08_196.jpg into outdir/2012-05-19_16-42-08_196.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-41-54_552.jpg into outdir/2012-05-19_16-41-54_552.jpg with these dimensions: 562x1000

script-fu-Warning:    scale-to-max-fileglob: scaling 2012-05-19_16-42-34_497.jpg into outdir/2012-05-19_16-42-34_497.jpg with these dimensions: 562x1000



real    0m16.179s
user    0m13.229s
sys    0m2.236s




The above code was cobbled together from these sources:
  1. Christopher Campbell's blog: Batch image scaling with Gimp
  2. TinySCHEME Version 1.40 Manual is rather skimpy so you may desire to refer to The Racket Reference instead.
  3. Gimp Batch Mode Introduction

Saturday, October 8, 2011

Developing Software Productively through selective automation

How do you increase your software development productivity over the long haul? Here's how: Examine your daily task work to identify tasks that are amenable to automation, and then automate it. For me, this means to do the following:
  1. Maintain a constant awareness of all of your development activities, specifically patterns of behavior or groups of actions that are repeated multiple times throughout the day.
  2. Of those patterns, identify the ones that are comprised of tasks that do not change regardless of the circumstances.
  3. Determine if those tasks are amenable to automation (some will, some won't). This excludes tasks that should be delegated to someone else to do.
  4. Schedule time to encapsulate the tasks in a software routine.
  5. Make executing that routine mindless and effortless, by associating the execution of the routine to a new and unique combination of key-bindings in the main window of the primary editing tool you use (e.g. Emacs, Eclipse, Jedit, etc.).
Some may think that the "schedule time" item will eat into their productivity. However, I have found in practice that the time saved by automation will pay for itself over time. But there is one more benefit: Having a machine execute the tasks frees up your mind to think at a higher level of abstraction, in a given project. Making a task mindless and effortless has the goal of not distracting your mind from the flow of adding, deleting, and moving code around. Any requirement to pull down menus, bring other windows to the front, type in and execute long command lines, etc., are distracting to the mental process of software development and should be gradually eliminated by delegating those tasks to push-button automation. Therefore, as a software developer, those activities are best done right there in the text editing window itself, to be driven by carefully chosen key sequences that are easy to memorize. Below are some examples of tasks I discovered fit the above criteria, and that I could automate (this is specific to my focus on code development, but they could be generalized for other work domains):
  1. When the cursor is on a full or relative path to a file somewhere on the filesystem, typing a keystroke to open the file in the text editor. Compare that to opening up a new window, moving the mouse cursor into that window, navigating a file browser to find the file or typing in the full path to the file in the file system. Think about how often that task is done in given developers work day.
  2. When the cursor is sitting on a URL, typing a keystroke to open the URL in a browser. Think about how often you need to refer to reference material that is only on some remote web server somewhere.
  3. When the cursor is sitting on a symbol whose definition you need to alter, typing a keystroke to drive your editor to view and edit that definition. Compare that with using a file search to find the definition, and filter out the false positives.
  4. You need to go back to where you started when editing some code, so type a keystroke to go back to the place where you started. The idea here is that each time you navigate to a new view on some source, there is the equivalent of a "back" button in the form of a key sequence. This should be applicable for all types of navigation to some file, symbol, or web page.
  5. You need to reload your brain with the context after an interruption. The thing being automated away is the time wasted wondering where you left off, or clicking through various windows or views to answer that question. The solution is to track notes of decisions you are making in a searchable set of interlinked note files. This excludes writing them down on paper, since there is no search capability (and filing cabinets and other filing systems are yet another mental distraction). In my case, I use multiple text files that are interlinked (Muse mode in GNU Emacs). This also pays dividends later on when you need to refresh your memory on decisions that were made on the project done months later.

How to install Adobe Flash plugin versus Gnash under 32-bit FireFox 7.0.1 on Debian Linux


Overview


Herein I show a step-by-step procedure to install Adobe Flash plugin into Firefox, and remove the Gnash plugin which seems to be buggy as of 2011-10-08.  The version of Firefox I am using here is not the one that is installed using the Debian package manager, but the Firefox I downloaded directly from the Mozilla website.

Provided below is Procedure followed by the Backstory.

Procedure

  1. Close down Firefox. 
  2. Do step 165  which states: "If you installed via apt-get/aptitude (Debian/Ubuntu): sudo apt-get remove flashplugin-nonfree"
  3. Do step 167:
    1. Type about:config in the address bar and press Enter. 
    2. Find the option plugin.expose_full_path and change the value to "true" (double-clicking the preference name will toggle the setting).
    3. Type about:plugins and locate the flash plugin
  4. If you see the Gnash Shockwave plugin (you will see "gnash" somewhere in the pathname), then you need to continue below and remove it:
    1. Remove the gnash plugin from the Debian installation: sudo apt-get remove browser-plugin-gnash gnash-dbg
  5. Install Adobe Flash plugin:
    1. Download the .tar.gz file from the Adobe website specifically for 32-bit Linux (I did this by disabling all Shockwave plugins, then browsing to YouTube, and then clicking on the link to the Adobe website to find the link specifically for Linux).
    2. Into a temporary directory, extract the tarball via tar zxvf thefile.tar.gz
    3. Copy the file into ~/.mozilla/plugins/libflashplayer.so, overwriting any file that will be there.
  6. Reinvoke Firefox
  7. In the Address field, type about:plugins
  8. You should not see any Gnash references under any Shockwave Flash entry
  9. Test it out on a YouTube video:
    1. Browse to http://www.youtube.com
    2. Right mouse click on the video and insure it does not say HTML5. If it does, keep looking for other videos that are true flash videos.
    3. Right mouse click on the video and it should say "About Adobe Flash player ".
  10. Test it out on http://www.tfd.com/browser
    1. Click on the tiny blue speaker symbol to the right of the "browser" word in the definition. It should pronounce the word.
    2. Right mouse click on the icon and it should also say "About Adobe Flash Player ".

Backstory

I am using the Firefox version 7.0.1 that was downloaded directly from the Mozilla website, and not the one provided by Debian (i.e., I did not want the one rebranded as Iceweasel).  I did this because I want to be able to upgrade Firefox using the built-in Firefox upgrade mechanism versus be held up by the Debian release schedule.




I had recently upgraded my 32-bit laptop to use a recent version of Debian. I reused my existing Firefox installation that was installed into my HOME directory.  Everything was working smoothly, until today when I discovered that clicking on the pronunciation icons for definitions inside the http://www.tfd.com site no longer played the pronunciation links, but Flash YouTube videos would play properly.  This post shows what I did to fix the problem.

This post pertains to Firefox 7.0.1 and not Iceweasel running on a 32-bit Debian system.

From what I can gather, the main problem was that the gnash package was being used as the Shockwave Flash player and not the Adobe Flash player plugin.  Why Gnash could not handle http://www.tfd.com I do not know.

I discovered that there were two different kinds of flash plugin being referenced in my Firefox sessions. This may not be the underlying cause of the problem, but having both in the mix seemed wrong in concept, so this shows how I removed the Gnash plugin from my system, and install the latest version of Adobe Flash plugin.

The key trick is to step 167 which states (grammar editing applied):
  1. Type about:config in the address bar and press Enter. Find the option plugin.expose_full_path and change the value to "true" (double-clicking the preference name will toggle the setting).
  2. type about:plugins and locate the flash plugin.
I saw two flash plugins be displayed from the about:plugins page:
Shockwave Flash
File: /home/brentg/.mozilla/plugins/libflashplayer.so
Version:
Shockwave Flash 11.0 r1
MIME Type    Description    Suffixes
application/x-shockwave-flash    Shockwave Flash    swf
application/futuresplash    FutureSplash Player    spl

Shockwave Flash
File: /usr/lib/gnash/libgnashplugin.so
Version:
Shockwave Flash 10.1 r999.
Gnash 0.8.8, the GNU SWF Player. Copyright (C) 2006, 2007, 2008, 2009, 2010 Free Software Foundation, Inc.
Gnash comes with NO WARRANTY, to the extent permitted by law. You may redistribute copies of Gnash under the terms of the GNU General Public License. For more information about Gnash, see http://www.gnu.org/software/gnash.
Compatible Shockwave Flash 10.1 r999.
MIME Type    Description    Suffixes
application/x-shockwave-flash    Shockwave Flash    swf

Setting the "plugin.expose_full_path" option inside about:config to true is what causes the about:config output above to show the "File:" lines highlighted above.  That was the key information I needed, since with that file path, I could find out what provides the gnash plugin and remove the corresponding Debian packages:

brentg@bg1:~/Downloads/flash$ apt-file search /usr/lib/gnash/libgnashplugin.so
browser-plugin-gnash: /usr/lib/gnash/libgnashplugin.so
gnash-dbg: /usr/lib/debug/usr/lib/gnash/libgnashplugin.so
brentg@bg1:~/Downloads/flash$ sudo apt-get remove browser-plugin-gnash gnash-dbg
Reading package lists... Done
Building dependency tree      
Reading state information... Done
Package gnash-dbg is not installed, so not removed
The following packages will be REMOVED:
 browser-plugin-gnash
0 upgraded, 0 newly installed, 1 to remove and 0 not upgraded.
After this operation, 369 kB disk space will be freed.
Do you want to continue [Y/n]? y
(Reading database ... 116648 files and directories currently installed.)
Removing browser-plugin-gnash ...
I believe that the removal is required so as to prevent Firefox from even considering gnash as the plugin that handles Flash videos when using the Adobe Flash plugin is the one I had intended to use.

I did try step 165 below but it turns out that I did not have the flashplugin-nonfree package(s) installed (but I left in that step in the procedure for completeness).


Sunday, November 28, 2010

YouTranscript for text transcripts of online videos

It's interesting what you stumble upon by accident. I ran across a project the author of Let Over Lambda is working on, called YouTranscript. It is something I've wanted for a long time. It provides transcripts of some technically oriented YouTube videos. What I thought was really interesting is the way the web page for each video highlights the text as the video is playing, and each fragment of text is a clickable entity. For example, 6-Minute Memristor Guide.

Friday, August 14, 2009

Usage of SSH and VLC

This is a followup to an earlier post about VLC in order to elaborate a bit on how I use SSH in that context. First, you need to insure that your SSH works properly from the local to the remote hosts. I am assuming that you know the IP addresses of both hosts here, and both machines are expected to be running Linux. To that end, insure that you can run this command to list files on the remote machine:
echo ls -d .bash\* | ssh -X -Y "REMOTE_USER_NAME@REMOTE_IP_ADDRESS"
You need to change "REMOTE_USER_NAME" to be the username on that remote host, and "REMOTE_IP_ADDRESS" should be the IP address of that remote host (I am using an IP address instead of a hostname to side-step questions discussion about how to set up DNS on your local network given the complexity of DNS). When I do this from my Linux laptop to my Linux desktop, both of which are on my local area network, I simply see a list of files that match the ".b*" expression:
.bash_history
.bash_logout
.bash_profile
.bashrc
Note the backslash in front of the "*" on the command on the local machine, which avoids shell expansion on the local host. If you are able to do that, then you should be able to use the same "echo" command to send vlc commands to the remote host. You may or may not have a SSH agent running on your local system. I do, and it is called seahorse. If you are running GNOME on Debian Linux, it is likely to be available to you by running "seahorse" at a shell command prompt. That seahorse program is an interface to a daemon that runs in the background, handling requests for passwords and such, such that when you request a ssh connection to a remote machine, the seahorse daemon will display an X window dialog box that prompts you for the password for authentication. I'm not exactly sure as to how it determines the password to type in if you don't have a ~/.ssh/ directory setup. If you don't have a .ssh directory, I would encourage you to read up on Linux SSH tutorials on the web for more detailed info. Second, you need to use the ssh command to send a VLC command to stream the AVI file back to the local host, and invoke VLC in GUI mode to receive the stream and display it. Below is the VLC commands I run from the local machine to (a) start the remote VLC session to stream it back, and (b) to start a VLC GUI session locally that will be the receiver:
LOCAL_IP_ADDRESS=you_must_set_this_value
REMOTE_IP_ADDRESS=you_must_set_this_value

# senderVLCCommand is the command we want to execute on the remote
# machine.  I included the sed command that just adds " sender --> "
# to the front of every line so that we can see it on the local
# terminal. Note that although this is placed in the background
# (&), we will still see the "sender" output lines:

senderVLCCommand="vlc -vvv --sout \
  '#std{access=udp,mux=ts,dst=${LOCAL_IP_ADDRESS}:1234}' \\\"$file\\\" 2>&1 \
  | sed 's%^%  sender --> %g'"
sshSenderCommand="echo \"$senderVLCCommand\" \
  | ssh -X -Y \"${REMOTE_USER_NAME}@${REMOTE_IP_ADDRESS}\" sh &"
sh "$sshSenderCommand"

# Note spawn the local VLC session, which will read the stream. Note
# the port number used here in the sender and receiver sessions
# happens to be 1234 (chosen arbitrarily, as long as the number is >
# 1024 and not in use by some other process).

$receiverVLCCommand="vlc -vvv udp://\@:1234 2>&1 | sed 's%^%receiver -->%g' &"
sh "$receiverVLCCommand"

Both commands are put into the background. It has been my experience that this isn't a problem for the sender to start before the receiver starts, as presumably it will block waiting for a receiver to connect to the sender port before transmission starts. Note that for the second command, I use a sed command to prefix "reciever" so that I can monitor errors that occur (and will occur if you have network setup problems or corrupt AVI files, or both). Word of warning: The position slider on the receiver GUI window does not work as you would expect it to. I have not yet found a solution, and would appreciate any comments as to a suitable fix.