Posted by Dan | Posted in ColdFusion | Posted on 02-19-2010
0
I put this ColdFusion UDF together the other day to turn relative URLs to Absolute. Code is pretty straightforward.
<cffunction name="URLRelativeToAbsolute" returntype="string"
hint="Converts relative URLs in an element and converts to absolute. It includes the http:// protocol prefix.">
<cfargument name="content" type="string" required="true" hint="HTML content that will be scanned and replaced." />
<cfargument name="domain" type="string" required="true" hint="Add domain name to relative links." />
<cfset var local = StructNew() />
<!--- The following regexp handles the following elements: link, a, img, script, form, frame. --->
<cfset local.contentFixed = REReplaceNoCase( Arguments.content, "(href|src|action)=""/?((\./)|(\.\./)+|)(?=[^http])", "\1=""http://" & domain & "/", "all" ) />
<!--- The following regexp handles the url() attribute of the background CSS property. --->
<cfset local.contentFixed = REReplaceNoCase( local.contentFixed, "url\((\s)?(')?/?((\./)|(\.\./)+|)(?=[^http])", "url(\2http://" & domain & "/", "all" ) />
<cfreturn local.contentFixed />
</cffunction>
Usage:
<cfsavecontent variable="htmlContent">
<textarea name="data" rows="20" cols="60">
<style>
body {
background-image:url('stars.png');
background-image:url('../stars.png');
background-image:url('/stars.png');
background-image:url('/../../../stars.png');
}
</style>
<a href="../../../images/shiny.jpg">Shiny</a>
<a href="http://www.google.com">This should not be touched</a>
<img border="0" src="/images/cool.png" />
<link rel="index" href="../../index.asp">
<form method="POST" action="cgi/processing.cgi"></form>
</textarea>
</cfsavecontent>
<cfoutput>
#htmlContent#
#URLRelativeToAbsolute( htmlContent, "www.shinylight.com" )#
</cfoutput>
Result:

In my last post, I made a quick script that checks for the date. It was very limiting, since it used the dir command. This one uses several date/time Python modules and is more capable.
import os, os.path, stat, time
from datetime import date, timedelta, datetime
# Reference
# http://docs.python.org/library/datetime.html
# http://docs.python.org/library/time.html
def getFileDate( filenamePath ):
used = os.stat( filenamePath ).st_mtime
year, day, month, hour, minute, second = time.localtime(used)[:6]
objDateTime = datetime(year, day, month, hour, minute, second)
return objDateTime
# Ways to reference this DateTime Object
# objDateTime.strftime("%Y-%m-%d %I:%M %p")
# objDateTime.year
# objDateTime.month
def isDaysOldFromNow( filenamepath, days ):
# Checks how old a file is. Is it older than "days" [variable] days?
inTimeRange = False
timeDeltaDiff = ( datetime.now()-getFileDate( filenamepath ) ).days
# Check if the file's date is days old or less:
if ( timeDeltaDiff >= days ):
inTimeRange = True
return inTimeRange
fname = "C:/temp/decision2.pdf"
# Set this variable to check if the file is this days old
howOld = 3
if ( isDaysOldFromNow( fname, howOld ) ):
print fname, "is more than", howOld, "days old"
else:
print fname, "is NOT more than", howOld, "days old"
Output:

Sometimes log files bog a system down. For one of our servers, I made this little Python script that compresses (via WinRAR) the log files in a directory, and then moves them to a backup location. The only little catch is that I wanted to leave the latest log files for in that directory. Log files are created daily, so the the latest log files have a datestamp of today. Here’s how I did it.
First Create the Python Script:
import os
import datetime
dateStamp = datetime.datetime.now().strftime("%Y-%m-%d")
imsLogPath = 'd:\\LogFiles\\'
# Don't use a mapped drive but use UNC for network drives. Task Schedule seems to choke when it calls Python.
newRARPath = '"\\\\192.168.1.2\\Root\\backups\\' + dateStamp + '.rar"'
rarPath = '"C:\\Program Files\\WinRAR\\rar.exe" a -m5 ' + newRARPath
# Get Latest Files
smtpLatest = os.popen(r"dir /od /a-d /b " + imsLogPath + "SMTP*.log").read().splitlines()[-1]
postLatest = os.popen(r"dir /od /a-d /b " + imsLogPath + "POST*.log").read().splitlines()[-1]
ischedLatest = os.popen(r"dir /od /a-d /b " + imsLogPath + "iSched*.log").read().splitlines()[-1]
relayLatest = os.popen(r"dir /od /a-d /b " + imsLogPath + "Relay*.log").read().splitlines()[-1]
qengLatest = os.popen(r"dir /od /a-d /b " + imsLogPath + "Qeng*.log").read().splitlines()[-1]
# Get List of All Files
allFiles = os.popen(r"dir /od /a-d /b " + imsLogPath + "*.log").read().splitlines()
# Remove Latest Files from All Files List
allFiles.remove( smtpLatest )
allFiles.remove( postLatest )
allFiles.remove( ischedLatest )
allFiles.remove( relayLatest )
allFiles.remove( qengLatest )
# allFiles Array Has the list of files
# Flatten Array allFiles to be used as a parameter in system command
flatLogPathList = ""
for filenameWithPath in allFiles:
flatLogPathList = flatLogPathList + imsLogPath + filenameWithPath + " "
# Execute WinRar
path = rarPath + " " + flatLogPathList.rstrip()
os.system( '"' + path + '"' )
# Delete all log files
os.system( '"del ' + flatLogPathList.rstrip() + '"' )
Then I set up the Scheduled Task:

With these Settings:

I often use both Winamp and my iPhone to listen to music. These two, unfortunately, show the time differently in the songs. Winamp displays the time in minutes (mm) while the iPhone does it hour/minutes (hh:mm). Here’s a quick little script I whipped together because I’m too lazy to do this in my head, especially for audio books where an audio book can be over 500 minutes, and I need to convert to iPhone time because I want to continue listening where I had just left off on Winamp.
use POSIX qw(ceil floor); # used for the floor function
sub GetToken {
# @_ = flatten args list from an array
# @_[0] = first argument
$data = @_[0];
$delimiter = @_[1];
$token = @_[2] - 1;
@tokens_array = split($delimiter, $data);
return @tokens_array[$token];
}
sub chr_conver_min {
if (length(@_[0]) == 1) {
return "0".@_[0];
}
else {
return @_[0];
}
}
sub iphone_time_convert {
# converts winamp time to iphone - winamp stores time only in minutes.
# @_[0] = winamp_time, e.g. 124:34
# $hour = floor($winamp_time/60);
# $minute = $winamp_time % 60;
$winamp_hour_min = GetToken(@_[0], ":", 1);
$winamp_seconds = GetToken(@_[0], ":", 2);
return floor($winamp_hour_min/60).":".chr_conver_min( ($winamp_hour_min % 60) ).":".$winamp_seconds;
}
sub winamp_time_convert {
# converts iphone time to winamp
# @_[0] = iphone_time, e.g. 3:43:34
$iphone_hour = GetToken(@_[0], ":", 1);
$iphone_min = GetToken(@_[0], ":", 2);
$iphone_seconds = GetToken(@_[0], ":", 3);
return (($iphone_hour * 60) + $iphone_min).":".$iphone_seconds;
}
sub show_help {
print "\nDisplays the conversion of time between winamp and iPhone.\n\n";
print " winamptime [-w2i|-i2p] [mm:ss][hh:mm:ss]\n\n";
print "Example to convert winamp time to iPhone: \n\n";
print " winamptime -w2i 212:41\n\n";
print "Example to convert iPhone time to winamp, seconds being optional: \n\n";
print " winamptime -i2w 2:31:41\n";
print " winamptime -i2w 2:31\n\n";
}
# START
# Optimize this:
if( $ARGV[0] eq "-w2i" )
{
# winamp to iphone time
if ( length($ARGV[1]) > 0 ) {
print "iPhone Time: ".iphone_time_convert( $ARGV[1] )."\n";
}
}
elsif( $ARGV[0] eq "-i2w" )
{
# iphone to winamp time
if ( length($ARGV[1]) > 0 ) {
print "Winamp Time: ".winamp_time_convert( $ARGV[1] )."\n";
}
}
else
{
show_help();
}
Output:

Posted by Dan | Posted in Development, Languages | Posted on 01-18-2010
0
Ouch, I guess the dream I had for having the world’s smallest program has been crushed. I made a program a long long time ago in Assembly using Windows 95’s DEBUG.EXE that rebooted the computer. The reason why it’s so small is that it reboots the computer, so once the BIOS Interrupt executes, there’s no need to do any other clean-up or maintenance. Unfortunately after Windows 95, Microsoft got smart and disabled DOS from executing these interrupts from DEBUG.EXE. Here was the code:
N REBOOT!.com
A 100
INT 19
R CX
2
W
Q
But what I really want is to see the code for this 0-byte code program written in C.
Posted by Dan | Posted in Development, Python | Posted on 01-18-2010
0
So I’m currently in process of reading the infamous “Code Complete” by Steve McConnell. So far it’s been an amazing book and I definitely guarantee it to any programmer out there. I’ve just read the section on recursion and it mentioned how doing recursion for a factorial (or fibonacci) function is not as efficient as a for-loop iteration. I guess I never thought about it, since in computer science I was always shoved recursion down my throat when doing factorials. I agree with him that computer science professors are eager to apply the idea of recursion on factorials, but I’ve never remembered a professor mention that it’s not the most efficient way. McConnell states in the book that doing recursion in factorials:
- Is not as fast as a for-loop.
- Not as clear to read as a for-loop.
- Use of run-time memory is unpredictable.
Just for fun, I wanted to test his point on speed. This is a Python script that tests the average speed of a factorial using a for-loop or recursion. I noticed that for numbers less than 3000! the time it took for both functions were exactly the same. It was only when I bumped it up to 5000!, which is a huge number (16,327 digits). Luckily Python lets you work with very large numbers easily. Just had to increase the number of recursion calls in Python from the default 1000.
import win32api
import sys
sys.setrecursionlimit(10000)
def factorial_forloop( n ):
count = 1
for i in range( n, 0, -1 ):
count = count * i
return count
def factorial_recursion(n):
if n == 0:
return 1
else:
return n * factorial_recursion(n-1)
total_time_recursion = 0
total_time_forloop = 0
number_of_tries = 500
for i in range( 1, number_of_tries ):
start = win32api.GetTickCount()
factorial_recursion( 5000 )
end = win32api.GetTickCount()
total = end - start
total_time_recursion += total
start = win32api.GetTickCount()
factorial_forloop( 5000 )
end = win32api.GetTickCount()
total = end - start
total_time_forloop += total
print "\n"
print "Average time for recursion: ", ( total_time_recursion / 10 ) * .001
print "Average time for for-loop: ", ( total_time_forloop / 10 ) * .001
So in 500 tries, the results were as follows:
Average time for recursion: 1.284 seconds
Average time for for-loop: 1.083 seconds
It doesn’t seem by much but the results are interesting. But then again, a factorial is a very simple algorithm. In future posts I’ll try to test more complicated algorithms and see how they battle out. Also, this is Python. The results for C, C++, or Java may differ.
This was a great read. Certainly learned a lot of useful lessons on front-end optimizations. Written by Steve Souders (previously lead Optimization efforts at Yahoo!), who also developed YSlow! – a Firefox add-on (actually an add-on to the Firefox add-on called Firebug) that gives your web pages a grade from A through F and tells you how to make it better.
If you have a build script, you may be able to automate a lot of these things, like combining JS and CSS files, and optimize PNG files (check out http://www.phpied.com/give-png-a-chance/ to see how to optimize from the command line). If you’re going to optimize JavaScript, I would recommend YUI Compressor (http://developer.yahoo.com/yui/compressor/) since it’s not as greedy as Google’s Closure Compiler for JavaScript. The Closure compiler (http://code.google.com/closure/compiler/) is relatively new and you may get even smaller files, but if your JavaScript is complex, it may have bugs because it’s a greedy compiler.
Anywhoot, here’s what I got from it:
- Reduce as many HTTP requests as possible.
- Minify JavaScript (don’t obfuscate, because it’s more trouble than it’s worth for the benefits you get)
- Minify CSS and optimize it (reduce duplication).
- Future-expire resources for caching (PNG, JPG, GIF, JavaScript and CSS).
- Minify HTML (get away from tables)
- Put CSS at the top, put JavaScript at the bottom.
- For design components (background images, button images, nav images), use CSS sprites.
- Use PNG for design components (they compress better than GIF, have partial transparency, and can have greater color palettes).
- Gzip non-binary data like HTML.
- Combine CSS and JavaScript into single files to reduce HTTP requests.
A summary of his optimization rules are found here, but of course, it’s not as detailed as the book: http://stevesouders.com/hpws/rules.php .
Stoyan Stefanov, another prominent developer who’s written tons on JavaScript and optimization, published 24 articles this month on optimization. I find these articles invaluable. It’s recent and he does actual optimization tests and tells you what tools he uses. Here’s the site: http://www.phpied.com/performance-advent-calendar-2009/
Posted by Dan | Posted in ColdFusion, XML | Posted on 01-03-2010
0
Whipped out this little script to read an OPML file from Google Reader. Thought it may be handy.
<cfset GoogleOPMLFile = "C:/google-reader-subscriptions.xml" />
<cffile action="READ" variable="xml" file="#GoogleOPMLFile#" />
<cfset xmlDoc = XMLParse(xml) />
<cfset StartingDataNode = 2 />
<cfset Categories = ArrayLen( xmlDoc.opml.xmlChildren[2].XmlChildren ) />
<cfoutput>
<cfloop index="i" from="2" to="#Categories#">
<strong>#xmlDoc.opml.xmlChildren[StartingDataNode].XmlChildren[i].XmlAttributes.Title#</strong>
<ul>
<cfloop index="j" from="1" to="#ArrayLen( xmlDoc.opml.xmlChildren[StartingDataNode].XmlChildren[i].XmlChildren )#">
<li>
<a href="#xmlDoc.opml.xmlChildren[StartingDataNode].XmlChildren[i].XmlChildren[j].XmlAttributes.htmlURL#">
#xmlDoc.opml.xmlChildren[StartingDataNode].XmlChildren[i].XmlChildren[j].XmlAttributes.title#</a>
</li>
</cfloop>
</ul>
</cfloop>
</cfoutput>
The code will display as follows:

Posted by Dan | Posted in ColdFusion, Python | Posted on 12-29-2009
0
I just tried to write a quick script in Python that scans CFCs and generates a yUML URL to diagram. I pointed my script to my root CFC path and I got a 13K strlen URL. I pasted it in the address bar to see what happened and I got the following:
Request-URI Too Large
The requested URL's length exceeds the capacity limit for this server.
Apache/2.2.3 (Debian) Phusion_Passenger/2.0.2 Server at Ess000235.gtcust.grouptelecom.net Port 80
I wonder what the limitation is. I suppose I’ll have to do a CFC per diagram and then bind them together somehow. I’m choosing Python so this script can be part of my build script.
Here’s the code so far, which of course, could be optimized:
import re
import os
# UML Syntax
# http://yuml.me/diagram/class/[User|Property1;Property2|Method1();Method2()]
# http://yuml.me/diagram/class/
# [
# User
# |
# Property1;
# Property2
# |
# Method1();
# Method2()
# ]
# Master Path
ROOT_PATH = 'C:\\temp\\cf-yuml'
def SearchForFile( rootpath, searchfor, includepath = 0 ):
# Search for a file recursively from a root directory.
# rootpath = root directory to start searching from.
# searchfor = regexp to search for, e.g.:
# search for *.jpg : \.exe$
# includepath = appends the full path to the file
# this attribute is optional
# Returns a list of filenames that can be used to loop
# through.
#
# TODO: Use the glob module instead. Could be faster.
names = []
append = ""
for root, dirs, files in os.walk( rootpath ):
for name in files:
if re.search( searchfor, name ):
if includepath == 0:
root = ""
else:
append = "\\"
names.append( root + append + name )
return names
def getCFCInfo ( FILE, path ):
FILE.seek( 0, 0 )
CFCLines = FILE.readlines()
CFCFunctions = []
CFCProperties = []
CFC = {}
for i in CFCLines:
# Get names of methods
if re.search( "^<cffunction", i , re.IGNORECASE | re.MULTILINE ):
CFCFunctions.append( re.search( r'name\s*=\s*"([\w$-]+)"', i, re.DOTALL | re.IGNORECASE).group(1) )
# Get names of properties
if re.search( "^<cfproperty", i , re.IGNORECASE | re.MULTILINE ):
CFCProperties.append( re.search( r'name\s*=\s*"([\w$-]+)"', i, re.DOTALL | re.IGNORECASE).group(1) )
CFC = { "properties":CFCProperties, "methods":CFCFunctions }
# Generate URL
strFunctions = ""
strProperties = ""
for i in CFCFunctions:
strFunctions += i + "();"
for i in CFCProperties:
strProperties += i + ";"
CFCFileName = re.search(r"\\([\w-]+)\.cfc$", path, re.DOTALL | re.IGNORECASE).group(1)
return "[" + CFCFileName + "|" + ( strProperties.strip()[:-1] + "|" if strProperties.strip()[:-1] else "" ) + strFunctions.strip()[:-1] + "]"
URL = ""
for i in SearchForFile( ROOT_PATH, "\.cfc$", 1 ):
CFCFile = open( i, "r" )
URL += getCFCInfo( CFCFile, i ) + ","
CFCFile.close()
URL = URL[:-1]
print "http://yuml.me/diagram/class/" + URL
I’ll keep working on this as time goes on. So far it just goes through all the CFC’s from the path you point to. It will crawl through all sub directories. There’s no relationship between classes, however. Not yet at least.
Posted by Dan | Posted in Python, SQL Server | Posted on 12-27-2009
0
Setting up Python to connect to SQL Server was relatively easy. First, you select a DB API driver. I chose pyodbc because I saw a Python article on Simple-Talk. There are two simple steps:
- Install Pywin32. Get the latest. It’s a dependency for pyodbc.
- Install pyodbc. Get it for the version of Python you’re using.
Once you’ve done this, you can query your SQL Server db as so:
import pyodbc
connection = pyodbc.connect('DRIVER={SQL Server};SERVER=192.168.0.5;DATABASE=MyAwesomeDB;UID=sa;PWD=password')
cursor = connection.cursor()
cursor.execute("select * from states")
for row in cursor:
print row.StateID, row.Abbreviation, row.Name
For more snippets and a tutorial, check out the documentation.
Now let’s try something more interesting. Let’s try doing some inserts and see how long it takes.
import win32api
import uuid
import pyodbc
connection = pyodbc.connect('DRIVER={SQL Server};SERVER=192.168.0.5;DATABASE=MrSkittles;UID=sa;PWD=password')
cursor = connection.cursor()
_start = win32api.GetTickCount()
for i in range( 0, 10000 ):
# Let's insert two pieces of data, both random UUIDs.
sql = "INSERT INTO Manager VALUES( '" + str( uuid.uuid4() ) + "', '" + str( uuid.uuid4() ) + "' )"
cursor.execute( sql )
connection.commit()
_end = win32api.GetTickCount()
_total = _end - _start
print "\n\nProcess took", _total * .001, "seconds"
After some tests, 10,000 records took roughly 20-30 seconds. 1,000,000 records took 30 to 40 minutes. A bit slow, but it’s not a server machine. My machine is a Core Duo, 1.8Ghz x 2, at ~4GB with PAE on WindowsXP, but I ran this on a VMware VM with 1GB and SQL Server 2005 w/Windows Server 2003. The table was a two column table both varchar(50). On a server machine, it should be a helluva lot faster.