Posts Tagged ‘open source’

Toggle non-consecutive checkboxes with jQuery UI

Posted on:Tuesday, December 27th, 2011 by Ashish Datta

You’re all probably familiar with the UI convention of allowing users to select ALL or NONE for a list of checkboxes (like in Gmail). Recently I was working on a project that had a large table full of checkboxes (imagine a 10×10 grid) where the user would need to toggle some but not all of the checkboxes in a given row. And to make matters more complex, they would need to toggle groups of non-consecutive checkboxes (say 15, skip 10, 5, etc.). I threw on the thinking cap but couldn’t think of any similar interactions I’d seen and couldn’t think of a particularly good way to achieve this.

Enter jQuery UI. I happened to stumble across the jQuery UI Selectable documentation and realized it would provide a good UI experience to toggle some but not all of the checkboxes. The code to implement this is surprisingly simple:

Note: You don’t actually need the div container – that was just for JSFiddle.

<div id="checkboxes">

<table id="checkboxTable">
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
     <tr>
         <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
          <td><input type="checkbox" /></td>
     </tr>
</table>
</div>

And then the Javascript (jQuery + jQuery UI):

$("#checkboxes").selectable( {filter: "input:checkbox",
            stop: function(event, ui) {

                $(".ui-selected").each( function(){

                    $(this).each( function(){
                        var val = $(this).attr("checked") ? null : "checked";
                        $(this).attr("checked", val);
                    });

                });
}});

You can check out a live demo at http://jsfiddle.net/whMyQ/3/

As always, questions and comments are welcome!

Facebook: How-to force users to LIKE page

Posted on:Friday, December 16th, 2011 by Ashish Datta

With Facebook’s move to deprecate FBML for tabs the documentation around how to make a “please Like! before…” has become much more choppy and inconsistent. Anyway, I recently found myself in a position where I needed to make this happen so here goes.

With in-line FBML deprecated, the only way to accomplish this without using a third party branded solution is to create a Facebook iframe app. Here are the steps you need to take to get something up using PHP and the Facebook PHP SDK.

1. Create a new Facebook Application at https://developers.facebook.com/apps

2. Configure your new Facebook App the enable “Website” and “Page Tab”. You’ll need to enter a valid URL for the following fields:

  • Site URL
  • Page Tab URL
  • Secure Page Tab URL

You’ll also want to use a HTTPs URL since Facebook sessions default to HTTPs by default and your iframe will be marked insecure if its over vanilla HTTP. For this walk through, lets assume were using https://www.setfive.com/fb/index.php? as the URL.

3. Now, you’ll want to add your new App to a Facebook Page. The easiest way to do this is to use this URL https://www.facebook.com/dialog/pagetab?app_id=YOUR_APP_ID&next=YOUR_URL replacing YOUR_APP_ID and YOUR_URL with your App ID and then a URL that is derived from your endpoint (or even just your endpoint). When you load that URL, you’ll be prompted to add your app to a page – select the page you want and submit the form.

4. The final piece is throwing together the actual PHP script. You’ll need the Facebook PHP SDK available on GitHub – https://github.com/facebook/php-sdk. Clone that and then this is the PHP script you’ll need:


<?php
require 'php-sdk/src/facebook.php';

$facebook = new Facebook(array(
  'appId'  => 'YOUR_APP_ID',
  'secret' => 'YOUR_APP_SECRET',
));

$req = $facebook->getSignedRequest();
?>

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"xmlns:fb="http://ogp.me/ns/fb#">

<head>
    <meta charset="utf-8" />
    <title></title>
</head>

<body>

<?php if( $req["page"]["liked"] ): ?>

	Content for users that have LIKED the page.

<?php else: ?>

	Content for users that HAVE NOT LIKED the page.

<?php endif; ?>

</body>

</html>

And thats it! Now you’ll be able to gate content from non-fans while growing the fanbase of your Facebook Page.

Drop any questions in the comments.

Fixing blank CCK Location fields in Views

Posted on:Sunday, September 25th, 2011 by Ashish Datta

Recently, we inherited a Drupal 6 site via a client of ours and ran into a pretty irritating bug with the Location module.

The site had been configured to allow users to create profiles using Node Profile along with the Location to allow users to input their street addresses.

Anyway, the issue was that when we created a View that included Location fields the fields were always rendering as blank even when we confirmed there was data in the database. A bit of poking around lead to this issue.

It turns out that due to an optimization in CCK or Views that the tables that have the data for the location fields are not getting JOIN’ed in when the view is executed. Unfortunately, the patch provided on the issue doesn’t work on the latest 3.x release of the Location module.

The fix that worked for us is #14 (copied below)

/**
* Preprocess hook for location().
*/
function yourtheme_preprocess_location(&$variables) {
  if (!isset($variables['location']['name']) && isset($variables['location']['lid'])) {
    $variables['location'] = array_merge($variables['location'], location_load_location($variables['location']['lid']));
    template_preprocess_location($variables);
  }
}

Basically, you’ll need to add the above snippet to a template.php file in your theme and change the name to reflect the theme you’re using. What this function does is basically pre-process the location fields to pull in the data so that the View will work properly.

Anyway, enough blogging it’s football time.

Getting started with Hadoop, Hive, and Sqoop

Posted on:Wednesday, September 14th, 2011 by Ashish Datta

I apologize for the buzzword heavy title but it was the best I could do. I couldn’t find a good quick start explaining how to get started with Hive so I thought I’d share my experiences.

Anyway, a client of ours came to us needing to analyze a dataset that was about ~200 million rows over 6 months and is currently growing at about 10 million rows a week and increasing. From a reporting standpoint, they were looking to run aggregate counts and group bys over the data and then display the results on charts. Additionally, they were also looking to select subsets of the data and use them later – basically SELECT * FROM table WHERE x AND y AND z.

Obviously, doing the calculations in real time was out of the question so we knew we were looking for a solution that would be easy to use, support the necessary requirements and that would predictably scale with the increasing generation rate of data.

On the surface, MySQL looks like a decent approach but it presents a couple of issues pretty quickly:

  • In order for the SUM, GROUP BY, and COUNT queries to be at all useful the MySQL tables would have to be heavily indexed. Unfortunately, due to the write heavy workload of the app this would mean having to copy data into an indexed MySQL database before running any reports.
  • Even with indexes, MySQL was pretty awful at selecting subsets of the data from a performance perspective.
  • And probably the biggest issue with MySQL is that it doesn’t scale linearly in the sense that if the data is growing at 500 million rows a week you can’t simply “throw more hardware” at it and be done with it.

With requirements in hand we hit the Internet and finally arrived at Hive running on top of Hadoop. Per Wikipedia,

From our perspective, this stack fits our requirements nicely since it doesn’t rely on keeping a second “reporting” MySQL database available, it will handle both sum/count/group by and selecting subets, and probably most importantly it will allow us at least in the near term to scale with the increasing rate of data generation.

“Apache Hadoop is a software framework that supports data-intensive distributed applications under a free license. It enables applications to work with thousands of nodes and petabytes of data. Hadoop was inspired by Google’s MapReduce and Google File System (GFS) papers.”

To grossly over simplify, Hadoop provides a framework that allows you to break up a data intensive task into discrete pieces, run the pieces in a distributed fashion, and then combine the results giving you the results of the completed task. The quintessential example of a task that can be parallelized in this fashion is sorting a *really* big list since the list can be sorted in pieces and then the results can be combined at the end. See Merge Sort

The second piece of the tool chain is Hive. Again via Wikipedia,

“Apache Hive is a data warehouse infrastructure built on top of Hadoop for providing data summarization, query, and analysis.Apache Hive is a data warehouse infrastructure built on top of Hadoop for providing data summarization, query, and analysis.”

Basically, Hive is a tool that leverages the Hadoop framework to provide reporting and query capabilities using a syntax similar to SQL.

That just leaves Sqoop, the app with a funny name and no Wikipedia entry. Sqoop was originally developed by Cloudera and basically serves as an import tool for Hadoop. For my purposes, it allowed me to easily import the data from my MySQL database into Hadoop’s HDFS so I could use it in Hive.

The rest of this post walks you through setting up Hadoop+Hive and analyzing some MySQL data.

Now that you know the players, lets figure out what we’re actually trying to do.

  1. We want to start a Hadoop cluster to use Hive on.
  2. Load our data from a MySQL database into this Hadoop cluster.
  3. Use Hive to run some reports on this data.
  4. Warehouse the results of this data in MySQL so we can graph it (not that exciting).

Starting the cluster

Theres actually one more tool you’ll need to get this to work – Apache Whirr. Whirr is actually really cool, it lets you automatically start cluster services (Hadoop, Voldermont, etc.) at a handful of cloud platforms (AWS, Rackspace, etc.)

NOTE: We exclusively use AWS for our hosting so everything described here is specific to AWS.

Fisrt, download the latest copy of Whirr – http://www.fightrice.com/mirrors/apache//incubator/whirr/ to your local machine. Whirr should work everywhere but these directions will match up against Linux/OSX the best.

The first thing you’ll need is a Whirr configuration file describing the cluster you want to build. Create a file called hadoop.properties and paste in the following:

whirr.cluster-name=hadoop
whirr.instance-templates=1 hadoop-namenode+hadoop-jobtracker,2 hadoop-datanode+hadoop-tasktracker
whirr.hadoop-install-function=install_cdh_hadoop
whirr.hadoop-configure-function=configure_cdh_hadoop

whirr.provider=aws-ec2
whirr.identity=[REPLACE THIS WITH YOUR AWS ID]
whirr.credential=[REPLACE THIS WITH YOUR AWS SECRET]

whirr.hardware-id=m1.large
whirr.image-id=us-east-1/ami-68ad5201
whirr.location-id=us-east-1

whirr.private-key-file=~/.ssh/id_rsa
whirr.public-key-file=~/.ssh/id_rsa.pub

There isn’t a ton going on in the file but you’ll need to switch out the credential lines for your AWS credentials. Also, you’ll need to double check that the ssh paths are accurate for your account.

The next step, is to actually launch the cluster. To do this run this command – double check the path to your hadoop.properties file is accurate:

./bin/whirr launch-cluster --config hadoop.properties

Just give it a few minutes, you’ll see a bunch of debug info scrolling across your terminal and hopefully a success message once its done. At this point, you’ll have a fully built Hadoop cluster with 3 nodes as described in your properties file ( 1 hadoop-namenode+hadoop-jobtracker,2 hadoop-datanode+hadoop-tasktracker ).

You can see all your nodes by checking out your Whirr cluster directory.

cat ~/.whirr/hadoop/instances

Prepping and loading the cluster

Now that the cluster is up, you’ll need to prep it and then load your data with Sqoop.

One of the most irritating “gotchas” I stumbled across was that Whirr adds the firewall rules necessary for Hadoop to its AWS security group.

Before you do anything, open your EC2 control panel and modify the new Whirr security group (#jcloud-something) so that all of your nodes can connect to each other on port 3306 (MySQL)

The next step is to install mysql-client across the entire cluster since Sqoop uses mysqldump to get at your data. You could manually ssh into every machine but Whirr provides a convenient “run-script” command to do just that.

Create a file called “prepCluster.sh” and put “sudo apt-get -q -y install mysql-client” in it. Then make sure the paths are right and run,

./bin/whirr run-script --script prepCluster.sh --config hadoop.properties

Once its done, you’ll see the aptitude output from all your nodes as they downloaded the MySQL client.

The next step is to install mysql-server, hive, and sqoop on the jobtracker. Doing this is pretty straightforward, look at the .whirr/hadoop/instances file from above and copy the namenode hostname.

Next, ssh in to that machine using your current username as the username. Once you’re in, just run the following to install everything:

sudo apt-get -q -y install sqoop
sudo apt-get -q -y install hadoop-hive
sudo apt-get -q -y install screen

NOTE: You’ll also need the MySQL ConnectorJ library so that Sqoop can connect to MySQL. Download it here and place it in “/usr/lib/sqoop/lib/”

Once everything is done installing, you’ll most likely want to move your MySQL data directories from their default location onto the /mnt partition since it’s much larger. Check out this article for a good walk through. Don’t forget to update AppArmour or MySQL won’t start. Once MySQL is setup, load the data you want to crunch.

Now, you’ll need to use Sqoop to load the data from the MySQL database into Hadoop’s HDFS. While logged into the jobtracker node you can just run the following to do that. You’ll need to swap out the placeholders in the command and change the u/p.

sqoop-import-all-tables --connect jdbc:mysql://[IP of your jobtracker]/[your db_name] --username root --password root --verbose --hive-import

Once it completes, Sqoop will have copied all your MySQL data into Hadoop’s HDFS file system and initialized Hive for you.

Crunching the data

Run “hive” on the jobtracker and you’ll be ready to start crunching your data.

Check out the Hive language manual for more info on exactly what queries you can write.

Once you’ve narrowed down how to write your queries, you can use Hive’s “INSERT OVERWRITE LOCAL DIRECTORY” command to output the results of your query into a local directory.

Then, the next step would be to TAR up these results and use scp to copy the results back to your local machine to analyze or warehouse.

Shutting it down

The final thing you’ll need to do is shut down the cluster. Whirr makes it pretty easy:

./bin/whirr destroy-cluster --config hadoop.properties

Give it a few minutes and Whirr will shutdown the cluster and clean up the EC2 security group as well.

Anyway, hope this walk through proves useful for someone. As always, feedback, questions, and comments are all more than welcome.

Adding HTML attributes to Drupal navigation items

Posted on:Tuesday, March 29th, 2011 by Ashish Datta

Check out Menu Attributes

It will allow you to add attributes like target=”_blank” or nofollow to your navigation menu items.

jQuery UI confirm

Posted on:Monday, March 21st, 2011 by Ashish Datta

I was looking around earlier for a jQuery plugin to allow me to use jQuery UI’s dialog() widget to popup a confirm dialog. Didn’t have any luck finding one so I whipped something up. It’s not pretty but it works. You could even go as far as to overload window.confirm() but thats probably a bad idea.

jQuery.confirm = function(options){

	var opts = jQuery.extend( { message: "", ok: function(){}, cancel: function(){ } }, options );

	jQuery("
" + opts.message + "" + "
").dialog({ autoOpen: true, modal: true, autoOpen: false, resizable: false, draggable: false, title: "", width: "400px", buttons: { "Cancel": function(){ opts.cancel.call( this ); }, "Ok": function(){ opts.ok.call( this ); } } }).dialog("open"); }; // use it jQuery.confirm( { "message": "Are you sure?", "ok": function( ){ $(this).find(".loader:first").show(); // do stuff $(this).dialog("close"); }, "cancel": function( ){ $(this).dialog("close"); } });

Drupal 7: Batch insert nodes with Drush

Posted on:Wednesday, February 9th, 2011 by Ashish Datta

Well D7 has been out for a little while now and we finally got a chance to use it on a site this week.

Anyway, this site is one of the heavier Drupal sites we’ve done and it involved loading ~200+ nodes of data just to set things up. This presented two problems, how to batch load data and then how to load custom content types with several custom fields.

The Drupal module documentation has example code for adding a node with drupal_exeucte here but it doesn’t deal with how to set custom fields on your content type. On top of this, drupal_execute has been renamed to drupal_form_submit in Drupal 7 and the function signature has changed a bit.

Anyway, I dug around a bit and finally managed to get this working. You’ll obviously need Drush installed for the following code to work but you could rip it out and use it outside a Drush command. I was looking to basically replicate the “load-data” task from Symfony so that I could seed my Drupal database with Nodes at any point so I chose to make this a Drush command.

Here’s what you need:

- You’ll need a module to hold the Drush task. I used Module Builder to generate my scaffolding.
- Create a file named [modulename].drush.inc in your module directory
- Here is the code I’m using for [modulename].drush.inc Replace “cm” with the name of your module:


/**
* Implementation of hook_drush_command().
*/

function cm_drush_command() {

        // callback is the function that will be called when the command is executed
	$items['load-rep-data'] = array(
	    'callback' => 'cm_load_rep_data',
            'description' => 'Loads the representative data.',
            'bootstrap' => DRUSH_BOOTSTRAP_DRUPAL_FULL,
	);

	return $items;
}

function cm_load_rep_data( ){
   // you need this to autoload the functions to create nodes
   module_load_include('inc', 'node', 'node.pages');

  // do some business logic to load your data from where it is
  foreach( $arr as $res ){

    // define the custom node type
    $node = array('type' => 'representative');

   // set up the form array
   $form_state = array();

   // set the title of the node
   $form_state['values']['title'] = $res["title"];

   // set a custom field that is a text type
   $form_state['values']['field_first_name']['und']['0']['value'] = $res["first_name"];

   // set a long text field and enable full_html - NOTE you'll need to allow anonymous users to use this for Drush to work
   $form_state['values']['body']['und']['0']['format'] = 'full_html';
   $form_state['values']['body']['und']['0']['value'] = $res["bio"];

  // set some custom select fields
  $form_state['values']['field_house_committees']['und'][ 0 ] = 34;
  $form_state['values']['field_house_committees']['und'][ 0 ] = 37;

  // can't leave this out or the form wont save
  $form_state['values']['op'] = t('Save');

  // actually try and "submit" the form
  drupal_form_submit('representative_node_form', $form_state, (object)$node);

  // printing from Drush is easy
  drush_print( $res["title"] );
  }
}

Thats about it.

With Firebug, it’s really easy to see the field names and the values that you can set by just looking at a form to create whatever type of node you want.

drupal_form_submit can also be used to “submit” any other type of form in Drupal.

An open question is how to “fill out” an ImageField field via the command line since nothing is actually going to be uploaded.

iPhone style checkboxes for Symfony

Posted on:Wednesday, October 13th, 2010 by Ashish Datta

No one worry, I did in fact survive my birthday and subsequent party!

Anyway, I was poking around for some cool UI elements for checkboxes and stumbled across this neat jQuery plugin – http://github.com/tdreyno/iphone-style-checkboxes Basically, what it does is converts checkboxes into iPhone style toggles.

Check out a demo at http://tdreyno.github.com/iphone-style-checkboxes/

This is for a symfony project (shocker!), so I figured I’d roll it into a widget and share.

You’ll need to download and include the JS+CSS+images for the plugin yourself and then copy the following code into your project:


class sfWidgetFormInputiPhoneCheckbox extends sfWidgetFormInputCheckbox {

	public function __construct($options = array(), $attributes = array())
	{

		$this->addOption('checked_label');
        $this->addOption('un_checked_label');

		parent::__construct($options, $attributes);
	}

	public function render($name, $value = null, $attributes = array(), $errors = array())
	{
		$str = parent::render( $name, $value, $attributes, $errors );

		$checkedLabel = $this->getOption("checked_label");
        $uncheckedLabel = $this->getOption("un_checked_label");
        $id = $this->generateId($name);

		$str .= <<

		  $(document).ready( function(){

                $('#$id').iphoneStyle({
                    checkedLabel: '$checkedLabel',
                    uncheckedLabel: '$uncheckedLabel'
                });

		  });
		
EOF;

		return $str;
	}

}

Using it is straightforward:

    $this->setWidgets(array(
      'show-upcoming-events-nav' => new sfWidgetFormInputiPhoneCheckbox( array("checked_label" => "on", "un_checked_label" => "off") ),
    ));

UPDATED: New Facebook Phonebook Script

Posted on:Monday, July 19th, 2010 by Ashish Datta

I realized this morning that Anonymous Coward’s Facebook Phonebook Greasemonkey script broke awhile back so I decided to rewrite it from scratch.

The original instructions for how to install the script are available here.

I updated the original Userscripts page with the new script so you can download it here.

Once again, this probably breaks your Facebook TOS so I can’t vouch for the safety of your account if you do decide to do this.

jQuery.trigger weirdness

Posted on:Thursday, June 10th, 2010 by Ashish Datta

Earlier today, I was trying to use jQuery to trigger the submission of a form after a radio button was clicked. The form tag looked something like:

...form..

So for a regular submit button:


Everything works fine, you’ll see the alert() and the form won’t submit because of the return false.

I ran into issues when I tried to trigger() the submit event with jQuery. I was trying to trigger the submit() event on the form via jQuery. The problem I ran into, was that the saysomething() function was getting called, but the “return false” seemed to have no effect.

The final form looked something like:

For some reason, if you submit the form via a jQuery trigger the form submits even though saysomething() gets called. I’m not sure if this is the expected behavior but it was certainly something of a shock. Anyway, a live version of the form is running here.