Saturday, August 31, 2013

AngularJS Lightbox directive

I was using lightbox2 in an AngularJS app and realized that it was pretty difficult to customize it.
The requirements were very simple,
  1. editing the album name/ picture description
  2. deleting album/picture 
  3. different overlay than the usual title below/above the image
Although the last one I would have found support in some library or the other if I searched but the first two needed to have callbacks to my AngularJS app. This prompted me to write a directive which could be easily configured/customized.

I made use of AngularUI modal since that was already used in my app. Besides, as they say, no point in rewriting stuff that's already there.

The usage is pretty simple,
<lightbox images="album"></lightbox>

where album is an array of image details. A sample image detail object would be
{src: "/path/to/img", header: "the data/info that should be displayed above the image", description: "the info to be displayed beside the image"}

The header and the description can also be HTML strings. The dimensions in tile view are 150px x 150px by default. 

The directive can be customized/configured to handle various cases (inline editing using contenteditable, delete, change tile size, background, etc)

Friday, March 1, 2013

How MapReduce works

Inspired by the map and reduce operations in functional languages, Google came up with a programming model and implementation to handle operations on huge data in a time-efficient manner.

In order to use MapReduce, the user needs to define two functions:
the Map function, which generates an intermediate map 
and the Reduce function, which operates on the intermediate map resulting in desired output.

When the user program calls the MapReduce function,

  1. The MapReduce library in the user program splits the input files into M pieces and copies of the program are started on a cluster of machines. One of these copies is master and is responsible for assigning the M map tasks and the R reduce tasks to the workers(others).
  2. When a map task is completed, the intermediate key/value pairs are buffered in memory. These buffered pairs are periodically written to local disk which is partitioned into R regions by the partitioning function. The master is responsible for forwarding these locations to the reducer workers. 
  3. When the master notifies a reduce worker about the locations, it uses remote procedure calls to read the buffered data from the local disks of the map workers. 
  4. After reading all the intermediate data, the reduce worker sorts the data by the intermediate keys. This ensures that all occurrences of a key are grouped together.
  5. Then, the reduce worker iterates over the sorted data and for each unique key encountered, it passes the key and the corresponding set of intermediate values to the user's Reduce function. 
  6. The output from the Reduce function is appended to a final output file for that reduce partition.

Once all the map and reduce tasks are completed, the MapReduce call in the user program returns back to the user code and the output of the MapReduce execution is available in the R output files.

Thursday, February 28, 2013

Converting Play 2.1 JSON to Scala XML

Working with JSON and XML is pretty simple in Play-framework. For JSON, it is recommended to use Play's type-class based library.

I recently, came across a scenario where I had to convert Play 2.1 JSON to Scala XML and vice versa. I didn't find any internal classes in Play which could handle this. Lift provides a tool to handle a similar conversion.

To convert the JSON into XML I used recursion. Although, the scala.xml.Elem constructor allows only one Node to be added as child, there is another method copy, which takes in a Seq[Node] as child.  

To handle conversion from XML to JSON, I modified the toJson method in Lift to result in Play JSON. 

Link to gist

Friday, January 11, 2013

File Upload using AngularJs

Although AngularJs does not support file upload, as of now, there are several ways to achieve it using the input tag.

One method is to integrate file upload plugins. An alternative to that is sending form-data.

Sending form data is simple,

$'/path/of/request', fd, {
     headers: { 'Content-Type': undefined},
     transformRequest: angular.identity
   }).success(function (result) {

where fd is a FormData Object.

The file can be set using the files property of the input element.

We could also use XMLHTTPRequest to upload a file. Link to a simple component to upload a file

In this directive, component is an angular module and it can simply be used by having a 'fileUpload' tag.

Note: This doesn't work in older versions of IE where there is no FormData object. Those interested can check stackoverflow or filepicker.