Friday, March 24, 2017

My First Google Chrome Extension! And Asynchronous Functions in Javascript

A while ago I published my first Google chrome extension, which you can find here. Basically the extension is an assignment tracker that turns your new tab page into a notepad. It also allows you to highlight text in the browser and right-click to add it to the assignment tracker clipboard.

Although the new tab notepad idea has already been implemented before, I wanted a notepad that would allow me to add text I see in my browser to the notepad without copying and pasting and without opening the new tabs window. My extension Assignment Tracker solves this problem.

The Assignment Tracker was easy to implement because I was able to study code of other google extensions I found on Github, but the add assignment part of my extension was performing unreliably. Fortunately, I discovered the problem later during Incube*.

At Incube, my friends and I are working on an extension that creates a dislike button for Facebook, and I discovered Assignment Tracker's problem while trying to fix something similar. It turns out that there exists something called an Asynchronous method invocation.

In my extension, I was using the chrome.storage API to store text users added to their assignment tracker clipboard, but chrome.storage is designed to be asynchronous; other processes can happen while the chrome.storage function completes. This messed up the chronology of how text was stored and updated on the new tabs page. As a result, selected text didn't always show up on the new tabs clipboard.

I used the get and set functions of chrome.storage to retrieve and edit stored text. These functions take two parameters: the first is the variable we want to retrieve or modify, and the second is the function that will be called after the get or set function has completed.

By nesting the set function inside the second function parameter of the get, I was reliably able to modify the clipboard text to include the new highlighted text information. I have included my solution in the following excerpt:

function add(event) {
  if (event.selectionText) {
    alert("Added to Assignment Tracker: \n\n" + event.selectionText);

    chrome.storage.sync.get("data", function(object) {
      text = object.data;

      if (text === "undefined") newtext = event.selectionText;
      else newtext = event.selectionText + "\n\n" + text;

      chrome.storage.sync.set({ "data" : newtext }, function() {
      if (chrome.runtime.error) console.log("Runtime error.");
      });
    });
  };
};

I am still trying to learn JavaScript so this stack overflow answer may be able to explain the situation more clearly. Because of this annoying experience, I also learned about the bad programming practice of callback hell.


A quote really stood out to me from the callback hell article that I linked above:
"Write small modules that each do one thing, and assemble them into other modules that do a bigger thing. You can't get into callback hell if you don't go there." 
- Isaac Schlueter (creator of npm)

In the future, I will be more careful to avoid writing modules that are too big and hard to debug.

Cheers!

* Incube is an organization where a bunch of people work on projects and eat Indian food together.

Friday, March 17, 2017

The End of Midterms and UROPing

This week was a stressful week because I had two midterms that each counted for around 16% of my grade. Although my classes this semester are definitely more interesting, I miss PNR and not having to care about my grades. I read online that it is relatively easier to get Bs at MIT, but much harder to get As. Because I want to qualify for MEng, I will need to get at least one-third As.

Outside of my classes, I spent around 6 hours working on a program called audio-pass, which I am developing as part of my UROP. Audio-pass takes live sound inputs and slows it down a given percentage. It is the first program that I've worked on in C, and C is very different than Python. For example, parsing arrays is much more difficult, libraries are harder to import, and one has to consider memory allocation. Nonetheless, I am am enjoying this learning experience.

Today, I wrote tests for and improved a function that reads an array from a given index to the last modified index and writes it to another array. I also implemented a plot function that behaves like matplotlib in python, but directly calls a command-line program called gnuplot to plot data.

Here's the cute little graph that took way too long to figure out!

I am grateful for not only learning a new language C, but also for developing good software development habits such as writing tests for every function and checking for differences in code before sending pull requests on git. My UROP adviser also taught me many other useful git commands like how to deal with merge conflicts.

Life is good.