Thursday, January 21, 2010

Rails 2.x scaffolding field types


Dude, where's my CRUD?

One of the powerful features of Rails 1.x was the ability to generate CReate, Update, and Delete (CRUD) admin screens automatically using the scaffolding script built into Rails.

The original scaffolding read the database models and created basic, but usable screens to let you add and edit database records. When the 2.x release of Rails came out, scaffolding lost that power. Now, you have to manually specify each table field and type on the command line when running scaffold. If you don't, the generated screens will be empty.

Worse, a basic reference to all valid field types was missing. Here are all the valid types I have been able to dig up:

string
text (long text, up to 64k, often used for text areas)
datetime
date
integer
binary
boolean
float
decimal (for financial data)
time
timestamp

A mapping of the scaffolding types to data types in corresponding databases can be found on Overooped.

Here is an example of using 2.x scaffolding with data types, run from the Rails application root directory:

ruby script/generate scaffold Modelname name:string title:string employed_on:date remarks:text


Here is an example of using rails 3.x scaffolding with data types, run from the Rails application root directory:

ruby script/rails generate scaffold Modelname name:string title:string employed_on:date remarks:text


Thursday, December 24, 2009

You ARE your operating system (among other things)

Whenever you make a choice among products with similar functions, that choice spills over into the realm of social status.

Cars are a common example where social rank often goes with brand, and even within brand, by model, and even within model, by variations, upgrades, and badges. All signify some social status. I became acutely aware of this after purchasing a car that did not fit my image. It was uncomfortable for everyone.

Your operating system

You can see the social aspect tied to an operating system by looking at the Apple "I'm a Mac" campaign, and the weak Microsoft "I'm a PC" campaign response. A choice to run Linux or other operating system also carries connotations and shared group identity. In this sense, you are your operating system.

Your collection of choices

Whether conscious or not, decisions and choices about purchases you make, where choices are available, weave together part of your social tapestry. The schools you attend, where you work, your clothes, your car, where you live, and yes, your operating system. You are those things, at least socially.

The question is, in the context of a consumer society, can a choice be made without the attachment of social status?

Saturday, December 5, 2009

Calculating the square root of 2 longhand

There are many numerical methods to calculate square roots. This is the long hand method I learned in junior high. It produces one (accurate) digit at a time, but the working numbers get larger each iteration. Eventually, it bogs down because it is doing math with integers hundreds, then thousands of digits long.

Still, it is fun for tinkering. If you run this Ruby script as is, it will calculate the square root of 2 to 1,000 digits. To adjust the precision, change the number of iterations on this line:

while iterations < 1000

Here is the entire script...

#!/usr/bin/ruby
# calculate a square root of 2 using longhand

def newroot(divisor, doubleroot)
# calculate new root
# formula is doubleroot _ * _ = closest to divisor
# try 9, then 8, then 7 ...

i = 9
while i >= 0
multiple1 = (doubleroot.to_s + i.to_s).to_i
multiple2 = i
product = multiple1 * multiple2

if product <= divisor
# found new root
root = i
# get modulus
modulus = divisor - product
break
end
i = i - 1
end


return root, modulus
end

roots = Array.new

# the nearest root to 2 is 1

root = 1
roots.push(root)
remainder = 2 - root

doubleroot = root * 2
divisor = remainder * 100

iterations = 0

while iterations < 1000
root,remainder = newroot(divisor, doubleroot)
roots.push(root)

# compute new doubleroot

return root, modulus
end

roots = Array.new

# the nearest root to 2 is 1

root = 1
roots.push(root)
remainder = 2 - root

doubleroot = root * 2
divisor = remainder * 100

iterations = 0

while iterations < 1000
root,remainder = newroot(divisor, doubleroot)
roots.push(root)

# compute new doubleroot
doubleroot = roots.to_s.to_i * 2

# compute divisor
divisor = remainder * 100

iterations = iterations + 1

print "iteration " + iterations.to_s + "\n"
end

print "final roots are " + roots.to_s + "\n"

Tuesday, November 10, 2009

Root 2: 500 million glyphs

Having generated a text file with the first billion digits of the square root of 2, I started thinking about how to convert it to text.

First Try

My first try was an attempt to convert groups of 2 or 3 digits into a character using the ASCII code table. This was not very straight forward for several reasons. To start, many characters in the range from 0-255 are either non-printable or produce symbols or punctuation. To get around this, I decided to only use the part of the table that started with the numbers and went through the end of the lower case letters.

That left some 2 digits numbers that had to be scaled up into the useful range and many 3 digit numbers (everything greater than 255) had to be scaled down to the range. I did get a script working that accomplished this, but the results were not satisfying.

Second Try

I decided to use a simpler solution and convert each pair of digits into a letter using the range 1-26. To do this, I added one to the modulus of 26 and each digit pair and indexed it into the alphabet. Because 26 does not go into 99 evenly, this produces a slight bias against the last few letters of the alphabet but I was will to live with the result.

As an example, the first two digits are 14. 14 divided by 26 is 0 with a modulus (remainder) of 14. Adding one to 14 is 15 returning the letter O. The next two digits are 14 also returning O. The next two are 21 returning the letter V.

At the end of another scriptaculous ruby adventure, I had converted my billion digit file into 500 million letters.

Signals in the noise

To make the file easy to search, I wrote the resulting text file out in 72 character lines. Yes, this causes some loss of continuity at line breaks, but again, I was willing to live with it.

I quickly found the string with my name "KEITH" 65 times. The first occurrence was 7,398,524 digits into the square root of 2. My wife's name appeared 125 times.

I found "GOD" 33,663 times with the first appearance at 3,186 digits.

As expected, the smaller the text string, the more likely it is to be found. Most words and strings up to 6 characters can be found in the first billion digits of the square root of 2. Strings 7 characters and longer, like "CALIFORNIA" are often not found.

For fun, I ran a few searches for dates and numbers in the integer file, finding things like my birthday and dates of historic events. Numeric strings are much easier to find.

Next, I'll post one of my ruby scripts to calculate the square root of 2 digit by digit. It is very slow and inefficient, but fun for tinkering. I have a few more ideas for grappling with the root of 2.

Friday, October 23, 2009

Root 2: the shallow end of infinity

A couple of months ago, I got the semi-psychotic idea to search for numbers and strings in the digits of the square root of 2. The idea is hardly unique. There has been a fair amount of research into this area, a variation on the infinite monkeys typing on a typewriter theorem.

Why Root 2?

Because it wasn't Pi. Pi is the probably the most studied math constant, so I wanted to start with something fundamental that wasn't pi.

I needed an irrational constant, one that generated an infinite stream of random numbers, and root 2 was as good a choice as any. I might argue that root 2 is even more commonly encountered than pi, in that it is found in the hypotenuse of a 1x1 square. Surely, 1x1 squares are more common than circles in the modern world.

Infinite Integers

The first challenge was to find or generate the integers of root 2. With a quick search, I found up to 10 million digit files that had been created by NASA. While a good start, I wanted a lot more than 10 million digits. I ended up using the 1 million file from NASA as a control file to make sure that any other method I used to generate digits was validated by NASA. My starting target was 1 billion digits, but I wanted the ability to go to an arbitrary number.

When I started thinking about how to generate digits with a computer, I realized there were some unique hurdles in trying to calculate infinite precision numbers. First, standard machine data types fail at the task. 64-bit integers give you a large work space, but floating point numbers are notorious about losing precision. The math libraries of most languages work to about 15 digits, so those were out.

I found more than 10 methods documented to compute square roots.

Baby Steps

The first attempt to calculate the square root of 2 was actually written by a colleague who was intrigued enough to implement the Babylonian method in clojure. The first few tests seemed promising and matched the NASA file up to roughly 25,000 digits. Where it broke down was after about 20 iterations where the run time exceeded 18 hours. Getting to a very large number of digits did not appear to be practical.

The next attempt was one I wrote using the Duplex method (in ruby). Duplex has the advantage of computing one digit at a time and I was hoping this would avoid some of the problems with doing multiplication with millions of digits. There may have been a flaw in my ruby implementation because it got off track past digit 53 when I compared the results with the NASA file. I was careful to follow the example I found in Wikipedia, but I must have made some kind of mistake because it always diverged.

Standing on Shoulders

Like any good programmer, I quickly decided to search for working code that someone else had written. I found a very old C++ implementation, but also a handful of working programs. The one I tried first was PiFast.

PiFast is a Windows program that can calculate many constants in addition to Pi. Since my main computer is a Macbook, I loaded it into my VMware virtual machine running XP. As you might imagine, it was more than a little CPU intensive. After a few short trial runs, I let it loose on a 1 billion digit computation that for all intents locked my machine for about 11 hours. At the end, I had a file of 1 billion digits, the first million of which validated perfectly against the NASA file.

To validate and test the file -- a 1 gigabyte file -- I wrote a number of scripts (ruby is my scripting language of choice these days) to test the digits, and manipulate the file in several ways.

In my next post, I'll talk about how I converted digits to letters and what my early searches turned up.

Friday, September 25, 2009

Introduction to AutoFS in Mac OS X

Note: I originally published this article on Low End Mac

OS X uses an AutoFS code stack based on Sun's Solaris version of Unix. Many of the advanced features are not documented very well, and this can be an issue unless you are familiar with Solaris. I was not and had to do quite a bit of digging.

AutoFS is often used in enterprise environments to set up network-based home directories and other network mounts for users at login. It can also dynamically mount network shares on access.

OS X auto_master and auto_home

The /etc/auto_master file controls the auto-mounted Network File System (NFS) file systems. If you are going to mount NFS volumes from a Linux server, there is one gotcha that I covered in an earlier blog post.

The auto_master defines all "maps" which are collections of automounts related by mount point and organized in one file (or directory service entry). Here is what the default file looks like on my Mac:
#
# Automounter master map
#
+auto_master # Use directory service
/net -hosts -nobrowse,nosuid
/home auto_home -nobrowse
/Network/Servers -fstab
/- -static


The plus (+) sign in front of the auto_master entry tells OS X to look in the directory service (Open Directory, LDAP, etc.) for an automount record and use it if found.

Notice the /home entry is set to auto_home, and because it is not a full path, it is assumed to be /etc/auto_home. It is an example of an indirect map. The mount point in the local directory is defined, but the remote mounts are defined in the /etc/auto_home map file. Network users who login to the local machine will have their home directories mounted in /home according to the details in /etc/auto_home.

Here is the default /etc/auto_home file:
#
# Automounter map for /home
#
+auto_home # Use directory service


Once again, we see the plus sign telling OS X to look for an auto_home record in the directory service. No further details are defined.

The last two lines in auto_master handle NFS mounts defined in the /etc/fstab file, the common file system mount table in Linux and other Unix flavors. The /etc/fstab file is deprecated in OS X and not recommended.

Applying changes to autofs

The automount process will not detect changes made to auto_master or other map files unless you tell it. This command tells the process to read all map files again:

sudo automount -vc

AutoFS wildcards

Wildcards can be used in mount map files to allow directory substitution. For example, if you had this defined in auto_master:

/opt auto_public

And this defined in /etc/auto_public:

* nfs.mydomain.com:/public/&


Then, when /opt/bin was accessed, nfs.mydomain.com:/public/bin would be mounted on /opt/bin. The same would apply for any subdirectory accessed under /opt.

Other Map Types

OS X AutoFS supports direct maps, where the local mount points are defined inside the mount map file, and indirect maps, where the local mount point is defined in auto_master. The wildcard example above is an indirect map. There are also executable maps where the mount map file is actually an executable shell script that returns the names of the mount points within the trigger folder. Exploring executable maps is left as an exercise for the reader. Finally, you can define static maps in /etc/fstab or in the Directory Utility Mounts tab.

Other file system types

All of the examples shown use the NFS file system. OS X autofs can also handle Apple File System (AFP) and Microsoft Server Message Block (SMB) file systems.

To use these file systems, add the -fstype=afp and -fstype=smbfs options when defining the remote mount points. (Note: You cannot use smbfs for remote home directories unless you are using the Microsoft Active Directory service plugin.)

Saturday, June 27, 2009

Playing nice with Linux NFS

I naively assumed that mounting an NFS volume exported by Linux would be uneventful, and it should be. My initial attempt to manually perform an NFS mount failed without any client side error message.

Checking system logs on the Mac revealed nothing.

The Linux NFS server (Red Hat Enterprise 5) complained with this warning:

nfsd: request from insecure port (192.168.7.130:49232)!


After some Internet sleuthing, I found Mac client side NFS tries to mount NFS volumes over high TCP ports (>1024). You must explicitly tell the Linux NFS server to accept mount requests on high ports by adding the "insecure" option to /etc/exports. For example,

/nfstest 192.168.206.0/24(rw,async,insecure)

Then, NFS mounts from OS X should work as expected.