Seneca Research Papers

During my time at Seneca, I had the chance to explore pretty much any topic related to my program (Informatics and Security). Given that I do enjoy messing around with code, even though I’m not a programmer, I was able to choose topics that captured my true interests related to computers: security, crypto, coding and networking. Here are two of the papers I wrote during my time at Seneca College.

Summer Research Paper: Building a Vulnerable Website to Inspire a Hacker Mindset
Tags: CSS / HTML / JavaScript / PHP / C / Assembly

Final Bachelor Thesis: Implementing Cryptographic Algorithms to Achieve Secure LAN Communication
Tags: C / Curses / DHKE / ARC4 / SHA256 / HMAC / GMP / UDP

Anyway, I just thought I’d publish them just in case anyone is bored and would like to read some of the work I did throughout my 4 years here. Thanks for reading my blog as always!

Jon Chiappetta

Seneca Research Papers

ARMv5 Assembly and a Simulated Buffer Overflow

So I get bored really really easily, especially when I’m at home alone for long periods of time with nothing to do (I should really get an xbox or playstation soon)… Anyway, I just wanted to see how hard it was to convert my extremely basic x86 assembly knowledge to ARM. Here is a basic tutorial on achieving a basic buffer overflow on an ARMv5 platform!

Some initial things to consider before exploiting (I haven’t done all of these steps below but you should!)

  • syntax style (at&t or intel)
  • compatible assembler and linker program
  • no dynamic function calls or shared library dependence (static code only)
  • function or method argument passing (registers or stack)
  • linux syscall numbers (kernel interrupts)
  • statically determined references to potential data areas
  • no null bytes in the final shellcode or machine code

Below is a really basic ARM compatible assembly program. It makes a call out to the write() method and passes the arguments in via the available registers. It makes reference to the data string at the end of the executable by using a static offset from the program counter during the time of execution. It then uses ARM’s version of the software interrupt call to get the kernel’s attention…

$ cat sc.s

.text

.global _start
_start:
	mov %r7, $4
	mov %r0, $1
	mov %r1, %pc
	add %r1, #20
	mov %r2, $12
	swi $0

	mov %r7, $1
	mov %r0, $0
	swi $0

	.string "hello world!"

To compile, link and dump the shellcode, you can run the following commands below (sorry for the huge perl one liner but I was too lazy/tired to hand format the output).

$ as -o sc.o sc.s && ld -o sc sc.o
# print shellcode words in reverse so that when it is stored in the chr array and accessed as an int word item it is read backwards (little endian)
$ objdump -d sc | grep -iv 'file format' | grep -i '[0-9a-f][0-9a-f]*:' | awk '{ print $2 }' | perl -e '$line=" ";while($line){$line=<STDIN>;$line =~ s/[\r\n]+//g;$code="";for($x=(length($line)-2);$x>-1;$x-=2){$code.=("\\x".substr($line,$x,2));}$code.="";printf("$code\n");}'

After getting the shellcode from the above command we can move on to playing with the victim. Here’s an amazingly feature packed program which reads any data it can from standard input and puts it in a pre-sized stack based variable. It then copies the data from the stack variable into a heap based variable and executes whatever is in it for good measure. We really want the attacker to succeed here people!

$ cat ex.c

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <strings.h>
#include <unistd.h>

void user(char *buff)
{
	char stac[64];
	read(0, stac, 256 * sizeof(char));
	bcopy(stac, buff, 64 * sizeof(char));
}

int main()
{
	char *heap = malloc(64 * sizeof(char));
	int (*ret)();

	user(heap);
	printf("self-exec\n");

	ret = (int(*)())heap;
	(int)(*ret)();

	return 0;
}


$ gcc -Wall -o ex ex.c

$ printf '\x04\x70\xa0\xe3\x01\x00\xa0\xe3\x0f\x10\xa0\xe1\x14\x10\x81\xe2\x0c\x20\xa0\xe3\x00\x00\x00\xef\x01\x70\xa0\xe3\x00\x00\xa0\xe3\x00\x00\x00\xef\x68\x65\x6c\x6c\x6f\x20\x77\x6f\x72\x6c\x64\x21' | ./ex

self-exec
hello world!

Exercise for the reader: Actually overflow the stack variable above and overwrite the return pointer before the self-exec part gets called to achieve a true buffer overflow attack. Tip: you may need to disable certain security features like DEP/NX-bit, ASLR and stack canaries. Also, always remember that return-to-libc is your friend!

As you can see above, this is just the extreme basics and real attackers are insane in what they can actually achieve without having to setup what I did above. Imagine having that program listening on a socket file descriptor instead of standard input and imagine sending it exec() based shell code which could make a system call out to netcat allowing it to listen on a new port as well as passing any of its socket data to a shell program like bash. Or maybe a system call out to wget and then an execution of the downloaded file as root possibly which could then result in bad things happening. Anyway…

I know this is all very noob’ish code but I plan to keep working on it,
Also thanks for reading my stuff!

Johnny Stoops

ARMv5 Assembly and a Simulated Buffer Overflow

Two Random Items

It’s exam week which means I’m pretty much useless. Here’s a link to a recent fix (including unified diff patch output) I created for etherpad-lite to allow for multi-user, real-time basic HTTP authentication to work.

and here’s the issue comments I submitted:

https://github.com/Pita/etherpad-lite/issues/628
https://github.com/Pita/etherpad-lite/issues/632

Here’s another script to help us search our wiki (using grep) for common spam patterns and pages.

#!/bin/bash

root='http://zenit.senecac.on.ca'
curl -sL "${root}/wiki/index.php/Special:AllPages" | sed -e 's/<a/\t<a/g' | tr '\t' '\n' | grep -i '^<a.*href=.*from=.*to=.*$' | sed -e 's@^.*href="\([^"]*\)".*$@\1@g' -e 's/\&amp;/\&/g' | sort | uniq > /tmp/pages.txt

while read page
do
	echo "Checking root page [ ${root}${page} ]" 1>&2
	curl -sL "${root}${page}" | sed -e 's/<a/\t<a/g' | tr '\t' '\n' | grep -i '^<a.*href=.*/wiki/index.php/.*$' | sed -e 's@^.*href="\([^"]*\)".*$@\1@g' -e 's/\&amp;/\&/g' | sort | uniq > /tmp/links.txt
	
	while read link
	do
		#echo "    Checking sub page [ ${root}${link} ]" 1>&2
		check=`curl -sL "${root}${link}" | tr -d '\0\t\r\n' | grep -i "$1"`
		
		if [ "${check}" != "" ]
		then
			echo "    Possible spam match [ ${root}${link} ]"
		fi
	done < /tmp/links.txt
done < /tmp/pages.txt

Two Random Items

Anaconda GUI Running On A Guru-ARMv5

Well here’s a possible beginning, Fedora’s official Anaconda installer running in GUI mode off a “anything-but-fast” ARMv5 F17 Guruplug!

Note: I told the internals of Anaconda to not partition or install any system/bootloader information onto the system as most ARM devices come pre-installed already.

Note: Here were the setup details in case you wanted to try and replicate my findings

# mount /dev/sdc1 /mnt/root
# wget 'http://fedora.roving-it.com/rootfs-f17-sfp-alpha1.tar.bz2'
# tar -xjvf rootfs-f17-sfp-alpha1.tar.bz2 -C /mnt/root
# echo install a guru kernel image here
# umount /mnt/root



#!/bin/bash
# /etc/rc.d/rc.local
date 1010102012
hostname "guru-`uname -m`"



# /etc/sysconfig/network-scripts/ifcfg-eth0
DEVICE="eth0"
NM_CONTROLLED="yes"
IPADDR="192.168.1.10"
NETMASK="255.255.255.0"
GATEWAY="192.168.1.20"
DNS1="4.2.2.1"
BOOTPROTO="none"
ONBOOT="yes"



# yum install -y xorg-x11-xauth
# yum install -y anaconda
# rpm -e anaconda
# wget 'http://142.204.133.82/jon/tmp/anaconda-armv5tel.rpm'
# rpm -i anaconda-armv5tel.rpm

# echo now on another computer
# ssh -CX [email protected]
# anaconda

Note: Anaconda may hang if your device does not have working Internet access pre-configured with NetworkManager ahead of time before the install starts. Also, if you see this error below, it seems to be safe to click thru it and continue on with the install process.

Anaconda GUI Running On A Guru-ARMv5

Tweaking Anaconda To Run On ARM

So I’ve been on this mission to help out with all of the guys doing hard work to try and get ARM pushed as a primary architecture. This means spending countless hours reading a huge Python framework which contains a non-stop mix of classes, libraries and even old C code. After many hours (mainly on the weekend) I have started the process of tailoring the Fedora Anaconda installer to run a bit better on ARM. Please note that I am not releasing anything yet as the code is basically just in “see-if-it-works” mode. I still have to connect it all together behind the scenes to try and get the changes to stick. Anyway, here’s a sneak-peak preview of Anaconda (and hopefully firstboot soon/next) running on one of our ARMv5 Guru machines with F17 on it. Note that the machine’s architecture is displayed up top.

My todo’s left for Anaconda:

  • Place all user configs in the right place
  • Allow for package selection/installation
  • Ensure firstboot works after reboot

 

Fedora release 17 (Beefy Miracle)
Linux fedora-arm 3.0.9 #11 PREEMPT Fri Feb 3 15:22:48 EST 2012 armv5tel armv5tel armv5tel GNU/Linux
anaconda-17.13-2.fc17





Tweaking Anaconda To Run On ARM

Some Koji Scripts (The Push For Primary)

The push for ARM to become primary arch is not as easy as one might think. Everyone in the community is working hard to prove how ARM is as capable in most areas to that of the machines in primary architecture. Anyway, here are a couple of scripts one could use to help determine some basic stats about ones current build process.

To find out the current error counts and types (and unbuilt packages) of a given tag:

(could help to show how far off one is in keeping up with primary and where the errors are)

#!/bin/bash

tagname="f17"
tagnumb=`echo "${tagname}" | sed -e 's/[^0-9]//g'`

if [ ! -f pripkgs.txt -o "$1" == "f" ]
then
	koji --server=http://koji.fedoraproject.org/kojihub list-tagged ${tagname} --inherit --latest --quiet | awk '{ print $1 }' | sed -e 's/-[^-]*-[^-]*$//g' > pripkgs.txt
fi

if [ ! -f armpkgs.txt -o "$1" == "f" ]
then
	koji --server=http://arm.koji.fedoraproject.org/kojihub list-tagged ${tagname} --inherit --latest --quiet | awk '{ print $1 }' | sed -e 's/-[^-]*-[^-]*$//g' > armpkgs.txt
fi

builtnum=0; builtstr=""
archnumb=0; archstri=""
depsnumb=0; depsstri=""
reqsnumb=0; reqsstri=""
confnumb=0; confstri=""
buildnum=0; buildstr=""
makenumb=0; makestri=""
unknnumb=0; unknstri=""
ubuilnum=0; ubuilstr=""

outpstri=""

while read pkgname
do
	pkgtagged=`cat armpkgs.txt | grep "${pkgname}"`
	
	if [ "${pkgtagged}" == "" ]
	then
		echo "[p] ${pkgname}" 1>&2
		
		pkgstat=`curl -Ls "http://arm.koji.fedoraproject.org/koji/search?match=glob&type=package&terms=${pkgname}" | tr -d '\t\r\n' | sed -e 's/<tr/\t<tr/g' | tr '\t' '\n' | grep -i "^<tr.*buildinfo.buildID" | sed -e 's/<a[^>]*buildinfo.buildID=\([0-9]*\)[^>]*>/ \1 /g' -e 's/<img[^>]*alt=.\([a-zA-Z]*\).[^>]*>/ \1 /g' -e 's/<[^>]*>/ /g' | grep -i "fc${tagnumb}" | sed -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'`
		builtstat=`echo "${pkgstat}" | grep -i "complete$" | head -n 1`
		failstat=`echo "${pkgstat}" | grep -i "failed$" | head -n 1`
		
		if [ "${builtstat}" != "" ]
		then
			if [ "$2" == "p" ]
			then
				let builtnum="${builtnum} + 1"
				builtstr="${builtstr}${pkgname} http://arm.koji.fedoraproject.org/koji/search?match=glob&type=package&terms=${pkgname}\n"
			
			else
				outpstri="${outpstri}\n\"${pkgname}\":[\"complete\", \"\", 0]"
			fi
		
		elif [ "${failstat}" != "" ]
		then
			pkgnumb=`echo "${failstat}" | awk '{ print $1 }'`
			tasknumb=`curl -Ls "http://arm.koji.fedoraproject.org/koji/buildinfo?buildID=${pkgnumb}" | tr -d '\t\r\n' | sed -e 's/<a/\t<a/g' | tr '\t' '\n' | grep -i "^<a.*taskinfo.taskID" | sed -e 's/<a[^>]*taskinfo.taskID=\([0-9]*\)[^>]*>/ \1 /g' | awk '{ print $1 }' | head -n 1`
			failnumb=`curl -Ls "http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${tasknumb}" | tr -d '\t\r\n' | sed -e 's/<a/\t<a/g' | tr '\t' '\n' | grep -i "^<a.*taskinfo.taskID.*failed" | sed -e 's/<a[^>]*taskinfo.taskID=\([0-9]*\)[^>]*>/ \1 /g' | awk '{ print $1 }' | head -n 1`
			logsoutp=`koji --server=http://arm.koji.fedoraproject.org/kojihub watch-logs "${failnumb}"`
			
			archerro=`echo "${logsoutp}" | grep -i 'error: architecture is excluded' | head -n 1`
			depserro=`echo "${logsoutp}" | grep -i 'error: no package found for' | head -n 1`
			reqserro=`echo "${logsoutp}" | grep -i 'error: package' -A 1 | head -n 2 | tr -d '\t\r\n' | tr -s ' '`
			conferro=`echo "${logsoutp}" | grep -i 'error: bad exit status from' | head -n 1`
			builderr=`echo "${logsoutp}" | grep -i 'error: file not found' | head -n 1`
			makeerro=`echo "${logsoutp}" | grep -i 'make: .* error' | head -n 1`
			
			if [ "${archerro}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let archnumb="${archnumb} + 1"
					archstri="${archstri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"arch-error\", \"${archerro}\", ${failnumb}]\n"
				fi
			
			elif [ "${depserro}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let depsnumb="${depsnumb} + 1"
					depsstri="${depsstri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"dep-error\", \"${depserro}\", ${failnumb}]\n"
				fi
			
			elif [ "${reqserro}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let reqsnumb="${reqsnumb} + 1"
					reqsstri="${reqsstri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"req-error\", \"${reqserro}\", ${failnumb}]\n"
				fi
			
			elif [ "${builderr}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let buildnum="${buildnum} + 1"
					buildstr="${buildstr}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"build-error\", \"${builderr}\", ${failnumb}]\n"
				fi
			
			elif [ "${makeerro}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let makenumb="${makenumb} + 1"
					makestri="${makestri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"make-error\", \"${makeerro}\", ${failnumb}]\n"
				fi
			
			elif [ "${conferro}" != "" ]
			then
				if [ "$2" == "p" ]
				then
					let confnumb="${confnumb} + 1"
					confstri="${confstri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"config-error\", \"${conferro}\", ${failnumb}]\n"
				fi
			
			else
				if [ "$2" == "p" ]
				then
					let unknnumb="${unknnumb} + 1"
					unknstri="${unknstri}${pkgname} http://arm.koji.fedoraproject.org/koji/taskinfo?taskID=${failnumb}\n"
				
				else
					outpstri="${outpstri}\"${pkgname}\":[\"unknown-error\", \"Error could not be interpreted.\", ${failnumb}]\n"
				fi
			fi
		
		else
			if [ "$2" == "p" ]
			then
				let ubuilnum="${ubuilnum} + 1"
				ubuilstr="${ubuilstr}${pkgname}\n"
			
			else
				outpstri="${outpstri}\"${pkgname}\":[\"unbuilt\", \"\", 0]\n"
			fi
		fi
	fi
done < pripkgs.txt

extranum=0; extrastr=""

while read pkgname
do
	pkgtagged=`cat pripkgs.txt | grep "${pkgname}"`
	
	if [ "${pkgtagged}" == "" ]
	then
		echo "[s] ${pkgname}" 1>&2
		
		if [ "$2" == "p" ]
		then
			let extranum="${extranum} + 1"
			extrastr="${extrastr}${pkgname}\n"
		
		else
			outpstri="${outpstri}\"${pkgname}\":[\"extra\", \"\", 0]\n"
		fi
	fi
done < armpkgs.txt

if [ "$2" == "p" ]
then
	printf '%10s|%10s|%10s|%10s|%10s|%10s|%10s\n' "Arch" "Deps" "Reqs" "Config" "Build" "Make" "Unknown"
	for i in `seq 1 80` ; do printf '-' ; done ; printf '\n'
	printf '%10s|%10s|%10s|%10s|%10s|%10s|%10s\n' "${archnumb}" "${depsnumb}" "${reqsnumb}" "${confnumb}" "${buildnum}" "${makenumb}" "${unknnumb}"
	echo
	if [ "${archstri}" != "" ] ; then echo -e "Arch-Errors:" ; echo -e "${archstri}" ; fi
	if [ "${depsstri}" != "" ] ; then echo -e "Dep-Errors:" ; echo -e "${depsstri}" ; fi
	if [ "${reqsstri}" != "" ] ; then echo -e "Require-Errors:" ; echo -e "${reqsstri}" ; fi
	if [ "${confstri}" != "" ] ; then echo -e "Config-Errors:" ; echo -e "${confstri}" ; fi
	if [ "${buildstr}" != "" ] ; then echo -e "Build-Errors:" ; echo -e "${buildstr}" ; fi
	if [ "${makestri}" != "" ] ; then echo -e "Make-Errors:" ; echo -e "${makestri}" ; fi
	if [ "${unknstri}" != "" ] ; then echo -e "Unknown-Errors:" ; echo -e "${unknstri}" ; fi
	if [ "${builtstr}" != "" ] ; then echo -e "Built but un-tagged/blocked pkgs = ${builtnum}" ; echo -e "${builtstr}" ; fi
	echo -e "Number of unbuilt/cancelled/building pkgs = ${ubuilnum}\n"
	if [ "${extrastr}" != "" ] ; then echo -e "Pkgs tagged in arm and not primary = ${extranum}" ; echo -e "${extrastr}" ; fi
	echo

else
	echo -e "${outpstri}"
	echo
fi

This script can help to compare build times between your various machines and primary:

(could help to compare how quickly ones build farm could keep up with primaries)

#!/bin/bash

function taskinfo
{
	roottask=`koji --server="$1/kojihub" buildinfo "$2" | grep -i '^task:' | awk '{ print $2 }'`
	curl -Ls "$1/koji/taskinfo?taskID=${roottask}" | tr -d '\t\r\n' | sed -e 's/<a/\t<a/g' | tr '\t' '\n' | grep -i 'taskinfo.taskID=.*buildArch' | sed -e 's/^.*taskinfo.taskID=\([0-9]*\).*$/ \1 /g' > /tmp/koji.task.$4.txt
	
	while read tasknumb
	do
		taskinfo=`curl -Ls "$1/koji/taskinfo?taskID=${tasknumb}" | tr -d '\t\r\n' | sed -e 's/<tr/\t<tr/g' | tr '\t' '\n'`
		begtime=`echo "${taskinfo}" | grep -i '^<tr>.*<th>.*Started.*</th>' | sed -e 's/^.*<td>//g' -e 's/<[^>]*>/ /g' -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'`
		endtime=`echo "${taskinfo}" | grep -i '^<tr>.*<th>.*Completed.*</th>' | sed -e 's/^.*<td>//g' -e 's/<[^>]*>/ /g' -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'`
		archname=`echo "${taskinfo}" | grep -i "^<tr>.*<th>.*Arch.*</th>" | sed -e 's/^.*<td>//g' -e 's/<[^>]*>/ /g' -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'`
		hostname=`echo "${taskinfo}" | grep -i "^<tr>.*<th>.*Host.*</th>.*<td>.*$3.*</td>" | sed -e 's/^.*<td>//g' -e 's/<[^>]*>/ /g' -e 's/^[ \t]*//g' -e 's/[ \t]*$//g'`
		
		if [ "${begtime}" != "" -a "${endtime}" != "" -a "${archname}" != "" -a "${hostname}" != "" ]
		then
			begepoch=`date --date="${begtime}" '+%s'`
			endepoch=`date --date="${endtime}" '+%s'`
			
			hourdiff=`echo "(${endepoch} - ${begepoch}) / 3600" | bc`
			if [ ${hourdiff} -lt 10 ] ; then hourdiff="0${hourdiff}" ; fi
			
			mindiff=`echo "((${endepoch} - ${begepoch}) / 60) % 60" | bc`
			if [ ${mindiff} -lt 10 ] ; then mindiff="0${mindiff}" ; fi
			
			echo "${archname} ${hourdiff}:${mindiff}"
		fi
	done < /tmp/koji.task.$4.txt
}

tagname="f17"
tagnumb=`echo "${tagname}" | sed -e 's/[^0-9]//g'`

if [ ! -f primary.built.txt ]
then
	koji --server=http://koji.fedoraproject.org/kojihub list-tagged ${tagname} --inherit --latest --quiet | awk '{ print $1 }' > primary.built.txt
fi

tempfile="$1"
uniqname=`head -c 1024 /dev/urandom | md5sum | awk '{ print $1 }'`

if [ "${tempfile}" == "" ]
then
	koji --server=http://arm.koji.fedoraproject.org/kojihub list-tagged ${tagname} --inherit --latest --quiet | awk '{ print $1 }' > arm.built.txt
	tempfile="arm.built.txt"
fi

builder="$2"

if [ "${builder}" == "" ]
then
	builder="cdot.trimslice"
fi

printf '%-40s | %10s | %10s | %10s | %10s | %20s\n' "Package Name" "x86" "x64" "ARMvSFP" "ARMvHFP" "(Time = HH:MM)"
for i in `seq 1 95` ; do printf '-' ; done ; printf '\n'

while read srpmname
do
	pkgname=`echo "${srpmname}" | sed -e 's/-[^-]*-[^-]*$//g'`
	primpkg=`cat primary.built.txt | grep "^${pkgname}-[0-9\.][0-9\.]*-" | head -n 1`
	
	arminfo=`taskinfo "http://arm.koji.fedoraproject.org" "${srpmname}" "${builder}" "${uniqname}"`
	
	if [ "${arminfo}" != "" ]
	then
		priminfo=`taskinfo "http://koji.fedoraproject.org" "${primpkg}" ".*" "${uniqname}"`
		
		tttime=`echo "${priminfo}" | grep -i '^i386 ' | awk '{ print $2 }' | head -n 1`
		sftime=`echo "${priminfo}" | grep -i '^x86_64 ' | awk '{ print $2 }' | head -n 1`
		astime=`echo "${arminfo}" | grep -i '^arm ' | awk '{ print $2 }' | head -n 1`
		ahtime=`echo "${arminfo}" | grep -i '^armhfp ' | awk '{ print $2 }' | head -n 1`
		
		printf '%-40s | %10s | %10s | %10s | %10s |\n' "${pkgname}" "${tttime}" "${sftime}" "${astime}" "${ahtime}"
	fi
done < ${tempfile}

Some Koji Scripts (The Push For Primary)

[really off topic] I also really like colorful circles moving around randomly!

If my server is still up -> Liquid Particles

liquid-particles.js

/**
*   Liquid particles canvas experiment
*   ©2010 spielzeugz.de 
*/

var PI_2        = Math.PI * 2;

var canvasW     = 8;
var canvasH     = 8;
var numMovers   = 1024;
var friction    = 0.96;
var movers      = [];

var canvas = null;
var ctx = null;

var mouseX;
var mouseY;
var mouseVX;
var mouseVY;
var prevMouseX;
var prevMouseY;
var isMouseDown;

function init(){
	canvas = document.getElementById("mainCanvas");
	
	canvasW = canvas.width;
	canvasH = canvas.height;
	numMovers = (canvasW + canvasH);
	
	if ( canvas.getContext ){
		setup();
		setInterval( run , 33 );
		trace("interact with the mouse, occasionally click or hold down the mousebutton");
	}
	else{
		trace("Sorry, needs a recent version of Chrome, Firefox, Opera, Safari, or Internet Explorer 9.");
	}
}
   
function setup(){
	ctx       = canvas.getContext("2d");
	
	var i = numMovers;
	while ( i-- ){
		var m = new Mover();
		m.x   = canvasW * 0.5;
		m.y   = canvasH * 0.5;
		m.vX  = Math.cos(i) * Math.random() * 34;
		m.vY  = Math.sin(i) * Math.random() * 34;
		movers[i] = m;
	}
	
	mouseX = prevMouseX = canvasW * 0.5;
	mouseY = prevMouseY = canvasH * 0.5;
}

function run(){
	ctx.globalCompositeOperation = "source-over";
	ctx.fillStyle = "rgba(8,8,12,0.65)";
	ctx.fillRect( 0 , 0 , canvasW , canvasH );
	ctx.globalCompositeOperation = "lighter";
	
	mouseVX    = mouseX - prevMouseX;
	mouseVY    = mouseY - prevMouseY;
	prevMouseX = mouseX;
	prevMouseY = mouseY;
	
	var toDist   = canvasW * 0.86;
	var stirDist = canvasW * 0.125;
	var blowDist = canvasW * 0.5;
	
	var Mrnd = Math.random;
	var Mabs = Math.abs;
	
	var i = numMovers;
	while ( i-- ){
		var m  = movers[i];
		var x  = m.x;
		var y  = m.y;
		var vX = m.vX;
		var vY = m.vY;
		
		var dX = x - mouseX;
		var dY = y - mouseY; 
		var d  = Math.sqrt( dX * dX + dY * dY ) || 0.001;
		dX /= d;
		dY /= d;
		
		if ( isMouseDown ){
			if ( d < blowDist ){
				var blowAcc = ( 1 - ( d / blowDist ) ) * 14;
				vX += dX * blowAcc + 0.5 - Mrnd();
				vY += dY * blowAcc + 0.5 - Mrnd();
			}
		}
		
		if ( d < toDist ){
			var toAcc = ( 1 - ( d / toDist ) ) * canvasW * 0.0014;
			vX -= dX * toAcc;
			vY -= dY * toAcc;			
		}
		
		if ( d < stirDist ){
			var mAcc = ( 1 - ( d / stirDist ) ) * canvasW * 0.00026;
			vX += mouseVX * mAcc;
			vY += mouseVY * mAcc;			
		}
		
		vX *= friction;
		vY *= friction;
		
		var avgVX = Mabs( vX );
		var avgVY = Mabs( vY );
		var avgV  = ( avgVX + avgVY ) * 0.5;
		
		if( avgVX < .1 ) vX *= Mrnd() * 3;
		if( avgVY < .1 ) vY *= Mrnd() * 3;
		
		var sc = avgV * 0.45;
		sc = Math.max( Math.min( sc , 3.5 ) , 0.4 );
		
		var nextX = x + vX;
		var nextY = y + vY;
		
		if ( nextX > canvasW ){
			nextX = canvasW;
			vX *= -1;
		}
		else if ( nextX < 0 ){
			nextX = 0;
			vX *= -1;
		}
		
		if ( nextY > canvasH ){
			nextY = canvasH;
			vY *= -1;
		}
		else if ( nextY < 0 ){
			nextY = 0;
			vY *= -1;
		}
		
		m.vX = vX;
		m.vY = vY;
		m.x  = nextX;
		m.y  = nextY;
		
		ctx.fillStyle = m.color;
		ctx.beginPath();
		ctx.arc( nextX , nextY , sc , 0 , PI_2 , true );
		ctx.closePath();
		ctx.fill();		
	}
}

function onDocMouseMove( e ){
	var ev = e ? e : window.event;
	mouseX = ev.clientX - canvas.offsetLeft;
	mouseY = ev.clientY - canvas.offsetTop;
}

function onDocMouseDown( e ){
	isMouseDown = true;
	return false;
}

function onDocMouseUp( e ){
	isMouseDown = false;
	return false;
}

function Mover(){
	this.color = "rgb(" + Math.floor( Math.random()*255 ) + "," + Math.floor( Math.random()*255 ) + "," + Math.floor( Math.random()*255 ) + ")";
	this.y     = 0;
	this.x     = 0;
	this.vX    = 0;
	this.vY    = 0;
	this.size  = 1; 
}

function rect( context , x , y , w , h ){
	context.beginPath();
	context.rect( x , y , w , h );
	context.closePath();
	context.fill();
}

function trace( str ){
	console.log(str);
}

lp.html

<html>
	<head>
		<title>Automatic Liquid Particles</title>
		
		<style>
			body
			{
				background-color: black;
			}
			
			canvas
			{
				border: 1px dotted white;
			}
		</style>
		
		<script src="liquid-particles.js"></script>
		<script>
			var mousepos = [0, 0, 1, 1];
			var lasttime = 0;
			
			function fakemove()
			{
				var dateobjc = new Date();
				var prestime = (dateobjc.getTime() / 1000);
				
				if ((canvasW > 8) && (canvasH > 8) && (canvas != null))
				{
					onDocMouseDown(null);
					
					if ((prestime - lasttime) >= 1)
					{
						mousepos[2] = parseInt(Math.random() * 2);
						mousepos[3] = parseInt(Math.random() * 2);
						
						if (mousepos[2] == 0) { mousepos[2] = -1; }
						if (mousepos[3] == 0) { mousepos[3] = -1; }
						
						lasttime = prestime;
					}
					
					mousepos[0] = Math.min(canvasW, Math.max(0, mousepos[0] + (16 * mousepos[2])));
					mousepos[1] = Math.min(canvasH, Math.max(0, mousepos[1] + (16 * mousepos[3])));
					
					var mouseeve = {"clientX":(mousepos[0] + canvas.offsetLeft), "clientY":(mousepos[1] + canvas.offsetTop)};
					
					onDocMouseMove(mouseeve);
				}
				
				setTimeout("fakemove();", 32);
			}
			
			function prepinit()
			{
				document.body.innerHTML = ("<center><canvas id='mainCanvas' width='" + (document.body.offsetWidth - 32) + "' height='" + (document.body.offsetHeight - 32) + "'></canvas></center>");
				init();
				fakemove();
			}
		</script>
	</head>
	
	<body onload="prepinit();"></body>
</html>
[really off topic] I also really like colorful circles moving around randomly!

[off topic] I like the horoscopes from thestar…

Ok so I was bored again and I was randomly reading my scopes from the star and I liked them so here’s an overly complicated bash command to get them for you!

u=`curl -s "http://www.thestar.com/horoscopes" | tr -d '\t\r\n' | sed -e 's/<a /\t<a /g' | tr '\t' '\n' | grep -i '/horoscopes/article/.*--' | sed -e 's/^.*<a href="//g' -e 's/">.*$//g' | head -n 1` ; h=`curl -s "http://www.thestar.com/${u}" | tr -d '\t\r\n' | sed -e 's/<b>/\t/g' | tr '\t' '\n' | sed -e 's/<[^>]*>/ /g' | tr -s ' ' | grep -i "^aqua"` ; echo "$u" ; echo ; echo "$h" ; echo

Just change the grep -i "^aqua" part near the end of the command to the start of your own horoscope name. Also note, if the star decides to change the structure of their html web pages even just a little, this script is likely to break!

johnny stoops

[off topic] I like the horoscopes from thestar…