We had to do a massive restructuring of one of our client’s applications and it required changes to the domain names and URL’s.
The command below will replace occurrences of www.infoexport.gc.ca/ie-en with www.tradecommissioner.gc.ca/eng in html files recursively. The \ is used to escape / in the URL’s.
If you are running this on Windows you HAVE to specify a backup file name using the -i parmeter. This is a limitation of the Windows file system, the side effect being its always good to have backups.
$ find . -type f | xargs perl -p -i’test.bak’ -e ’s/www.infoexport.gc.ca\/ie-en/www.tradecommissioner.gc.ca\/eng/g’ *.html
UNION NLSSORT ORDER BY
03/02/2009
I came across a bug in our codebase, the end user didn’t see the error message but just a empty result so it wasn’t considered high priority .. But anyways, after looking at the logs the problem was with the NLSSORT and SQL ..
The sql was generated dynamically so it was a bit tricky to debug, lets take a look at the valid sql below :
SELECT a, b FROM x, y UNION SELECT c, d FROM m, n ORDER BY a ASC
This worked fine but the error came up when looking at french content which was sorted using NLSSORT.
SELECT a, b FROM x, y UNION SELECTc, d FROM m, n ORDER BY nlssort(a, ‘nls_sort=french’) ASC
The above SQL is invalid because of the way NLSSORT works .. We need to explicitly select the columns needed from the result of the SQL, like this :
SELECT * FROM (SELECT a, b FROM x, y UNION SELECT c, d FROM m, n) ORDER BY nlssort(a, ‘nls_sort=french’) ASC
JDBC and Oracle dblinks
23/01/2009
I came across a small problem when trying to access a dblink in my SQL using java.sql.PreparedStatement .. I tried using java.sql.Statement instead to build my query and it worked fine.
Ruby : automated re-naming script
23/01/2009
I recently had a chance to work on a project which required massive amounts of file and folder restructring. I could’ve done this manually to minimize errors but I chose not to due to time constraints and the fact that most of the errors would be caught during UAT.
The script takes a parameter from the command line which sets the language. Depending on the language the script initializes the proper old -> new mappings for files and folders. It then replaces any references to the old file with new file name.
require “ftools”
class FileRename
# Define old – > new mappings for english
@@hashEn = Hash.new
@@hashEn["old-name.jsp"] = “new-name.jsp”
# Define old – > new mappings for french
@@hashFr = Hash.new
@@hashFr["old-name.jsp"] = “new-name.jsp”
@@changes = 0
# Initialize hash of old – new file names for jsp’s
def initialize(lang)
if lang.eql? “en”
@oldPrefix = “ie-en”
@newPrefix = “eng”
@oldNewHash = @@hashEn
elsif lang.eql? “fr”
@oldPrefix = “ie-fr”
@newPrefix = “fra”
@oldNewHash = @@hashFr
end
end
# Copy contents of old files to new files
def renameFiles
@logFile = File.new(“file_renaming.log”, “w”)
@oldNewHash.each do |key, value|
oldFile = File.new(@oldPrefix + “/” + key, “r”) # Open old file in READ-ONLY mode
newFile = File.new(@newPrefix + “/” + value, “w”) # Open new file in WRITE mode
oldFile.each_line do |line|
newFile.puts line # Copy each line in old file to new file
end
newFile.close # Close new file
oldFile.close # Close old file
@logFile.puts “Rename ” + key + ” to ” + value
File.delete(oldFile.path) # Delete old file
end
@logFile.close
end
# Replace references to old file names with new file names in the newly created jsp’s
def replaceOldFileNames(line)
newLine = String.new
newLine.replace(line) # create a new copy of the line passed
@oldNewHash.each do |key, value|
newLine.gsub!(@oldPrefix + “/” + key, @newPrefix + “/” + value) # replace absolute references to old jsp names such as /ie-en/old.jsp with /eng/new.jsp
newLine.gsub!(“/” + key, “/” + value) # replace <a href=”../old.jsp” with <a href=”../new.jsp”
newLine.gsub!(“\”" + key, “\”" + value) #replace <a href=”old.jsp” with <a href=”new.jsp”
newLine.gsub!(key, value) # replace old.jsp with new.jsp, ONLY needed for .properties files, comment out otherwise
end
newLine # return the new string
end
# Replace links to old jsp’s in files in current directory and its sub-folders
def replaceOldLinks(ext)
@logFile = File.new(“file_renaming.log”, “a”)
validFiles = File.join(“**”, ext) # File filter to recursilve extract all files for the given extension
Dir.glob(validFiles) do |path| # Scan every file
puts “Fixing paths in ” + path.to_s
@logFile.puts “Fixing paths in ” + path.to_s
aFile = File.new(path, “r”) # open the file in read-only
lines = aFile.readlines # Read all lines from file
aFile.close
aFile = File.new(path, “w”) # open the file in write now and scan each line for old links and write it back
lineNumber = 1
lines.each do |line|
newLine = replaceOldFileNames(line)
unless newLine.eql? line
@logFile.puts “Changed line number ” + lineNumber.to_s + ” in ” + path.to_s
@@changes += 1
end
aFile.puts newLine
lineNumber += 1
end
aFile.close
puts “Done fixing paths in ” + path.to_s
@logFile.puts “Done fixing paths in ” + path.to_s
end
@logFile.puts “Total changes made : ” + @@changes.to_s
@logFile.close
end
end
langCode = ARGV[0] == nil ? “en” : ARGV[0]
fr = FileRename.new(langCode)
fr.renameFiles
fr.replaceOldLinks(“*.html”)
fr.replaceOldLinks(“*.htm”)
fr.replaceOldLinks(“*.jspf”)
fr.replaceOldLinks(“*.jsp”)
fr.replaceOldLinks(“*.properties”)
If you are getting the error below:
The procedure entry point mysql_stmt_row_tell could not be located in the dynamic link library libmysql.dll
You have to copy the libmysql.dll from your mysql/bin directory to ruby/bin directory. I found this solution here.
Upgrading to Rails 2.1.0
12/08/2008
I tried to update to the latest Rails 2.1.0 version but got an error when trying to update the activesupport gem. So I decided to update each module manually and still got an error when updating activesupport
C:\InstantRails>gem update activesupport -y
Updating installed gems…
Bulk updating Gem source index for: http://gems.rubyforge.org
Updating metadata for 13 gems from http://gems.rubyonrails.org
………….
complete
Attempting remote update of activesupport
INFO: `gem install -y` is now default and will be removed
INFO: use –ignore-dependencies to install only the gems you list
ERROR: Error installing activesupport:
invalid gem format for C:/InstantRails/ruby/lib/ruby/gems/1.8/cache/activesupport-2.1.0.gem
The fix is to download the gem manually from here, save it and run gem install activesupport-2.1.0.gem.
scratch effect using Flash and Actionscript
16/07/2008
Read this tutorial to get the scratch effect going. I have modified my version to draw a square instead of a circle and check when the user is “almost” done scratching the card.
To check to see if the user is almost done scratching the card I use a 2D array to represent a grid on the background image. The 2D array size or Grid size is the same as your image size, the first dimension being x or width and second dimension being y or height. By default all the values in the array are set to undefined in Actionscript. Therefore, everytime we draw a square we set the value at those indices in the array to be true. For example, a user clicks at (20,20) and we draw a square from (10,10) (10,30) (30,10) (30,30). We will set the value for all the indexes from x = 10 to 30 and y = 10 to 30 to true in our 2D array.
When a user lifts the mouse button we check to see his/her progress. Doing this is just iterating through the 2D array and checking to see which pixels have been set to true. You can check to see if all the pixels are cleared or just the ones around the middle or even have a percentage of the total pixels set to true.
Here’s the source code:
this.createEmptyMovieClip(‘mask_mc’,0);
bg_mc.setMask(mask_mc);
var contor:Number=0;
var imageHeight:Number = 300; //Image Height
var imageWidth:Number = 400; //Image Width
var totalPixels:Number = imageHeight * imageWidth; //Total number of pixels in this image
var almostDonePixelCount:Number = 0.8 * totalPixels; //Number of pixels that have to be scratched to consider entire picture to be scratched. 80% of all pixels have to be scratched now.
var pixelArray:Array = create2DArray(imageWidth, imageHeight); // 2D array to represent the image grid. For my image x is 400 and y is 300
// function create2DArray creates a 2D array with x = width and y = height
function create2DArray(width:Number, height:Number):Array
{
var array:Array = Array();
for(var index:Number = 0; index < width; ++index)
array.push(Array(height));
return array;
}
// function drawSquare draws a square on mask_mc MovieClip of sides length 2*r and having center to mouse coordinates.
function drawSquare(mask_mc:MovieClip):Void
{
var r:Number = 20; // this controls how far off the clicked point we start drawing a square
var xcenter:Number = _xmouse; // x co-ordinates of user click
var ycenter:Number = _ymouse; // y co-ordinates of user click
//Draw the square
mask_mc.moveTo(xcenter-r, ycenter-r);
mask_mc.beginFill(0×000000, 100);
mask_mc.lineTo(xcenter-r, ycenter-r);
mask_mc.lineTo(xcenter+r, ycenter-r);
mask_mc.lineTo(xcenter+r, ycenter+r);
mask_mc.lineTo(xcenter-r, ycenter+r);
mask_mc.endFill();
//Loop to set pixels within the square to true
for(var xIndex:Number = xcenter-r; xIndex <= xcenter + r; xIndex++)
{
for(var yIndex:Number = ycenter-r; yIndex <= ycenter + r; yIndex++)
{
pixelArray[xIndex][yIndex] = true;
}
}
}
// function allScratched checks if the user has scratched off most of the upper layer which is set in almostDonePixelCount
function scratchDone():Boolean
{
var pixelsScratched:Number = 0;
for(var xIndex:Number = 0; xIndex < imageWidth; xIndex++)
{
for(var yIndex:Number = 0; yIndex < imageHeight; yIndex++)
{
if(pixelArray[xIndex][yIndex] == true)
{
pixelsScratched++;
}
}
}
return pixelsScratched > almostDonePixelCount;
}
// contor variable is used to hold if the mouse is pressed (contor is 1) or not (contor is 0)
this.onMouseDown=function()
{
contor=1;
}
// if the mouse is hold and moved then we draw a square on the mask_mc
this.onMouseMove=this.onEnterFrame=function()
{
if (contor==1)
{
drawSquare(mask_mc);
}
}
// check to see if the upper layer has been scratched
this.onMouseUp=function()
{
contor=0;
if(scratchDone())
{
trace(“Scratch Done”);
}
}
Flexible Rails Iteration 6 issues
16/07/2008
I came across some roadblocks while reading the Flexible Rails book.
Here’s a few of them, I’ll update if I come across more of them.
- On a POST Rails will return a HTTP Status code of “201 Created”. Flex treats this as an error code and will therefore throw an error even though the method call executed fine. To prevent this change the following line in your rails controller:
format.xml { render
ml = > @task, :status = > :created }
to
format.xml { render
ml = > @task, :status = >
k }
So you are forcing rails to send a “200 OK” status code.
- IE caches HTTPService calls, so when you call a HTTPService the second time IE wont even fire the request to your rails server. It works fine in Firefox but you need to clear the IE cache and reload your flex application.
Rails to_xml method problem with Flex
03/06/2008
I ran into a problem while trying to receive data form my Rails app and consuming it in Flex. The attributes were named first_name and last_name in my Rails app but I couldnt read them in Flex. I looked at the xml generated and realized that Rails changes the ‘_’ to ‘-’ by default. To avoid this run the to_xml method with to_xml(:dasherize => false) set to false.
Max open cursors exceeded
07/04/2008
You might come across this exception ORA-01000: maximum open cursors exceeded while using JDBC. This usually happens when you have too many ResultSet and Statement objects in a loop fetching thousands of rows.
To avoid this error, close every ResultSet and Statement before using it again. These are closed automatically when you close the connection but you don’t want to re-open the connection every time you iterate through the loop.