playing with appjet

Posted in General on January 3rd, 2009 by Ashish Datta

The other day one of my friends jokingly mentioned that he thought strippers were being “marginalized” as profession. I thought this was funny, so I leveraged the powers of the internet to prove to him that in fact strippers are less marginalized then say podiatrists.

Enter amimarginalized.com

Anyway, with all of the hub-dub about Javascript being the next “big thing” I decided to give appjet a whirl. Appjet allows developers to develop and deploy server side Javascript applications. Additionally, appjet recently released “appjet in a jar” which lets users deploy the appjet platform on a different server.

Getting the appjet platform up and running was really simple. I already had Java 6 installed on one of our servers so all I had to do was download the appjet jar and fire it up with “java -jar appjet.jar”

In general, getting things moving was pretty easy with appjet. It also just “feels” natural to write Javascript for the client and the server. Switching between client and server is done with a comment directive:

/* appjet:client */
/* appjet:server */

appjet also provides a special directive for CSS styles:

/* appjet:css */

The other feature I really liked about appjet is its support for printing HTML elements. Appjet comes with a tag library that makes creating HTML tags particularly simple. The syntax looks something like this:

print(

FORM({action:”/”, method:”get”, onsubmit: “javascript: return submitJob()”},
SPAN({id: “job-label”}, “Job Title: “),
INPUT({text:”text”, name:”jobField”, id: “jobField”}),
INPUT({type:”hidden”, name:”isPost”, id: “isPost”, value: “1″}),
INPUT({type: “submit”, value: “Submit”})
)
);

And boom you have a XHTML compliant form.

The other neat feature, (from the appjet docs) is that “You can also treat a tag like a JavaScript array (it has all the same methods) and add to it programmatically.” so something like this works:

var list = UL();

list.push(LI(”One item”));
list.push(LI(”Two item”));

["Red","Blue"].forEach(
function(color) {
list.push(LI(color+” item”));
}
);

printp(”The following “+list.length+” items may be of interest.”);
print(list);

I was also really impressed with the appjet persistent storage system. The platform lets you persist arbitrary Javascript objects in “collections” that can then be iterated, filtered, and sorted. On amimarginalized.com I have about 800 elements loaded up and it seems to perform reasonably well.

The one issue I have with the storage library is that there isn’t any way to just load a bunch of data into the system. You can only load data from inside an appjet script file. The problem I ran into is that I hit the Java 64kb file size limit pretty quickly. It would be really awesome if the JAR had some functionality to load up say a file full of JSON objects.

All and all, using appjet has been a positive experience. It was really easy and fun to build an “easy” app using it. I’d really like to know some more about how appjet is put together but the documentation is sparse. The only information I could find was the logos on the download page. They suggest that appjet is composed off AppJet, Rhino, Jetty and of course Java. I’d be interested to know if there are any plans to expose JVM libraries to appjet code. It seems like this would allow the platform to quickly gain extensive library support - including the JDBC.

Anyway, the amimarginalized.com site uses “advanced” algorithms to determine how marginalized your career is. It just counts the number of results on Yahoo BOSS for the job you enter and compares it to a set of about 800 saved jobs.

You can download the source code here.

Tags: , ,

Merry Christmas and Happy Holidays

Posted in General on December 25th, 2008 by Matt Daum

Setfive would like to wish everyone a merry Christmas and happy holidays.  We hope everyone has a great holiday season.  We’ll be bringing in the new year with a bang, and look forward to working with you.

Happy Holidays All!

JSON explorer for Firebug!

Posted in General on December 18th, 2008 by Ashish Datta

As Firefox plugins go, Firebug is definitely one of my favorites. It has saved me and the rest of the Setfive team dozens of development hours. One of the nicest features of Firebug is the NET panel. The NET panel allows a developer to monitor HTTP requests that Firefox is making during the course of a page’s execution. This is particularly useful to AJAX heavy applications because it allows a developer to easily debug XHR requests and responses.

Although this is great, the NET panel is severely lacking when it comes to dealing with JSON responses. Since JSON must be a legal JavaScript string, it can’t contain any line breaks. As a consequence, debugging long JSON strings is extremely painful.

This issue has been on the Firebug TODO list for some time. I figured this would be a good place to jump into the Firebug codebase. I dropped an email to the Firebug working group and received some great feedback. Honza gave me a template extension to extend the NET panel and provided some great insight and advice on implementing a JSON viewer.

After a couple of weeks of intermittent work, the JSON-Viewer extension is ready to play with. Honza has committed the code into the Firebug 1.4+ branch so if you grab a new build you’ll be able to use the JSON viewer.

Screenie:

Read more at Honza’s blog post

Tags: , ,

Importance of Having Technical Knowledge Onboard

Posted in Free Advice, General on December 5th, 2008 by Matt Daum

Today I want to take the chance to stress the importance of having someone onboard that knows some technology. Through our experience we’ve often had clients who were mislead or taken advantage of by other technology firms. Whether it is being given poor advice or being overcharged for simple tasks, we’ve seen it quite a bit. In many of these situations a person with some technological knowledge would have saved them money and time.

What can a person with technical knowledge do?

  • Know what questions to ask - “Do you provide documentation for your code? Do you use a framework? Is your code MVC compliant? etc.”
  • Know when you are being taken advantage of - We’ve seen in the past many clients purchased servers and functionality they just don’t need. A technical person can make sure that you aren’t purchasing five servers when one will do, that you aren’t overpaying for simple hosting, etc.
  • To help choose your development firm. It is very difficult to tell whether a firms code is good. If you do not have knowledge in the area, good code and bad code appear to be the same. Choosing the development firm for your project can make or break the project. If the firm chosen produces messy, inefficient code, it dooms your product before it is even launched.
  • To monitor code quality. Once you’ve picked your development firm, it is important to check in now and then to make sure the quality of the code is of the caliber you are paying for. It is crucial to catch poor code in the beginning, to make sure the firm doesn’t continue to use the same coding style.

What if you don’t want to have a technical person on staff full time? Hire a consulting firm. Many firms provide assistance with choosing your development team and to monitor most of the technical aspects of the product. We offer these services.

Moral: Having technical knowledge onboard prevents your company from being taken advantage of and will often pay for itself in saved time and a quality delivered product.

Tags: , ,

Artificial artificial intelligence - our experience with Mechanical Turk

Posted in General on November 20th, 2008 by Ashish Datta

So Amazon Web Services (AWS) has a pretty neat service called the Mechanical Turk. The name of the service is inspired by this story where a human was hidden inside a chess playing “robot” which impressed crowds during the late 18th century. Amazon’s service doesn’t hide the fact that its powered by humans but the end result is the same - humans performing tasks in lieu of a computer.
The task we needed “turked” was the transcription of various text labels that were on top of overlays on a particular large image. The goal of all of this was a Google Maps product so we all ready had the overlays loaded into a Google Maps UI.  To recap:

  • We had a Google Maps application which loaded an image layer with about 3000 discrete overlays.
  • We had lat/lng coordinates for all of these overlays.
  • Each of these images had a text label that uniquely described it.
  • We wanted the Turks to transcribe these labels.

Next, we began to investigate how the Mechanical Turk service actually works. The process is delightfully simple. The idea is to break the tasks out into discrete and reproducible actions called human intelligence tasks (HITs). This pattern aligned well with our problem because all of the overlays were independent and we had coordinates for each of them. Amazon displays each of these HITs inside a template that the “requester” constructs.

The templates are HTML pages (Amazon allows javascript) which plug-in variables for each HIT when the tasks go live. They also capture the data that you want to save from the task - in our case the labels. Designing templates is pretty straightforward and javascript is a nice touch.

For our task, we embeded Google Maps with our image overlaid and used HIT variables to display 3 markers per task. This is where we hit our first and only snag. Because of directory restrictions on Google Maps API keys our HIT template kept generating javascript errors because it was being executed on un-predictable domain names. We didn’t think this was a huge deal so we plowed ahead as planned.
We ran the first set of HITs with a 2 cent/HIT payment and a minimum approval rating of 95%.

The results were less than stellar - within an hour or so we received this email:

A strange error message pops up for your/these HITS.
“The Google Maps API key used on this web site was registered for a different web site. You can generate a new key for this web site at http://code.google.com/apis/maps/.”
Also, the mouseover that displays at screen bottom is “javascript: void (0)”…and no label appears below the marker either.  I do NOT have any javascript blockers operational, so no problem there.
Also, I would appreciate it if you NOT deny me credit for this HIT, as the technical error message was not my fault and not explained or warned in the instructions.
I would like to do several, possibly many of these HITS, if you can tell me what to do to overcome this problem.
Thanks,
[REDACTED]

People were obviously not getting the instructions and were scared away by the JS error and fear of HIT rejection. One of the problems with the service is that you can’t modify your HIT template once a set has been published. You have to cancel the batch and re-start after your edits. At this point, we decided to cancel the run and modify the instructions. With the new instructions people seemed to “get it” and were generally more willing to forgive the JS error.

At the end of the run, the accuracy of the Turks was around 90% or so on transcribing the labels. We got about 25 man hours of work accomplished in about 42 hours of actual time at a cost of about $25. All told we were really impressed with the service as well as the Turks themselves. We definitely recommend the service for any discrete and repeatable tasks.

Things we learned:

  • Be EXTREMELY clear in your instructions - try to be as un-ambiguity as possible.
  • The Turks live and die by their approval rating so be nice (we just accepted every task).
  • Unexpected popups and JavaScript errors probably scare people away so try to avoid them.
  • Obviously higher reward rates are going to attract more Turks - something to take into account.

We’ve also recently become fascinated by other things that could be played out or experimented with the Turks. Notably it seems like an ideal venue to experiment with some game theory topics.

Tags: , ,

Timelapse Twitter+Election map

Posted in General on November 12th, 2008 by Ashish Datta

This is an update to our Twitter+Election ‘08 mashup that was over at Setfive Election HQ

Well as everyone saw last Tuesday night, Obama won the election by a pretty significant margin and has all ready taken steps to announce his transition agenda.

Anyway, at the end of our run, we captured 11021 tweets with the breakdown being 2501 for McCain and 8520 for Obama. Since we had been generating maps all day we decided to take snapshots at 5 minute intervals so that we could watch the progression of the map. The timelapse map is embedded below:

We hope everyone had a good election experiance - we had a lot of fun building this mashup. Now to find the next big thing…

Tags: , , ,

Guestimating the election with twitter

Posted in General on November 4th, 2008 by Matt Daum

We were sitting around tonight and decided to whip something together to leverage twitter to get some real time election information.

It is ugly and open to bias but we’re hopping it might show something interesting.

We’re also planning to take snapshots of the map and assemble a time lapse for Wednesday.

See the map live at: http://election.setfive.com

Update at 4.40 EST:

So we’ve captured about 6000 tweets and the map is basically all blue. Just to clarify - we never intended this to be a serious vizualization or estimation of how the election is progressing. The project was soley meant to be a fun peak at how information spreads across Twitter.

Anyway, a couple of people have been asking about our methodoly so I’ll try and explain a bit.

We are using the Twitter Search API to run searches that we thought would indicate that someone just voted or intends to vote for either John McCain or Barrack Obama. Next, we apply some heuristics to the tweets to make sure they really are “just voted” tweets. If the tweet passes through the heuristics we record it for whichever candidate and then record the “from_user_id” to ensure a single user can’t blow up the vote totals.

In order to geolocate a user we are using the twittervision API I get the impression that the twittervision API just scrapes user profiles but I can’t verify this. We probably could have avoided using their API and just scraped ourselves but one less thing to deal with at 4am is always good.

The graph colors are calculated by taking the larger vote total (red vs blue) and then determining in percent, how much larger this is than the total number of votes for that state:

$totalScore=$state['redscore']+$state['bluescore'];
$percentage=($state['redscore']-$state['bluescore'])/$totalScore;

Anyway, there are defitley other entertaining things to do with twitter - we just haven’t thought of them yet. - Ashish

Tags: , ,

Joins, for better and for worse

Posted in General on October 7th, 2008 by Matt Daum

Recently I’ve been having one hell of a time with SQL Joins. It isn’t that I don’t understand how to use them, its that they have came to haunt me in completely opposite instances.

First: An application I had written a while ago that was suppose to be kept small, and very simple which continually was enlarged and became very big was running slow. I upgrade the person to our faster server believing it was just that our server that is meant for static sites couldn’t handle it. While it did greatly reduce the load time of the site(1/6) it was still slow for me. I looked into it and found that after all the alterations of the application which we had done, that one page had 1600 queries at its current state.

Before you think down upon our development abilities and our code efficiency let me put everything in perspective. The project was started as a very simple CRUD only database, that we did basically free for the a client who was a friend. Shortly after it continually was being expanded upon, and the friend could only afford minimal costs, so he asked us to just “hack” it together as it was a prototype. Well about a month later after development, we had possible one of the most hacked together prototypes for him. He never wanted to redo it from scratch so we could architect it correctly due to the cost. For the prototype, it worked fine and very fast. However the prototype turned into a beta test for the friend. He added much more information to the database, and the inefficient queries began to show. Now the application is loaded with information, and the inefficient queries are terrible. We have told him that if he plans to use this we should rewrite it from scratch as many other cool features could be used.

So back to the problem. Well we attempted to add JOINs to the program which should cut the number of queries by at least 1/10th. However when I added the left joins via Criteria/Propel I found that it was adding the joins twice. The reason they needed to be left joins is because the foreign keys were not required,

Tags: , ,

we’re alive - we promise!

Posted in General on September 24th, 2008 by Ashish Datta

So things have been absolutely crazy since the summer ended. We realize we’ve been neglecting ye ole blog (all 5 of our readers), but I promise we’ll have some goodies soon.

In the meantime lets sit back and watch the fiasco that is the US economy…

Tags: ,

Rich Date Input Widget for Symfony 1.1 Forms

Posted in General on September 14th, 2008 by Matt Daum

I noticed that for some reason the 1.1 forms do not allow for the rich date input that many people like to use, so I just created a new widget that allows for rich date input. See below for the widget’s code. It uses the input_date_tag widget in the ‘Form’ helper.

/**
* myWidgetFormRichDate is a rich date widget for 1.1+ forms
*
* @author Matt Daum matt [at] setfive.com
*/
class myWidgetFormRichDate extends sfWidgetFormDate
{

  /**
  * @param array $options An array of options
  * @param array $attributes An array of default HTML attributes
  *
  * @see sfWidgetForm
  */
  protected function configure($options = array(), $attributes = array())
  {
    parent::configure($options, $attributes);
  }

  /**
  * @param string $name The element name
  * @param string $value The value displayed in this widget
  * @param array $attributes An array of HTML attributes to be merged with the default HTML attributes
  * @param array $errors An array of errors for the field
  *
  * @return string An HTML tag string
  *
  * @see sfWidgetForm
  */
  public function render($name, $value = null, $attributes = array(), $errors = array())
  {
    //Get the date input function from Form helper
    use_helper(’Form’);
    //Make the widget rich
    $attributes['rich']=true;
    return input_date_tag($name,$value, $attributes);
  }
}

Tags: , , , ,