Random thoughts (ep 1)

I’ve always wanted to jot down random thoughts as my brain functions throughout the day so this series of blog posts is meant to keep track of tidbits and stories and I randomly picked up and processed. Also, I realized that the action of blogging actually helps me remember the stuff that I wrote, since the amount of blogs that I wrote is a reasonable finite number.

So every time I have a conversation that is related to my work, whether it’s with a technical, remotely technical or non-technical one, the topic of “what does it actually do” typical comes up. Quite frankly I like talking and do in fact talk a lot. Strangely enough I found explaining to non-technical folks more interesting and rewarding than others, mainly due to the fact that they always question the very fundamentals of computer and computer science. Sometimes when I can’t answer those, my inner curiosity forces me to go look it up, and there goes the momentum of knowledge.

A few weekends ago a friend of mine, whose field of expertise is not remotely related to coding or computer at all, asked me this: “I really don’t understand how you can write code to do stuff. How does that happen?” It is indeed a fundamental question. I recall taking my 1st computer science class and not questioning such thing, but follow the instructor’s directions instead, earning points like a little kid.

It is not until after taking quite a few amount of courses that I realize computer architecture and design mimics the very same concept as human thought process. After all, it is human who evaluates and assess how well certain algorithms function. So how do you write code to do stuff?

“Code”, IMHO, is a set of instructions that, in turn, instruct certain entities (can be machines, humans or animals) to complete certain tasks. Now imagine machine as a Brazilian (or pick any country man who doesn’t understand your language), Portugese, at some level, to me is just like code. It’s a mean of communication from an entity to another entity.

A machine can only understand binary, so there’s definitely a “translator” from codes to binaries, which I won’t go into details. Binary also very much represents human thinking in terms that there’re only 0 and 1, yes and no, true and false, right and wrong. I believe that every human question can be answered with simply yes (1) or no (0). The method to do that is to break down the question into atomic decision, which in turn will guide the machine to a final decision and execute certain operations.

For example: “What’s today’s weather?” can be achieved from yes’ and no’s based on a set of knowledge: Is it raining? Is it sunny? Is it windy? Is it snowing? How does machine define “raining” and such? It doesn’t. Such information can be input as a fact or derived from a set of conditions, such as the humidity, temperature…

The list of decisions build up to a form of a “decision tree”, where a set of answer can lead to a different output, or same output depending on the level of distinction. So given that “stuff” is a piece of knowledge that was given and “do” is a final output from a series of decision tree, that’s basically how I instruct (code) another entity (machine) to do (make decision) stuff (on a certain piece of information).

Brief summary of wassup in the tech world…

Everyday after I settle myself down on my medicine ball eating my happy sausage & egg white on a whole wheat toast breakfast, I start reading tech news. It’s important, very. Hell, it’s vital I’d say. By tech news I mean ranging from gadget sites like Gizmodo & Engadget, to Ars Technica, TechCrunch, Mashable and Hacker News. HN is still so far the best one cause the top page contents are generally filtered by rather tech-savvy members.

A lot of articles on HN are very specialized and specific to certain topics. It can range from assessment of certain techniques and patterns, to new framework, library and even micro-optimization in bitwise operations. I’ve learned a ton from those. Basically this blog post is to highlight some of the things I thought was cool, broken down to hopefully non-technical human-readable pieces :)

1.  Egor Homakov hacked GitHub

GitHub

GitHub

So what is GitHub? For non-geeks, GitHub is a social coding sites. Instead of sharing life dramas, you share codes and cool projects you’ve been working on. It’s incredibly popular and if you’re a developer without a GitHub/BitBucket account, it’s like a designer without a portfolio. Having cool projects on GitHub (cool is defined by the number of forks, a.k.a how many people develop things based on your code, and # of watchers, a.k.a how many people care about your projects) can easily get you a job at any tech company, cause it actually demonstrates your ability to produce good maintainable code, which is the unit of work developers produce.

So GitHub is like Facebook for coder and it’s built on top of a framework called Ruby on Rails (actually just Rails, Ruby is the language). In designing a framework it’s always tricky to measure the amount of customizability you want to offer. There’s no one size fit all, really. And from what I’ve read, there’s been a debate on how Rails enforces whitelisting, or security in general. How much security does a developer want? It’s always been a tough question.

What Egor found has been a know vulnerability in Rails. He posted an issue which got ignored, thus led to his demo on the master branch of Rails project itself. GitHub disabled his account while they were trying to patch it, then enabled it later on, which was ok. You can read more about this right here: Hacker commandeers GitHub to prove Rails vulnerability

2. Sabu, leader of LulzSec got arrested

So Sabu is the leader of LulzSec, which got merged into Anonymous earlier. The group has been conducting a series of DDoS attacks against banks and government websites to protest or sometimes, revenge for certain characters such as the soldier got arrested for leaking to WikiLeaks.

Sabu betrayed Anonymous

First of all, what is DDoS? DDoS is Distributed Denial of Service attack. The key is distributed. A DoS attack means someone floods your website/server with tons of requests (by tons I mean it can go up to billions and more). Since those requests occupy a large chunk of your server’s capacity to serve other users, it will eventually got overwhelmed and shut down. If you bounce/restart it, same thing happens.

Such attack coming from 1 machine is easily blocked due to unique IP address. You can simply blacklist such IP. A distributed one is much harder since it comes from multiple IP addresses running malicious software without users knowing. Such machines can be called zombies.

Now an organization can function the very same way. A normal company today has the board of directors, CEO, CTO, Cxx and such which are decision makers for the company. This can lead to what is called “single point of failure”, which means if the top tier is gone, the company collapses. LulzSec was like that, with a leader, Sabu. Sabu got arrested and LulzSec is gone.

Anonymous, however, isn’t. It is a “distributed” organization meaning there’s no single point of failure. Each subgroup, or even person, functions on his own will to serve the organization’s philosophy, which can be interpreted in any way one can. Therefore, with LulzSec gone, Anonymous isn’t guaranteed to be weaker, since LulzSec might function by itself, still following the philosophy and is in charge of its own operation.

In the computer world this allows an infrastructure to be scaled horizontally by replicating and synchronizing redundant data source. However, humans clearly cannot (yet) replicate ourselves to such an extent that we can backup ourselves to the cloud and such. Anyway, you guys can read the article right here: Sabu betrayed Anonymous

Just some random thoughts… :)

Tagged , , , , , , , ,

Some life updates…

So I’ve been pretty busy with, you know, life but who hasn’t. Actually I’ve been trying to write another blog post after my last one which was sort of a post but not really (just a generic generated past-year result the WordPress offers, for people busy (a.k.a lazy) such as myself.

So far life has been pretty good. My last year performance got me a promotion a few months ago and ever since I got to be sort of Tech Lead for the Web & Mobile Team, which is in charge of all the front-end webapps, including both internal & client-facing. I’d say dealing with this domain has been very interesting as it’s something I have wanted to do for a long time, until I took an arrow… w/e it is still very fun, being the guy who can work on both back-end and front-end and sometimes applying design patterns interchangeably. Some of those have failed miserably due to differences in the nature of the 2 domains (1 being a beefy powerhouse serving large data in a timely manners to all sorts of requests, 1 being a lightweight routing layer with some minimal caching & compression of resources).

A change in domain also means a change in technology as well. Getting myself better with NodeJS, Backbone, jQuery and now Bootstrap has been really challenging, all of which I’ll write another post about later. Ideally I’d like to push for the stack to be more well-used within the team myself. This stack can easily be distributed and scaled horizontally. However we’re not really dealing with a consumer-product business the scalability of the UI sometimes is not a development bottleneck.

Other than work stuff, I got an email this morning, which kinda cheered me up a lil bit:

Hi Long,

I came across http://longho.wordpress.com/ while searching for resources around recipes and food and was wondering if this is the correct contact in regards to the content on the site. My team just created a graphic on the topic, would you be interested in taking a look? I’d appreciate any feedback.

Thanks in advance.

Peter

So someone actually reads my blog! And feedback. Based on the statistics I know someone reads my blog but normally it’s search query from Google and those can be highly irrelevant. I actually visited their site and the statistics about ramen, IMO, is indeed very interesting. Surviving on ramen has been 1 of the most important life skills in college. My Japanese neighbor was obsessed over ramen. I mean the dude was literally chewing through packs of those…

In case you guys wondered what he sent me, here it is:
We Love Ramen Infographic
Created by: Hack College

Pretty amazing isn’t it?

Tagged , , , , , , , , , ,

2011 in review

The WordPress.com stats helper monkeys prepared a 2011 annual report for this blog.

Here’s an excerpt:

The concert hall at the Syndey Opera House holds 2,700 people. This blog was viewed about 11,000 times in 2011. If it were a concert at Sydney Opera House, it would take about 4 sold-out performances for that many people to see it.

Click here to see the complete report.

What stuff I’ve been working on lately

So it’s been a while since my last blog post, partially because I was swamped with work and some personal business, but mainly because my friend Haruki and I are still trying to design and set up the 1st phase of the MetaDB project. It is currently being actively developed right here on GitHub. We’ve put quite some thoughts into the data model of the project, which lead to several architecture and technology choices.

We’re still using NodeJS as the meat of the whole project. It has been the initial choice since the beginning due to various (unverified) reasons of speed, both in performance and development, scalability and lightweightness. I said unverified cause we’ve read a lot about it but technologies are sometimes YMMV kinda thing and for our specific use cases, NodeJS seems to be a good fit.

PostgreSQL-9.0.1

PostgreSQL-9.0.1

We dropped the idea of using NoSQL to using PostgreSQL as the database technology. NoSQL is great for unstructured data but there seems to be way too many relationships among our model objects that maintaining a NoSQL model and doing map-reduce just doesn’t seem to be worth it. For NoSQL if we separate some the components then hybrid objects would be a result of a map-reduce instead of a join, which turns out to be definitely not as efficient. If we store those components inside a certain object collection, the reusability would be a big mess. In the end, partially due to our lack of a solid NoSQL modeling skills, we took the easy way out which is SQL.

The framework that drives our API would be a custom in-house developed module called njrpc (Node-JsonRPC). It’s an implementation of the Json-RPC 2.0 protocol with some additional bells & whistles that allow you to do namespacing and interceptors of requests. It also exposes enough low-level calls (at least to our needs) that you can do manual response override in callbacks and such.

Part of my purpose for this blog post is also to share our development set up, mainly for experiments with distributed system and workflows.

Prod environment:

1. For our production environment, Haruki & I both have our VPSes, each of which has an instance of PSQL running and replicating master-slave. Configuring this took a while which we’ll document later but basically it’s running right now.

2. Each of the boxes would also have an instance of metadb-core serving API calls. A simple load-balancer (HAProxy for ex) will be placed on 1 box and will serve as the entry point of all API calls. This does produce an somewhat unpredictable response time for the calls but the tradeoff is redundancy, which is definitely needed for prod env.

3. UI will be set up on 1 of the boxes. It’s really lightweight right now so we don’t immediately see the need of having 2 UIs running.

4. We still have to set up database backup and archive, u know, disaster recovery stuff.

Test environment:

We’re planning to get another smaller VPS instance for our CI server (Continuous Integration). This pretty serves as the integration testing environment for both metadb-core & metadb-ui. Although njrpc is currently set up in Travis-CI, using a 3rd-party CI doesn’t allow us to do some customization and setup. Travis-CI uses RoR and allows testing of NodeJS projects but there’s version skew and database setup and all that. It’d be much less painful to have our own box dedicated to testing.

Development environment:

1. IDE: I actually use cloud9 running locally as my IDE. It doesn’t have code auto-complete and stuff but the syntax hi-lighting and JsHint are pretty decent and helpful. Interface is simple and lightweight enough.

2. Dev environment is pretty much a replicated of prod/test env so it definitely needs PSQL and NodeJS. We also maintain a separate test database with a much smaller set of data so that we can easily wipe out and dump it back in for a fresh copy.

That’s pretty what we have in mind… so much for 2 developers. It’s very time-consuming but rewarding at the same time as I’m getting much better at handling async stuff in JS.

Aight guys, have fun and keep on brogramming! Oh BTW we got our VPS from AlienVPS. They have pretty decent pricing.

Tagged , , , , ,

How to write NodeJS Unit Test

I wasn’t a big fan of unit tests during college since the project scope are so tiny that writing them became really dumb and repetitive. But now that the requirements and logic for my projects have become a lot more complex, unit test is actually really useful. NodeJS itself has an assert module that is used to write unit test. The reason I’m writing this post is that doing some googling didn’t help me much when I first started writing those. Some of the articles were also outdated. I’m sure this one will also but I’ll try to keep it updated.

So u wanna test your server? Here’s how to do it. The code below was used to unit test my JSON-RPC server. I started with importing the modules:

var http = require('http');
var assert = require('assert');
var jrpcs = require('./jrpc');
var options = {
   host: 'localhost',
   port: 3000,
   method : 'POST'
};

In order to test my server, I have to fire it up:

var server = http.createServer(function(req, res) {
   jrpcs.handle(req, res);
});

Now the tricky part is here: Since everything is callback, invoking tests after calling createServer doesn’t guarantee the server is initialized. The trick is to put test request inside listen:

server.listen(3000, 'localhost', function() {
   var req = http.request(options, function(res) {
      console.log('Test empty body POST request');
      checkBadResponse(res);
      server.close();
   });
   req.end();
});

So that guarantee that when I fire my test request, server is definitely up. Once I got my response and check everything, I close my server. I do that right away cause I only had 1 tests but if you have have more than 1, this has to be coordinated.

Anw, just a quick blog post on how to write unit test in NodeJS.

Writing my own JSON-RPC server in NodeJS

So summer is over (I know, like it matters for working people… but it does) and all of my friends who were interning in NYC are gone. Sounds pretty depressing but the good thing about it is that now I got some time to work on my side projects. 1 of those is my implementation of the JSON-RPC protocol in NodeJS. The source code can be found https://github.com/longlho/node-jsonrpc. Therefore, this blog post would sorta serve the purpose of what I found out while writing this module (It’s not finished yet!!!). Oh the JSON-RPC spec can be found here: http://groups.google.com/group/json-rpc/web/json-rpc-2-0

So my goals for writing this module is to sorta create a framework for MetaDB, another project my friend and I have been working on. Thus, although I tried to keep it as generic as I can, there’re some design patterns that utilizes my server and allows it to (in the future) grab metadata from service classes themselves and do some magic (whether it’s better error feedback or introspection or authentication, I’m still working on it). I also found quite a few other implementations out there, including 1 in Connect but it doesn’t seem to do some of the stuff I want it to do.

For example, I want my server to have to ability to automatically register all public methods in a module, which allows namespacing when I write my service handlers. The other thing is Introspection, which proves to be pretty challenging. Streaming and authentication would also be on my list and those are a bit tricky to implement without bloating up the API.

Once this server is complete, ideally I would try to fire up 2 instances, 1 on my VPS, 1 on my friend’s VPS and grab a reserve-proxy/load-balancer to test run this thing, hopefully with distributed MongoDB/CouchDB as well.

So why JSON-RPC but not RESTful? I personally find  JSON-RPC more convenient for programmers as the design was to call a method (Procedure Call) remotely, thus the name RPC. For me personally it’s more intuitive than sending GET/POST/PUT/DELETE. JSON-RPC servers also serves 1 entry point instead of RESTful multiple URLs which IMO makes the driver layer a little bit easier to manage. The other reason was that it’s message type is JSON and NodeJS is in JavaScript. That actually got rid of a lot of serialize/deserialize/type conversion code.

One of the challenging things about JSON-RPC and NodeJS (or at least challenging for me coming from a heavy static-typing Java background) is that everything is in callback and it’s dynamic typing. For example, here’s how I get a response body in Java:

response.getBodyAsString();

And here’s how I get response body in NodeJS:

var resString = "";
response.on('data', function(chunk) {
   resString += chunk;
});
response.on('end', function() {
   console.log(resString);
});

The dynamic typing part is actually very flexible when ur writing a service, but when it comes to generating documentation for Introspection. Again, I’m spoiled since Java has Annotation and static-typing, but when I first started using jQuery, for example, it was pretty hard to figure out what the format of a parameter is. They’ve improved that a lot but the point is it might require a lot of manual efforts instead of auto-generate one.

Anyway this project has helped me a lot in learning NodeJS and JS in general. Some of the stuff below might be useful is ur doing this:

http://www.yuiblog.com/blog/2010/08/30/yui-theater-douglas-crockford-crockford-on-javascript-scene-6-loopage-52-min/

http://www.olympum.com/future/nodejs-to-v8-or-not-to-v8/

 

 

 

 

Me likey eating!!! Eat those if you’re in NY!!!

So I moved (close) to NYC half a year ago and although during college I’ve been to the Big Apple quite a few times, I haven’t got a change to hunt down places with decent Asian food (I said decent cause, u know, it’s the States, not Asia). I pretty much take my friends to the places listed below and they’ve been pretty satisfied so far with the list. This was gather through various friends’ recommendations along with my own personal experience. I normally talk about those as “best <something> in NY”:

1. Poomes Frites (near St Mark Pl and 2nd Ave): This place is crowded most of the time and it’s at a really good location (St Mark – NYU, right close to Baoguette). It’s actually not French Fries but Belgian Fries and serves up to 25 different kinds of sauces, 1 of which I always order (that’s right, Vietnamese Pineapple Mayo cause… u know why)

2. Baoguette Cafe (St Mark & 2nd Ave): Also pretty popular although the sandwiches are just a lil over priced but they’re actually good. I normally grab the Classic and Sloppy Bao. They’re also cool w/ u bringing outside food in so get some Pommes Frites close by!!!

3. Oh! Taisho (also St Mark between 2nd and 3rd Ave): They got plum wine. Actually all the Jpnese restaurants close by have plum wine but this is the 1st place I get plum wine from so credit to that. They have the Party Set (packed w/ meat, my favorite) and decent Takoyaki

4.Saint Alps Dessert (9th Street and 3rd Ave): This place has my favorite bubble-tea-but-tastes-like-sugar-cane-juice. Lol their green tea toast is also decent and it’s in the same area as the other 3.

Moving up to KTown:

5. H-Mart (32nd Street and Broadway, near Herald Square): Not a restaurant but u can get almost any type of Korean food here (Kimchi, Jajjangmyun, Galbi…). I normally take a sweep here every weekend to restock my fridge. My friend from DC goes nuts every time she comes here lol

6. Kunjip (32nd Street KTown): This place is ridiculously crowded most of the time. It has really good Korean BBQ but keep in mind, your clothes will smell. If u don’t wanna get Korean BBQ (Bibimbap or sth like that), don’t waste ur time lining up, u can get those anywhere else.

7. Pocha (same street): This place looks kinda sketchy on the outside cause it’s a tiny staircase up. The inside is also kinda tiny but this reminds of Korean street bars I saw in those dramas. They have really good watermelon Soju, casserole and the stuffed squid thingy…

Watermelon Soju

Watermelon Soju

The portions are HUGE!!! Unfortunately it’s not very cheap (still average in KTown) so…

Down to Chinatown! Keep in mind that you definitely need cash down here!!!

8. Jing Fong (Elizabeth Str & Canal Str): Best dim sum in NY, always crowded and winds down at around 1pm or so. They only serve dim sum from like 11am – 3:30pm but by 1pm everything is almost gone so come early!! Speaking Cantonese is a huge plus here.

9. Thai Son (Baxter Str & Canal Str): This is a typical Vietnamese restaurant with pho and everything, also very reasonably priced. I always got pho Xe Lua cause it’s easy and decent here. For some reasons my friends said Pho Co Ba is better and I honestly think that place is tiny, overpriced and the portion is too small. It got a better atmosphere but hell, I come to eat.

10. Pho Bang (Mott Str & Grand Str): Everything here is pretty much on par with Thai Son/Nam Son except for their Bun Cha Hanoi. Its actually decent!! However the waiters have the habit of slapping the receipt right after they deliver your food which annoys me a lil bit.

11. Cong Ly Restaurant (Hester Str & Chrystie Str): This place got CHAO LONG!!! I was impressed, really!! I just tried it today and it’s actually gooood!!! Also, chao long and bubble tea don’t mix… Learned it the hard way >.<

12. X.O Kitchen (Elizabeth Str & Hester Str): If you’re here, get the Congee and Fried Dough (quay) ONLY!!! The fried dough and congee portion are pretty big (2 is enuf for like 4 ppl) so don’t underestimate those.

13. Banh My Saigon (Mott Str & Grand Str): This place has the best Banh My IMO but it’s like in the back of a jewelry store so it gets a bit tricky to find. Also very cheap for its value!!

14. Tao pho (Grand Str & Bowery Str): I always get tao pho (tofu fa) from this one old woman’s shop at the corner of Grand Str & Bowery cause it’s like super cheap for a huge portion ($2.5). The thing is the shop closes pretty early so by the time I get out of my office to get there, she already closes >.<

Scattered around NY:

15. Shakeshack (23rd Str & Madison Ave): Don’t even try to come here during lunchtime, it’s impossible. The line is ALWAYS ridiculously long, even in the winter. Best burger in NY!!

16. Menkui tei (56th Str & 5th): Really good and cheap ramen!! They got alcohol from the store next door though which is kinda weird. I haven’t tried Ippudo cause the line is always damn long but my Japanese friend recommended this place!

17. Kyotofu (48th Str & 9th Ave): This place has really good dessert although a bit overpriced and the service is slow. Their signature sweet tofu is the best. The atmosphere is also very suitable to bring a date (which I have none T_T)

Jump over Hudson River to New Jersey:

18. Pho Thanh Hoai (Newark Ave, JC): This place is right close by so I come here for my Vietnamese food craze for a while. Things here are decent and cheap enough that I’d soooo rather get this than Chinese food.

19. Mitsuwa (Edgewater): Not a restaurant but a huge Japanese marketplace that has a bunch of ramen shops and dessert inside, along with grocery shopping. They have, guess what, PLUM WINE and LYCHEE SAKE here. Def my 2 favorite alcoholic drinks :) They also got grilled eel and sushi and bento and a bunch of other really good Asian stuff!!

Tagged , , , , , , ,

Yeah so my audio player in jQuery Mobile and NodeJS (part 2)

Ok so my prev post was about how to construct a playlist in jQuery Mobile with some simple NodeJS file serving. This one is to construct the audio player itself! Mine looks like this (cause I was kinda too lazy to do the styling properly):

My audio player

My audio player

Ok so it’s very basic: we got a toggle Play/Pause button, Next button, Prev button, the progress bar for download progress and a fake album art (cause I didn’t know how to extract mp3 metadata yet). The features that I implemented are pretty basic:

1. Play/Pause

2. Next/Prev Song

3. Progress bar for song buffering

4. Time Left

5. Auto-play the next one if this one ended

6. Header shows song name

The HTML structure itself is rather simple as jQuery Mobile does most of the styling for u:


<div data-role="page" class="player">

    <div data-role="header">
        <h1>My collection</h1>
    </div><!-- /header -->

    <div data-role="content">

	<div class='cover-art' style='text-align:center'>
		<audio src='music/kpop/ttl2.mp3' preload autoplay></audio>
		<img src='images/no-album-art.png' />
	</div>
    </div><!-- /content -->
    <div data-role='footer' style='text-align:center'>
	<p class='track-info'>
		<span class="song-progress">
			<input type="range" min="0" max="100" value="0" />
		</span>
		<span class="timeleft"></span>
	</p>
	<div class='playback' data-role="controlgroup" data-type='horizontal' style='text-align:center'>
<button class='playback-prev' data-icon='back'>Prev</button>
<button class='playback-play' >||</button>
<button class='playback-next' data-icon="forward" data-iconpos="right">Next</button>
</div>
	</div>
<script type="text/javascript">
	$('div.player').bind('pageshow', function(ev, ui) {
		if (!$(this).attr('data-init')) {
			Player.init('div.player.ui-page-active', $.getUrlVar($(this).attr('data-url'), 'song'));
			$(this).attr('data-init', 'true');
		}
	});
</script>
</div><!-- /page -->

So again, I bind some initialization to the “pageshow” event of the page and make sure it doesn’t get initialized twice. Since the href in each <li> points to the same page but different parameter, jQuery loads this again every single time even if it’s the same one. This only prevents the forward history button to reload the song. However, this does not prevent having multiple songs playing at the same time cause jQuery mobile loads those as different div. You can customize the changePage behavior when user clicks on a <li> but I didn’t, just to keep it simple.

The parameter is stored in the main player div (with selector “div.player”, class “ui-page-active” indicates its the active one) so $.getUrlVar just extract the parameter song from it (which indicates the song index):

$.extend({
	getUrlVars : function(string) {
		var vars = [];
		var hash;
		var href = string ? string : window.location.href;
		console.log(href);
		if (href.indexOf('#') > -1) {
			var hrefArr = href.split('#');
			href = hrefArr[hrefArr.length - 1];
		}
    		var hashes = href.slice(href.indexOf('?') + 1).split('&');
		for (var i = 0; i < hashes.length; i++) {
			hash = hashes[i].split('=');
			vars.push(hash[0]);
			vars[hash[0]] = hash[1];
		}
		return vars;
	},

	getUrlVar : function(string, name) {
		return $.getUrlVars(string)[name];
	}
});

Pretty simple, just basically splitting the data-url field into a map of parameter names and values. The Player.init function takes in the parent div selector (so that I can locate the control relative to the parent div) and the song index. I basically keep track of all the control DOM elements:

var $next = $(div + ' button.playback-next');
var $prev = $(div + ' button.playback-prev');
var $play = $(div + ' button.playback-play');
var $trackInfo = $(div + ' p.track-info');
var $songProgress = $trackInfo.find('.song-progress');
var $loading = $songProgress.find('.loading');
var $timeLeft = $trackInfo.find('.timeleft');
var $slider = $songProgress.find('.ui-slider');
var $handle = $slider.find('.ui-slider-handle');
$songProgress.find('input[type="number"]').hide();
var $title = $(div + ' h1.ui-title');
var $audio = $(div + ' audio');
var audio = $audio.get(0);

I have this habit of prefixing jQuery objects with $ to distinguish from actual DOM element ($audio is the jQuery-wrapped object of audio). Play/pause is really easy:

$play.click(function(ev) {
    var $buttonText = $(this).parent().find('.ui-btn-text');
    if (audio.paused) {
        $audio.attr('data-state', 'play');
        audio.play();
        $buttonText.text("||");
    }
    else {
        $audio.attr('data-state', 'pause');
        audio.pause();
        $buttonText.text("Play");
    }
});

Prev/Next is also straightforward:

$next.click(function(ev) {
    var state = $audio.attr('data-state');
    var current = parseInt($audio.attr('data-current'));
    Player.getSongPath(current + 1, $audio, $title, function() {
        $audio.attr('data-current', current + 1);
        if (state == 'play') {
            audio.play();
        }
    });
});
$prev.click(function(ev) {
    var state = $audio.attr('data-state');
    var current = parseInt($audio.attr('data-current'));
    Player.getSongPath(current - 1, $audio, $title, function() {
        $audio.attr('data-current', current - 1);
        if (state == 'play') {
            audio.play();
        }
    });
});

So we’ve done 1 and 2. Let’s jump to 5 cause its also easy:

$audio.bind('ended', function(ev) {
    $next.click();
});

I did 6 as a separate functionality that ping the server for the song’ path, change the audio source and also title:

getSongPath: function(index, $audio, $title, fn) {
    $.post('playlist?song=' + index, null, function(data) {
        console.log(data);
        $audio.attr('src', data.result);
        var filenameArr = data.result.split('/');
        var filename = filenameArr[filenameArr.length - 1];
        $title.text(filename);
        if ($.isFunction(fn)) {
            fn();
        }
    }, 'json');
}

For some reason I put null in the POST request data instead of the actual data (song=2) cause I wasn’t getting that data on the server side (I tried req.body, req.query and everything… didn’t seem to show up, will look into it a bit more). OK now lets get back to 3:

if (!$loading.get(0)) { //this inject the white loading bar before the handler
    $handle.before('<div class="ui-slider loading" style="width: 3%; float: left; top: 0; left: -3%; background-color: buttonface;"></div>');
    $loading = $slider.find('div.loading'); //update var
}
$audio.bind('progress', function() {
    var loaded = parseInt(((audio.buffered.end(0) / audio.duration) * 100) + 3, 10);
    $loading.css({
        width: loaded + '%' //change width accordingly
    });
});
var manualSeek = false;
var loaded = false;
$handle.css({
    top: '-50%' //somehow I think the styling of footer and handler conflicted and messed it up so I had to bump it up 50%
});

I actually didn’t know how to get the current time of the audio but after googling around and looking at audio attributes, things got a bit clearer. Here’s 4:

$audio.bind('timeupdate', function() {
    var rem = parseInt(audio.duration - audio.currentTime, 10),
        pos = Math.floor((audio.currentTime / audio.duration) * 100),
        mins = Math.floor(rem / 60, 10),
        secs = rem - mins * 60;
    $timeLeft.text('-' + mins + ':' + (secs > 9 ? secs : '0' + secs));
    if (!manualSeek) {
        $handle.css({
            left: pos + '%'
        });
    }
    if (!loaded) {
        loaded = true;
    }
});

Ok so that’s how I made a sorta functional audio player. There’re still problems with it but hopefully this DIY guide gave u some idea on how to control the audio element manually.

Tagged , , , , , , ,

What I’ve been up to… (a.k.a making an audio player using jQuery Mobile & NodeJS) Part 1

So I recently signed up for a VPS from AlienVPS at a ridiculously low price and guess what, it crashed on me twice today… -_- But $19/month is still pretty darn cheap. At least it gave me some sandbox to play around with NodeJS and jQuery Mobile.

OK so far NodeJS has been rather simple and straightforward. I actually use Express framework on top of NodeJS which ease the work a little bit. However, I can really see how this can become complicated really really fast. 1st of all, I sorta have to implement all the HTTP protocol code manually in NodeJS (except for 500 Internal Error and 200 OK I think). So that includes 404, 403, blah blah. Not that it matters that much except I wanna maximize my site traffic by taking advantage of Search Engine bots. Well I disallow everything in robots.txt right now so if those bots behave, I should be good. You can check it out at http://208.93.155.39:8080/playlist.html but please please don’t spread it around or I’m gonna have to shut it down due to my limited bandwidth. The app is still buggy since it’s a work in progress but a refresh should make it behave a bit better.

Anyway, now the 1st thing a web server should be able to do is to serve static web pages and it can be achieved pretty easily:

var app = require('express').createServer();
var fs = require('fs');
var public_path = 'public/';
var PORT = 8080;
app.get('/', function(req, res) {
        res.sendfile(public_path + 'index.html');
});
app.get('/*', function(req, res) {
        var page = req.params[0];
        res.sendfile(public_path + page);
});

Easy enuf… Now I want to query some specific stuff like, idk my KOREAN POP playlist!!

var songs;
app.post('/playlist.html', function(req, res){
        Controller.handlePlaylist(req, res);
});
var Playlist = {
        get : function(name) {
                return fs.readdirSync(public_path + MUSIC_PATH + name);
        }
};
var Controller = {
        handlePlaylist : function(req, res) {
                if (!songs) { //lazy-initialize this
                        songs = Playlist.get(req.param('playlist'));
                }
                var index = req.param('song');
                if (index && index >=0 && index < songs.length) { //if I query a specific song number, give me the path to the song
                        res.send({ 'result' : MUSIC_PATH + 'kpop/' + songs[index] });
                } else { //otherwise give me the whole list
                        res.send({ 'filenames' : songs });
                }
        }
};

Now when I hit up playlist.html?playlist=kpop with POST, I can get my playlist and playlist.html?song=1 with POST gives me the 2nd song. This is a simple enuf song serving mechanism that will help me build my audio player.

Playlist Page

Playlist Page

Since I’m not using any view rendering engine, in playlist.html I actually have to use the trick of loading the file 1st, then make an ajax call to populate the data. This gets very very tricky with jQuery mobile since it doesn’t have a lot of control events on when it’s done rendering and what not. This combines with ambiguous timing from AJAX callbacks can lead to a pretty disruptive UX (I’m still having trouble with synchronizing stuff in JavaScript). But anyway, the playlist.html has a pretty simple structure:

<div data-role="page" class="playlist">
    <div data-role="header">
        <h1>My collection</h1>
    </div><!-- /header -->

    <div data-role="content">
        <ul data-role="listview" data-inset="true">
                <li data-role="list-divider">Kpop</li>
        </ul>
    </div><!-- /content -->
    <script type='text/javascript'> 
    $('div.playlist').bind('pageshow', function() {
        var $page = $(this); // to use inside callback since "this" in the callback function is different
        if (!($page.attr('data-init'))) { // Initialize once
                $.post('playlist.html?playlist=kpop', null, function(data) { //retrieve the data
                        var i;
                        var filenames = data['filenames'];
                        var $playlist = $page.find('ul[data-role="listview"]');
                        for (i in filenames) { //populate the list of songs
                                $playlist.append('<li><a href="player.html?song=' + i + '">' + filenames[i] + '</a></li>'); 
                        }
                        $page.attr('data-init', 'true');
                        $playlist.listview('refresh'); //refresh the view
                }, 'json');
        }
    });
    </script>

</div><!-- /page -->

The HTML structure itself is simple the the JavaScript is kind of a hack. “Pageshow” event in jQuery Mobile gets invoked after page has been initialized (a.k.a after jQuery converts basic elements into its themed mobile looks). Why not “pagecreate” or “pagebeforecreate”? Because the callback is actually an AJAX call to grab the data and listview can only be refresh after it’s been initialized (also not guaranteed in the previous 2 event hooks). If I were to use a view rendering engine to populate the data, then send across the wire, I wouldn’t have had this problem so… something to look at next time.

OK so that’s the easy part, I write next time about how to actually make the player cause that took me like 3 days… >.< sleep now!

Tagged , , , , , ,
Follow

Get every new post delivered to your Inbox.