Thursday, January 3, 2019

Java jdb Error: "ERROR: transport error 202: getaddrinfo: unknown host"

I was trying to debug a java program on the command line using the Java jdb debugger when I was faced with a "transport error 202: getaddrinfo: unknown host" error:
$ jdb MyProg
Initializing jdb ...
> run
run MyProg
VM start exception: VM initialization failed for: /Library/Java/JavaVirtualMachines/jdk-11.0.1.jdk/Contents/Home/bin/java -Xdebug -Xrunjdwp:transport=dt_socket,address=mycomputername.local:58341,suspend=y MyProg

ERROR: transport error 202: getaddrinfo: unknown host
ERROR: JDWP Transport dt_socket failed to initialize, TRANSPORT_INIT(510)
JDWP exit error AGENT_ERROR_TRANSPORT_INIT(197): No transports initialized [:732]

Fatal error:
Target VM failed to initialize.
The jdb documentation has this to say:
C:\> jdb MyClass
When started this way, jdb invokes a second Java VM with any specified parameters, loads the specified class, and stops the VM before executing that class's first instruction.
We can see the exact command jdb used do run this second Java VM in the error output above:
java -Xdebug -Xrunjdwp:transport=dt_socket,address=mycomputername.local:58341,suspend=y MyProg
The problem seemed to occur when jdb was trying to resolve the host name "mycomputername.local".
getaddrinfo: unknown host
Adding the host mycomputername.local to my Mac /etc/hosts did the trick.

/etc/hosts:

127.0.0.1    localhost
127.0.0.1    mycomputername.local
After that change jdb was able to run the class without any issues.
$ jdb MyProg
Initializing jdb ...
> run
run MyProg
Set uncaught java.lang.Throwable
Set deferred uncaught java.lang.Throwable
>
VM Started: 

Hello World

The application exited

References

jdb - The Java Debugger
https://docs.oracle.com/javase/7/docs/technotes/tools/windows/jdb.html
JDWP - Java Debug Wire Protocol
https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/introclientissues005.html
getaddrinfo
http://man7.org/linux/man-pages/man3/getaddrinfo.3.html

Tuesday, December 8, 2015

Block WordPress XML-RPC Requests Using Apache .htaccess

I recently noticed an increase in unauthorized attempts to access the /xmlrpc.php endpoint of the company WordPress blog. Although the attempts seem to have been unsuccessful, we did decide to limit access to the endpoint to requests originating from the company networks and VPN nodes. The following are some steps you can take if you are facing a similar situation.

Edit the blog .htaccess file:

vi /var/www/html/style-blog/style-blog/.htaccess

Add or update the following:

# Block WordPress xmlrpc.php requests
<Files xmlrpc.php>
order deny,allow
deny from all
allow from 50.111.111.111
allow from 127.0.0.1
</Files>

This blocks access to xmlrpc.php from all hosts except localhost and 50.111.111.111 (the fictitious IP address for the San Francisco Office).

To grant access to a host, simply white-list the host's IP address using the `allow from` directive. The Apache daemon may have to be restarted for the changes to take effect:

sudo /etc/init.d/httpd restart

To test whether it works access http://blog.mycompany.com/xmlrpc.php . The following cURL command can be used to check XML-RPC access is:

curl http://blog.mycompany.com/xmlrpc.php

You should see the following message accessed from a machine whose public IP address is white-listed:

"XML-RPC server accepts POST requests only."

You should see the following output when accessed from a machine whose public IP address is NOT white-listed:

<!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML 2.0//EN">
<html><head>
<title>403 Forbidden</title>
</head><body>
<h1>Forbidden</h1>
<p>You don't have permission to access /xmlrpc.php
on this server.</p>
<hr>
<address>Apache/2.2.31 (Amazon) Server at blog.weddingtonway.com Port 80</address>
</body></html>

Thursday, November 5, 2015

Creating and Verifying MD5 Checksums

Creating MD5 Checksums

The md5sum command found on most Unix/Linux operating systems can be used to create MD5 checksums for files or to verify the integrity of files if the MD5 checksums for those files are already available.

Let us suppose you want to create an MD5 checksum file containing the checksums for the binary files my_disk_image-1.iso, my_disk_image-2.iso and my_disk_image-3.iso. You can accomplish this by passing the three files as arguments to the md5sum command and redirecting the output to a text file:

$ md5sum -b my_disk_image-1.iso my_disk_image-2.iso my_disk_image-3.iso > MD5SUM

The "-b" option instructs the md5sum command to treat each file as a binary file. If you are working text with files, you can use the "-t" option. The generated checksum file "MD5SUM" will look similar to the following:

302d1a8fa7e13871d9909947eb23935d *my_disk_image-1.iso
2f5be4a2fe3d80b134aba6c6023eca57 *my_disk_image-2.iso
52237af3336321e0b03586055b8e5d78 *my_disk_image-3.iso

The first 32 characters of each line is the MD5 checksum for the file mentioned on that line. The asterisk that precedes the file name indicates that the file is a binary file.

Directories and Subdirectories

The following command can be used to compute checksums for file in a given directory and it's sub-directories.

find /path/to/the/directory -type f -print0 | xargs -0 md5sum > MD5SUM

This command creates a file called "md5sums" containing the MD5 checksum for all the files in /usr/share/man and its sub-directories.

find /usr/share/man -type f -print0 | xargs -0 md5sum -b > md5sums

As you can see the by the path names, the command has created MD5 hashes for files residing at various levels of the directory tree.

...
3710f7bc99303ceb90a1ae1e75361913 */usr/share/man/fr/man7/backend.7.gz
f3f6fb8a04b9e78971d875ed8645f848 */usr/share/man/fr/man7/filter.7.gz
9caaf4f56d9f2a72ce9fe977c703475c */usr/share/man/man5/sane-dc210.5.gz
f170bb97e4fc6b919426cfecc2ef583b */usr/share/man/man5/faillog.5.gz
...

Verifying a File's Integrity Using it's MD5 Checksum

To generate the MD5 checksum for a file you can do the following:

$ md5sum -b my_disk_image-1.iso
e36e064cf65e4dc62ea279dc860c8f9a *my_disk_image-1.iso

Checking each of the 32 characters of the checksum against the original is tedious. If you already have the original MD5 checksum file, you can perform the following:

$ cat MDSUM
302d1a8fa7e13871d9909947eb23935d *my_disk_image-1.iso
2f5be4a2fe3d80b134aba6c6023eca57 *my_disk_image-2.iso
52237af3336321e0b03586055b8e5d78 *my_disk_image-3.iso
$ ls my*.iso
my_disk_image-1.iso  my_disk_image-2.iso my_disk_image-3.iso
$ md5sum -c MD5SUM 
my_disk_image-1.iso: OK
my_disk_image-2.iso: OK
my_disk_image-3.iso: OK

Here are some status messages you may see:

OK                   - MD5 checksums matched.
FAILED               - Generally means the MD5 checksums did not match.
FAILED open or read  - The file could not be read or is missing.

When Checksums Fail

Here is a case where validating the checksums failed:

my_disk_image-1.iso: OK
my_disk_image-2.iso: FAILED
md5sum: my_disk_image-3.iso: No such file or directory
my_disk_image-3.iso: FAILED open or read
md5sum: WARNING: 1 of 3 listed files could not be read
md5sum: WARNING: 1 of 2 computed checksums did NOT match

In the above scenario:

  • my_disk_image-1.iso was identical to the original.
  • my_disk_image-2.iso was different from the original.
  • my_disk_image-3.iso was missing from the directory.

Beyond MD5

The sha1sum (that is a "one", not lowercase "L") command can be used to create a SHA-1 Checksum. The sha225sum, sha256su, sha384sum, and sha512sum commands compute the 224, 256, 384, and 512 bit (respectively) SHA-2 hashes. The usage and options of these commands are the same as for the m5sum command.

Links

MD5
http://en.wikipedia.org/wiki/MD5
checksum
http://en.wikipedia.org/wiki/Checksum
md5sum
http://en.wikipedia.org/wiki/Md5sum

Tuesday, June 9, 2015

Using Peddler to Access Amazon Marketplace Web Service (MWS)

Peddler is a Ruby Gem that can be used to access Amazon Marketplace Web Service (Amazon MWS) from Ruby. The following are some Ruby snippets that can be used to write a Ruby script that accesses MWS or to make ad-hoc queries against MWS from within IRb (Interactive Ruby.

Install Peddler Gem:

gem install peddler
Successfully installed excon-0.45.3
Successfully installed jeff-1.3.0
Successfully installed peddler-0.16.0

You may have to use sudo, depending on how you installed RubyGems.

Setup the Peddler client instance:

require 'peddler'

# Setup client
client = MWS::Orders::Client.new({
  :primary_marketplace_id => "ATVPD00000000",                             # Marketplace ID
  :merchant_id            => "A1UX7000000000",                            # Seller ID
  :aws_access_key_id      => "AKIAJ000000000000000",                      # AWS Access Key ID
  :aws_secret_access_key  => "fT+tcCTUBUsd7w00000000000000000000000000"   # Secret Key
})

# Setup error callback. This helps debugging Amazon API error messages.
client.on_error{|req,resp| puts resp.body }

# Get API Status
puts client.get_service_status

The following are some of the ways you can query MWS orders:

# Retrieve orders. CreatedAfter or LastUpdatedAfter must be specified.
# - created_after
# - created_before
# - last_updated_after
# - last_updated_before
# - order_status  (Unshipped, Shipped, Canceled)

resp1 = client.list_orders(:created_after => '2015-05-01')
puts resp1.body

resp2 = client.list_orders(:created_after => '2015-05-01', :order_status => ['Unshipped', 'PartiallyShipped'])
puts resp2.body

resp3 = client.list_orders(:created_after => '2015-05-01', :order_status => ['Shipped'])
puts resp3.body

These are some documentation pages that were helpful when investigating Peddler:

Peddler
https://github.com/hakanensari/peddler
Peddler API Docs
MWS::Orders::Client
MWS::Orders::Client#list_orders
Amazon API Docs
List Orders

Friday, October 24, 2014

Images in Active Admin Index pages.

An example of how images can be embedded in Active Admin index pages in a Ruby on Rails application:
ActiveAdmin.register ColorGroup do
  index :download_links => [:csv] do
    selectable_column
    column(:id) { |it| auto_link it, it.id }
    column(:name) { |it| auto_link it, it.name }
    column(:slug) { |it| auto_link it, it.slug }
    column(:family) { |it| auto_link it.color_family, it.color_family.name if it.color_family.present? }
    column :asset_url
    column :order
    column :image do |it|
      if it.nil?
        "N/A"
      else
        # Use image_tag here...
        link_to sanitize("<img src=\"#{it.asset_url}\" class=\"cgs-img\" width=\"101\" height=\"24\" />"), it.asset_url
      end
    end
    actions
  end
end

Monday, October 13, 2014

Block IP Addresses Using iptables

This post describes the steps to block the IP address that is the origin of a brute-force attack against a WordPress blog.

WARNING!

Make sure you DO NOT block your own IP addresses, or apply and global rules which would block the SSH port (port 22).

Identify IP Addresses to Block (Blog Server)

Tail the blog server apache logs:

sudo tail -f /var/log/httpd/access_log
199.188.70.163 - - [12/Oct/2014:16:29:03 +0000] "POST /wp-login.php HTTP/1.0" 200 4432 "-" "-"
37.59.125.22 - - [12/Oct/2014:16:29:03 +0000] "POST /wp-login.php HTTP/1.0" 200 4432 "-" "-"
199.188.70.163 - - [12/Oct/2014:16:29:04 +0000] "POST /wp-login.php HTTP/1.0" 200 4432 "-" "-"
37.59.125.22 - - [12/Oct/2014:16:29:05 +0000] "POST /wp-login.php HTTP/1.0" 200 4432 "-" "-"
37.59.125.22 - - [12/Oct/2014:16:29:05 +0000] "POST /wp-login.php HTTP/1.0" 200 4432 "-" "-"

This shows two ip addresses, 199.188.70.163 and 37.59.125.22 attempting to brute-force the blog's Word Press login page:

It is worth checking the Apache error log:

sudo tail -f  /var/log/httpd/access_log

Blocking IP Addresses Using iptables

List existing iptables rules:

# List iptables rules
sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT

The output of the -S switch can be used to re-create the given rule from the command line or a rule script. To block a single IP addresses 199.188.70.163 and 37.59.125.22 do the following:

sudo iptables -A INPUT -s 199.188.70.163 -j DROP
sudo iptables -A INPUT -s 37.59.125.22 -j DROP

Listing the iptables rules once more should show the DROP rules that were added in the previous step:

# List iptables rules
sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 199.188.70.163 -j DROP
-A INPUT -s 37.59.125.22 -j DROP

The two rules that were added have not taken effect yet. To save them do the following:

# Save the iptables rules
sudo /etc/init.d/iptables save

NOTE: The /sbin/service command is available on the blog server, so you can use that to save iptables rules:

sudo /sbin/service iptables save
The service command runs /etc/init.d/ scripts without passing on environment variables defined by the user.

When successfully saved, it should display a message such as:

iptables: Saving firewall rules to /etc/sysconfig/iptables:[  OK  ]

Removing iptables Rules

List iptables Rules:

sudo iptables -S
-P INPUT ACCEPT
-P FORWARD ACCEPT
-P OUTPUT ACCEPT
-A INPUT -s 199.188.70.0/24 -j DROP
-A INPUT -s 37.59.125.0/24 -j DROP

The following lists the form in a more readable form:

# List rules with line number in verbose mode
sudo iptables -L -n -v --line-numbers

In the following output the "num" column represents the line number within each Chain (INPUT, FORWARD, and OUTPUT). This number will be will be used to remove the rules.

Chain INPUT (policy ACCEPT 31267 packets, 2159K bytes)
num   pkts bytes target     prot opt in     out     source               destination
1      206 12472 DROP       all  --  *      *       199.188.70.0/24      0.0.0.0/0
2      313 20047 DROP       all  --  *      *       37.59.125.0/24       0.0.0.0/0

Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
num   pkts bytes target     prot opt in     out     source               destination

Chain OUTPUT (policy ACCEPT 14419 packets, 75M bytes)
num   pkts bytes target     prot opt in     out     source               destination

Look at the number on the left in the "num" column, then use number to delete the rule. For example delete line number 2 (subnet 37.59.125.0/24), enter:

sudo iptables -D INPUT 2

This will not take effect until it the rule is saved:

# Save the iptables rules
sudo /etc/init.d/iptables save

Identify Other IP Addresses Performing Similar Attacks

Use the following command to identify IP addresses making large number of login attempts the WordPress blog:

# IP addresses making POST request to the WordPress login page
grep wp-login /var/log/httpd/access_log | grep POST | awk '{print $1}'| sort | uniq -c | sort -nr
  20154 199.188.70.163
  14105 194.65.224.242
   3732 37.59.125.22
     40 37.1.222.114
     25 192.187.99.194

Make sure that you EXCLUDE remove your own IP addresses and other legitimate IP addresses from the above list before blocking them. In this case we should probably block the first three ( 20154 199.188.70.163, 194.65.224.242, and 37.59.125.22) and not the last two (37.1.222.114 and 192.187.99.194).

You may want to use an IP address lookup tool such as MaxMind GeoIP Lookup to see where the IP address is located:

Finding Your Public IP Address on the Command Line

The following is a Bash command that can be used to quickly find the public IP address your internet service provider (ISP) has given you. This is not the same as the IP address seen by your broadband router, which is usually an private IP address within the ISPs network, or the IP address given to your computer, which is a private IP address issued by my home router.

This command simply makes a "what is my ip" query to Google, which in turn displays the IP address it sees the request originating from. The awk command parses the IP address from the rest of the HTML and prints it to the command line.

curl -s 'https://www.google.com/search?q=what+is+my+ip' | awk 'match($0, /\(Client.*: (.*)\)/){print substr($0, RSTART, RLENGTH)}'
(Client IP address: 50.x.x.x)

Saturday, May 18, 2013

Using Gnuplot in Bash Shell Scripts

This is an example of how Gnuplot scripts can be embedded within Bash scripts using Bash Here Documents (heredocs):

#!/bin/bash

filename="log/load_me.log.1368725550"

awk '/for 10000000/ {c+=1; if(c > 46){n+=1; printf "%s\t%s\n", n, $2} }' $filename > log/values.dat

window_size=50
ruby running_average.rb log/values.dat $window_size > log/averages.dat

gnuplot -p <<EOSCRIPT

set title 'Time to Insert Relationships in Batches of 10M in Neo4j batch-import'
set xlabel 'Batches of 10M Rels on `date "+%Y-%m-%d at %H:%M:%S %Z"`'
set ylabel 'Time Taken (s)'
set grid

# Draw trend line
f(x) = a*x**3 + b*x**2 + c*x + d

set fit quiet
fit f(x) 'log/values.dat' using 1:(\$2/1000) via a,b,c,d
unset fit

# Scale column No.2 by 1000 to turn ms in s.
plot 'log/values.dat' using 1:(\$2/1000) title 'Time to Insert Rels' with lines, f(x) title 'Fit', 'log/averages.dat' using 1:5 title "Average $window_size" with lines

pause -1 "\n\nHit return to continue\n\n"

EOSCRIPT

num_stats=`wc -l log/values.dat | awk '{print $1}'`

tail -$window_size log/values.dat | awk -v num_stats="$num_stats" '{n+=1; s+=$2}
END{
  avg=s/(n*1000);
  print "Average of last", n, "is", avg, "(s)";
  print "Num Rels Stats =", num_stats;
  print "Hours Remaining =", (3300-num_stats+46)*avg/3600;
  printf "Percentage complete = %.2f%%\n", (num_stats * 100 / 3300.0); 
}'

echo -e "Completed at `date`\n\n"

References

Gnuplot fit command
http://www.manpagez.com/info/gnuplot/gnuplot-4.6.0/gnuplot_263.php
Bash Here Documents
https://www.tldp.org/LDP/abs/html/here-docs.html
Wikipedia Here Document
https://en.wikipedia.org/wiki/Here_document

Monday, September 17, 2012

Installing percona-tools Using Homebrew

Try installing percona-tools using Homebrew:

brew install percona-tools

and it will throw the following error:

indika$ brew install percona-toolkit
Unsatisfied dependency: DBD::mysql
Homebrew does not provide Perl dependencies; install with:
  cpan -i DBD::mysql

The solution is to first install the DBD:mysql CPAN module manually:

cpan -i DBD::mysql

When prompted for parameters for Makefile.PL, enter the following:

Parameters for the 'perl Makefile.PL' command? [] --testuser=root

Here "root" refers to the DB user, not the system user by the same name. When I tried to install DBD:mysql without the "--testuser=<username>" option on my computer, it resulted in the following error:

t/80procs.t ................. 1/29 DBD::mysql::db do failed: alter routine command denied to user ''@'localhost' for routine 'test.testproc' at t/80procs.t line 41.
DBD::mysql::db do failed: alter routine command denied to user ''@'localhost' for routine 'test.testproc' at t/80procs.t line 41.
# Looks like you planned 29 tests but ran 2.
# Looks like your test exited with 255 just after 2.

Now CD into your CPAN build directory:

cp ~/.cpan/build
ls -l

drwxr-xr-x  28 indika  staff  952 Sep 16 23:32 DBD-mysql-4.022-Sl9Tjw
drwxr-xr-x  28 indika  staff  952 Sep 16 22:59 DBD-mysql-4.022-XOJVB7
drwxr-xr-x  28 indika  staff  952 Sep 16 23:30 DBD-mysql-4.022-mnhn3t

... and make the package:

cd DBD-mysql-4.022-mnhn3t

make
make test
sudo make install

Now install percona-tools using Homebrew:

brew install percona-tools

You should see it successfully:

==> Downloading http://www.percona.com/redir/downloads/percona-toolkit/2.1.2/percona-toolkit-2.1.2.tar.gz
######################################################################## 100.0%
==> perl Makefile.PL PREFIX=/usr/local/Cellar/percona-toolkit/2.1.2
==> make
==> make test
==> make install
/usr/local/Cellar/percona-toolkit/2.1.2: 79 files, 5.6M, built in 11 seconds

Tuesday, December 7, 2010

Turning Over a New Leaf

It has a been few years since I started this blog. I had chosen one of the stock templates offered by Blogspot, and never felt the need to put too much effort into customizing it. Even when Blogspot/Blogger released the new templates, which I have to admit are much nicer than the ones before, yet that alone did not justify switching templates.

This changed today when I realized that the new templates could have a maximum width of 1000px while the old templates had a fixed width. This is something I had desperately needed. The usable area for a text of a blog post was around 460px. The source code snippets and console output dumps which I include in my posts as pre-formatted text often wrap around or need to be scrolled due to the limited width of the post area.

With the new template the usable area for the blog post text is approximately 670px. It doesn't seem like much of an improvement, but it makes a huge difference!

The new design took effect at 11:47pm PST today. It is a slightly modified version of one of the new stock designs. I am not yet done tweaking the new blog design, but I feel that this is a good starting point... for now.

Here is a screenshot of this post with the previous blog template I used, included here more for the sake of nostalgia than anything else.

Tuesday, November 23, 2010

Configuring Aptana to Treat Gemfiles as Ruby Files

Aptana Studio 2 does not recognize Gemfiles used by Bundler as Ruby files. This means that Aptana will treat the Gemfile you are editing as an ordinary plain text file. You will not have Ruby syntax highlighting, word completion, and syntax checking available within the editor. In order to specify that the Gemfile (or any other file for that matter) is a Ruby file, do the following:
  1. Open the "Window Menu" --> Preferences
  2. Go to General --> "Content Types"
  3. Expand "Text" node under "Content types"
  4. Select "Ruby Source File"
  5. Click the "Add..." button and enter "Gemfile" as the content type.
  6. Click the "OK" button to save your changes.



The above procedure can be used to add files for the following content types:
  • CSS Source Files
  • ERB Source Files
  • HAML Source Files
  • HTML Source Files
  • JAR Manifest Files
  • Java Property Files
  • Java Source Files
  • JavaScript Source Files
  • SASS Source Files
  • XML Build Files (Ant, etc)
  • XML Source Files (xml, xslt, etc)

Friday, March 26, 2010

Nondiscriptive Rail Error "Errors running test:units!"

Errors Running test:units!


The "Errors running test:units!" error while creating a brand new Rails application under Cygwin:

rails world_app -d mysql
cd world_app


$ rake test

This results in the following error message:

(in /cygdrive/d/workspace/tt/world_app)
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
Errors running test:units!

Attempting to execute the Rails tests results in the same eror:

$ rake test --trace
(in /cygdrive/d/workspace/tt/world_app)
** Invoke test (first_time)
** Execute test
** Invoke test:units (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:abort_if_pending_migrations
** Invoke test:functionals (first_time)
** Invoke db:test:prepare
** Execute test:functionals
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
** Invoke test:integration (first_time)
** Invoke db:test:prepare
** Execute test:integration
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
Errors running test:units!


Fixing the Error


The following steps fixed the error:

  1. Edit config/database.yml
  2. Make sure the db password is correct.
  3. Make sure the db is created.
  4. Change "host: localhost" to "host: 127.0.0.1" if need be.


$ rake test --trace
(in /cygdrive/d/workspace/tt/world_app)
** Invoke test (first_time)
** Execute test
** Invoke test:units (first_time)
** Invoke db:test:prepare (first_time)
** Invoke db:abort_if_pending_migrations (first_time)
** Invoke environment (first_time)
** Execute environment
** Execute db:abort_if_pending_migrations
** Execute db:test:prepare
** Invoke db:test:load (first_time)
** Invoke db:test:purge (first_time)
** Invoke environment
** Execute db:test:purge
** Execute db:test:load
** Invoke db:schema:load (first_time)
** Invoke environment
** Execute db:schema:load
** Execute test:units
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
** Invoke test:functionals (first_time)
** Invoke db:test:prepare
** Execute test:functionals
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"
** Invoke test:integration (first_time)
** Invoke db:test:prepare
** Execute test:integration
/usr/bin/ruby.exe -I"lib:test" "/usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb"

Thursday, October 15, 2009

Rails Error: "interning empty string"

The "interning empty string" error kept popping up in some of our code written prior to upgrading to Ruby on Rails 2.3.4.
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/attribute_methods.rb:344:in `respond_to?'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/attribute_methods.rb:344:in `respond_to?'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:40:in `value'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:79:in `generate_message'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:30:in `message'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:34:in `full_message'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:275:in `full_messages'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:275:in `map'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:275:in `full_messages'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/base.rb:2036:in `inject'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:274:in `each'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:274:in `inject'
C:/Ruby/lib/ruby/gems/1.8/gems/activerecord-2.3.4/lib/active_record/validations.rb:274:in `full_messages'
C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_view/helpers/active_record_helper.rb:201:in `error_messages_for'
C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/enumerable.rb:59:in `map'
C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/enumerable.rb:59:in `sum'
C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_view/helpers/active_record_helper.rb:201:in `error_messages_for'
C:/Ruby/lib/ruby/gems/1.8/gems/activesupport-2.3.4/lib/active_support/core_ext/object/misc.rb:78:in `with_options'
C:/Ruby/lib/ruby/gems/1.8/gems/actionpack-2.3.4/lib/action_view/helpers/active_record_helper.rb:192:in `error_messages_for'
C:/workspace/epanel_latest1/app/helpers/application_helper.rb:184:in `error_messages_for'
C:/workspace/epanel_latest1/app/views/login_users/login.html.erb:60:in `_run_erb_app47views47login_users47login46html46erb'

The culprit turned out to be:
model.errors.add('', 'Some message')
and the fix was to change this to
model.errors.add_to_base('Some message')

Wednesday, October 7, 2009

Rails: undefined method `use_transactional_fixtures=' in Rails 2.3

Problem: You try to run your Rails tests under Rails 2.3 and you run across the "undefined method `use_transactional_fixtures='" error.
./test/integration/../test_helper.rb:29: undefined method `use_transactional_fixtures=' for Test::Unit::TestCase:Class (NoMethodError)
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
        from /usr/lib/ruby/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
        from ./test/integration/survey_user_interface_test.rb:1
        from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in `load'
        from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
        from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5:in `each'
        from /usr/lib/ruby/gems/1.8/gems/rake-0.8.7/lib/rake/rake_test_loader.rb:5
rake aborted!
Command failed with status (1): [/usr/bin/ruby.exe -I"lib:test" "/usr/lib/r...]

Fix:
Change the class definition in test_helper.rb from
class Test::Unit::TestCase
to
class ActiveSupport::TestCase

Wednesday, September 2, 2009

MySQL Error: Can't connect to local MySQL server through socket

You try to run your Rails project and keep getting the "Can't connect to local MySQL server through socket" MySQL Error.
Can't connect to local MySQL server through socket '/tmp/mysql.sock' (2)
/usr/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/mysql_adapter.rb:548:in `real_connect'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/mysql_adapter.rb:548:in `connect'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/mysql_adapter.rb:198:in `initialize'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/mysql_adapter.rb:74:in `new'
/usr/lib/ruby/gems/1.8/gems/activerecord-2.2.2/lib/active_record/connection_adapters/mysql_adapter.rb:74:in `mysql_connection'

The quickest way to fix this issue is to edit the database.yml file and replace localhost with 127.0.0.1.

Saturday, July 25, 2009

Why Programmers Should Use Portrait Mode Screens

Assume you have 1680x1050 (WSXGA+) monitor.

Window border + Menu bar + Tool Bars = 175px (vertical)
Status Bar + Horizontal Scroll Bar   =  55px
Total                                = 230px

Landscape Mode Active code area      = 1050px - 230px
                                     =  820px

Portrait  Mode Active code area      = 1680px - 230px
                                     = 1450px

Ratio                                = 1450/820
                                     = 1.768

Vertical coding area gained          = (1450-820)*100%/820
                                     = 76.83%

Friday, July 24, 2009

Crop Images in Batches Using ImageMagick and Ruby

Let us suppose you have an image named caps-1.png and you want to crop it to a 450x760 area, where top left corner of the crop region is the point (613,130) in the original image. You can easily do this by using the convert command that comes with ImageMagick. The command you might want to use might look like this:

convert "caps-1.png" -crop "450x760+613+130" "out/caps-1.png"

The numbers in the above are:
(613,130)  - top left corner
450x760    - the crop area (x,y)

Now let us suppose you have a directory full of images that need to cropped to the same dimensions as above at the same point as above. You can use a little Ruby snippet to execute the same convert command as above, but for each file in the current directory.

Dir.foreach('.'){|f| system  'convert \"%s\" -crop \"450x760+613+130\" \"out/%s\"' %[f, f.downcase] if f.downcase =~ /\.png$/}

This can be executed from the command line through the ruby interpreter:
ruby -e "Dir.foreach('.'){|f| system  'convert \"%s\" -crop \"450x760+613+130\" \"out/%s\"' %[f, f.downcase] if f.downcase =~ /\.png$/}"

If you want to simply generate script file with a series of convert commands, then simply replace the Ruby "system" statement with a "puts" statement:
ruby -e "Dir.foreach('.'){|f| puts    'convert \"%s\" -crop \"450x760+613+130\" \"out/%s\"' %[f, f.downcase] if f.downcase =~ /\.png$/}" > convert_files.sh

There the puts statements write the convert commands with parameters to standard out (STDOUT), and that output is redirected to the file convert_files.sh. Now you can set the executable bit of the script file
chmod +x convert_files.sh
and execute it over and over again.

If your source files are, say, PNG files but you want the convert command to save the output as JPEG files, use the following:
ruby -e "Dir.foreach('.'){|f| system  'convert \"%s\" -crop \"450x760+613+130\" \"out/%s\"' %[f, f.downcase.sub('.png', '.jpg')] if f.downcase =~ /\.png$/}"

For more information take a look at the "Command Line Processing" section of the ImageMagick manual:
http://www.imagemagick.org/script/command-line-processing.php#geometry


The commands listed here were used to extract the areas of interest of frames grabbed from an iPhone application demo video.

Friday, June 26, 2009

Firefox Shortcut to Quickly Access Labelled E-mails

You can use the "Quick Find Link", which is activated using the apostrophe (') key, to select a Label from the sidebar by typing in part or all of the Label name. You can use the F3 key to find the next matching link. Once th Label you wish to select is highlighted, pressing the Enter key activates the link, which will take you to page listing the e-mails which have been tagged with the selected Label.

Gmail natively allows you to do something similar by typing "in:label_name" in the search field (which can be activated by the "/" keyboard shortcut). However there are a couple of differences between this method and the previously mentioned Firefox specific method:

1. You need to type in the *full* Label name after the "in:" search parameter.
2. Gmail only displays 20 e-mails for each "results" page it returns, even if you have set the default value to 100 e-mails per page.

Saturday, March 21, 2009

Chrome Experiments

If you ever wondered how fast Google Chrome's V8 JavaScript engine is, you have to look no further. The recently launched ChomeExperiments.com has a number of computationally intensive demos written in JavaScript which will let you compare Chrome's JavaScript performance with that of your favourite browsers.

I tried out Monster on Firefox 2, Safari 3.1.1, and Google Chrome 0.4.154.


A Bit About Monster



Monster is 3D demo which uses the HTML Canvas element to render 3D animations. It starts with a square which morphs into a rotating cube which morphs into a sphere which morphs into a rotating "Monster".



Firefox 2.0.0


I wanted to see how well Monster performed in Firefox 2. Firefox showed a lot of promise as the initial square morphed to a cube and then a sphere. However, my optimism was short lived as the sphere morphed to a "Monster" and the rendering went from frames-per-second to seconds-per-frame. Saying "the demo did not perform well" would be a huge understatement.


Safari 3.1.1


The demo started a little slowly under Safari. After my experience running Monster under Firefox 2 I was expecting even less from Safari. But Safari surprised me by maintaining a low, but consistent, frame rate throughout the demo. The experience did not seem to degrade as the polygon count of the demo increased. Having said that, the performance was far from fluid.


Google Chrome


I had been disappointed by both Firefox 2 and Safari. I had seen the video clip, but I could not help wondering if it was something with the machine I was using. I fired up Chrome 0.4.154 which I had downloaded shortly after Chrome was launched. I waited as the square turned into a cube and then into a sphere and then into the "Monster" without skipping a beat.


Internet Explorer 6


We all know that Internet Explorer 6 does not have support for the HTML Canvas element, but I launched Monster in it just for the fun of it. The result? A JavaScript error. Enough said about IE!!!


Final Thoughts...


I knew Chrome was ahead of the pack in terms of JavaScript performance, but I had not realize by how much until I did a side-by-side comparison with the aforementioned browsers. I also need to try this Demo using Firefox 3, Safari 4, Internet Explorer 7, Internet Explorer 8, and Opera, but that will have to wait for now.


Sunday, August 3, 2008

"Really Achieving Your Childhood Dreams" by Dr. Randy Pausch

Carnegie Mellon Professor Randy Pausch (Oct. 23, 1960 - July 25, 2008) gave his last lecture at the university Sept. 18, 2007, before a packed McConomy Auditorium. In his moving presentation, "Really Achieving Your Childhood Dreams," Pausch talked about his lessons learned and gave advice to students on how to achieve their own career and personal goals. For more, visit www.cmu.edu/randyslecture.






Randy Pausch's Web Site:
http://download.srv.cs.cmu.edu/~pausch/

This video can be found at:
http://www.youtube.com/watch?v=ji5_MqicxSo


CNN article:
http://www.cnn.com/2008/SHOWBIZ/books/07/25/obit.pausch/index.html

Friday, February 29, 2008

WPM: How Fast Can You Really Type?

I recently read a job application form that contained a rather interesting question. The question read "Typing Speed (WPM):". Now this would be a perfectly normal question if the job application was for a secretary or typist position, but the job in question was actually for a software engineering position.

I have been touch-typing (yes, all ten fingers--not just the two index fingers) since I was about 10 years old, and I must say that I can type rather quickly. But I have never actually measured my typing speed in terms of words-per-minute (WPM). So I decided to fire up a Linux console and find out once and for all.

The method I used is actually very simple.

  1. Type a bunch of words in the console
  2. Find out how many words I typed
  3. Find out how long it took me to type those words
  4. Use those two figures to compute my typing speed in words-per-minute

Here is what I did:

time cat | wc -w
The quick brown fox jumped over the lazy dog's head
[^D]



10

real 0m9.113s
user 0m0.008s
sys 0m0.000s


For those of you who are new to the Linux console, this is what is happening in the above chain of commands:

  • The cat command captures whatever you type at the keyboard until you type Ctrl+D.
  • This text is then "piped" to the wc (Word Count) command. The -w option tells wc to return the number of words in the text piped to it.
  • The above mentioned commands are executed through the time command which measures how much time it took to execute those commands. What is of interest is the first line with the "real"time required to execute.


Computing the Words-per-Minute



The output of the chain of commands (also known as a "pipeline") tells us the two things we need to compute my typing speed: The number of words I typed and the time it took me to type them. Here's some simple math:

In 9.113 seconds I typed 10 words
So in 1 second I could type 10/9.113 words
So in 60 seconds (1 minute) I could type 60*10/9.113

Therefore my typing speed is 65.84 words per minute


Improving the Accuracy


You can only get a rough idea of your typing speed if you type in only 10 words. To get an accurate idea of your typing speed you should try entering a paragraph or two (or more) of text and using the above formula to compute the speed.

Characters-per-Minute


If you want to compute the number of characters you can type in a minute, you should use the wc command's -c switch instead of -w.