The theme of this year's annual World Usability Day will be "Designing for a Sustainable World". Designers are increasingly looking at product design in a more holistic way, looking at the impact of products on the natural world. As the event's website explains, "the ‘Cradle to Cradle’ approach is to start the design with the premise of using materials that can fully enter a new life cycle by either going back to nature or going back into the design process as a new product". The event is scheduled this year for November 12.
The potential of designers to address complex social issues is also the theme of an upcoming talk by Mark Rettig for the IxDA on Tuesday, March 31 entitled "How to Change Complicated Stuff (e.g., the World)"
For enterprise software, the topic of environmental impact doesn't seem immediately relevant. However, enterprise software exists in a type of ecosystem - both technical (involving all the other technologies it co-exists with) and social (the users who operate it directly and/or depend on its outcome). It should be valuable to hear ideas for designing in a way that incorporates the needs and concerns of a wider community of people who may be effected but are not necessarily directly involved in developing a product. It is also intriguing to consider approaches for designing for the full lifecycle of a product, from its introduction through its ultimate retirement and replacement.
Just finished reading this book "The Journey of the Accidental Leader" – Steve Gladis. Here, the author tries to share his leadership experiences in the Marine CORPS in 10 simple Lessons. He has adopted a narrative story line where he explains these principles as an experience in the life of his protagonist Sam, who is forced to lead his father's consultancy Firm after his untimely death. Though most of the Lessons listed in this book are known to most of us (consciously/subconsciously), it will help us reflect if we are able to follow it in our daily routine. Hence I Thought of listing down those 10 lessons here in my Blog along with other highlights I could relate to in this book. Some Good Liners from this book:
competence, caring, commitment, and consistency."
four: Change isn't easy, but if you do it right, everyone
wins. People resist change as they are comfortable with what they are doing
vision to make it come true . The vision thing. If you can stop yourself every now and then and check all your basic assumptions, you may find you've been doing things a certain way—and those things could certainly stand a re-Vision. Also take team opinion for their vision.
create a positive culture, show people by your actions
what you believe in, don't just tell them
first bold step.
happen—embrace it while sticking to your core principles
Leaders have a passion
for people.
customer alike) as an individual
fix them
the table.
My company has been running a GO tournament and since its around NCAA March Madness time I thought it'd be easy to find a site to manage the draw. I looked but couldn't find anything that did what I wanted so I wrote my own. Caveat: I just spent a few days on this and it could stand to be enhanced with more features and a rewrite of the ui implementation but I'm open to suggestions if anyone finds this useful.
To use it

My company has been running a GO tournament and since its around NCAA March Madness time I thought it'd be easy to find a site to manage the draw. I looked but couldn't find anything that did what I wanted so I wrote my own. Caveat: I just spent a few days on this and it could stand to be enhanced with more features and a rewrite of the ui implementation but I'm open to suggestions if anyone finds this useful.
To use it

My research on Semantic web and possibilities of 'Linked data' continues...
The more I tried figuring it out, my understanding got fuzzier in the the myriad complexities of Ontology's, RDFs, OWLs and SPARQLs.. that is untill I came across this nice introduction on youtube.
Recommended Introduction on Semantic web for all those uninitiated, like me..
Welcome to the world of Semantics..
??? ???? ????? ???? ??,
???-???? ?? ?? ??? ???? ?? ???,
???? ???? ??? ??,
?? ?? ??? ???? ?? ??,
?? ???? ??? ??,
?? ?? ???? ??,
??? ?? ?????,
????? ??? ???? ??? ?? ????? ??,
??? ?? ?? ??? ???? ?? ????,
??? ??? ??? ? ??? ???-???,
????? ?????? ??,
???? ?????? ?? ????,
???, ???? ?? ???? ??,
?? ????? ?? ????? ???,
????-????? ????? ?? ?????? ??? ????,
???? ?? ?????????? ???,
???? ?? ???? ???,
???? ?????? ?? ????? ???? ??,
????, ?? ?? -- ?? ?? ? ????,
?? ????? ??? ?????? ???,
???? ??? ????,
??? ??? ???? ???? ???? ?? ??? ????,
?? ???? ?? ???? ?? ???????? ??,
????? ?? ????? ?? ??? ??..???? ???,
?? ???? ??? ?? ???? ???? ???? ??,
????? ????? ?? ??? ??,
?? ???? ????? ?? ?????,
?? ?????? ?????, ???? ?????? ?? ??,
?? ????-?????? ??? ?? ?????
????? ?? ?? ???? ???,
?? ???????? ?? ?? ??? ???? ????? ??? ?? ??,
?? ?? ??? ???? ?? ??? ??...
What makes the Nano so small and cheap? I’m glad you asked: a lack of air conditioning and air bag, wind-down windows, manual steering, a 43mph engine, plastic welding and bodywork made of sheet-metal and plastic.
Tata is hoping that the Nano will take a chunk form India's bike market; sighting 700 million bike sales last year.
I read a very interesting article by someone who works for Yahoo about how he wrote a basic search engine in Ruby in just a few files. I wouldn't use this for a production system for as an example of how search engines work its fascinating and I plan to keep following his site to see how he enhances it
Description: http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/
Source: http://github.com/sausheong/saushengine
... and he's got a really cool css/javascript formatter for the source in his blog. I've gotta learn more about SyntaxHighlighter
I read a very interesting article by someone who works for Yahoo about how he wrote a basic search engine in Ruby in just a few files. I wouldn't use this for a production system for as an example of how search engines work its fascinating and I plan to keep following his site to see how he enhances it
Description: http://blog.saush.com/2009/03/write-an-internet-search-engine-with-200-lines-of-ruby-code/
Source: http://github.com/sausheong/saushengine
... and he's got a really cool css/javascript formatter for the source in his blog. I've gotta learn more about SyntaxHighlighter
At TED, Pattie Maes & Pranav Mistry unveiled next generation wearable technology.
This can revolutionalize our personal (shopping, socializing) and professional (network, problem solving) life by meshing the information that was accessible only through a PC/handheld so far, in our daily interactions.
How would you use this platform?
A good video on how Google's AdWords works. It is a very clever business model without compromising on user experience.
Have a look.
Just a quick post to share the very exciting news (via Grub Street): Chocolate Bar, the fantastic, down-to-earth chocolatier, is re-opening in April. Their new digs will be in the West Village, not far from the old shop on Jane Street (which shuttered in 2008).
I visited Chocolate Bar during my very first eGullet foodblog back in 2006, and I have a very soft spot for their hot chocolate and their ridiculously addictive salty pretzel bars. Not like I couldn't visit them at Bendel's or online this whole time - but, still, this is exciting!
A reminder of why Chocolate Bar is just so freakin' good...
Yup. That's why.
I came across this article titled Java as Legacy Language today. As an ex-Java guy who is now committed to Ruby I was amused by the title but also think he makes a good point.
One thing is for sure: If you're in the software development business, don't cling to old ways of doing development. And also, don't get too carried away thinking that something like Scrum is going to be the Bandaid that fixes your agility problems, because it may turn out that your main problem is Java itself. Keep an open mind. Try new things. Be ready when the next disruption arrives, or you may find yourself without a chair when the music stops.
I came across this article titled Java as Legacy Language today. As an ex-Java guy who is now committed to Ruby I was amused by the title but also think he makes a good point.
One thing is for sure: If you're in the software development business, don't cling to old ways of doing development. And also, don't get too carried away thinking that something like Scrum is going to be the Bandaid that fixes your agility problems, because it may turn out that your main problem is Java itself. Keep an open mind. Try new things. Be ready when the next disruption arrives, or you may find yourself without a chair when the music stops.
My colleague Pat Shaughnessy has spent a lot of time recently enhancing the auto_complete plugin. I suggest you read his blog posts and check out his fork of auto_complete on github to see the details.
I was reading his latest change to allow filtering of auto complete picklists and really like what he did but thought there was one thing that didn't quite feel right - the fact that you have to mix the application logic to filter the list with the plugin logic to find the list in the block in your controller.
Here's the code Pat wrote in his controller and what I'd like to avoid is having to re-implement the "LOWER(tasks.name) LIKE ?" portion that's already implemented in the filtered_auto_complete_for method of autocomplete.rb in the plugin.
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
class ProjectController < ApplicationController
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | list, params |
list.by_project(params['project']['id'])
end
end
class Project < ActiveRecord::Base
named_scope :by_project,
lambda {|project_id| {:conditions => {:project_id => project_id} } }
end
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
@items = object.to_s.camelize.constantize.scoped(find_options)
@items = yield(@items, params) if block_given?
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
User Load (1.2ms) SELECT * FROM `tasks` WHERE ((`tasks`.`project_id` = '7') AND (LOWER(name) LIKE '%tas%')) ORDER BY name ASC LIMIT 10
My colleague Pat Shaughnessy has spent a lot of time recently enhancing the auto_complete plugin. I suggest you read his blog posts and check out his fork of auto_complete on github to see the details.
I was reading his latest change to allow filtering of auto complete picklists and really like what he did but thought there was one thing that didn't quite feel right - the fact that you have to mix the application logic to filter the list with the plugin logic to find the list in the block in your controller.
Here's the code Pat wrote in his controller and what I'd like to avoid is having to re-implement the "LOWER(tasks.name) LIKE ?" portion that's already implemented in the filtered_auto_complete_for method of autocomplete.rb in the plugin.
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
class ProjectController < ApplicationController
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | list, params |
list.by_project(params['project']['id'])
end
end
class Project < ActiveRecord::Base
named_scope :by_project,
lambda {|project_id| {:conditions => {:project_id => project_id} } }
end
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
@items = object.to_s.camelize.constantize.scoped(find_options)
@items = yield(@items, params) if block_given?
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
User Load (1.2ms) SELECT * FROM `tasks` WHERE ((`tasks`.`project_id` = '7') AND (LOWER(name) LIKE '%tas%')) ORDER BY name ASC LIMIT 10
This story is about a man who once upon a time was selling Hotdogs by the roadside. He was illiterate, so he never read newspapers. He was hard of hearing, so he never listened to the radio. His eyes were weak, so he never watched television. But enthusiastically, he sold lots of hotdogs.
He was smart enough to offer some attractive schemes to increase his sales. His sales and profit went up. He ordered more a more raw material and buns and sold more. He recruited more supporting staff to serve more customers. He started offering home deliveries. Eventually he got himself a bigger and better stove. As his business was growing, the son, who had recently graduated from college, joined his father.
Then something strange happened.
The son asked, "Dad, aren't you aware of the great recession that is coming our way?" The father replied, "No, but tell me about it." The son said, "The international situation is terrible. The domestic situation is even worse. We should be prepared for the coming bad times."
The man thought that since his son had been to college, read the papers, listened to the radio and watched TV. He ought to know and his advice should not be taken lightly. So the next day onwards, the father cut down the his raw material order and buns, took down the colorful signboard, removed all the special schemes he was offering to the customers and was no longer as enthusiastic. He reduced his staff strength by giving layoffs. Very soon, fewer and fewer people bothered to stop at his Hotdog stand. And his sales started coming down rapidly and so did the profit. The father said to his son, "Son, you were right". "We are in the middle of a recession and crisis. I am glad you warned me ahead of time."
Moral of the Story: It's all in your MIND! And we actually FUEL this recession much more than we think.
The king of macarons himself, the great Pierre Hermé, is featured today on The Selby. They have a recurring series that takes you inside the homes and studio spaces of creative people, and today they have some great photos of Hermé's Paris apartment.
Since I am a bit of a design addict and more than a bit of a macaron lover, this is pretty much online Nirvana for me. I think New Yorkers can learn a lot from how Parisians effortlessly mix the ancient and the modern - just look at that yellow Eames rocker next to the intricate marble fireplace.
This isn't the apartment I'd choose for myself, but you have to admire the courage. Too often Americans let the space dictate the style, rather than expressing themselves within the space provided. I'll remember this chair + fireplace combination the next time I start with a new apartment.
Photos courtesy of The Selby.
Normally, I'm not a big advocate for chains. Outside of an annual visit to McDonald's and an admitted fondness for Ikea, I try to frequent small and/or locally-owned businesses whenever possible, particularly when it comes to all things food-related.
That said, I might just be in love with Bouchon Bakery. It sits in the closest thing Manhattan has to a mall (the Time Warner Center), and it's an offshoot of the original in Yountville, but that doesn't make its coffee any less delicious or its pastries any less divine.
Part of Thomas Keller's ever-expanding empire, Bouchon Bakery features coffee, pastries, sandwiches, salads and soups. Everything looks delicious, but I can't ever seem to make it past the macarons. They slay me every time.
The caramel is my favorite, but I try to work at least one seasonal flavor into the mix on each visit. Today, they had raspberry, and lemon with chocolate buttercream. Neither of these was enough to tear me away from my beloved caramel, but I feel confident saying they were both delicious.
Seriously, go buy a macaron, as soon as possible. Bring some home, and your family will be your slaves. For reals.
About three years ago, while I was writing my first eGullet foodblog, I started exchanging emails with a fellow eGullet member named Lorna. She and I had become friendly during an extensive and obsessive period of eGulleting, and she wanted some advice: should she meet up with another eGulleter, a guy named Henry, who'd asked her to dinner?
I think I told her that I found the whole thing a bit sketchy.
It's a good thing she didn't listen to me: Lorna and Henry are now married and living in Seattle, where they've bought a house (Henry's an architect and has some pretty amazing plans for the place) and Lorna has begun penning a column for Seattle magazine.
Even more exciting? She's also working on her first cookbook. You can follow along as she writes and tests recipes, because she's recording the whole experience via her gorgeously-photographed blog, The Cookbook Chronicles. You'll want to pay special attention to the desserts - Lorna's got a renowned sweet tooth, and she knows how to treat it right.
Photo courtesy of The Cookbook Chronicles.
By now, even the less technology-savvy among us have heard of Twitter, the micro-blogging, social networking phenomenon currently sweeping the interwebs. When I joined Twitter back in November, my goal was to connect with experts and mavens in my new field (user experience) and possibly rustle up some new Queenie readers.
Little did I know my dabblings in the Twitterverse would soon become a full-blown obsession, on par with the great Facebook addiction of 2007.
The latest development to fuel my passion was my discovery that several of my food world idols are Twittering - Ruth Reichl, Mark Bittman, Pete Wells, Amanda Hesser, Grant Achatz, Adam Roberts.
While I do think there's only so much value to be shared via Twitter's 140 characters per update, there's no denying that it's kinda cool to know when Ruth Reichl is working on a new project, or to recommend the Bar at Etats-Unis to the Amateur Gourmet.
Want to join the fun? Come follow me - you can find me @queenie_nyc. See you on Twitter!
I work in 'Professional Services' Industry. Out here Information is 'vital' and making structural inferences out of disorganized information is 'Money' ($$). In my current organization, we have information stored in multiple data sources such as warehouse, wikis, blogs, document management systems, lotus notes based collaboration systems etc. The key challenge we are facing is how to find information ranked by relevance. How to link data from different sources to make meaningful inferences?
I heard Sir Tim Berners Lee, outlining the concept of Linked Data, and was greatly moved by it. Can Semantic web bring about the next revolution in the way we see, perceive and interpret data? Let's find out..
Try out the following steps.
1. Check out the Ontology viewer on Yago (a semantic knowledge base developed by Max-Plank Institute, Saarbrucken). NOTE - This would require Java applet enabled on your viewer
2. You should see an entity 'India' and it's relationships with other entities.
3. Click on other entities and browse through the semantic web (of course limited to the 2 million entities that Yago has put up so far)..
Hope this primer gets you initiated on Semantic web..more to follow on future posts.
I’ve written a lot here during the past few months about the auto_complete plugin and how to get it to work with repeated text fields on a complex form. Back in January I modified Ryan Bates’s complex forms sample app to illustrate how to use my version of the auto complete plugin to handle repeated text fields. Here’s what the form looks like in that sample app:

Here as the user types into a “Task” text field, a list of all of the existing task names in the system that match the characters typed in by the user are displayed in a drop down list. But what if I didn’t want to display all of the matching task names? What if I wanted to display only the tasks for a given project? Or if I wanted to filter the task names in some other way based on other field values?
In this simple example, what if I only wanted to display Tasks 2a, 2b and 2c, since they belonged to Project Two?
Today I took a look at this problem and expected to see a number of simple solutions, but instead I was surprised to find that it is fairly difficult to do this. I got started by reading this nice solution from Andrew Ng (nice work Andrew!). Andrew explains how to get the Prototype javascript code to pass an additional HTTP parameter to the server when the user types into an autocomplete field. This additional parameter can then be used to filter the list of auto complete options differently. I’ll let you read the details, but basically Andrew found that you can use a Javascript callback function like this to load a value from another field on your form, and pass it to the server in the Ajax request as an additional query string parameter:
<script type="text/javascript">
new Ajax.Autocompleter(
'task_name',
'task_name_auto_complete',
'/projects/auto_complete_for_task_name',
{ callback: function(e, qs) {
return qs + '&project=' + $F('project_name');
}
}
);
</script>
(I’ve renamed the variables to use my project/tasks example.) What I didn’t like about this was the need to manually code all of this javascript; there must be a way to get the auto_complete plugin to do this instead… and there is! If you look at the definition of text_field_with_auto_complete in auto_complete_macros_helper.rb, you’ll see that it takes both tag_options and completion_options as parameters, and eventually calls auto_complete_field with the completion_options. Here’s what auto_complete_field looks like in the auto_complete plugin:
def auto_complete_field(field_id, options = {})
function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
function << "'#{field_id}', "
etc...
js_options = {}
js_options[:tokens] = etc...
js_options[:callback] =
"function(element, value) { return #{options[:with]} }" if options[:with]
js_options[:indicator] = etc...
js_options[:select] = etc...
js_options[:paramName] = etc...
etc...
function << (', ' + options_for_javascript(js_options) + ')')
javascript_tag(function)
end
If you look closely at the line I bolded above, you’ll see that we can actually generate Andrew’s Javascript callback function automatically by simply passing in a value for the “with” completion option when we call text_field_with_auto_complete in our view, like this:
text_field_with_auto_complete :task, :name, {},
{
:method => :get,
:with =>"value + '&project=' + $F('project_name')"
}
Again, this line of Javascript code is called when the user types into the task name field, and appends “&project=XYZ” to the query string for the Ajax request. “XYZ” is the name of the project typed in by the user on the same form, loaded with prototype’s “$F” (Form element get value) function. The “:method => :get” completion option is used to avoid problems with CSRF protection; see http://www.ruby-forum.com/topic/128970. If you look at your server’s log file, you’ll see HTTP requests that look something like this now:
127.0.0.1 - - [13/Mar/2009:16:17:03 EDT] " GET /projects/auto_complete_for_task_name?task%5Bname%5D=T&project=Project%20Two HTTP/1.1" 200 57
Here we can see the “auto_complete_for_task_name” route is called and given two request parameters: “task[name]” and “project”. The task name is the standard parameter generated by the autocompleter javascript, and “project” is the additional parameter created by the callback function generated by the :with option.
Now… how do we handle the “project” parameter in our controller code? Without modifying the auto_complete plugin itself, you would have to write your own controller method and not use the “auto_complete_for” macro at all. Andrew shows how to do this on his blog. What I want to explore here now is whether there’s a way to change the auto_complete_for method to allow for customizations of the query used to load the auto complete options.
To understand the problem a bit better, let’s take a look at how “auto_complete_for” is implemented in the auto_complete plugin:
def auto_complete_for(object, method, options = {})
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }.merge!(options)
@items = object.to_s.camelize.constantize.find(:all, find_options)
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
When this is called as your Rails application initializes, it adds a new method to your controller called something like “auto_complete_for_task_name” with your model and column names instead. What we want to do is filter the query results differently, by using a new HTTP parameter – so we need to modify the “conditions” hash passed into find :all. At first I tried to do this by passing in different values for the “options” parameter, since that’s merged with the default options and then passed into find :all. However, the problem with this approach is that whatever you pass in using “options” will not have access to the request parameters, since it’s passed in when the controller is initialized, and not when the HTTP request is received.
So the solution is to pass in a block that is evaluated when the request is received, and when the generated method is actually called. I wrote a variation on auto_complete_for called “filtered_auto_complete_for:”
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
yield find_options, params
@items = object.to_s.camelize.constantize.find(:all, find_options)
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
Filtered_auto_complete_for takes a block and evaluates it when the actual HTTP Ajax request is received from the auto complete Javascript. The block is provided with the find options hash and also the request parameters. This enables the controller’s block to modify the find options in any way it would like, possibly using the HTTP request parameters provided. I’ve also removed the options parameter since that’s not necessary any more.
As an example, here’s my sample app’s controller code:
class ProjectsController < ApplicationController
# Handle auto complete for project names as usual:
auto_complete_for :project, :name
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
def index
@projects = Project.find(:all)
end
etc...
The code in this sample block modifies the find_options by adding “:include => :project”. This causes ActiveRecord to use a JOIN to include columns from the project table in the query (in this sample app Project has_many Tasks, and each Task belongs_to a Project). Then it matches on the project name, in addition to the portion of the task name typed in by the user so far. This limits the auto complete values to just the tasks that belong to the given project:

When I have time during the next few days I’ll add “filtered_auto_complete_for” to my forked version of the auto_complete plugin… first I need to write some unit tests for it, and be sure it works as intended. After that, I’ll post this sample app back on github and you can try it yourself.
I’ve written a lot here during the past few months about the auto_complete plugin and how to get it to work with repeated text fields on a complex form. Back in January I modified Ryan Bates’s complex forms sample app to illustrate how to use my version of the auto complete plugin to handle repeated text fields. Here’s what the form looks like in that sample app:

Here as the user types into a “Task” text field, a list of all of the existing task names in the system that match the characters typed in by the user are displayed in a drop down list. But what if I didn’t want to display all of the matching task names? What if I wanted to display only the tasks for a given project? Or if I wanted to filter the task names in some other way based on other field values?
In this simple example, what if I only wanted to display Tasks 2a, 2b and 2c, since they belonged to Project Two?
Today I took a look at this problem and expected to see a number of simple solutions, but instead I was surprised to find that it is fairly difficult to do this. I got started by reading this nice solution from Andrew Ng (nice work Andrew!). Andrew explains how to get the Prototype javascript code to pass an additional HTTP parameter to the server when the user types into an autocomplete field. This additional parameter can then be used to filter the list of auto complete options differently. I’ll let you read the details, but basically Andrew found that you can use a Javascript callback function like this to load a value from another field on your form, and pass it to the server in the Ajax request as an additional query string parameter:
<script type="text/javascript">
new Ajax.Autocompleter(
'task_name',
'task_name_auto_complete',
'/projects/auto_complete_for_task_name',
{ callback: function(e, qs) {
return qs + '&project=' + $F('project_name');
}
}
);
</script>
(I’ve renamed the variables to use my project/tasks example.) What I didn’t like about this was the need to manually code all of this javascript; there must be a way to get the auto_complete plugin to do this instead… and there is! If you look at the definition of text_field_with_auto_complete in auto_complete_macros_helper.rb, you’ll see that it takes both tag_options and completion_options as parameters, and eventually calls auto_complete_field with the completion_options. Here’s what auto_complete_field looks like in the auto_complete plugin:
def auto_complete_field(field_id, options = {})
function = "var #{field_id}_auto_completer = new Ajax.Autocompleter("
function << "'#{field_id}', "
etc...
js_options = {}
js_options[:tokens] = etc...
js_options[:callback] =
"function(element, value) { return #{options[:with]} }" if options[:with]
js_options[:indicator] = etc...
js_options[:select] = etc...
js_options[:paramName] = etc...
etc...
function << (', ' + options_for_javascript(js_options) + ')')
javascript_tag(function)
end
If you look closely at the line I bolded above, you’ll see that we can actually generate Andrew’s Javascript callback function automatically by simply passing in a value for the “with” completion option when we call text_field_with_auto_complete in our view, like this:
text_field_with_auto_complete :task, :name, {},
{
:method => :get,
:with =>"value + '&project=' + $F('project_name')"
}
Again, this line of Javascript code is called when the user types into the task name field, and appends “&project=XYZ” to the query string for the Ajax request. “XYZ” is the name of the project typed in by the user on the same form, loaded with prototype’s “$F” (Form element get value) function. The “:method => :get” completion option is used to avoid problems with CSRF protection; see http://www.ruby-forum.com/topic/128970. If you look at your server’s log file, you’ll see HTTP requests that look something like this now:
127.0.0.1 - - [13/Mar/2009:16:17:03 EDT] " GET /projects/auto_complete_for_task_name?task%5Bname%5D=T&project=Project%20Two HTTP/1.1" 200 57
Here we can see the “auto_complete_for_task_name” route is called and given two request parameters: “task[name]” and “project”. The task name is the standard parameter generated by the autocompleter javascript, and “project” is the additional parameter created by the callback function generated by the :with option.
Now… how do we handle the “project” parameter in our controller code? Without modifying the auto_complete plugin itself, you would have to write your own controller method and not use the “auto_complete_for” macro at all. Andrew shows how to do this on his blog. What I want to explore here now is whether there’s a way to change the auto_complete_for method to allow for customizations of the query used to load the auto complete options.
To understand the problem a bit better, let’s take a look at how “auto_complete_for” is implemented in the auto_complete plugin:
def auto_complete_for(object, method, options = {})
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }.merge!(options)
@items = object.to_s.camelize.constantize.find(:all, find_options)
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
When this is called as your Rails application initializes, it adds a new method to your controller called something like “auto_complete_for_task_name” with your model and column names instead. What we want to do is filter the query results differently, by using a new HTTP parameter – so we need to modify the “conditions” hash passed into find :all. At first I tried to do this by passing in different values for the “options” parameter, since that’s merged with the default options and then passed into find :all. However, the problem with this approach is that whatever you pass in using “options” will not have access to the request parameters, since it’s passed in when the controller is initialized, and not when the HTTP request is received.
So the solution is to pass in a block that is evaluated when the request is received, and when the generated method is actually called. I wrote a variation on auto_complete_for called “filtered_auto_complete_for:”
def filtered_auto_complete_for(object, method)
define_method("auto_complete_for_#{object}_#{method}") do
find_options = {
:conditions => [ "LOWER(#{method}) LIKE ?", '%' +
params[object][method].downcase + '%' ],
:order => "#{method} ASC",
:limit => 10 }
yield find_options, params
@items = object.to_s.camelize.constantize.find(:all, find_options)
render :inline => "<%= auto_complete_result @items, '#{method}' %>"
end
end
Filtered_auto_complete_for takes a block and evaluates it when the actual HTTP Ajax request is received from the auto complete Javascript. The block is provided with the find options hash and also the request parameters. This enables the controller’s block to modify the find options in any way it would like, possibly using the HTTP request parameters provided. I’ve also removed the options parameter since that’s not necessary any more.
As an example, here’s my sample app’s controller code:
class ProjectsController < ApplicationController
# Handle auto complete for project names as usual:
auto_complete_for :project, :name
# For task name auto complete, only display tasks
# that belong to the given project:
filtered_auto_complete_for :task, :name do | find_options, params|
find_options.merge!(
{
:include => :project,
:conditions => [ "LOWER(tasks.name) LIKE ? AND projects.name = ?",
'%' + params['task']['name'].downcase + '%',
params['project'] ],
:order => "tasks.name ASC"
}
)
end
def index
@projects = Project.find(:all)
end
etc...
The code in this sample block modifies the find_options by adding “:include => :project”. This causes ActiveRecord to use a JOIN to include columns from the project table in the query (in this sample app Project has_many Tasks, and each Task belongs_to a Project). Then it matches on the project name, in addition to the portion of the task name typed in by the user so far. This limits the auto complete values to just the tasks that belong to the given project:

When I have time during the next few days I’ll add “filtered_auto_complete_for” to my forked version of the auto_complete plugin… first I need to write some unit tests for it, and be sure it works as intended. After that, I’ll post this sample app back on github and you can try it yourself.
A phone management service which allows - “one phone number for all your phones, for life.”
https://www.google.com/voice/about
While writing someone's year-end evaluation in 2008, I highlighted how their style was exemplary and resulted in delighted stakeholders, including sponsors, development partner and other IT teams (Security, Infrastructure, Operations).
We have talented individuals with many hard skills but we often ignore the softer aspect of service delivery, understanding the wins for sponsors and other stakeholders.
Do you have "soft hands" to deal with all the undertakings in your project?
Litmus test to check if you have "soft hands"
- Do you have a win-win mindset and practice it in your interactions/negotiations?
- Do you ask yourself "was I helpful?" after every interaction
- Are you okay with agreeing to disagree?
- Do you have a calming effect on volatile discussions?
- Do your colleagues reach out to you for help/advice in dealing with tough situations?
- Do you lead tough negotiations or take the back seat?
-
Litmus test to check if you don't have "soft hands"
- Do you often come out of security discussions deflated?
- Do you shut down when its a business or product adoption problem?
- Do you find stakeholders reaching out to you through someone else in your team/portfolio?
-
Tips for success:
- Listen, be in the moment
- 50% of what we do has nothing to do with technology
- Learn from your colleagues who do it well
- Be passionate but never raise your voice
- What else has worked for you?
Lead by example. Attitude is addictive.
Jurgen Appelo at noop.nl created another great list...the top 50 new software development books. The list includes books covering various aspects of software development: project management, business analysis, user experience, testing, refactoring, agile practices, architecture, web services, etc. The list was created using a weighted list of the following criteria and includes books that are less than two years old...
- Number of ratings on Amazon.com
- Average rating on Amazon.com
- Number of ratings on GoodReads.com
- Averate rating on GoodReads.com
Note: The time that has passed since a book's release date was part of the calculation. For example: A book that got three 5-star ratings in just four months is listed higher than a book that got the same ratings in a much longer period of time
Yesterday evening I decided it was time to refresh my work laptop's background. The European travel background (below) served me well for about three months, but it's time for something a bit lighter.
Enter a collage of Poladroided Greenmarket photos from 2008. Yay!
Want to make your own collage? I did these using Picasa, Google's photo editing software. The latest version has a collage feature - you can do grids, mosaics, picture piles, and the like. Oodles of time-wasting potential.
I was pleasantly surprised to find that Carnegie Mellon University has a new Institute for Social Innovation as part of the Heinz College. Hopefully, with CMU's strength in computer science and engineering, we will see some additional focus on how technology can enable and scale some of the innovations that are being explored.
The research center is a welcome complement to a similar effort at the Center for Social Innovation at the Stanford School of Business.
Today, the fantastic food-in-litblog Lashings and Lashings of Ginger Beer posted the poem "Strawberries" by Scottish poet Edwin Morgan. All my life, I have had a fondness for all things strawberry, and, since my trip there in 2007, a fondness for all things Scottish. Therefore, I am doubly delighted by this selection.
Not to mention, it's one of the hotter poems ever written about a food item. Tastefully hot, of course. Sensual, you might even say. Enjoy!
"Strawberries" by Edwin Morgan
There were never strawberries
like the ones we had
that sultry afternoon
sitting on the step
of the open french window
facing each other
your knees held in mine
the blue plates in our laps
the strawberries glistening
in the hot sunlight
we dipped them in sugar
looking at each other
not hurrying the feast
for one to come
the empty plates
laid on the stone together
with the two forks crossed
and I bent towards you
sweet in that air
in my arms
abandoned like a child
from your eager mouth
the taste of strawberries
in my memory
lean back again
let me love you
let the sun beat
on our forgetfulness
one hour of all
the heat intense
and summer lightning
on the Kilpatrick hills
let the storm wash the plates
The term “affirmative action” was initially used in Executive Order No. 10925, signed in 1961 by John F. Kennedy. The Order required that federal contractors “take affirmative action to ensure that applicants are employed, and that employees are treated during employment, without regard to their race, creed, color, or national origin.” The Order was later expanded by Lyndon Johnson in 1967, to include women.
Affirmative action is part of a panoply of laws, regulations, and agencies that were designed to remedy socio-historical inequities, and are generally limited to addressing historical discrimination against groups such as women and people of color. It is undergirded by the notion of societal responsibility, so that in the same manner that society perpetuated discrimination against these groups, so too society must be responsible for rectifying its previous discrimination against them. It is important to understand that affirmative action is as much of a legal matter as equal employment opportunity, and that it is rooted in issues related to historical discrimination, not just present-day inequities.
Diversity, on the other hand, is a more inclusive concept and includes people of various religions, marital status, sexual orientation, economic status, and a variety of other different states of being. It is undergirded by the notion that organizations benefit most when they leverage the abilities of all of their employees, and implicitly positions discrimination as an impediment to organizational profitability and productivity. Rather than being rooted in the law, diversity is a strategic business imperative, which continues to increase in importance as distinctions among people become more prevalent in the workplace.
Diversity and affirmative action deal with issues related to discrimination, but in different ways. Affirmative action is a legal redress of historical discrimination, while diversity views discrimination as an impediment to company profitability. They are complementary in function, but different in their origins and goals."
Picture courtesy of *charminglyBohemian on Flickr.
CNN reports on a mobile app game developed by the US State Department and distributed via Facebook and mySpace to gamers in the middle east:
http://www.cnn.com/2009/TECH/03/06/xlife.game/index.html
OK, so, it's not as good as the real thing - but it's 58 degrees out today, and headed to be about 65 before things are all said and done. We don't get the asparagus or the strawberries or the ramps yet, but we do get the sunshine and the opportunity to break out the dresses and flats!
To celebrate today's preview of spring, I took a walk along the East River and then hit my favorite local bakery, Two Little Red Hens, for a coffee and a cinnamon roll. Totally sinful, but totally worth it. The roll was a delicious, yeasty nest of buttery icing, plump raisins, and spicy cinnamon. I highly recommend a trip to the Upper East Side (or Park Slope!) to indulge yourself.
What are the rest of you doing to welcome our little burst of springtime?
Most successful organizations have a vision, similar to the vision we have for our App Dev organization - "Excellence in software development". Similarly, each of us should have one too. Fast forward three to five years and write down now.. what you want your career to look like in 2014 (even 10 to 15 years later) or what you want to be. This could be extended later to other domains of your life, i.e. your family, self (mind, body and spirit) or your community/society etc.
This statement of your personal vision is intended to provide a focus for your long-term and short-term actions. It's expected that you will revise it over time as the environment changes and your priorities change just like any other organization. It will be of most use if your vision is a "compelling image of an achievable future, a story or picture that inspires" as my professor Stewart D. Friedman puts it.
Before you write down your goals for the year, I would recommend creating your personal vision. Then only you would know the goals you are putting for yourself this year is aligned to your personal vision. Ask yourself, "Is this going to help me get to my vision?" If not, it is not probably worth trying to achieve those goals...
Creating a personal vision has helped me a lot in deciding what my priorities should be at work. I have found it helpful to many of the folks I help with in their professional development as well.
Do you have a personal vision? If yes, how is it helping you? or I encourage you to create one and see the difference it makes ...
Most successful organizations have a vision, similar to the vision we have for our App Dev organization - "Excellence in software development". Similarly, each of us should have one too. Fast forward three to five years and write down now.. what you want your career to look like in 2014 (even 10 to 15 years later) or what you want to be. This could be extended later to other domains of your life, i.e. your family, self (mind, body and spirit) or your community/society etc.
This statement of your personal vision is intended to provide a focus for your long-term and short-term actions. It's expected that you will revise it over time as the environment changes and your priorities change just like any other organization. It will be of most use if your vision is a "compelling image of an achievable future, a story or picture that inspires" as my professor Stewart D. Friedman puts it.
Before you write down your goals for the year, I would recommend creating your personal vision. Then only you would know the goals you are putting for yourself this year is aligned to your personal vision. Ask yourself, "Is this going to help me get to my vision?" If not, it is not probably worth trying to achieve those goals...
Creating a personal vision has helped me a lot in deciding what my priorities should be at work. I have found it helpful to many of the folks I help with in their professional development as well.
Do you have a personal vision? If yes, how is it helping you? or I encourage you to create one and see the difference it makes ...
CNN reports on the One Laptop Per Child program, which provides low cost (US$180) laptops to needy kids : http://www.cnn.com/2009/TECH/03/05/one.laptop.per.child/index.html
Expectations from individuals
1) Exceptional project work (bread and butter)
Demonstrate:
This past weekend I had the pleasure of judging at the New York City Science and Engineering Fair, held at City College. Students from 300 city schools displayed impressive projects across a variety of technical disciplines. With all the grim news we hear about the state of science education in the US, the event left me thankfully optimistic.
There were no exploding volcanos or potato-powered light bulbs, which is what I remember from science fairs in my day. Instead, I met kids who analyzed data from MRI machines, lab tested flammable household materials, and ran rats through mazes. The enthusiasm of the students was infectious. It was also great be in the company of area scientists and engineers who took time out of their day to encourage young people to pursue science.
Finals for the NYCSEF will be held on March 25 in the beautiful whale room of the American Museum of Natural History. About 20 students will ultimately be selected to compete in the Intel International Science and Engineering Fair (ISEF) in Reno, NV.
I started receiving a lot of error notifications recently from my ExceptionNotfier plugin for an error with ActionController::InvalidAuthenticityToken. It turned out the error was occurring because one of my users was pasting a link to my app in an MS Office document and when Office sees the link it makes a request that Rails could not handle. Here I'll show you a simple fix you can use to avoid these errors with much credit going to an article at
Dealing with Microsoft Office Protocol Discovery in Rails
.
My execptions looked something like this (lots of boring details omitted)
A ActionController::InvalidAuthenticityToken occurred in events#1164:
ActionController::InvalidAuthenticityToken
[RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'
-------------------------------
Environment:
-------------------------------
* HTTP_USER_AGENT : Microsoft Data Access Internet Publishing Provider Protocol Discovery
* REQUEST_METHOD : OPTIONS
#around line 270 of routing.rb
module ActionController
module Routing
HTTP_METHODS = [:get, :head, :post, :put, :delete]
end
end
class ApplicationController < ActionController::Base
before_filter :options_for_microsoft_office_protocol_discovery
...
def options_for_microsoft_office_protocol_discovery
render :nothing => true, :status => 200 if request.method == :options
end
end
# Rails 2.3 and above
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
process '/any/goofy/path', nil, nil, nil, 'OPTIONS'
response.should be_success
end
# Rails < 2.3 version
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
@request.env['REQUEST_METHOD'] = 'OPTIONS'
process '/any/goofy/path'
response.should be_success
end
curl -X OPTIONS http://localhost:3000/
I started receiving a lot of error notifications recently from my ExceptionNotfier plugin for an error with ActionController::InvalidAuthenticityToken. It turned out the error was occurring because one of my users was pasting a link to my app in an MS Office document and when Office sees the link it makes a request that Rails could not handle. Here I'll show you a simple fix you can use to avoid these errors with much credit going to an article at
Dealing with Microsoft Office Protocol Discovery in Rails
.
My execptions looked something like this (lots of boring details omitted)
A ActionController::InvalidAuthenticityToken occurred in events#1164:
ActionController::InvalidAuthenticityToken
[RAILS_ROOT]/vendor/rails/actionpack/lib/action_controller/request_forgery_protection.rb:86:in `verify_authenticity_token'
-------------------------------
Environment:
-------------------------------
* HTTP_USER_AGENT : Microsoft Data Access Internet Publishing Provider Protocol Discovery
* REQUEST_METHOD : OPTIONS
#around line 270 of routing.rb
module ActionController
module Routing
HTTP_METHODS = [:get, :head, :post, :put, :delete]
end
end
class ApplicationController < ActionController::Base
before_filter :options_for_microsoft_office_protocol_discovery
...
def options_for_microsoft_office_protocol_discovery
render :nothing => true, :status => 200 if request.method == :options
end
end
# Rails 2.3 and above
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
process '/any/goofy/path', nil, nil, nil, 'OPTIONS'
response.should be_success
end
# Rails < 2.3 version
it 'should not throw an exception on OPTIONS request (from ms office protocol discovery)' do
@request.env['REQUEST_METHOD'] = 'OPTIONS'
process '/any/goofy/path'
response.should be_success
end
curl -X OPTIONS http://localhost:3000/
Unless you've been living under a rock, you know that the Northeast got dumped with a foot of snow yesterday. Here in New York, it's been a long, quiet, cold winter, weather-wise, and so the child inside of me was excited to finally have a good amount of the white stuff on the ground.
The petulant toddler inside of me, however, is positively crying out for a dose of spring. I want tender asparagus and stinky ramps and sweet strawberries. I want new lamb and fresh chicken and orange-yolked eggs. And I want it now!
Spring is my favorite time in New York - we wake up from our long hibernation, the farmer's market is buzzing again, the flowers and the food are local once more, and I get to trade my wool overcoat in for a chic trench.
What are you most excited for when it comes to the impending change of season?
One of my new favorite sites, Mobile Active, posted a recent article about fundraising via mobile devices. Power-blogger Katrin Verclas covers a lot of ground in her post, which I won't reproduce here. I will, however, include a couple great links to sites that show examples of successful implementations of mobile fundraising:
Just completed reading Simon Stapleton's ebook titled '10 habits of highly effective IT professionals'. Here are the habits Simon propounds
My take - it's a nice refresher of habits we know but at times ignore. Good news it's available for free download at SimonStapleton.com after a quick registration.
Recommended reading.
Recently I came across this cool new feature from Google Labs about having your Gmail offline !
In the world of agile development, refactoring of code is an essential practice.
Watch Ward Cunningham reflecting on the history and common misunderstanding of the 'debt metaphor', as he presents the case for continuous refactoring.