July 24, 2008
I’ve been working a lot this week with sphinx and ultrasphinx on a project that’s a fork of Insoshi. Insoshi is in the process of switching search from ferret to sphinx, and sphinx has been integrated into the Insoshi edge branch.
I’ve had dozens of problems, in fact it’s fair to say I’ve spent upwards of 15 hours just debugging ultrasphinx and getting my tests to pass. There were several problems; here are the main three and how I fixed each one.
This should be useful to anyone upgrading Insoshi to the sphinx version, or to anyone else trying to get ultrasphinx working in their Rails project. I definitely don’t recommend starting with this post if you’re just starting out with sphinx. Instead, go read this much better introductory tutorial from the guys over at Insoshi. Then if you have problems, come back here and you may find solutions.
Getting search tests (or specs) to pass with sphinx
This one is pretty simple, in retrospect, but it can be frustrating and opaque if you are used to ferret. Unlike ferret, sphinx (at least via ultrasphinx) runs only via a daemon. Where acts_as_ferret uses a daemon only for the production environment and just accesses the index files directly in test or development, ultrasphinx can only get to the indexes through the daemon.
So, to run your tests, you just build up the indexes for test and run them. In this case, I’m running the specs for Insoshi’s searches controller:
From the command line in $RAILS_ROOT:
rake db:test:prepare
rake ultrasphinx:configure RAILS_ENV=test
rake ultrasphinx:index RAILS_ENV=test
rake ultrasphinx:daemon:start RAILS_ENV=test
script/spec spec/controllers/searches_controller_spec.rb
The problem, of course, is that it doesn’t work! The reason is that db:test:prepare creates the structure of your database, but doesn’t load any of your fixtures as data: the test db is empty.. So when you run the index command, an empty index is built. You can see this from the output of that first index command, which will look something like this:
collected 0 docs, 0.0 MB
total 0 docs, 0 bytes
total 0.078 sec, 0.00 bytes/sec, 0.00 docs/sec
Ultrasphinx has built an empty index.
The solution
The solution, believe it or not, is to run the tests, let them fail, re-index, and run the tests again (Many thanks to Long Nguyen at Insoshi for helping me figure this one out):
rake db:test:prepare
rake ultrasphinx:configure RAILS_ENV=test
rake ultrasphinx:index RAILS_ENV=test
rake ultrasphinx:daemon:start RAILS_ENV=test
script/spec spec/controllers/searches_controller_spec.rb #FAIL!!
rake ultrasphinx:index RAILS_ENV=test
script/spec spec/controllers/searches_controller_spec.rb #PASS!!
The first attempt to run the specs loads the fixtures, and leaves them in the database, thus letting the subsequent index command build an actual index.
Running sphinx for both test and development environments at the same time
The next big challenge was enabling behavior-driven development. I like to work with autotest and growl running constantly in the background. But this was tough to do with sphinx, because the daemon needed to be stopped and re-started, and the index re-created for each environment, alternately running all of the above commands either with or without RAILS_ENV=test.
The solution is to set up your ultrasphinx base configuration to completely separate both the test and development indexes and to let the daemons for the two environments listen on different ports. I had tried something like this and come close, but not quite, when Long at Insoshi again bailed me out. You need to change the port (in two places), and the paths of the logs, pidfile, and index directories so that test and development daemons are using entirely separate resources. Here’s a diff of my test.conf and default.conf:
33c33
< port = 3312
---
> port = 3322
35c35
< log = log/searchd.log
---
> log = log/searchd_test.log
39c39
< pid_file = log/searchd.pid
---
> pid_file = log/searchd_test.pid
50c50
< server_port = 3312
---
> server_port = 3322
57c57
< sql_range_step = 5000
---
> sql_range_step = 999999999
64c64
< path = sphinx
---
> path = sphinx_test
The sql_range_step is related to the next issue, which is that sphinx does not play well with foxy fixtures. Anyway, make the above changes and you should be able to run test and development sphinx daemons at the same time:
rake db:test:prepare
rake ultrasphinx:configure
rake ultrasphinx:configure RAILS_ENV=test
rake ultrasphinx:index
rake ultrasphinx:index RAILS_ENV=test
rake ultrasphinx:daemon:start
rake ultrasphinx:daemon:start RAILS_ENV=test
If it worked, you should see separate indexes in $RAILS_ROOT/sphinx and $RAILS_ROOT/sphinx_test, and two daemons running, which you can confirm with ps waux | grep searchd:
evan 1339 0.0 0.0 78100 292 s000 S 5:37PM 0:00.52 searchd --config <YOUR_RAILS_ROOT>/config/ultrasphinx/test.conf
evan 1326 0.0 0.0 78100 292 s000 S 5:36PM 0:00.68 searchd --config <YOUR_RAILS_ROOT>/config/ultrasphinx/development.conf
Getting sphinx to play well with foxy fixtures
The next problem I discovered was that on some machines, but not others, running my search specs would result in these weird errors:
1)
ActiveRecord::RecordNotFound in 'SearchesController Person searches should search by name'
Couldn't find Person with ID=328556765
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:308:in `reify_results'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:286:in `each'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:286:in `reify_results'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search.rb:362:in `run'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search/internals.rb:352:in `perform_action_with_retries'
/var/www/domains/unithrive/vendor/plugins/ultrasphinx/lib/ultrasphinx/search.rb:342:in `run'
/var/www/domains/unithrive/app/controllers/searches_controller.rb:38:in `index'
./spec/controllers/searches_controller_spec.rb:51:
script/spec:4:
When I poked into this “Couldn’t find Person with ID=328556765″ error, it seemed like sphinx was almost working. The index was set up, and the search was finding someone in the index during the test. Ultrasphinx was passing back the id 328556765, which didn’t exist in the database. So why would Sphinx “find” a record in its index but then pass back an ID for a database record that didn’t exist?
And furthermore, why would it work on one machine, but not on another?
The brainstorm came when I checked what the actual database IDs were for this particular record, with Person.find_by_name(”fixtures’ name”).id. On machines where it worked, the id was a huge number (is it generally is with foxy fixtures), but on machines where it didn’t work, the id was an even huger number.
Sphinx tries to make sure that all items that get indexed have a different index in sphinx, and it does this by multiplying all of your id’s by N, where N is the number of models getting indexed, and adding an offset of 0 for the first model, 1 for the second, etc. This guarantees that every record from every table will have a unique id. In the case of this application, all of my Person records were getting indexed by sphinx as (Person#id * 4 + 2).
Danger, Will Robinson: 32-bit int rollover!
The problem is that foxy fixtures generate their own ids from a hash of the fixture label, and those ids can be anywhere in the 32-bit unsigned integer space. But Sphinx also stores ids as 32-bit unsigned integers. This means if you happen to get a large fixture id, and then sphinx multiplies it by 4 (or whatever; it could be higher if you have more indexed models), your id will rollover and come out as (id * N + n) % (2^32). Sphinx will store that result, and then when it finds the record in a search, it will try to recreate the original id by subtracting n and dividing by N … giving you the wrong id. Your test will fail to find the record.
Incidentally, this problem with foxy fixtures is why your test.base file needs the line sql_range_step = 999999999. Sphinx builds indexes by searching a few ids at a time. But the ids generated by foxy fixtures are so big that if sphinx only collects them in ranges of 5000 at a time, it will take forever to find them all.
After some googling, I found that these issues are discussed in a thread over at RubyForge.
The solution
I’m working on a plugin that monkeypatches foxy fixtures to create sequential, low-numbered IDs. In the meantime, you can just compile sphinx to support 64-bit ids, which should give you plenty of headroom to handle foxy fixture ids multiplied by N in sphinx*:
In your sphinx source directory:
configure --enable-id64
make
sudo make install
That should do it. Let me know in comments if any of this information helped you.
*At least until you start approaching 2^32 models in your application, that is.
July 16, 2008
This is pretty basic and there’s plenty of documentation on the web, but this morning I found it difficult to locate with a google search. Maybe I just didn’t know the right terms. (searching “git repository change origin” seems obvious to me, but the results were useless.) Hopefully this post will help people find the documentation they are looking for if they are searching the same way I was.
Anyway, suppose you have a local git repository that you cloned from some remote repository at, say git://user@dev.foo.com/git/repos/path, and you’ve been happily pulling, pushing and rebaseing to and from that remote repository. But now you or your team leader have moved that remote repository to a new location, and you’d like to point your repository to the new URL without having to do a full checkout.
What you need to do is change your ‘origin’ setting. Unfortunately, there’s no trivially easy way to do this from the command line in current versions of git. Instead, you edit .git/config in your project root, which may look something like this:
...
[remote "origin"]
url = git://user@dev.foo.com/git/repos/path
fetch = +refs/heads/*:refs/remotes/origin/*
...
or if your ‘remote’ is actually local:
...
[remote "origin"]
url = /path/to/repos/on/this/machine
fetch = +refs/heads/*:refs/remotes/origin/*
...
All you need to do is edit that file with your favorite editor and change the url = setting to your new location. Assuming the new repository is correctly set up and you have your URL right, you’ll be happily pushing and pulling to and from your new remote location.
July 10, 2008
In one of my Rails projects, I maintain a user-visible log of updates to the database by recording entries into a table that looks like this (from schema.rb):
create_table "log_entries", :force => true do |t|
t.integer "user_id", :limit => 11
t.datetime "created_at"
t.datetime "updated_at"
t.string "item_type"
t.integer "source_id", :limit => 11
t.string "table"
t.string "action"
t.text "changes"
end
Whenever a record is created, updated, or deleted, I create and save an instance of LogEntry, containing for example {:table => 'task', :action => 'update'} and in the ‘changes’ column I save a serialized hash showing which attributes of the task object changed before and after save. In addition, I save which logged-in user made these changes, and when.
This is convenient, it gives my client a log that’s much more user-accessible and allows them to easily back-trace who did what to the database and when, which is important for their process and certain certifications.
When I upgraded the project to Rails 2.1 a couple of weeks ago, most of the code still worked fine, but the hashes showing the object changes were no longer showing up in views of the log. The culprit turned out to be Rails 2.1’s new dirty feature. Why? Because it adds the method ‘changes’ to ActiveRecord::Base. This is a great new feature that lets you know what has changed to an ActiveRecord object since you loaded it from the database, with all kinds of benefits like doing more selective updates, or not writing to the database at all if no changes have occurred, thus reducing system load if you call save! a lot.
Unfortunately, the new method ‘changes’ was obscuring my attribute ‘changes’ in some circumstances, and at the very least confusing the heck out of me, the programmer.
The solution, of course, is not to name your fields anything that corresponds to any Ruby core method or any method of ActiveRecord::Base. I fixed my problem with a migration to rename the column ‘details’:
def self.up
rename_column :log_entries, :changes, :details
end
def self.down
rename_column :log_entries, :details, :changes
end
July 10, 2008
This morning we launched a refreshed site and an all-new online store for one of my clients, CordobaSzekely Productions.
Robert Cordoba and Deborah Székely are dance instructions and multiple-time national champions at the U.S. Open West Coast Swing Championships. They teach West Coast Swing and other dances all around the US and the world, and market a line of dance instructional DVDs.
Their former site had gotten a bit long in the tooth, so this was a just a quick refresher, keeping the former graphics design but bringing the HTML and CSS up to contemporary standards. Their online store was completely reimplemented using the open-source Zen Cart, where formerly they’d used the proprietary (and often difficult to use) Miva Merchant.
June 23, 2008
Sometimes you may want to generate a selector with a fixed set of options. In one recent task of mine, we needed a selector for an integer 1 through 10, but the client wanted them labeled also with text to identify how the numbers mapped to the words “High” “Medium” and “Low”. (We were selecting the priority level of a task in a project management application). Essentially, I want to generate this HTML output:
<select id="task_priority" name="task[priority]">
<option value="1">1 - High</option>
<option value="2">2 - High</option>
<option value="3">3 - High</option>
<option value="4">4 - Med</option>
<option selected="selected" value="5">5 - Med</option>
<option value="6">6 - Med</option>
<option value="7">7 - Med</option>
<option value="8">8 - Low</option>
<option value="9">9 - Low</option>
<option value="10">10 - Low</option>
</select>
These are fixed name/value pairs, so it made sense to me to store them as a constant hash in my Task model:
Hash in Task.rb
PRIORITY_OPTIONS = { "1 - High" => "1", "2 - High" => "2", "3 - High" => "3",
"4 - Med" => "4", "5 - Med" => "5", "6 - Med" => "6", "7 - Med" => "7",
"8 - Low" => "8", "9 - Low" => "9", "10 - Low" => "10" }
However, I was rather dismayed to discover that this didn’t produce the results I wanted, because Ruby hashes (in Ruby 1.8.6) do not preserve order. This is what came out:

That’s not what I wanted! I knew that select will also take arrays, but of course I needed separate name/value pairs, which I can’t get with just straight arrays. I spent a while playing around with OrderedHash, which exists in Rails but is essentially undocumented and, as it turns out, does not support any useful functions of Hash like merge! and insert! that might make it easy to construct my list of options.
The Fix: Array of Arrays, or Array of Hashes
The documentation is not entirely clear on this, but if you send an array of 2-element arrays to select, rails will use the two elements of each inner array as if they were key and value pairs, and because the entire structure is an array it will preserve order. So, to get the results I wanted, I just need to change my constant to this:
PRIORITY_OPTIONS = [ ["1 - High", 1], ["2 - High", 2], ["3 - High", 3],
["4 - Med", 4], ["5 - Med", 5], ["6 - Med", 6], ["7 - Med", 7],
["8 - Low", 8], ["9 - Low", 9], ["10 - Low", 10] ]
And I get the result I was looking for :

As it turns out, the way ActionView processes the options is fairly general: if you pass it any enumerable object, it will iterate that object, and for each element will check to see if that element supports the methods :first and :last (and isn’t a string). If so, it will generate an option with the text set to element.first and the value set to element.last. If it was a string, or didn’t support first and last, both the text and value of the option are set to the element itself.
Testing it
Here’s a handy function I use for testing it the presence of a selector. You pass it the name of your selector, the name of hash or array of options (in the any format supported by select), and optionally the value of an item that should be pre-selected, and it will assert the existence of each of those things. If you need to handle selectors with multiple selections, you can just wrap the last assertion in a loop.
Drop this in test/test_helper.rb
# Assert existence of form select input
# the <option> tags can be passed either as
# a hash like this: {'foo'=>'bar', 'baz'=>'qux'}
# or an array of arrays like this: [ ['foo', 'bar'], ['baz', 'qux'] ]
# either will be asserted to match:
# <option value='bar'>foo</option>
# <option value='qux'>baz</option>
# or as an array like this:
# [ 'foo', 'bar' ] will be asserted to match
# <option value='foo'>foo</option>
# <option value='bar'>bar</option>
def assert_select_input(name, option_values, options={})
attributes = { :name => name }
# first assert that the select tag exists
selector = { :tag => "select", :attributes => attributes }
assert_tag selector
option_values.each do | opt |
if !opt.is_a?(String) and opt.respond_to?(:first) and opt.respond_to?(:last)
assert_tag({:tag => "option", :attributes => { :value => opt.last },
:parent => selector, :content => opt.first })
else
assert_tag({:tag => "option", :attributes => { :value => opt },
:parent => selector, :content => opt })
end
end
# check for the pre-selected option, if any
if options[:selected]
assert_tag :tag => "option", :attributes => {:selected => 'selected',
:value => options[:selected] }
end
end
As an example of how to use it, here’s my method for testing the task priority selector pictured above:
# asserts a <SELECT> field, targeting task[priority], containing ten
# appropriately formatted <OPTIONS>, and with selected_num (if any) the
# pre-selected option
def assert_priority_select(selected_num = nil)
options = selected_num ? { :selected => selected_num } : Hash.new
assert_select_input "task[priority]", Task::PRIORITY_OPTIONS, options
end
Where the array specified in the Task model looks like this:
PRIORITY_OPTIONS = [ ["1 - High", 1], ["2 - High", 2], ["3 - High", 3],
["4 - Med", 4], ["5 - Med", 5], ["6 - Med", 6], ["7 - Med", 7],
["8 - Low", 8], ["9 - Low", 9], ["10 - Low", 10] ]
June 18, 2008
It’s a scourge that inflicts nearly every website: the dreaded empty page stating “Your search returned no results.” Or even worse, the search results page with a header “Search results” and zero content, the footer immediately following the header. This is not only useless, but also confusing to the user, because it takes the reader several seconds to even realize that the search returned no results.
For example, I just got this one on the otherwise lovely workingwithrails.com when I searched for RoR developers in Pasadena, CA:

This is lame, lame, lame. A search results page with no results is guaranteed not to be useful to the user! From a user interface perspective, it’s akin to redirecting a user to a login page after they try to access some resource, and then sending them back to the front page or a super-lame “thank you for logging in” page afterwards. The user should always see a useful page, and should never have to waste clicks getting back to what they wanted.
It’s not only bad UI, it’s also entirely unnecessary, because in Rails you can fix this for good with two lines of code.
Avoid wasted pages and annoyed users with redirect_to: back
If your user’s search doesn’t find anything, don’t make them waste their time at a whole page that tells them only that. Instead just send them straight back to the search page. Better yet, redirect them back to wherever they came from, since they might well be able to invoke search from any number of different contexts in your application. You don’t need a whole page to tell them the search didn’t find anything - a flash notice is more than sufficient:
Redirecting back with a flash after an empty search:
def search
@results = YourModel.execute_some_search(params[:some_parameter]);
if @results.size == 0
flash[:notice] = "No items found matching '#{params[:some_parameter]}'"
redirect_to :back
end
end
Testing redirect_to :back
Testing redirect_to :back isn’t completely trivial, because of course there’s no previous page when you render a page in a test context. So, when you try to run a controller that redirects back, you’ll see an error. The easiest thing to do is to artificially set a previous page. I have these two methods in test/test_helper.rb:
def fake_referer
@request.env['HTTP_REFERER'] = 'http://previous_page'
end
def assert_redirected_back
assert_redirected_to 'http://previous_page'
end
Then anytime I am working on a controller that involves back redirects, I drop fake_referrer in my setup method and then use assert_redirected_back. For example, in a search controller test (this is from a controller that has an action called ‘contents’ for searching items by text content - the search itself uses ferret):
def setup
super
fake_referer
end
def test_contents_search_fails
get :contents, :contents => "some&junk*that(will@never)match$anything"
assert_not_nil flash[:notice]
assert_redirected_back
end
June 18, 2008
It’s Firefox 3 Download Day! Go get it, please.
I am excited about this, but perhaps not for the same reason most other people were. I am excited because Firefox 3 is the first version to implement the CSS rule “display: inline-block”. Inline-block allows you to generate chunks of content of rectangular shape that will flow inline in your content (like text, images, or tables) but whose contents act like a block, and whose borders and margins are respected in the flow.
Let’s make it clear what I mean.
The beauty and versatility of display: inline-block
Setting a CSS element’s display: property to inline-block tells the browser to treat the element as a rectangular block, with internal flow just like any other block, and to respect the padding, border, and margins, but to flow that rectangle with other inline content - exactly the way the browser would flow an image. In addition, you can specify the width and height of inline-block items. This is a crazy useful concept from a layout perspective: it would allow you to make buttons out of text that lay out horizontally, or to layer images on top of each other inside a small span or div.
Here’s an example of a series of list items set with border, padding, and a width and height. The code first:
<style>
ul {
width: 400px;
border: 2px solid black;
background: #aaf;
}
li {
border: 2px dotted blue;
padding: 1em;
width: 100px;
height: 35px;
}
ul.inline li {
display: inline;
}
ul.inline-block li {
display: inline-block;
}
</style>
<h2>Padded words wrapped with display: inline;</h2>
<p>
<ul class="inline">
<li>Lorem</li>
<li>ipsum</li>
<li>dolor</li>
<li>sit</li>
<li>amet</li>
<li>consectetur</li>
<li>adipisicing</li>
<li>elit</li>
<li>sed</li>
<lido</li>
<li>eiusmod</li>
</ul>
</p>
<h2>Padded words wrapped with display: inline-block;</h2>
<p>
<ul class="inline-block">
<li>Lorem</li>
<li>ipsum</li>
<li>dolor</li>
<li>sit</li>
<li>amet</li>
<li>consectetur</li>
<li>adipisicing</li>
<li>elit</li>
<li>sed</li>
<li>do</li>
<li>eiusmod</li>
</ul>
</p>
Here’s how Safari renders the above code (correctly):

And here’s how Firefox 2 renders it (incorrectly):

Horrific - FF2 simply ignores inline-block, causing the list elements to render in their default display mode, block. What’s galling about this is that for several years Firefox has been the only browser that gets it wrong! That’s right, even Internet Explorer 6 gets this right … at least on some elements, specifically those that are natively display: inline, like spans and anchors.
The Firefox bug report was filed way back in the days of Firefox 1 nine years ago. Yes, you read that right. It sat there, unfixed, while every other browser in the world implemented it.
Anyway, today web developers everywhere can rejoice. Now, at last, the released version of every major browser supports display: inline block. So, with only another year or two waiting while FF2 users upgrade to FF3, designers will be able to start using this singularly useful CSS rule (at least in cases where IE supports it as well).
A parting example
A parting example of the kind of cool trick you can play with inline-block: text flowing inside a sized box that is itself flowing inside text.
Code for flowing text inside flowing text:
<div style="font-size: 250%; width: 600px;">
Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor
<span style="width: 130px; height: 40px; font-size: 9px; display: inline-block;
padding: 1em; border: 1px solid black; overflow: hidden;">
Duis aute irure dolor in reprehenderit in voluptate velit esse cillum
dolore eu fugiat nulla pariatur.
</span>
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam.
</div>
How it renders in a compliant browser … including IE6!*

*Well, more or less. IE6 gets it reasonably close.
May 29, 2008
Apparently I can’t stop playing, because today I built and uploaded a third design for the LRDesign main site: “Blue Art”. This one required the IE PNG fix from Twin Helix for IE 6.0 compatibility.
I think there are still a few annoying bugs in the stylesheet switcher on IE; once I clean those up I plan to write a post explaining how to easily set up this kind of stylesheet switcher in a Rails project.
May 29, 2008
For quite a while I’ve wanted to decorate the main Logical Reality site with multiple, switchable themes, implementing each with pure CSS on top of semantic HTML markup, a la the CSS Zen Garden. Last night I finally got a start on that, implementing a simple stylesheet switcher and a grunge theme with textures from Urban Dirty.
To check it out, load the main site and click the “Change Skin” link in the upper left.
May 26, 2008
Looking for used cars on Craig’s List, my girlfriend and I found what appears to be a classic web escrow auto scam: Web Auto Trades. An ad we responded to (a used Honda Accord at a surprisingly low price for the mileage) claimed to be using their service, which included a “five day guarantee” if you didn’t like the car, and said we wouldn’t have to meet the seller in person. These are all signs of a typical scam: buyer beware!
Other scam signs: though their snazzy flash-based website presents them as worldwide experts in escrow services, a google search for their domain name results in zero hits, and the domain has only been registered for five days and lists no telephone contacts:
Registrant:
Domain Privacy Group, Inc.
c/o webatrades.com,
5160 Yonge St. Suite 1800
Toronto, ON M2N 6L9
CA
Domain name: webatrades.com
Administrative Contact:
Domain Privacy Group, Inc. privacy-356772@domainprivacygroup.com
c/o webatrades.com,
5160 Yonge St. Suite 1800
Toronto, ON M2N 6L9
CA
Fax:
Technical Contact:
Domain Privacy Group, Inc. privacy-356772@domainprivacygroup.com
c/o webatrades.com,
5160 Yonge St. Suite 1800
Toronto, ON M2N 6L9
CA
Fax:
Registrar of Record: Netfirms Inc.
Record expires on 2009-05-21.
Record created on 2008-05-21.
Database last updated on 2008-05-28 12:54:04.
If you are finding this post because you googled their address after considering buying a car from someone using their service, I strongly consider you to avoid doing business with them, or at least to investigate the company much more thoroughly. Check with your state’s attorney general’s office to see if they’ve heard of them or have any complaints, and also consider checking with the BBB. Be very careful not to have your money taken by escrow scams, which this company gives every appearance of being.
Here’s a screenshot of their front page, in case they pop up somewhere later under a different name.

Update: How to Avoid Escrow Fraud
Here are some useful links on escrow fraud, what it is, and how to avoid it: