Showing posts with label howto. Show all posts
Showing posts with label howto. Show all posts

14 June 2012

automatic mysql backups

On a debian server with mediawiki installed and running with a local mysql.

root@myserver:~# apt-get install automysqlbackup

root@myserver:~# crontab -e

# m  h  dom mon dow   command
  5  4  *   *   *     automysqlbackup


root@myserver:~# automysqlbackup
root@myserver:~# cd /var/lib/automysqlbackup/
root@myserver:/var/lib/automysqlbackup# find .
.
./weekly
./weekly/wikidb
./weekly/information_schema
./daily
./daily/wikidb
./daily/wikidb/wikidb_2012-06-14_16h03m.Thursday.sql.gz
./daily/information_schema
./daily/information_schema/information_schema_2012-06-14_16h03m.Thursday.sql.gz
./monthly


Result! No longer need to write a custom cron script each time.


Project homepage: http://sourceforge.net/projects/automysqlbackup/

22 May 2012

Enabling TCP/IP in SQL Express 2008 R2

Programs > .. R2 > SQL Server Configuration Manager
Network config > Protocols > tcp/ip > enable & properties



Clear the dynamic port under IPAll
Set the TCP Port to 1433 (which is the standard sql server port).

You can then connect to "localhost" (with no instance specified) in management studio.

refs:

16 November 2011

Multiple working folders for git on Windows XP

Multiple working folders for git on Windows XP (lucky me)

It is assumed that you have a git working copy of your project already in place at C:\code\myproject\ and that you want another copy of your project sharing all history but with a different branch checked out at C:\code\othercopy\

This is useful for:
  • rapidly switching between branches where a switch would normally cause a time consuming recompile / rebuild
  • tracking the branch structure of Visual SourceSafe (which you aren't using in this century are you?) aka VSS aka Visual Source Shredder (or maybe TFS)

This can be achieved by use of NTFS symbolic links (other related keywords: junction points, reparse points, hard links). Grab Sysinternals' Junction to provide access to NTFS symbolic links. Extract the contents and put junction.exe on your path.

Word of warning for NTFS symbolic links in Windows XP:
  • Windows Explorer in XP doesn't know about the NTFS symbolic links, and if you delete the containing folder it will delete the real copy of your linked folder (facepalm). Take backups first! You have been warned!
Open a command prompt and run the following commands:
cd c:\code\
mkdir othercopy
cd othercopy
mkdir .git
cd .git

junction hooks C:\code\myproject\.git\hooks
junction info C:\code\myproject\.git\info
junction logs C:\code\myproject\.git\logs
junction objects C:\code\myproject\.git\objects
junction refs C:\code\myproject\.git\refs

C:\code\othercopy\.git>copy C:\code\myproject\.git\* .
If you make a mistake, use "junction -d" to remove the branch point you have created, do not use explorer to delete a branch point as it will delete all your actual files.

You can now go into C:\code\othercopy\ and switch to a different branch, eg in git-bash:
cd c:
cd \code\othercopy\
git branch mynewbranch
git checkout -f mynewbranch
At this point you have two different checkouts sharing the same git data. Yay.

Word of warning for multiple working copies and git-extensions:
    • Git extensions gets confused if you remove a branch that one of your working copies is on; and incorrectly shows the folder as uninitialised. To resolve this use the context menu in explorer or the console to force checkout a different branch.
    This howto was written with "git version 1.7.6.msysgit.0" and git-extensions v2.26.

    References / see also:

    25 October 2011

    LVM + ReiserFS for the win

    LVM + ReiserFS for the win!

    It's so easy to add more space
    root@atom:~
    # lvextend -L +100G /dev/vg2/local
    Extending logical volume local to 200.00 GiB
    Logical volume local successfully resized
    root@atom:~
    # resize_reiserfs /dev/vg2/local
    resize_reiserfs 3.6.21 (2009 www.namesys.com)

    resize_reiserfs: On-line resizing finished successfully.
    root@atom:~
    # df -h /dev/mapper/vg2-local
    Filesystem Size Used Avail Use% Mounted on
    /dev/mapper/vg2-local
    200G 18G 183G 9% /media/local
    root@atom:~

    07 July 2011

    Auto-expanding django formset with jQuery

    As it took me quite a while to get it how I like it, here's the relevant bits for making a django formset (custom markup in a table), that automatically adds rows (formset forms) client-side / in the browser keeping up as you fill in the form.

    Do with the code as you wish, no licence needed.

    In the view (.html file server side) I have:

    @login_required
    def invoiceEdit(request, invoice_id):
    ...
    InlineInvoiceItemsFormSet = inlineformset_factory(Invoice, InvoiceItem, form=DeleteIfEmptyModelForm, formset=DeleteIfEmptyInlineFormSet, can_delete=True, extra=10)
    ...
    itemFormSet = InlineInvoiceItemsFormSet()
    ...
    return render_to_response('foo/edit.html', {'invoiceForm': invoiceForm, 'itemFormSet': itemFormSet, 'invoice': invoice}, context_instance=RequestContext(request))


    In the template I have:

    <script type="text/javascript">
    $(function() {
    setupInvoiceFormset();
    });

    var initialRows;

    function setupInvoiceFormset() {
    initialRows = parseInt($('#id_invoiceitem_set-INITIAL_FORMS').val());
    // remove all but last two empty rows
    resizeInvoiceFormset();
    // add handlers to all inputs to automate row adding
    $('.invoiceItemRow :input').blur(resizeInvoiceFormset);
    }

    const targetExtra = 2; // number of extra rows desired

    function resizeInvoiceFormset() {
    // count the blank rows at the end
    var rows = $('.invoiceItemRow').filter(':not(#templateItemRow)');
    var totalRows = rows.length
    var blankRows = countBlankRows(rows);
    var targetRowCount = totalRows - blankRows + targetExtra;
    targetRowCount = Math.max(targetRowCount,initialRows); // don't trim off real rows otherwise delete breaks
    if (totalRows > targetRowCount) {
    // if there too many blank rows remove the extra rows
    rows.slice(targetRowCount).remove(); // negative to strip from ends
    } else if (totalRows < targetRowCount) {
    // add new blank rows to bring the total up to the desired number
    for (var newRowIndex = totalRows; newRowIndex < targetRowCount; newRowIndex++) {
    addRow(newRowIndex);
    }
    } else {
    return;
    }
    // update the hidden form with the new form count
    $('#id_invoiceitem_set-TOTAL_FORMS').val(targetRowCount);
    }

    function countBlankRows(rows) {
    // count the empty rows from the bottom up, stopping at the first non-blank row
    var blankRows = 0;
    for (var i = rows.length -1; i>=0; i--) {
    if (isEmptyRow(rows[i])) {
    blankRows++;
    } else {
    break;
    }
    }
    return blankRows;
    }

    function isEmptyRow(row) {
    // loop through all the inputs in the row, return true if they are all blank
    // whitespace is ignored
    var inputs = $(row).find(':input').filter(':not(:hidden)');
    for (var j = 0; j < inputs.length; j++) {
    if ($.trim(inputs[j].value).length) {
    return false;
    }
    }
    return true;
    }

    function addRow(newRowIndex) {
    var newRow = $('#templateItemRow').clone(true);
    newRow.addClass('invoiceItemRow');
    newRow.removeAttr('id'); //prevent duplicated template row id
    newRow.show();
    // replace placeholder with row index
    newRow.find(':input').each(function() {
    $(this).attr("name", $(this).attr("name").replace('__prefix__', newRowIndex));
    $(this).attr("id", $(this).attr("id").replace('__prefix__', newRowIndex));
    });
    $('.invoiceItemRow:last').after(newRow);
    }
    </script>
    ...
    {{ itemFormSet.management_form }}
    <tr id="templateItemRow" class="invoiceItemRow" style="display: none;">
    <td><strong>Item:</strong></td>
    <td>
    {{ itemFormSet.empty_form.id }}
    {{ itemFormSet.empty_form.description }}
    {{ itemFormSet.empty_form.description.errors }}</td>
    <td class="price">£{{ itemFormSet.empty_form.price }} {{ itemFormSet.empty_form.price.errors }}</td></tr>
    {% for item in itemFormSet.forms %}
    <tr class="invoiceItemRow">
    <td><strong>Item:</strong></td>
    <td>
    {{ item.id }}
    {{ item.description }}
    {{ item.description.errors }}</td>
    <td class="price">£{{ item.price }} {{ item.price.errors }}</td></tr>
    {% endfor %}
    ...


    The result is a form that intuitively shrinks/grows as the content is added/removed.

    The javascript is of course actually in a separate .js file.

    References:


    Footnote. You may have noticed the delete-if-empty customisation which I like for usability. References for this at

    16 November 2009

    getting supybot to announce new bugzilla bugs

    getting supybot to announce new bugzilla bugs - I've just put here the key non-obvious things that tripped me up when trying to set this up.

    All done on Ubuntu 8.04.3 LTS

    Install supybot and the supybot bugzilla plugin.

    Create a system group (supybot) and user (bugbot) to run supybot as.

    Set up your supybot configuration file as desired.

    Getting supybot to start at startup:
    http://www.schwer.us/journal/2005/04/17/supybot-init-script-for-debian/

    Here's my modified init script

    $ cat /etc/init.d/bugbot
    #! /bin/sh
    #
    # supybot init script
    # http://www.schwer.us/journal/2005/04/17/supybot-init-script-for-debian/
    #

    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    DAEMON=/usr/bin/supybot
    NAME=supybot
    DESC=supybot

    test -f $DAEMON || exit 0

    set -e

    case "$1" in
    start)
    echo -n "Starting $DESC: "
    start-stop-daemon --start --quiet \
    --chuid bugbot --exec $DAEMON -- --daemon /etc/supybot/bugbot.conf
    echo "$NAME."
    ;;
    stop)
    echo -n "Stopping $DESC: "
    start-stop-daemon --stop --quiet \
    --oknodo --exec /usr/bin/python
    echo "$NAME."
    ;;
    restart)
    $0 stop
    $0 start
    ;;
    *)
    echo "Usage: $0 {start|stop|restart}" >&2
    exit 1
    ;;
    esac

    exit 0


    Set up bugzilla to send a copy of all bugmail to a local address (eg bugbot@localhost), and configure exim4 to accept local mail (as well as smart host delivery), using the mbox format.

    sudo dpkg-reconfigure exim4-config

    Start a conversation with bugbot, get it to identify you, then set the required configuration by sending it messages (you can also set these in the supybot .conf file for your bot):
    • config plugins.Bugzilla.mbox /var/mail/bugbot

    • config plugins.Bugzilla.bugzillas.your-bugzilla-name.watchedItems.all True
      which will turn on the announcements (i had to read the code to find that one!)


    Note that supybot doesn't immediately write config changes to disc.

    23 October 2009

    backuppc and windows vista

    Steps I took to get a backuppc server on an ubuntu 8.10 pc in order to be able to back up a windows vista business pc. I've only documented the non-obvious and undocumented items here.
    • Added a user called backup to the vista pc.
    • Added the backup user to the "administrators" group. I tried the "backup operators" group but it didn't give access to the user profiles. It looks like robocopy has some black magic that allows it to bypass ACLs when a member of backup operators.
    • Enabled admin shares (ie \\machine\C$) by adding DWORD registry key "LocalAccountTokenFilterPolicy" to HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Policies\System and setting the value to 1. See How to access Administrative Shares on Vista (C$) by PaulSpoerry
    • Removed the "-N" from the SmbClientFullCmd etc options in backuppc's transfer (xfer) settings as it didn't seem to be using the provided password. Troubleshooting was aided by running "/usr/share/backuppc/bin/BackupPC_dump -v -f vistamachine" directly as user backuppc.
    • Hide the backup user from the welcome screen by adding DWORD HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\SpecialAccounts\UserList\backup with value 0 to the registry. "backup" is the name of the user to hide, 0 means hide, 1 means show.
    enjoy.

    See also:
    Current status: This has only been partially successful so far. The backup runs but has lots of files missing due access denied errors on many of the important folders. It looks like I will have to manually give "backup operators" permissions to these folders. Sigh. Vista is proving to be less than easy for me to support.

    18 December 2008

    password-free ubuntu login with facebrowser

    If you trust everyone who has physical access to a pc (if not then you are encrypting your files, right?) then there seems little point in having to type a password just because more than one user uses the pc.

    So here's how to log in from the gdm "face browser" with a single click.
    Instructions tested with Ubuntu 8.04 Hardy Heron and 8.10 Intrepid Ibex.


    as root, create a new file containing the usernames of all the users you want be able to log in through gdm without entering a password:

    sudo -i
    echo 'username' >> /etc/gdm/nopassusers

    now still as root modify the pam settings for gdm to check this file and allow this user in based on being in the list:
    vi  /etc/pam.d/gdm

    vi /etc/pam.d/gdm

    and modify to contain the new listfile item

    #%PAM-1.0
    auth requisite pam_nologin.so
    auth required pam_env.so readenv=1
    auth required pam_env.so readenv=1 envfile=/etc/default/locale
    auth sufficient pam_listfile.so item=user sense=allow file=/etc/gdm/nopassusers onerr=fail #add this line
    @include common-auth
    auth optional pam_gnome_keyring.so
    @include common-account
    session required pam_limits.so
    @include common-session
    session optional pam_gnome_keyring.so auto_start
    @include common-password

    now simply restart gdm (or the whole machine) and try your new one-click login

    /etc/init.d/gdm restart



    Notes:
    This means the keyring isn't unlocked, so you may have to type in your password anyway before your wireless connects.


    references:
    http://mirror.hamakor.org.il/archives/linux-il/05-2004/10149.html
    http://www.kernel.org/pub/linux/libs/pam/Linux-PAM-html/sag-pam_listfile.html

    24 August 2008

    reseting home folder permissions in ubuntu linux

    If you are like me and my coworkers, you often end up running stuff as root in your home folder and end up not able to access your own files.

    For the record, here's the commands to reset the permissions (leaving all execute flags off, which may not be what you want).
    Warning, this could have undesired side effects. If you have executable files in your home folder that you actually want to be executable, you will have to manually mark them as executable again.

    # Become root (as you don't currently have permissions to modify your own files)
    sudo -i


    # Reset ownership & group to yourself
    chown -R tim:tim /home/tim


    # give yourself the default read-write permissions, set group and other to read only
    chmod -R 644 /home/tim


    # re-apply excecute permissions on all the directories
    find /home/tim -type d -print0 | xargs -0 -II chmod 755 'I'


    # Don't leave your private keys showing:
    chmod -R 700 /home/tim/.ssh


    My latest use for this was after extracting files from my p910i with p3nfs, which as with so many desktop/device tasks needed root to work.

    You could do this slightly more neatly if you know what permissions you have ended up with by using chmod u+w etc so you don't have to re-apply directory permissions, but I wanted to easily guarantee permissions are right regardless of what state they have ended up in.

    It occurs to me it might be sensible to set the sticky bit on the home folders so that anything added by root stays owned by the user. (chmod u+s g+s /home/tim)

    29 May 2008

    sharing work between computers with a usb flash drive and git


    I couldn't find anything exactly matching this on the net when I was figuring it out, so here's what I did.

    This is working against a remote svn (subversion) server, but applies even without one.

    On the first computer, grab your git working copy from svn with git-svn clone (or clone a git repo, or just start a new one).

    mkdir ~/project.git
    cd ~/project.git
    git-svn clone svn://project-server/trunk
    git repack #for good measure


    Plugin your usb flash drive/stick/external harddrive, I'll presume it's a vfat/fat32/fat16 formated device mounted at /media/flash.
    Create an empty repository on the drive, I'll use a bare one as there's no need to keep the working copy as well.

    mkdir /media/flash/project.git
    git --bare init /media/flash/project.git


    Then add the flash drive git repo as a remote source in your local git repo. "flash" is the name I've given to the remote branch reference, you can call it whatever you like.

    git remote add flash /media/flash/project.git

    If you push immediately it will fail (as I discovered) because fat doesn't support the execute flag on files, so all the hooks are automatically active. I deleted all the hooks as I wasn't planning on using them, this may be wrong so no promises, but it seems ok so far for me. So remove the hooks with:

    rm /media/flash/project.git/hooks/*

    Then push your current local copy to the flash drive with:

    git push flash

    This will copy all your committed work onto the flash drive, even if you haven't pushed it upstream to the svn server with "git-svn dcommit" yet. Bonus! It won't copy any of your branches across though, so you if you want them you can add those independently with:

    git push flash mybranch

    Now move over to the second computer and plug the flash drive in. I'm making the same assumptions on paths and devices. Do another completely independent svn checkout as above:

    mkdir ~/project.git
    cd ~/project.git
    git-svn clone svn://project-server/trunk
    git repack #for good measure


    Then add the flash drive's repo to the git repo on the second pc and pull all changes from the flash drive, optionally including any branches:

    git remote add flash /media/flash/project.git
    git pull flash master
    git pull flash mybranch #if you like


    When you've committed changes to git or pulled the latest changes from svn on either pc, you can then update the flash drive with the simple command:

    git push flash

    Which pushes all your changes on your master branch on to the flash drive. You are now ready to run the pull command on the other computer to get back in sync:

    git pull flash master

    If you don't push changes to the flash drive before committing to svn then things will be very simple. If you push changes to the flash drive, and then commit them to the svn server you will need to do a little more work. This is because when you run "git svn dcommit" it pushes your latest git commits to the svn server, deletes your locally committed changes, and then fetches them back from the svn server. This means that git won't recognise your local changes as being the same as the ones on the flash drive because they have different commit message and SHA1 hash. Attempting to push to the flash drive fails with the message "! [rejected] master -> master (non-fast forward)" as the old copy of the commits are still there.

    To resolve this you need to throw away the matching set of changes on the flash drive. To do this you can use git reset as follows, where HEAD~1 should be the number of commits you need to throw away (eg HEAD~3 to throw away the last 3 commits that were pushed to the flash drive):

    cd /media/flash/project.git
    git --bare log #to see how many changes don't have svn information
    git --bare reset HEAD~1


    You can then push your changes as above.

    cd ~/project.git
    git push flash


    I've glossed over subtleties with fetch vs pull, but hopefully you will find this useful.

    This howto makes use of git's ability to pull from multiple sources, and I've found that git quite happily copes with changes that were checked in to svn coming via the flash drive, even when later running "git-svn rebase".

    Please do comment or contact me with any problems, errors, extra info and feedback, and let me know if it was useful.

    17 May 2008

    Removing the execute flag from many files

    Here's how to recursively remove execute permissions on files that have been copied from a windows system.

    find * -type f -exec chmod -x {} \;

    ie, find all files (not directories), and execute a command to remove all execute permissions for each file.

    27 March 2008

    stop motion animation on linux

    A quick howto...
    1. Take a series of photos on your digital camera.
    2. Copy them onto your linux box.
    3. shrink the photos to a more managable size:
      mogrify -verbose -resize 600x400 -quality 60% *.JPG
    4. Preview the animation with animate:
      animate -delay 8 *
    5. Optionally rotate the image to match the exif information from your camera (mine was sideways):
      exiftran -ai *
    6. Convert the jpg files to png:
      mogrify -format png *.JPG
    7. Create the flash animation from the PNG files:
      png2swf -r 15 -o flower2.swf -v -X 399 -Y 600 *.png
    8. Create an html file to hold the animation containing the following:
      <object>
      <param name="movie" value="flower2.swf" />
      <param name="loop" value="true" />
      <param name="quality" value="high" />
      <embed src="flower2.swf" width="399" height="600" />
      </object>
    9. Write a blog article to tell everyone about it ;-)
      "history" is a handy command for reviewing your activities for writing up your achievements.
    And here it is, providing I've kept up with my hosting fees and not been slashodotted:





    28 December 2007

    Preparing photos for a digital picture frame

    Challenge of the day was to fit as many photos as possible on a single flash card to stick in a digital photo frame. Here's how it's done.

    The frame from Philips goes by the memorable name of 9FF2M4 , and by way of a quick review it is very nice. If I were a normal person, I would probably have copied the original 2.5MB / 5 megapixel images to the frame's flash card (1GB Compact Flash in this case, though it can take others), and put up with not being able to fit all the photos on, and having some of them show sideways. But being a perfectionist I instead sacrificed precious sleeping time to figure out what to do. In the end I managed to trim the files down to around 200KB each, and put portrait photos on a black background the right way up in order to save neck ache from squinting at a sideways eiffel tower. This was all done by the power of OSS and bash scripting. Here I present for your convenience the methods I used, and highlight some of the useful things I picked up along the way.

    The first thing that taxed me was what size the photos needed to be to display best whilst taking up minimal space. You would think the answer would be emblazened on the product's box, but no! Philips don't seem to be too keen on promoting the resolution of the display, and even the shop keeper struggled to give me a number. The owner's manual states: "Resolution: 800 x 480 pixels (viewing area 680 x 480)" but after some time experimenting with test images created with the gimp I came to the conclusion that it was impossible to get the frame to display an image pixel perfect as it seemed to be re-scaling every picture regardless of original size. There appears to be no guidance from Philips as to what a good resolution for the photos would be, so after some experimentation I settled on 800x600 as this is slightly higher than the frame's native resolution, and fills the screen nicely without loosing too much off the edges when displayed.

    The frame does not appear to read orientation from the exif data so I looked into rotating all the portrait images to display correctly. I am using the frame in its landscape orientation as that is the form of most of the photos, even though it can be placed in portrait orientation. When a portrait photos is displayed (eg 480x600), the frame puts a fair amount of the image off the top and bottom of the display, and by default puts it on a full white background which is a little hard on the eyes and detracts from darker photos. I therefore opted to create landscape images of 800x600 with a black background for all the portrait photos. I later discovered that you can on this frame change the background colour as follows: Main menu > Slideshow > Background colour > White / Black Grey.

    The process I have used is a little specific to my setup and needs, but hopefully will give you a good starting point. I have created 3 bash scripts that call each other to orchestrate the conversion from my raw photo collection to a new set suitable for the frame, which in turn make use of imageMagick and exiftran to do the work.

    I found out about imageMagick through searching, and tutorials such as HowTo - Batch Image Resize on Linux. The version packaged with Ubuntu 7.10 is quite old, so I ended up building and installing the latest version (6.3.7) from source to get all the functionality I needed.

    exiftran is a nifty utility that reads the exif orientation information in a photo, losslessly rotates the photo to match and then updates the exif data. It is closely related to jpegtran.

    My folder structure in my home folder (so the scripts make sense):
    • scripts (for bash scripts)
    • photos (originals)
      • 2005
        • 2005-12-31 event name
        • etc
      • 2006
      • etc
    • photos_frame (for the modified and shrunk photos which will be copied onto the flash card)
    So without further ado, here's the scripts:

    frame.sh - runs the processing scripts on each year folder of interest
    #!/bin/bash -v
    ~/scripts/frame_photo_folder.sh 2005 ~/photos_frame/
    ~/scripts/frame_photo_folder.sh 2006 ~/photos_frame/
    ~/scripts/frame_photo_folder.sh 2007 ~/photos_frame/


    frame_photo_folder.sh - runs the processing script on subfolder of the year
    #!/bin/bash
    #arg 1 = input folder
    #arg 2 = output folder

    INPUTPATH=$1
    OUTPATH=$2
    cd $INPUTPATH
    if [ ! -d "$OUTPATH$INPUTPATH" ]
    then
    echo creating output folder \"$OUTPATH$INPUTPATH\"
    mkdir $OUTPATH$INPUTPATH
    fi
    for fname in *
    do
    if [ -d "$fname" ]
    then
    if [ ! -d "$OUTPATH$INPUTPATH/$fname" ]
    then
    echo creating output folder \"$OUTPATH$INPUTPATH/$fname\"
    mkdir "$OUTPATH$INPUTPATH/$fname"
    fi
    echo searching for jpg files in \"$fname\"
    cd "$fname"
    find . -maxdepth 1 -type f -name \*.JPG | xargs -iimgfile ~/scripts/frame_photo.sh "imgfile" "$OUTPATH$INPUTPATH/$fname"
    cd ..
    fi
    done

    frame_photo.sh
    • creates output folder(s)
    • copies original photo into output folder
    • uses exiftran to rotate the photo to the correct orientation
    • shrinks the photo to a maximum of 800x600, and fills any remaining space with a black background
    #!/bin/bash

    #arg 1 = photo file name
    #arg 2 = where to put result
    #resizes and pads suitable for a photo frame.

    INPUTFILE=$1
    OUTPATH=$2
    #pwd
    echo copying \"$INPUTFILE\" into \"$OUTPATH\"
    cp "$INPUTFILE" "$OUTPATH"
    cd "$OUTPATH"
    #pwd
    #echo processing \"$INPUTFILE\"
    exiftran -ai "$INPUTFILE"
    convert "$INPUTFILE" -resize '800x600>' -background black -gravity center -extent 800x600 "$INPUTFILE"


    I timed the whole operation using the time command, and copied all output to a log file as follows.

    $ time ./frame.sh 2>&1 | tee frame.log

    The conversion of around 6000 photos took around one and a half hours.

    The concept of redirection of stdout & stderr was neatly explained by the article CLI magic: need redirection?, so now I know that 2>&1 means redirect ouput number two into output number one, in other words redirect stderr into stdout, which then alows you to pipe the whole lot into something else like "tee" (No, not tea, though it may be interesting redirecting my photos into my tea...)

    Add a comment or drop me a line if you find it interesting or useful or if you have any questions or criticisms.

    Update:
    I've worked this script into a small python gui app, check it out at http://github.com/timabell/photo-frame-prep

    09 December 2007

    Enabling TV-Out on Ubuntu Linux 7.10 on a Dell Inspiron 8500

    This weekend, I finally got the tv-out working under linux (Ubuntu 7.10 aka gusty gibbon) on my laptop. Here's what was involved, including some of the (time consuming) red herrings involved in getting this set up.

    I've included the full xorg.conf files for normal display and tv output at the end of this post.

    I used the composite video output as that's what I have cables for. I haven't ever tried the s-video output, and I haven't tried the digital audio output since I divorced microsoft windows and threw her things out into the rain a couple of years ago.

    The quality is pretty poor, but good enough. I think there's a limit of 800x600 for the video out. I'm getting a fair amount of interference on both the video and audio when the laptop is on mains and connected to my amplifier / tv. I'm not sure what the cause it but it's not bad enough to be unusable.

    I installed the nvidia proprietary (that's a negative word in case you don't live in my world) drivers some time ago in order to get 3D acceleration, and I think this is a prerequisite to running the tv-out.

    In my intial investigation I came across nvoption, which in theory allows you to turn on the tv-out on the nvidia cards. I did manage to compile and run it after several hours of trial, error and finding build dependencies but when I finally got it built and running I found that it would seg fault when I hit the "apply" button, hurrah! In the process of playing with nvoption however, I noticed the nv-online page that this person has very generously set up. Reading this it dawned on me that nvoption purely modifies the /etc/X11/xorg.conf file, and that I don't actually need the tool to get tv-out running. I had originally presumed (the brother of all ...) that the nvoption tool did some magical proprietary prodding of the graphics card directly. After a bit of searching to find out where the options should go (the device section), I was then able to use the documentation of options in the second frame of the nv-online page to configure my own X. After a bit of experimenting with different options and lots of restarting of the X server (ctrl+alt+backspace) I was able to get the desired result of the display mirrored/cloned on both the lcd and the television.

    I tried the nvidia-settings gui tool that comes with the proprietary drivers, but it was no use for this task. This tool modifies the xorg.conf file. It did help me recently with a normal dual screen setup (using a crt monitor plugged into the vga port on the laptop), but it was no help for the tv-out, which was not even mentioned in the interface.

    There is a tool called displayconfig-gtk which is fairly new to Ubuntu that allows you to save named display profiles for different configurations (including dual screen, though it didn't quite behave for me). It can be found under System > Administration > Screens and Graphics. This stores an xorg.conf file for each profile in /var/lib/displayconfig-gtk/locations/, and an index file in /var/lib/displayconfig-gtk/locations.conf. This is almost ideal, as I have created a set of xorg.conf files for my various setups, however it doesn't seem to cope with applying these custom xorg files. Additionally nvidia seem to have a weird way of setting the screen to run at its native resolution of 1920x1600, and this tool doesn't cope with it. This was corrected by selecting the right resolution under System > Preferences > Screen Resolution.

    Sadly it looks like there are no tools for easy switching X configuration files, so the process for now is involves manually copying the config files. I've created multiple files in /etc/X11, one for each set up including xorg.conf_lcd and xorg.conf_tv. The switching process is then something along the lines of "cd /etc/X11/", "sudo cp xorg.conf_tv xorg.conf", ctrl+alt+backspace (restart x server).

    If it's any consolation I recall the process in windows involved starting from scratch in a distinctly non-intuitive gui and trying to get a whole load of settings just right, so being able to save the settings is a big step up. I think it took similar amounts of time to get tv-out running under windoze. I guess that's the price we pay for allowing companies to deny us access to the hardware specs so it can be integrated properly. I bought this laptop before I knew how much control I was giving away, and I endeavour not to make such mistakes these days.

    The "designed for windows xp" sticker has been moved to the equally shiny microwave oven which brings me a small piece of joy when I make porridge in the morning.



    xorg.conf for just the laptop screen
    # nvidia-settings: X configuration file generated by nvidia-settings
    # nvidia-settings: version 1.0 (buildmeister@builder3) Mon Apr 16 20:38:05 PDT 2007

    Section "ServerLayout"
    Identifier "Layout0"
    Screen 0 "Screen0" 0 0
    InputDevice "Keyboard0" "CoreKeyboard"
    InputDevice "Mouse0" "CorePointer"
    Inputdevice "Synaptics Touchpad"
    EndSection

    Section "Files"
    RgbPath "/usr/X11R6/lib/X11/rgb"
    EndSection

    Section "Module"
    Load "dbe"
    Load "extmod"
    Load "type1"
    Load "freetype"
    Load "glx"
    EndSection

    Section "ServerFlags"
    Option "Xinerama" "0"
    EndSection

    Section "InputDevice"
    # generated from default
    Identifier "Mouse0"
    Driver "mouse"
    Option "Protocol" "auto"
    Option "Device" "/dev/psaux"
    Option "Emulate3Buttons" "no"
    Option "ZAxisMapping" "4 5"
    EndSection

    Section "InputDevice"
    Identifier "Synaptics Touchpad"
    Driver "synaptics"
    Option "SendCoreEvents" "true"
    Option "Device" "/dev/psaux"
    Option "Protocol" "auto-dev"
    Option "HorizScrollDelta" "0"
    EndSection

    Section "InputDevice"
    # generated from default
    Identifier "Keyboard0"
    Driver "kbd"
    EndSection

    Section "Monitor"
    # HorizSync source: edid, VertRefresh source: edid
    Identifier "Monitor0"
    VendorName "Unknown"
    ModelName "Sharp"
    HorizSync 30.0 - 75.0
    VertRefresh 60.0
    Option "DPMS"
    EndSection

    Section "Device"
    Identifier "Videocard0"
    Driver "nvidia"
    VendorName "NVIDIA Corporation"
    BoardName "GeForce4 4200 Go"
    EndSection

    Section "Screen"
    Identifier "Screen0"
    Device "Videocard0"
    Monitor "Monitor0"
    DefaultDepth 24
    Option "metamodes" "DFP: nvidia-auto-select +0+0"
    SubSection "Display"
    Depth 24
    Modes "1600x1200" "1280x1024" "1024x768" "800x600" "640x480"
    EndSubSection
    EndSection




    xorg.conf for running the tv-out at 800x600, with the laptop displaying the same
    # nvidia-settings: X configuration file generated by nvidia-settings
    # nvidia-settings: version 1.0 (buildmeister@builder3) Mon Apr 16 20:38:05 PDT 2007

    Section "ServerLayout"
    Identifier "Layout0"
    Screen 0 "Screen0" 0 0
    InputDevice "Keyboard0" "CoreKeyboard"
    InputDevice "Mouse0" "CorePointer"
    Inputdevice "Synaptics Touchpad"
    EndSection

    Section "Files"
    RgbPath "/usr/X11R6/lib/X11/rgb"
    EndSection

    Section "Module"
    Load "dbe"
    Load "extmod"
    Load "type1"
    Load "freetype"
    Load "glx"
    EndSection

    Section "ServerFlags"
    Option "Xinerama" "0"
    EndSection

    Section "InputDevice"
    # generated from default
    Identifier "Mouse0"
    Driver "mouse"
    Option "Protocol" "auto"
    Option "Device" "/dev/psaux"
    Option "Emulate3Buttons" "no"
    Option "ZAxisMapping" "4 5"
    EndSection

    Section "InputDevice"
    Identifier "Synaptics Touchpad"
    Driver "synaptics"
    Option "SendCoreEvents" "true"
    Option "Device" "/dev/psaux"
    Option "Protocol" "auto-dev"
    Option "HorizScrollDelta" "0"
    EndSection

    Section "InputDevice"
    # generated from default
    Identifier "Keyboard0"
    Driver "kbd"
    EndSection

    Section "Monitor"
    # HorizSync source: edid, VertRefresh source: edid
    Identifier "Monitor0"
    VendorName "Unknown"
    ModelName "Sharp"
    HorizSync 30.0 - 75.0
    VertRefresh 60.0
    Option "DPMS"
    EndSection

    Section "Device"
    Identifier "Videocard0"
    Driver "nvidia"
    VendorName "NVIDIA Corporation"
    BoardName "GeForce4 4200 Go"
    Option "TwinView" "1"
    Option "TwinViewOrientation" "Clone"
    Option "MetaModes" "800x600, 800x600;"
    Option "TVStandard" "PAL-I"
    Option "ConnectedMonitor" "DFP,TV"

    EndSection

    Section "Screen"
    Identifier "Screen0"
    Device "Videocard0"
    Monitor "Monitor0"
    DefaultDepth 24
    #Option "metamodes" "DFP: nvidia-auto-select +0+0"
    SubSection "Display"
    Depth 24
    Modes "1600x1200" "1280x1024" "1024x768" "800x600" "640x480"
    EndSubSection
    EndSection

    03 September 2007

    Creating a blogroll

    Update 11th Sep 2007:
    xsession responded to my support request, and the opml file is now served, complete with the correct mime type.


    Update 26th Dec 2009
    Now on a linux host so no mime type issues now.

    Podcast list added: podcasts.opml.

    Now styled with custom xslt file opml.xsl.


    As people may want to see my rss and podcast subscriptions, I have created a blogroll for you.

    I've started with an OPML file, created by hand and uploaded to my web host. Unfortunately my web host won't (currently) serve the ".opml" file extension so I've had to use .txt.

    so http://www.timwise.co.uk/blogroll.opml became http://www.timwise.co.uk/blogroll.opml.txt

    I then validated the file with http://validator.opml.org/
    I then added my feed to http://share.opml.org/ so you can now see the list at http://share.opml.org/viewsharedfeeds/?user_id=7189
    In the opml I've separated podcasts and news feeds, but share.opml doesn't use this info.

    There is some controversy over opml, but hell, it does the job. We can all upgrade when a better alternative goes mainstream.

    Useful references:
    http://www.kbcafe.com/rss/?guid=20051003145153
    http://www.rss-tools.com/opml-generators.htm
    http://www.bioneural.net/2005/10/09/iblog-opml-bloglines-reading-list/
    http://nayyeri.net/archive/2007/02/17/create-a-blogroll-from-opml-files.aspx

    02 July 2007

    Blocking web adverts

    A friend asked me to write this up.

    To remove all those annoying adverts from the web as you see it:


    Job done. Thanks for listening.

    Ubuntu screen locking

    Howto prevent ubuntu locking the screen when closing the laptop lid.

    Thanks to jrib in irc://freenode.net/#ubuntu for this one.

    • Run gconf-editor (with alt+F2)

    • Go to or search for /desktop/gnome/lockdown

    • Tick disable_lock_screen

    • Restart gnome (ctrl+alt+backspace - after saving your documents it's a bit brutal!)