Archive for the 'Code Samples' Category

I use MediaCoder for most of my encoding/transcoding of video for playback on my PC and other devices. The N800 has a peculiar set of parameters for it’s video - if it doesn’t match up then it either won’t play back or will be very choppy.

I ended up selling the N800 but I thought I would pass this profile along to anyone who might use it.

<?xml version="1.0" encoding="UTF-8"?>
<MediaCoderPrefs>
  <node key="overall">
    <node key="generic">
      <node key="autoRevert">
        <value>Never</value>
      </node>
    </node>
    <node key="ui">
      <node key="optionTab">
        <value>3</value>
      </node>
      <node key="param">
        <value>1069,767,47,50</value>
      </node>
      <node key="noWelcome">
        <value>4068</value>
      </node>
    </node>
    <node key="task"/>
    <node key="output"/>
    <node key="tagging"/>
    <node key="subtitle"/>
    <node key="decoding"/>
    <node key="audio"/>
    <node key="video">
      <node key="format">
        <value>XviD</value>
      </node>
    </node>
    <node key="container">
      <node key="format">
        <value>AVI</value>
      </node>
    </node>
    <node key="mplayer"/>
    <node key="preview"/>
    <node key="plugin"/>
    <node key="presets"/>
    <node key="httpd"/>
    <node key="server"/>
  </node>
  <node key="audiosrc">
    <node key="mplayer"/>
    <node key="winamp"/>
    <node key="lame"/>
    <node key="wavefile"/>
  </node>
  <node key="audioenc">
    <node key="lame"/>
    <node key="vorbis"/>
    <node key="faac"/>
    <node key="aacplus"/>
    <node key="nero"/>
    <node key="helix"/>
    <node key="helixmp3"/>
    <node key="fraunhofer"/>
    <node key="speex"/>
    <node key="musepack"/>
    <node key="ffmpeg"/>
    <node key="aac3gpp"/>
    <node key="amr"/>
    <node key="wavpack"/>
    <node key="flac"/>
    <node key="ape"/>
    <node key="tta"/>
    <node key="als"/>
    <node key="ofr"/>
    <node key="pcm"/>
    <node key="cli"/>
  </node>
  <node key="videosrc">
    <node key="mplayer"/>
    <node key="avisynth"/>
  </node>
  <node key="videoenc">
    <node key="xvid"/>
    <node key="x264"/>
    <node key="mencoder"/>
    <node key="ffmpeg"/>
    <node key="theora"/>
    <node key="dirac"/>
    <node key="amv"/>
    <node key="vfw"/>
    <node key="dumper"/>
    <node key="wm"/>
    <node key="remote"/>
  </node>
  <node key="container">
    <node key="mp4box"/>
    <node key="matroska"/>
    <node key="mencoder"/>
    <node key="mp4creator"/>
    <node key="atom"/>
    <node key="pmp"/>
    <node key="vcd"/>
  </node>
  <node key="audiofilter">
    <node key="resample"/>
    <node key="equalizer"/>
    <node key="channels"/>
    <node key="volume"/>
    <node key="surround"/>
    <node key="compressor"/>
    <node key="delay"/>
    <node key="extraStereo"/>
    <node key="extra"/>
    <node key="shibatch"/>
  </node>
  <node key="videofilter">
    <node key="scale">
      <node key="enabled">
        <value>true</value>
      </node>
      <node key="width">
        <value>352</value>
      </node>
      <node key="height">
        <value>288</value>
      </node>
    </node>
    <node key="crop"/>
    <node key="expand"/>
    <node key="frame"/>
    <node key="eq"/>
    <node key="postproc"/>
    <node key="rotate"/>
    <node key="itf"/>
    <node key="denoise"/>
    <node key="unsharp"/>
    <node key="delogo"/>
    <node key="screenshot"/>
    <node key="thumb"/>
    <node key="extra"/>
  </node>
</MediaCoderPrefs>

You can also download the file here: N800.xml

I created this Bash script as a project for the system administration course I’m taking for the summer. I’m sure there are bugs in it, so let me know if you find any.

It basically uses an XML configuration file, which includes the source, destination, and any excludes from the transfer. You then pass either -u or -d (upload or download) and the options -x (delete if not in source) and -f (force). Destination can be local or remote, but source must be local.

Here is the code:

#!/bin/bash
## Transfer Script
## By David Drager
## CSC586: Summer II 2008
## Requires: xml2, rsync

## Settings
tempdir="/tmp/"
rsynccommand="/usr/bin/rsync"

## Usage command
usage="usage: transfer.sh [options] <config-file>.xmlnoptions:n  -d or -u:t download or upload, resp. one and only one must be presentn  -f:ttforce transfer regardless of 'newness' of filen  -x:ttdelete items in target not present in source"

# Check to make sure temporary directory exists
[ -d $tempdir ] || { echo -e "Error: Could not locate a temporary directory. See file settings."; exit 1; }

# Usage Command
[ $# -eq 0 ] && { echo -e "ERROR: Needs at least the -d or -u flag plus a config file.nn$usage"; exit 1; }

## Get options passed to the program
while getopts "dufx" flag
do
  [ "$flag" = "?" ] && echo -e "ERROR: Flag(s) not valid.nn$usage" && exit 1;
  eval "opt_$flag=1"
done
shift $((OPTIND-1))
configfile="$1"

if [ "$opt_d" = 1 ] && [ "$opt_u" = 1 ]
then
  echo -e "Error: Use either -u Upload or -d Download, but not bothn$usage"; exit 1;
elif  [ "$opt_u" = "" ] && [ "$opt_d" = "" ]
then
    echo -e "Error: Use either -u Upload or -d Download, but not bothn$usage"; exit 1;
fi

if [ "$opt_f" = 1 ]; then
  force=1
fi

if [ "$opt_x" = 1 ]; then
  deltar=1
fi

## Make sure config file is located
if [ "$configfile" != "" ]
then
  [ -f "$configfile" ] || { echo -e "Error: Config file not found.n$usage"; exit 1; }
else
   echo -e "Error: Config file not specified.n$usage"; exit 1;
fi

## End of swich verification

# echo Action: "$action"
# echo Force: "$force"
# echo Delete Target Files: "$deltar"
# echo Config: "$configfile"

## Now read config file

## Set temp file for XML parsing
tempfile="$tempdir"transferscript_$$
tempexcludes="$tempdir"transferscriptexcludes_$$
# echo -e "Temp:$tempfile"

# Run config file through xml2
xml2 < "$configfile" > "$tempfile"

[ -f "$tempfile" ] || { echo -e "There was a problem processing the XML file."; exit 1; }

# Make sure that source and destination are found
excludelist=""
while read line; do
    key=$(echo $line | awk -F '=' '{print $1}')
    value=$(echo $line | awk -F '=' '{print $2}')
    if [ "$key" = "/sync/@src" ]; then
      source="$value";
    elif [ "$key" = "/sync/@dst" ]; then
      destination="$value"
      # Add any exclude options to array
    elif [ "$key" = "/sync/exclude" ]; then
      tempexcl=("$value")
      excludelist=("${excludelist[@]}" "${tempexcl[@]}")
    fi
done < "$tempfile"

[ "$source" ] || { echo "Error: Config file must include a source"; exit 1; }
[ "$destination" ] || { echo "Error: Config file must include a destination"; exit 1; }

source="$source/"
destination="$destination/"

[ -d "$source" ] || { echo "Error: Source must be a local directory"; exit 1; }

excludes=""
excludes=${excludelist[@]}

# echo Excludes: "(${#excludelist[@]}): $excludes"

## Clean up temp file from xml process
rm "$tempfile"

## Build up the command line

[ -f "$rsynccommand" ] || { echo -e "Error: Could not locate rsync command."; exit 1; }

fullcommand="$rsynccommand"
fulltestcommand="$rsynccommand"

if [ "$opt_f" == "1" ]
then
    fulltestcommand="$fulltestcommand -nva"
    fullcommand="$fullcommand -a"
else
    fulltestcommand="$fulltestcommand -nvau"
    fullcommand="$fullcommand -au"
fi

if [ "$opt_u" == "1" ]
then
  fileorder="$source $destination"
  echo "Evaluating transfer from $source ==> $destination"
elif [ "$opt_d" == "1" ]
then
  fileorder="$destination $source"
  echo "Evaluating transfer from $destination ==> $source"
fi

[ "$opt_x" == "1" ] && { fulltestcommand="$fulltestcommand --delete"; fullcommand="$fullcommand --delete"; }

## Move exclude list to a file.
## This duplicates as above but I originally thought we were passing it to rsync as a list and not as a file.

[ "${#excludelist[@]}" -gt 0 ] && {
    tempfile="$tempdir"transferscript_$$
    touch "$tempfile"
    echo "$excludes" | tr " " "n" > "$tempfile"
    fulltestcommand="$fulltestcommand"" --exclude-from=$tempfile"
    fullcommand="$fullcommand"" --exclude-from=$tempfile"
}

fulltestcommand="$fulltestcommand $fileorder"
fullcommand="$fullcommand $fileorder"

# We only want lines minus top line and bottom 3 lines
testresult=`$fulltestcommand | tail --lines=+2 | head --lines=-3`

# If this is empty, then notify that no files would be transferred.
 [ "$testresult" ] || { echo "This command would not transfer any files. Script exiting."; rm "$tempfile"; exit 1; }

# Display changes
echo -e "Changes to be made:n--------------------n$testresultn--------------------"

# Check to see if we really want to run the command.
echo "Do you wish to perform this command? $fullcommand (y/n)[y]"
read confirm
if [ "$confirm" = "y" ] || [ "$confirm" = "" ]
then
    echo "Performing transfer..."
    # Without -v this will not output anything.
    $fullcommand
    echo "Transfer complete."
    rm "$tempfile"
else
    echo "Cancelling transfer..."
    rm "$tempfile"
fi

exit 0

Here is the sample config file:

<sync src="/home/dir/bash-prog/dir1/" dst="login@some.machine:/home/dir/dir2">
        <exclude>
          .test3
          another.*
        </exclude>
</sync>

The AskApache blog has a great comprehensive guide to .htaccess. A must read for anyone who does a lot of work with Apache.

http://www.askapache.com/htaccess/apache-htaccess.html

Windows lacks the linux ’shutdown’ command, so it is a pain to get it to schedule a reboot in the future. Linux’s shutdown command make this easy, just issue the command ’shutdown -r +60′ for example to reboot an hour in the future.

No such luck in Windows, you need to download a separate program to do this. It is a sysinternals program, you might remember sysinternals from such utilies like FileMon and ProcessMonitor.

The program we use for this is called PsTools and more specifically the file psshutdown.exe.

[Download PsTools here]

Place psshutdown.exe into a directory for future use, for this example we will use c:\tools\.

Then open a command prompt and type the following command:

at 2:00am c:\tools\psshutdown.exe -r -f -c -t 10 /accepteula

This will result in:

Added a new job with ID = 1

You can verify this task has been added by looking at the Scheduled Tasks - the job name will be At1 if you haven’t scheduled any other tasks via the command line.

If all goes will, Windows will reboot at 2:00am, or your specified time.

For some reason, Firefox started to display a blinking cursor, like web pages I have been viewing were editable. Thinking that some errant plugin was causing this behavior, I manically disabled a few I had recently installed. However that didn’t fix the problem.

Good ole Google to the rescue.

Firefox has a ‘feature’ that lets you select text with more visual feedback. I guess the little one must have been hitting keys and turned this on.

Turning it off is easy! Press F7 to turn off caret browsing.

Alternatively, type “about:config” in the URL area, then filter for “caret“. Change accessibility.browsewithcaret to “false”.

Wow - I get so frustrated when I try to copy some files over old ones and I get:

[root@server1 wordpress]# cp -Rf * ../public_html/
cp: overwrite `../public_html/license.txt'? y

-R is recursive, but -f is supposed to copy over without confirmation. What could it be?!

Check out your alias command using ‘alias’:

[root@server1 wordpress]# alias
alias cp='cp -i'

Sure enough - alias is set on Redhat Based systems into -i, or interactive mode. Remove this alias with ‘unalias cp’ and it will be removed.

Happy copying!

In case you were wondering, I just invented the phrase PVPN - Personal Virtual Private Network.

I use Hamachi to connect my work, home and laptop PCs and I’ve found it invaluable over the past few years for a number of reasons. Music over VPN, Remote Desktop/VNC over VPN, and more. So now, I’d like to join my N800 to this growing network to make easy and secure access and file transfer wherever I am connected.

Fortunately the folks at Logmein have compiled a client for the N770, and this also works on OS2008 on the N800 (Let me know on the N810).

This is an alternate take on the wiki article at Logmeinwiki.

Note: For the commands below I will have assumed that you have already installed the openssh server so you can access the N800 via an SSH client with root access. You can also use the built in Xterm and gainroot but it is a pain in the ass typing all of those commands in via the touchpad. If you are using gainroot some of the directories below will change, for example Hamachi will install in /home/user/.hamachi instead of /root/.hamachi. Also I downloaded the client to my memory card in /media/mmc2/ but you can put it anywhere.

Your login should look like this:

BusyBox v1.6.1 (2007-09-27 18:08:59 EEST) Built-in shell (ash)
Enter 'help' for a list of built-in commands.

Nokia-N800-51-3:~#

Make sure wget is installed:

apt-get install wget

Make to get the latest Logmein Client from http://files.hamachi.cc/linux/nokia-770/.

Just follow my process below for installing the Hamachi client and joining your network.

Nokia-N800-51-3:/media/mmc2/tmp# wget http://files.hamachi.cc/linux/nokia-770/hamachi-0.9.9.9-20-lnx-n770.tar.gz
--10:31:47-- http://files.hamachi.cc/linux/nokia-770/hamachi-0.9.9.9-20-lnx-n770.tar.gz
= `hamachi-0.9.9.9-20-lnx-n770.tar.gz'
Resolving files.hamachi.cc... 72.5.76.16
Connecting to files.hamachi.cc|72.5.76.16|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 116,020 (113K) [text/plain]

100%[==========] 116,020 256.95K/s

10:31:48 (256.33 KB/s) - `hamachi-0.9.9.9-20-lnx-n770.tar.gz' saved [116020/116020]

Nokia-N800-51-3:/media/mmc2/tmp# tar zxvf hamachi-0.9.9.9-20-lnx-n770.tar.gz
hamachi-n770-0.9.9.9-20/
hamachi-n770-0.9.9.9-20/LICENSE
hamachi-n770-0.9.9.9-20/README
hamachi-n770-0.9.9.9-20/LICENSE.tuncfg
hamachi-n770-0.9.9.9-20/LICENSE.openssh
hamachi-n770-0.9.9.9-20/LICENSE.openssl
hamachi-n770-0.9.9.9-20/hamachi
hamachi-n770-0.9.9.9-20/tuncfg/
hamachi-n770-0.9.9.9-20/tuncfg/Makefile
hamachi-n770-0.9.9.9-20/tuncfg/tuncfg.c
hamachi-n770-0.9.9.9-20/tuncfg/tuncfg
hamachi-n770-0.9.9.9-20/CHANGES
hamachi-n770-0.9.9.9-20/install
Nokia-N800-51-3:/media/mmc2/tmp# cd hamachi-n770-0.9.9.9-20/
Nokia-N800-51-3:/media/mmc2/tmp/hamachi-n770-0.9.9.9-20# sh install

install: line 7: HAMACHI_DST: not found
Copying hamachi into ..
Creating hamachi-init symlink ..
Copying tuncfg into /sbin ..

Hamachi is installed. See README for what to do next.

Nokia-N800-51-3:/media/mmc2/tmp/hamachi-n770-0.9.9.9-20#
Nokia-N800-51-3:/media/mmc2/tmp/hamachi-n770-0.9.9.9-20# cd
Nokia-N800-51-3:~# tuncfg
Nokia-N800-51-3:~# hamachi-init
Initializing Hamachi configuration (/root/.hamachi). Please wait ..

generating 2048-bit RSA keypair .. ok
making /root/.hamachi directory .. ok
saving /root/.hamachi/client.pub .. ok
saving /root/.hamachi/client.pri .. ok
saving /root/.hamachi/state .. ok

Authentication information has been created. Hamachi can now be started with
'hamachi start' command and then brought online with 'hamachi login'.
Nokia-N800-51-3:~# hamachi start
Starting Hamachi hamachi-lnx-n770-0.9.9.9-20 .. ok
Nokia-N800-51-3:~#

Hamachi is now running on our little tablet!

But it has not joined our network at this point, so we follow the logmein Hamachi documentation to do so.

Nokia-N800-51-3:~# hamachi set-nick DaveN800
Setting nickname .. ok
Nokia-N800-51-3:~# hamachi login
Logging in ....>....... ok
Nokia-N800-51-3:~# hamachi join YourNetwork
Password:
Joining YourNetwork .. ok
Nokia-N800-51-3:~# hamachi go-online YourNetwork
Going online in YourNetwork .. ok
Nokia-N800-51-3:~#

And now…checking other Hamachi clients, shows our little device is online!

hamachi on n800

Now we need to tell our tablet to put hamachi online whenever we restart the system and also set the keepalive lower.

To lower the keepalive:

Nokia-N800-51-3:~/.hamachi# echo "KeepAlive 20" >> ~/.hamachi/config

This is all great, and you should be online now. But you would need to start Hamachi on every reboot which isn't going to cut it. We will add the Hamachi start process to the init scripts. Add the following lines to the file '/etc/init.d/rcS' right before the line which says 'exit 0'

<code>/sbin/tuncfg;/usr/bin/hamachi -c /root/.hamachi start

In order to do this, use VI.

vi /etc/init.d/rcS

  • Press capitol ‘G‘ to scroll to bottom of the file
  • type ‘i‘ to enter insert mode
  • hit up a few times to a blank line before exit 0, or hit enter at the beginning of the line to create a new line.
  • Paste the above line into the file
  • Press “esc” using the special xterm button, or hit escape if you are using ssh.
  • type “:wq!” — this command enters the command, mode, tells it to write the file, then quit and execute

That should be all you need! Power off the N800 and power it back up. After restarting your N800 you should see it connect to your PVPN Hamachi network and be online!

Let me know if you have any problems or comments about the above installation procedure!

If you upload those new fancy-shmancy file formats to your web server - namely .docx, .pptx and .xlsx - and you are running Apache; chances are that your web server doesn’t know how to serve those files because they are unknown file formats. Your browser may try to download them as a .zip file (IE) or just display the binary format (Firefox) which ends up looking like jibberish with some XML data.

It’s relatively easy to fix this problem, you just need to tell apache how to handle those files.

Find the file mime.types, this may be in /etc/ or in /etc/httpd/conf/.

Add the following line to this file:

application/vnd.openxmlformats docx pptx xlsx

In one line:

echo "application/vnd.openxmlformats docx pptx xlsx" >> /etc/httpd/conf/mime.types

Restart both Apache and your web browser. Clearing the cache doesn’t work (I learned the hard way :))

Your file should now be downloaded properly to your PC.

The goal here is to watermark all images in a certain directory, except for thumbnails or other selection. You can either do this on each file prior to placing on your webserver - which is probably wise for CPU load issues - but let’s just say you want to do this for all files served in a single directory dynamically, a gallery for example.

The first step is to create a .png file with transparency which holds your watermark image. For this exercise, I’ve created this image:

tbwm.png

(I’ve added the border to stand the image out from the background of the page).

Here is the original image we are going to test with:

boratwow.jpg

After we have our watermark and sample image, we need to write a php file to use PHP’s GD function to apply this image to our original image. The particular function we use is imagecopy(). Here is the code I am using, I name it w.php:

<?php

$basedir="/home/user/public_html/com/gallery/";
$watermarkimage="tbwm.png";

$file=basename($_GET['i']);

$image = $basedir."/".$file;
$watermark = $basedir."/".$watermarkimage;

$im = imagecreatefrompng($watermark);

$ext = substr($image, -3);

if (strtolower($ext) == "gif") {
if (!$im2 = imagecreatefromgif($image)) {
echo "Error opening $image!"; exit;
}
} else if(strtolower($ext) == "jpg") {
if (!$im2 = imagecreatefromjpeg($image)) {
echo "Error opening $image!"; exit;
}
} else if(strtolower($ext) == "png") {
if (!$im2 = imagecreatefrompng($image)) {
echo "Error opening $image!"; exit;
}
} else {
die;
}
imagefilledrectangle($im2, 0 , (imagesy($im2))-(imagesy($im)) , imagesx($im2) , imagesy($im2) , imagecolorallocatealpha($im2, 0, 0, 0, 100) );
imagecopy($im2, $im, (imagesx($im2)-(imagesx($im))), (imagesy($im2))-(imagesy($im)), 0, 0, imagesx($im), imagesy($im));

$last_modified = gmdate('D, d M Y H:i:s T', filemtime ($image));

header("Last-Modified: $last_modified");
header("Content-Type: image/jpeg");
imagejpeg($im2,NULL,95);
imagedestroy($im);
imagedestroy($im2);

?>

This file is placed in the images directory.

Also in the images, create an .htaccess file with the following code:

RewriteEngine on
RewriteRule ^([^thumb].*\.[jJ].*)$ /com/gallery/w.php?i=$1

This tells the web server that instead of serving jpg files out of this directory, that we should instead process the filename with w.php and then serve to the browser. It also adds in a clause that if it starts with thumb_, that it will not run on this file. This is so it does not run on thumbnails.

Here is the resulting image, with watermark! This is served right out of an image directory with no watermark on the original picture:

Borat with watermark from php

Let’s say you use a piece of software which is horribly designed (or maybe you just don’t know how to use it properly) and you need to click a button thousands of times.

See specifics below if your are curious of my particular predicament!

Instead of clicking your mouse button like a crazy person - you can automate this task using software such as AutoHotKey. Using this software, it allows you to create a keyboard shortcut that lets you do a number of things without human intervention. This is handy for just about any sort of automated tasks where you find yourself clicking alot.

These instructions are for getting your mouse to click at a particular point on your screen a number of times.

Install AutoHotKey

First step of course is to install AutoHotKey.

Figure out where you need to click

Launch the included program AutoIt3 Window Spy. This will start reporting a bunch of information to you including Window Title and Class, Mouse Position, and other information that is useful if you are creating a more complicated AutoHotKey script.

Point the mouse to the Window where you want to click a bunch of times, at the place you wish to click. Make sure the window is active - this is important as we want to be specific as to where we click. Write down the coordinate for the “In Active Window”.

Create the Script

When you first run AutoHotKey (AHK from now on) it will ask you if you want to create a sample script in My Documents. Go ahead and do this.

At the bottom of this screen, add the following line:

!g::Click x,y,n

Where x = X coordinate, y = Y coordinate, and n = the number of times you want to click. For example in my use I used !g::Click 334,333,3000 which clicks in the active window at 334,333 exactly 3000 times.

!g means that the key combination will be Alt-G

Save this file and then Run AHK again. This will load it into memory.

Activate the window you wish to click in - then press Alt-G (at the same time)

Clicks away….

Your PC will click however many times in the active window at the specified location. Now your mouse will not wear down from the clicking and your time will also be saved!

Warning: Rant: This is why I needed to do this. The ever-fabulous Adobe Photoshop Elements does not have a great system to change your disk file structure. So when I wanted to change my photos directory from having lots of directories like 2006-01-23-10234323 into subdirectories like 2006/2006-01-23-10234323, it does not provide an easy way to do this. I wish it had advanced folder management like the MP3 Library Manager Media Monkey does - it allows you to rebuild your folders based on date, album, title, and just about every other piece of data imaginable. So when I did this manually and then wanted to “Reconnect” my photos to the correct location on the disk - Photoshop Elements has a horrible reconnect dialog that makes you click “Reconnect” on every picture you want to reconnect. I couldn’t find a way around this.

  • Welcome to systemBash, a technology and system administration blog by David Drager. If you enjoy this sort of content, can can subscribe to the RSS using the link to the right.