Ankur Sethi's Blog

A campaign of shock and awe.

Book Review: The Essence of Camphor by Naiyer Masud

The Essence of Camphor is a collection of short stories by Naiyer Masud, considered one of the foremost Urdu short-story writers in India. This collection contains English translations of ten of his stories.

This is not the sort of book I would have picked up on my own. It was Pratul who urged me to read it, comparing Masud's style to that of Haruki Murakami. While Masud and Murakami write about completely different people in completely different cultural contexts, I feel Pratul's comparison is not entirely inapt. There are many parallels between the works of the two writers, which is not surprising considering both of them are strongly influenced by Kafka.

Masud's stories are surreal and dreamlike, and as one would expect, they don't conform to traditional narrative structures. Many of them are told in a stream of consciousness style by narrators who appear to be reminiscing about their early years. Themes of childhood and family life in old India are prominent throughout. Someone on Goodreads called them "mood stories" – stories with the sole purpose of evoking a sense of time and place, or I suppose the lack thereof. In other words, Kafkaesque. Some of them are vaguely terrifying (Obscure Domains of Fear and Desire, The Woman in Black), others are sorrowful (The Essence of Camphor, Nosh Daru), all of them are beautiful. Masud captures the sights, sounds and smells of old Lucknow in such vivid detail that you almost start reminiscing about the good old days yourself.

Beautiful as they are, these stories are also inscrutable. I rarely read the introduction to a book before reading the book itself, but I'm glad I broke my rule this time. Muhammad Umar Memom – who wrote the introduction and translated some of the stories – has this to say about Masud's work:

[...] reading Masud's stories evoked the sensation of being thrown headlong into a self-referential circularity.

Which I interpret to mean: don't think too hard kids, just enjoy the ride. And what a ride it is.

To be honest, I often felt frustrated with this collection. I would not recommend reading it from beginning to end in one sitting. This is a book best consumed slowly, over a span of many weeks. Despite my frustration, some of these stories have left a deep impression on my mind.

If you enjoy Murakami and/or Kafka, I'd highly recommend picking up a copy of The Essence of Camphor. If you're not into surrealism, keep away.

My Reading List for 2014

The hardest thing to do after finishing a book is deciding which one you want to read next. Things become harder still when you and your roommates collectively own hundreds of books, most of which have been on your to-read list for years. And if you own an e-reader with even more books on it – you see where I'm going with this, right?

This is why I have made a reading list for this year, and it looks something like this:

  • The Essense of Camphor by Naiyer Masud
  • Shantaram by Gregory David Roberts
  • Ready Player One by Ernest Cline
  • Sea of Poppies by Amitav Ghosh
  • River of Smoke by Amitav Ghosh
  • The Shadow Lines by Amitav Ghosh
  • In the Miso Soup by Ryu Murakami
  • Coin Locker Babies by Ryu Murakami
  • Almost Transparent Blue Popular Hits of the Showa Era by Ryu Murakami
  • Siddhartha by Herman Hesse
  • Flowers for Algernon by Daniel Keyes
  • Oryx and Crake by Margaret Atwood
  • The Year of the Flood by Margaret Atwood
  • MaddAddam by Margaret Atwood
  • The Handmaid's Tale by Margaret Atwood
  • The Left Hand of Darkness by Ursula K. Le Guin
  • The Dispossessed by Ursula K. Le Guin
  • Ghostwritten by David Mitchell
  • number9dream by David Mitchell
  • One Flew Over the Cuckoo's Nest by Ken Kesey
  • Something Happened by Joseph Heller
  • The Spy Who Came in from the Cold by John Le Carré
  • Tinker Tailor Soldier Spy by John Le Carré
  • The Honourable Schoolboy by John Le Carré
  • Smiley's People by John Le Carré

Update: Since I couldn't find an electronic version of Ryu Murakami's Almost Transparent Blue, and the physical version was too expensive in India, I decided to replace it with Popular Hits of the Showa Era.

2013: Year in Review

The Good

  • Moved to Bangalore. Probably the best decision I've made in the last five years. When I moved here, I told myself I'd stay for at most one year. Now it's starting to look like I'll be here for a while.
  • Started cycling. This is Bangalore rubbing off on me.
  • Passed all my college exams.
  • Started working full time.

The Bad

Can't think of anything, really. Minor existential crises don't count. 2013 was a suspiciously good year.

The Ugly

  • Picked up wrist and back injuries because of bad posture while working on the computer. The injuries are minor, but they inhibit my ability to work for long periods of time. I've made several lifestyle changes to combat these, and they're slowly paying off. Still, the road to recovery is long and fraught with many setbacks.

The Highlights

  • Best book read: a close tie between Cloud Atlas and Speaker for the Dead.
  • Best musician discovered: Janelle Monáe.
  • Favorite albums of the year: Good Kid m.A.A.d City, Doris.
  • Favorite new software: PyCharm, Pinboard.in, Google Keep.

Unlockments Achieved

  • Streamlined my web development and deployment workflow. I've started using Vagrant and Ansible a lot, and unit tests have become an integral part of my work.
  • Read (slightly) more than I did in 2012. I read fifteen books in 2013, but fell short of my goal of twenty-five.
  • Started exercising.
  • Moved to Bangalore.

What Next?

There were several goals that I couldn't achieve in 2013. I'd like to tackle them again this year.

  • Release one or two useful webapps into the wild. (If possible, monetize these.)
  • Start keeping track of how I spend my time.
  • Start keeping track of the movies I watch, the books I read and the music I listen to.
  • Read more. Twenty-five books, at least.
  • Super secret goal.

Besides these leftover goals from last year, I have some new goals for this year.

  • Manage my time better.
  • Start contributing to an open source project.
  • Write more. Technical blog posts, book reviews, music reviews, private journals, fiction, whatever.
  • Learn about machine learning and statistics. Perhaps a MOOC is the best way to do this.

Have a happy new year, folks. Make it one worth remembering!

Loading Spinners With AngularJS and Spin.js

Spin.js is a tiny JavaScipt library that helps you create beautiful loading spinners on every web browser up from IE6. It is highly customizable, fast, and has zero dependencies. I'm using it in my AngularJS application to display loading spinners inside my ng-views while my REST API responds with the data the view needs to render itself.

I add a viewLoading boolean to the $scope of each controller that talks to the REST API. The initial value of viewLoading is true.

angular.module('MyApplication')
  .controller('MakesTonsOfAPICallsController', function($scope) {
    $scope.viewLoading = true;
  });

After all the API calls complete successfully, I set viewLoading to false.

angular.module('MyApplication')
  .controller('MakesTonsOfAPICallsController', function($scope, MyLargeModel) {
    $scope.viewLoading = true;

    // Grab all MyLargeModel objects.
    MyLargeModel.get({}, function(result) {
      // Do something with the result.
      $scope.viewLoading = false;
    });
  });

If I have to make multiple calls, I use the $q service to create a promise for each of them. Each promise is resolved or rejected depending on the status code that the API call returns. I then use $q.all() to call a function when all of the promises have been resolved. This function sets viewLoading to false. I will talk more about $q in another post, but here is a rather simplistic example for now:

$q.all([promise1, promise2 ... promiseN]).then(function(data) {
  $scope.viewLoading = false;
});

I want the loading spinner to be displayed for as long as $viewLoading is true, and be replaced by the actual view content as soon as viewLoading becomes false. I use a directive to do this. This is what the markup looks like:

<div ng-controller="MakesTonsOfAPICallsController">
  <div my-loading-spinner="viewLoading">
    <!-- actual view content goes here. -->
  </div>
</div>

And this is what the directive looks like:

angular.module('MyApplication')
  .directive('myLoadingSpinner', function() {
    return {
      restrict: 'A',
      replace: true,
      transclude: true,
      scope: {
        loading: '=myLoadingSpinner'
      },
      templateUrl: 'directives/templates/loading.html',
      link: function(scope, element, attrs) {
        var spinner = new Spinner().spin();
        var loadingContainer = element.find('.my-loading-spinner-container')[0];
        loadingContainer.appendChild(spinner.el);
      }
    };
  });

For this to work correctly, the Spin.js code has to be loaded before the directive code.

The directive is restricted to attributes only and replaces the original content on the page with the content from my template. I set transclude to true so I can re-insert the original content back into the page later. If you look back at the HTML for the view, you will find that the value of the myLoadingSpinner attribute is viewLoading. When Angular encounters our markup, it will create a two-way binding between the loading variable in the directive's scope and the viewLoading variable in the parent controller's scope. If you find this confusing, you may want to read about directives on the AngularJS website.

Before I explain the link function, take a look at the directive's template:

<div>
  <div ng-show="loading" class="my-loading-spinner-container"></div>
  <div ng-hide="loading" ng-transclude></div>
</div>

The markup is simple enough. The div with class my-loading-spinner-container is displayed when loading is true, and hidden if it is false. The second div is hidden if loading is true, and displayed if it is false. The second div also uses ng-transclude to re-include into the page the original content that was replaced by our directive.

Finally, the link function creates a new loading spinner, finds the div with the class my-loading-spinner-container, and puts the spinner inside the div. Hence, the spinner is displayed as long as loading is true, and the actual content is shown when it becomes false, which is exactly what we want.

Simulating a Slow Internet Connection

I am currently working on a single page web application written with AngularJS that communicates with a REST API written with Django and Tastypie. Since I run both the client and the server locally on my machine, every HTTP request that my AngularJS application makes receives a response from the REST API in tens of milliseconds. This is not ideal.

In the real world, Internet connections have latencies that range anywhere from a few hundred milliseconds to tens of seconds. To give my user a smooth experience even on a slow internet connection, I need to ensure that she receives appropriate feedback whenever she performs an action that requires a round-trip to the server. For example, when she navigates to a view that requires a large amount of data to be fetched from the server, my application needs to display a loading spinner of some sort on the screen to indicate progress. I cannot have the UI be completely blank for the time it takes my API to respond to the HTTP request.

Unfortunately, if I run the application locally, it becomes impossible for me to test my progress indicators. The request-response cycle completes so quickly that they are replaced by the actual content within a split second.

After searching the Internet in vain for a solution that would let me simulate a "real" Internet connection from within my browser, I wrote a Django middleware that uses time.sleep() to delay each HTTP response that my application returns by 0 to 4 seconds.

import random
import time

class SlowPony(object):
    def process_response(self, request, response):
        time.sleep(random.randint(0, 4))
        return response

Then I added this middleware to my MIDDLEWARE_CLASSES:

MIDDLEWARE_CLASSES = (
    # ...
    'my_application.middleware.SlowPony',
)

I don't like this solution. For one, this does not cause any of the requests to time out, which happens frequently on mobile Internet connections. It's better than nothing, though.

I find it surprising and disappointing that neither Firefox nor Chrome let me simulate slow Internet connections via their developer tools. Fast, reliable, low-latency Internet connections are a rarity, especially since a large and growing number of people browse the web using mobile Internet. This situation is unlikely to change for several years in the future, and tools to test our web applications in such scenarios are either incomplete or non-existent.