Zero Wind – Jamie Wong Inside the mind of a Waterloo Software Engineering student

14Aug/100

Javascript Dependency Loading – jquery.atreq

For a project I'm working on, I have a fairly complex dependency tree and was getting fed up with manually including every single one in my haml layout file. So I started looking up other solutions and eventually decided none met my needs, so, as usual, I wrote my own.

jquery.atreq @ github

Because there's not much to say beyond what I have in the readme, and because this blog is conveniently set up to format with markdown, I'm just going to display the current state of that here.

jquery.atreq

jquery.atreq loads your javascript dependencies asynchronously.

How to use

First, include your main application file with $.atreq


<script type='text/javascript' src="jquery.atreq.js"></script>
<script type='text/javascript'>
$.atreq('application.js');
</script>

Then inside your application.js and any other required files, place a require statement in the comments.

// application.js
// @require 'lib/lib1.js'
// @require 'lib/lib2.js'

Library1Function();
Library2Function();

NOTE: While //@require "blocks", $.atreq does not. This means the following will not work:

$.atreq('lib/lib1.js');
Library1Function();

Relative Require Paths

Unless the require paths begin with a /, they're assumed to be relative to the location of the file they're in.

This means, since lib1.js is in lib/, the require statement below will load lib/deb/lib1dep.js. This makes your code portable across locations.

Each of the library files can also have their own dependencies, and $.atreq will make sure they're run in the correct order.

// lib/lib1.js
// @require `dep/libdep.js`

function Library1Function() {
    alert('Awesome!");
}

Redundant or Duplicate Requires

Duplicate requires of the same file will neither request nor run the same file twice. This is true even if the relative path is different from files. This means that:

// lib/lib2.js
// @require '../shared/shared.js'

and

// lib/lib3.js
// @require '../shared/shared.js'

will only make one request out to shared/shared.js.

Alternatives and How They're Different

$.include

A jQuery plugin by Tobiasz Cudnik, this does load external files asynchronously, but these dependencies are non-blocking. He dodges this issue by delaying the document.ready event

It even has the ability to load dependencies for included scripts like so (taken from his blog post):

$.include(
    // URL
    'js/my-script.js',
    // will be loaded after this script
    $.include(baseURL+'js/my-other-script.js')
);
$.include('js/src/behaviors.js',
    // dependencies can also be an array
    [
        $.include('js/src/jquery-metadata.js'),
        $.include('js/src/jquery.form.js')
    ]
);

This is great, except that it requires all the dependencies to be loaded from the same file. This means you won't get useful behaviour if one of the files you're including has internal dependencies.

See: $.include() @ tobiasz123.wordpress.com

$.require

Another jQuery plugin, $.require doesn't have the problem of $.include: required files can require files of their own and scripts will still be parsed in the correct order.

The way it does this is it forces the scripts to be included synchronously. Functionality wise, this has no effect. However, it will result in slower load times for complex dependency trees.

The require paths in this script are relative to the inclusion point (the HTML file), not the script itself.

Comparison of load times for the following dependency tree:

application.js
|--- 1.js
|    |--- 1a.js
|    |--- 1b.js
|    \--- shared.js
\--- 2.js
     |--- 2a.js
     |--- 2b.js
     \--- shared.js

Inside each file is the required include statements, a loop iterating 10000 times, and ~4kb of lorem ipsum in comments to bloat the file size.

$.atreq:

$.atreq firebug

$.require:

$.require firebug

Note the difference in the load order - there's no reason why 1.js and 2.js shouldn't load at the same time.

See: $.require @ plugins.jquery.com

WARNING: At time of writing, the script provided on that page does not work and makes some strange assumptions about the location of your javascript files on the server. Use with caution.

Filed under: Uncategorized No Comments
16Jul/104

JSONimal – Elegant DOM Contruction with jQuery

Occasionally for Javascript projects, I found myself building a lot of HTML programatically, and I wasn't satisfied with any of the techniques available, so I built JSONimal. I was originally going to just call it JSONML, but that was taken.

What's it do? This example should demonstrate my goal fairly well.

$(function() {
    $.mktag("#demo").jsonimal([
        ["h1", {text: "JSONimal!"}],
        ["table",{style: 'border: 1px solid black'},[
            ["thead",[
                ["tr",{style: 'text-transform: uppercase'},[
                    ["th", {text: "one"}],
                    ["th", {text: "two"}],
                    ["th", {text: "three"}]
                ]]
            ]],
            ["tbody", [
                ["tr",[
                    ["td", {html: "<u>a</u>"}],
                    ["td", {text: "b"}],
                    ["td", {text: "c"}]
                ]],
                ["tr",[
                    ["td",[
                        ["a", {href: "http://www.google.ca", text: "Google"}]
                    ]],
                    ["td", {text: "b"}],
                    ["td", {text: "c"}]
                ]],
                ["tr",[
                    ["td", {text: "a"}],
                    ["td", {text: "b"}],
                    ["td", {text: "c"}]
                ]]
            ]]
        ]]
    ]).appendTo("body");
});

Which will add this to the body:

JSONimal!

onetwothree
abc
Googlebc
abc

For more information and examples, check out the github page: JSONimal @ github.

I also posted it as on the jQuery plugins page - but that just points to the github page anyway. JSONimal @ plugins.jquery.com

7Jul/100

Flex/Actionscript 3: Debug Output to Console

I recently started messing around with the Flixel framework - something built on top of Flex to make retro games. One of the first things I noticed was how difficult it is to debug things - especially complex objects.

The first problem is capturing any debug output. For whatever reason, I was unable to output traces to anywhere useful. My first success was with using De MonsterDebugger to capture the output. While this was better than nothing, I needed very little of the functionality of De MonsterDebugger and it still didn't give me what I really wanted: formatted console output.

print_r style output in actionscript

I found a good starting point here, but the output of this wasn't exactly what I wanted. I messed around with it until I got something more familiar to me.

package learning {
  import org.flixel.*;

  public class Debugger {
    public static function pr(obj:*, level:int = 0, output:String = ""):* {
      var objtype:String = typeof(obj);
      if (objtype == "boolean" || objtype == "string" || objtype == "number") {
        return obj;
      }

      var tabs:String = "";
      for(var i:int = 0; i < level; i++) { 
        tabs += "\t"
      }

      output += "{\n";
      for(var child:* in obj) {
        output += tabs +"\t["+ child +"] => ";

        var childOutput:String = pr(obj[child], level+1);
        if(childOutput != '') output += childOutput

        output += "\n";
      }
      output += tabs + "}\n";

      return output;
    }

    public static function log(obj:*):void {
      FlxG.log(pr(obj));
      // This is a flixel thing. If you're not using flixel
      // Just use trace(pr(obj));
    }
  }
}

Example output

{
    [0] => {
        [tile] => 4
        [rule] => {
            [0] => xxx
            [1] => x1x
            [2] => x1x
        }
    }
    [1] => {
        [tile] => 8
        [rule] => {
            [0] => x1x
            [1] => x1x
            [2] => xxx
        }
    }
}

NOTE: The colored output is from Prettify, not the script

trace output to console

This, fortunately, was much less of a hassle for me to get working.

Reference: Configuring the debugger version of Flash Player

Step 1

Locate/create your mm.cfg file. For me this was in ~/mm.cfg. See reference.

Stick this in it: TraceOutputFileEnable=1

Or, in one command: echo "TraceOutputFileEnable=1" > ~/mm.cfg

Step 2

Locate the location of the log file. Mine is in

~/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt

See reference.

You don't want to type this in every time you want to view the log, so add a function to your .bash_profile

This is what I have:

flashlog() { 
  tail -f $* ~/Library/Preferences/Macromedia/Flash\ Player/Logs/flashlog.txt; 
}

Step 3

Start debugging!

  [learning]  flashlog -100
Warning: 'flash' has no property 'prototype'
Warning: 'flash' has no property 'prototype'
flixel v2.35 [debug]
----------------------------------------------------
{
    [0] => {
        [tile] => 4
        [rule] => {
            [0] => xxx
            [1] => x1x
            [2] => x1x
        }
    }
    [1] => {
        [tile] => 8
        [rule] => {
            [0] => x1x
            [1] => x1x
            [2] => xxx
        }
    }
}
29Jun/102

Commandline Tips and Tricks

Alas, I have been stricken with the plague of half-finished posts and projects. But, as I feel the need to have at least one post per month, here's some stuff you might find useful.

I forget where I discovered this, but commandlinefu.com is an awesome site.

It's so awesome in fact, that I think the productivity gains I've gotten from it almost outweigh the time I wasted looking through the site and testing it.

Here are some of the more useful ones from the site and a few I learned at work and elsewhere.

In all the examples below, the stuff inside [ ]'s is my current working directory. It's the result of my .bash_profile command

export PS1="[\e]2;Jamie@Local \a\e[32;1m] 
\033[1;32m  [\W]  \033[1;34;40m\033[1;32;0m"

And yes, I have been spending a lot of time on Stack Overflow.

Change to previous working directory

From: Change to the previous working directory @ commandlinefu.com

  [stackoverflow]  pwd
/Users/jamiewong/code/stackoverflow

[stackoverflow] cd /usr/bin

[bin] pwd /usr/bin

[bin] cd - /Users/jamiewong/code/stackoverflow

[stackoverflow] pwd /Users/jamiewong/code/stackoverflow

Rerun the last command

From: Run the previous command with sudo @ commandlinefu.com

  [stackoverflow]  echo hello
hello

[stackoverflow] !! echo hello hello

  [stackoverflow]  ln -s some_script.sh /usr/bin/some_script
ln: /usr/bin/some_script: Permission denied

[stackoverflow] sudo !! sudo ln -s some_script.sh /usr/bin/some_script

[stackoverflow] ls -l /usr/bin/some_script lrwxr-xr-x 1 root wheel 14 30 Jun 00:44 /usr/bin/some_script -> some_script.sh

  [stackoverflow]  cat /etc/apache2/passenger_pane_vhosts/searchgraph* 
<VirtualHost :80>
  ServerName searchgraph.local
  DocumentRoot "/Users/jamiewong/Code/searchgraph/public"
  RailsEnv development
  <Directory "/Users/jamiewong/Code/searchgraph/public">
    Order allow,deny
    Allow from all
  </Directory>
</VirtualHost> 
  [stackoverflow]  echo "!!"
echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph "
cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf

Modify the last command and run it

From: Runs the previous command but replacing @ commandlinefu.com

  [stackoverflow]  echo hello world
hello world

[stackoverflow] ^world^friends echo hello friends hello friends

  [stackoverflow]  ls *.php
bolding.php shd.php     stream.php

[stackoverflow] ^php^rb ls *.rb hms.rb split_orderby.rb

  [stackoverflow]  cds ..
-bash: cds: command not found

[stackoverflow] ^s cd ..

[code]

List your last n commands

  [stackoverflow]  history 10
  522  locate mysqld
  523  sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
  524  sudo /Library/PreferencePanes/MySQL.prefPane/Contents/MacOS/MySQL
  525  sudo mysqld_safe
  526  sudo /usr/local/mysql/bin/mysqld_safe
  527  mysql
  528  history
  529  history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
  530  history
  531  history 10

Edit and run a previous command

From: Edit the last command line in an editor then execute @ commandlinefu.com This one requires a bit of explanation. The fc command will, by default, open your last command in the console editor you specify (emacs by default - yuck). If you want it to be vim (yay!), stick this in your .bash_profile to just run it when you want to use it.

export EDITOR=vim
Then run fc, and it will open up your editor with your last command in it. Save and exit (:wq) to run that command. If you just want to execute it immediately, use fc -s.
  [stackoverflow]  history 5
   86  cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf 
   87  echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf "
   88  history 10
   89  echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf "
   90  history 5

[stackoverflow] fc -s 87 echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf " cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf

If you don't care to look up the history number but happen to remember that it was the command you executed two lines ago, you can use negative history numbers
  [stackoverflow]  echo hello
hello

[stackoverflow] echo world world

[stackoverflow] fc -s -2 echo hello hello

Follow new output to a log

This one comes from my coworkers

  [stackoverflow]  tail -f ~/code/searchgraph/log/development.log

Processing HomeController#bp (for 127.0.0.1 at 2010-06-23 22:19:27) [GET] Rendering home/bp Completed in 6ms (View: 5, DB: 0) | 200 OK [http://searchgraph.local/bp]

Processing HomeController#bp (for 127.0.0.1 at 2010-06-23 22:20:46) [GET] Rendering home/bp Completed in 9ms (View: 7, DB: 0) | 200 OK [http://searchgraph.local/bp]

Then if I go open up searchgraph.local, my console window will get updated on its own

Copying and pasting from files

The pbcopy and pbpaste commands copy and paste from your clipboard.

  [stackoverflow]  echo test > test.txt

[stackoverflow] pbcopy < test.txt

[stackoverflow] pbpaste test

And if you want to paste content you have in your clipboard to a file, just redirect, with
pbpaste > output.txt

That's all for now - I'll write more down as I find them.

Filed under: Uncategorized 2 Comments
11May/101

Google Codejam 2010 Solutions – Qualification

I'm happy to have qualified for Codejam for the second year running - I managed to make it to Online Round 2 last year, so let's see if I can top that this year.

The opening round was not very difficult, and were it not for a very stupid mistake on my part on the first question, I easily could have gotten perfect in under 2.5 hours. Instead I got 76 in 3.5 hours. Bah.

Read the questions here: Qualification Round 2010 @ code.google.com

Problem 1: Snapper Chain

This is the one I screwed up, because I somehow overlooked the fact that each snap was simply equivalent to an binary increment of the snappers states. Instead, I did a foolish simulation, which did actually pass me the small test case. But anyway, the real solution is O(1).

For interest, here's what the snapper chain looks like in the first 30 iterations. The left side, labeled "P:" shows which of the snappers are powered, and the right side, labeled "S:" shows the current state of the snappers, with "#" being ON and "." being OFF in both cases. I did this so it would be easier to see the pattern. The first row is the initial set up, before any snaps.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
P: #.........	S: ..........
P: ##........	S: #.........
P: #.........	S: .#........
P: ###.......	S: ##........
P: #.........	S: ..#.......
P: ##........	S: #.#.......
P: #.........	S: .##.......
P: ####......	S: ###.......
P: #.........	S: ...#......
P: ##........	S: #..#......
P: #.........	S: .#.#......
P: ###.......	S: ##.#......
P: #.........	S: ..##......
P: ##........	S: #.##......
P: #.........	S: .###......
P: #####.....	S: ####......
P: #.........	S: ....#.....
P: ##........	S: #...#.....
P: #.........	S: .#..#.....
P: ###.......	S: ##..#.....
P: #.........	S: ..#.#.....
P: ##........	S: #.#.#.....
P: #.........	S: .##.#.....
P: ####......	S: ###.#.....
P: #.........	S: ...##.....
P: ##........	S: #..##.....
P: #.........	S: .#.##.....
P: ###.......	S: ##.##.....
P: #.........	S: ..###.....
P: ##........	S: #.###.....

What we're interested in is how to tell where a specific snapper is on. It turns out that this is quite simple - so long as all snappers before it are on the ON settings, it will be powered. This means that ultimately, the power column above is irrelevant. All we need to know is that the N-1 least significant bits are set. This is fairly trivial to check.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream>
using namespace std;
int main() {
	int T,N,K;
	cin >> T;
	for(int t = 0; t < T; t++) {
		cin >> N >> K;
		int mask = (1 << N) - 1;
		printf("Case #%d: ",t+1);
		if ( (mask & K) == mask) puts("ON");
		else puts("OFF");
	}
	return 0;
}

Time for the large case:

1
2
3
4
5
  [google]  time ./a.out < snapper.in > snapper.out
 
real    0m0.071s
user    0m0.026s
sys     0m0.040s

Problem 2: Fair Warning

This problem took me about 40 minutes to think of the solution for and about 5 minutes to code. Honour's Algebra (MATH 115) came in handy here. You can first calculate T (the optimal anniversary) by looking at the gcd (greatest common divisor) of the differences between the time elapsed since the events. This works because in order for T to divide the time elapsed since the events, it must also divide the time elapsed between the events. After that, you just need to find the first y that makes any of the numbers divisible by T. I just wrote out the congruences on my whiteboard (which I probably shouldn't have needed to do) then typed in my answer.

The only remaining problem here is dealing with the large numbers, which is hardly a problem in python. Here's my solution:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def gcd(x,y):
    while x:
        x, y = y % x, x
    return y
 
testcases = open("warning.in").readlines()
t = 1
for tc in testcases[1:]:
	tc = map(lambda x: int(x), tc.split(" ")[1:])
	if len(tc) == 0:
		break
	tc.sort()
	#print tc
 
	diff = []
	for i in range(len(tc)-1):
		diff += [tc[i+1] - tc[i]]
 
	T = diff[0]
	for d in diff[1:]:
		T = gcd(T,d)
 
	#print T
	print "Case #%d: %d" % (t, (-tc[0] % T))
 
	t += 1

Time for large case:

1
2
3
4
5
  [google]  time python warning.py > warning.out
 
real    0m0.250s
user    0m0.037s
sys     0m0.021s

Problem 3: Theme Park

This is an optimization problem. There are a lot of different optimizations you can apply, but I figured "to hell with it" and decided the solution getting it down to O(R) was probably sufficient. If you want to look at a better list of optimizations, go look here: Google Codejam 2010 Qualification Round Contest Analysis.

All I figured I needed to do was make it so I didn't have to find the groups every single time the ride was loaded. To do this, I simulated using queue until I arrived at a position where the group at the front of the line had been at the front before. While doing this, I record how many euros were made for a given start of the line, and who ends up at the front of the line while they're on the roller coaster. After this, the O(R) loop is very simple. Just add the number of euros for the run, then move on to the next front of the line.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
#include <cmath>
#include <algorithm>
#include <iostream>
#include <fstream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <queue>
#include <set>
#include <map>
#include <sstream>
#include <vector>
using namespace std;
 
#define FR(i,a,b) for(int i=(a);i<(b);++i)
#define FOR(i,n) FR(i,0,n)
#define SETMIN(a,b) a = min(a,b)
#define SETMAX(a,b) a = max(a,b)
#define PB push_back
#define FORALL(i,v) for(typeof((v).end())i=(v).begin();i!=(v).end();++i)
#define CLR(x,a) memset(x,a,sizeof(x))
#define BEND(v) v.begin(),v.end()
#define MP make_pair
#define A first
#define B second
 
typedef unsigned long long int ull;
typedef long double ld;
 
int main() {
    freopen("themepark.in","r",stdin);
    freopen("themepark.out","w",stdout);
 
    int T;
    cin >> T;
    FOR(t,T) {
        int R,k,N;
        cin >> R >> k >> N;
        int grps[1001], done[1001], pts[1001], next[1001];
        CLR(done,0);
        queue<pair<int,int> > q;
        FOR(i,N) {
            cin >> grps[i];
            q.push(MP(i,grps[i]));
        }
 
        while(!done[q.front().A]) {
            int cur = 0;
            int start = q.front().A;
            done[start] = 1;
 
            FOR(i,N) {
                if (cur + q.front().B > k) break;
 
                cur += q.front().B;
                q.push(q.front());
                q.pop();
            }
            next[start] = q.front().A;
            pts[start] = cur;
        }
 
        while (!q.empty()) q.pop();
 
        int curFront = 0;
        ull ans = 0;
        FOR(i,R) {
            ans += pts[curFront];
            curFront = next[curFront];
        }
 
        printf("Case #%d: %lld\n", t+1, ans);
    }
    return 0;
}

Time for large test case:

1
2
3
4
5
  [google]  time ./a.out
 
real    0m11.606s
user    0m11.542s
sys     0m0.022s

I might code up an O(N) solution later, which really isn't that difficult, but at this point in the contest, it simply didn't matter enough.

19Apr/100

AJAX Method Callbacks and Omegle Voyeur Update

I finally got back around to updating Omegle Voyeur with the ability to interfere, and decided to re-implement the whole thing in jQuery while I'm at it. Since jQuery doesn't come with a built-in method of building classes, I used lowpro for jQuery. It's a port of a class building scheme from Prototype. It doesn't do everything I could have hoped for, but it served most of my needs.

The other thing I implemented was a way of knowing when Omegle is blocking requests. They have a more robust form of detection now - it isn't just manual IP ban. Once you request too many things from them too fast, they start requesting a captcha. Locally, this isn't a problem - I simply embed an iframe with Omegle in it and provide instructions to the user. Hosted, this is a more troublesome problem, since the captcha is directed towards an IP, so it must be responded to from that IP. I have no solution to this problem at the moment, but I'm going to look into implementing the whole thing using Greasemonkey so this isn't an issue at all.

For now, you can see the latest version here: Omegle Voyeur. Don't be surprised if it's down, and please go grab your own copy: Omegle-Voyeur @ github.

Now on to the customary technical concept to go along with my own self promotion.

AJAX Method Callbacks

While passing functions as arguments is a pretty standard thing among almost all languages, attempting to pass methods of specific instances as arguments in Javascript presents an interesting problem. Consider the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function car(price) {
    this.price = price;
 
    this.setPrice = function(price) {
        this.price = price;
    };
}
 
function pass666(func) {
    func(666);
}
 
var redcar = new car(2000);
alert(redcar.price);
redcar.setPrice(123);
alert(redcar.price);
pass666(redcar.setPrice);
alert(redcar.price);

As you might expect, the first two alerts will say 2000 and 123 respectively. But the last one also says 123. Why? It all has to do with what "this" refers to. Both in the initialization of redcar and the modifier call redcar.setPrice, "this" refers to the instance of the function car given the identifier name "redcar". In the pass666 version, "this" refers to the function pass666. As a result, it does nothing to modify the properties of the car because it isn't told anything about redcar.

One way to fix this is to use a placeholder variable. I used "self". Change the definition of car to the following yields the desired result.

1
2
3
4
5
6
7
8
function car(price) {
	this.price = price;
 
	var self = this;
	this.setPrice = function(price) {
		self.price = price;
	};
}

In this example, it's difficult to see why you would ever want to use this in the first place. The reason I encountered this problem is my need to use instance methods as callback functions for AJAX calls. Here's an excerpt of the jQuery version of Omegle Voyeur to see what I'm talking about.

106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
sendQuery: function(target,respFunc) {
	// Send a query to the omegle server
	//log('sending');
	var self = this;
	if (respFunc == null) {
		respFunc = function(self,data) {}
	}
	$.ajax({
		url: 'omegle.php?'+target,
		type: 'GET',
		dataType: 'json',
		success: function(data) {
			respFunc(self,data);
		}
	});
},

Sending a request to the Omegle server is a very common task in Omegle Voyeur, so I wanted all the AJAX requests leaving from the same method. This means I have to accept the callback function as a parameter. I've written all the callback methods to accept a parameter "self" which will refer to the instance of interest.

This aspect is one of the many things that makes Prototype's class system superior to jQuery's. However, since jQuery makes a lot of other things nicer and the two libraries don't play together very well, I decided to port over to jQuery nonetheless. In Prototype, there's a function called bind (not to be confused with jQuery's bind which does something completely different,) which solves this problem elegantly.

To fix the redcar problem with the aid of Prototype without having to use a placeholder variable, you can use bind like so:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
function car(price) {
    this.price = price;
 
    this.setPrice = function(price) {
        this.price = price;
    };
}
 
function pass666(func) {
    func(666);
}
 
var redcar = new car(2000);
alert(redcar.price);
redcar.setPrice(123);
alert(redcar.price);
 
pass666(redcar.setPrice.bind(redcar));
 
alert(redcar.price);

The line

18
pass666(redcar.setPrice.bind(redcar));

is what makes this work out. We're explicitly saying that we want setPrice executed from the scope of the instance.

If I ever have to hire someone for a web development job, I'll be sure to ask something about this.

9Mar/103

Learn Source Control with Git

One of the gaps among my tech skills upon entering university was source/revision control.

For those of you unfamiliar, revision control is a method of tracking and storing the changes made to files. This is particularly useful when keeping track of all the changes made to source code being worked on in a group. This allows you to all work on the same set of files at once and merge together the changes later.

This doesn't mean it isn't useful for projects you're working on by yourself. If you've ever coded something up, then decided you have a better way of solving the problem, then finally realize your new solution doesn't work, you need to go back. Except the deleted code is one undo step beyond your history. Crap.

And no, allowing for more undo steps is not the solution to this problem. If you want to look at older versions across multiple files from weeks ago, undo won't help you. Revision control will.

After speaking with employers, it seems that the most commonly used source control system at the moment is git. I'd like to note that most of the people I interviewed with were small, fairly new, web or mobile based companies. Older companies may be using svn or possibly even cvs. Then there's the whole set of Microsoft source control systems such as Microsoft Visual Source Safe.

You can see a summary of source control options here: Comparison of revision control software @ Wikipedia

I'm posting about this now because I'm working on a collaborative project using git for the first time. Since this is a private project, I'm using Project Locker instead of Github. To be honest, I probably should have just set up my own private repository and I might look into that later.

You don't actually need to have a remote repository. You can use a git repository to control your source locally if you're the only one working on it. You might consider doing this for school projects so you don't accidentally overwrite your working code in an attempt to appease Marmoset (automated testing in CS at U Waterloo).

In order to learn how to use git, I can recommend two sources of information.

  1. GitCasts: these are screen casts, going through git and explaining things along the way. I'm in the middle of the fourth cast right now, so I can't say for sure these are all of high quality, but I'm seeing things I didn't know before, and that's enough for me.

  2. Visual Git Guide: Pictures are awesome, especially for those people of the tl;dr mindset. Or those attracted to colourful pictures. The picture at the top of the post is from the visual git guide. This is a fairly in depth explanation of some of the functionality of git and shows you what's actually happening behind the scenes.

For those of you more interested in learning Mercurial (Hg), Zameer Manji has recommended the following guide: Hg Init: a Mercurial tutorial by Joel Spolsky.

I would recommend you go grab an account of GitHub to help yourself learning. If you're in need of something to fool around with, fork one of my projects: phleet @ github.

5Feb/104

Jobmine Improved (Greasemonkey & jQuery)

JobmineImproved

I, like many (most) Waterloo Co-op students, am forced to use Jobmine and am extremely dissatisfied with its functionality. So I decided to kill three birds with one stone: improve Jobmine, learn Greasemonkey and learn jQuery all at the same time.

The result is, unsurprisingly, a Greasemonkey script written using jQuery that improves on some features of Jobmine.

Features

  • Table sorting - all major tables are now sortable (Interviews, Job Short List, Applications)
  • Improved navigation - no more Student -> Use ridiculousness
  • No more frames - you can refresh and it will stay on the same page!
  • Colour highlighting for tables - pictured above, you see the applications page with various statuses highlighted. Selected is green, not selected is red.
  • No more spacers - the Jobmine page is riddled with spacer images just sitting there, stealing screen real estate

How to Install You'll either need Firefox & Greasemonkey, or a recent build of Chrome (Windows only?). You can get Greasemonkey here: Greasemonkey @ addons.mozilla.org

Once you've done that, navigate to the script and click install. You can get the script here: Jobmine Upgrade @ userscripts.org

Now for the part where I explain the tech I used.

Greasemonkey

Greasemonkey is a tool for customizing the way a web page displays and interacts using javascript. More or less, it overlays javascript you write on top of pages you specify by URLs with wildcards (*). It doesn't overlay it directly, but wraps it in some way as to prevent it from messing things up in the global scope. It also seems to run once the page is done loading, not when the page head is loaded. There are plenty of tutorials out there for doing cool stuff with Greasemonkey, but I started here: Dive into Greasemonkey. I know it says it's hideously outdated, but the metadata information it provides is still good enough. If you want more up to date information, go here: GreaseSpot (Greasemonkey Wiki).

jQuery

jQuery is a javascript framework specifically designed for doing things involving the DOM tree absurdly quickly. Example: highlighting alternating rows of a table (zebra-striping).

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Standard Javascript method:
var tables = document.getElementsByTagName("table");
for (var i = 0; i < tables.length; i++) {
    var rows = tables[i].tBodies[0].rows;
    for (var j = 0; j < rows.length; j++) {
        var rowColor;
        if (j % 2 == 1) {
            rowColor = "#eef"; 
        } else {
            rowColor = "#fff";
        }
 
        var cells = rows[j].cells;
        for (var k = 0; k < cells.length; k++) {
            cells[k].style.backgroundColor = rowColor;
            cells[k].style.borderBottom = "1px solid #ccc";
        }
    }
} 
 
// jQuery way:
$("td").css("border-bottom","1px solid #ccc");
$("tr:even > td").css("background-color","#fff");
$("tr:odd > td").css("background-color","#eef");

Now before someone says it, I know usually you can set the background-color for the whole row, and the cells will inherit it. But since, for some crazy reason, each cell is assigned a background colour on Jobmine, each cell needs to be set individually. In any case, you can see that things are made substantially easier with jQuery. I figured out jQuery mostly just using the API and looking at other people's code, but this is a decent place to start: Getting Started with jQuery.

For the table sorting functionality, I decided to use a jQuery plugin as opposed to write my own (I'd rather be able to distribute this sooner). You can read all about it here: jQuery Plugin: Tablesorter 2.0

What features do you want to see in this? By the way, the source is all available on the userscripts site, so feel free to tinker with it yourself.

EDIT: As Trevor points out, the script in its current state won't work in Chrome due to the @require. You can grab his fix to make it work in chrome here: Jobmine Improved (Chrome)

7Jan/100

Tools: ideone, RegExr, jitouch 2, open, ditaa

Through reading proggit and hearing about new technology from classmates, every once in a while, I build up a list of tools which I plan on checking out and see whether they're useful enough to add to my regular routine. The first four on this list fall into that category, and I may eventually find a use for the last.

ideone

ideoneideone is an in-browser, syntax-highlighted code editor complete with interpreters and compilers. Basically, if you've ever wanted to try out a language but really didn't feel like installing it on your system, this is the perfect place to start. The site even runs Brainf**k.

There's another site which accomplishes the same task, but less elegantly: Codepad. This site is so much less elegant that I wasn't originally planning on posting it, but decided to once I saw there was a Codepad vim plugin. There's also emacs integrations.

RegExr

regexr Regexr is an online tool, implemented in Adobe Flex, to test out regular expressions in real time. If you haven't learned about regular expressions yet, go learn right now. They're just about the most powerful text matching, user verification and error correction tool in existence. They're also implemented in nearly all languages now in some form or another. Before I saw this site, I would test out all my regular expressions just using vim, but found it frustrating when the expressions needed to be changed to be compatible with php. So I'm likely going to start using RegExr instead.

jitouch 2

Screen shot 2010-01-07 at 11.09.43 AM Jitouch 2 is an application expanding on the multi-touch gestures available to MacBook Pro users who want to do more with just the touch pad. The two big things that this enables me to do that I love are opening links in new tabs using only taps on the keypad, and switching tabs using a gesture equivalent to ctrl-tab to switch tabs. I actually saw this reading Randal Munroe's blag.

Mac OS X/Gnome open

Screen shot 2010-01-07 at 11.16.08 AMopen & gnome-open are terminal commands in Mac OS X and gnome respectively, but they do the same thing. Whenever you double click on a file in Finder or Nautilus, the operating system has a database of which extensions are opened by which applications. What's actually happening here is that it's called open. Examples:

open "Office Space.avi"
Open up Office Space in your default viewer.
open http://www.jamie-wong.com
Visit my website from the commandline, opening in your default browser
open -a "Adobe Photoshop CS3"
Launch Photoshop. Open -a opens files with an application.

ditaa

Screen shot 2010-01-07 at 11.44.21 AM ditaa is a tool for converting ASCII art diagrams into graphical diagrams. This is pretty well illustrated in the picture to the left. I haven't actually found much of a use for this yet, but some of you might.

27Dec/093

UWAngel-CLI

Screen shot 2009-12-27 at 1.39.50 AM

Near the end of the semester, I was getting kind of tired of navigating UW-ACE so frequently through my browsing and opening all the different tabs to grab all the files I wanted. While all the pretty graphics make for a decent user interface, it reduces the speed of the service.

But aside from that, I like being able to do as much as I possibly can from the console.

So I made a Command Line Interface (CLI) for UW-ACE in php using cUrl. I built in on my Macbook Pro in Snow Leopard, but it should work just fine on any *nix machine, and possibly in Cygwin or other emulators.

As always, source is available on github: UWAngel-CLI @ Github.

Since I always like to post snippets of code from my projects that may be universally useful, I'll do that here too.

CLI Colour in PHP cli_colours.php included in the UWAngel-CLI source is just a collection of constants which allow you to print out colours in your CLI scripts.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?
$COLOR_BLACK = "\033[0;30m";
$COLOR_DARKGRAY = "\033[1;30m";
$COLOR_BLUE = "\033[0;34m";
$COLOR_LIGHTBLUE = "\033[1;34m";
$COLOR_GREEN = "\033[0;32m";
$COLOR_LIGHTGREEN = "\033[1;32m";
$COLOR_CYAN = "\033[0;36m";
$COLOR_LIGHTCYAN = "\033[1;36m";
$COLOR_RED = "\033[0;31m";
$COLOR_LIGHTRED = "\033[1;31m";
$COLOR_PURPLE = "\033[0;35m";
$COLOR_LIGHTPURPLE = "\033[1;35m";
$COLOR_BROWN = "\033[0;33m";
$COLOR_YELLOW = "\033[1;33m";
$COLOR_LIGHTGRAY = "\033[0;37m";
$COLOR_WHITE = "\033[1;37m";
$COLOR_DEFAULT = "\033[0;37m";
 
echo <<< EOT
One fish, 
two fish, 
{$COLOR_RED}red{$COLOR_DEFAULT} fish, 
{$COLOR_BLUE}blue{$COLOR_DEFAULT} fish.
 
EOT;
?>

The only gripe I have about this is that COLOR_DEFAULT it's the same colour as I have on by default in iTerm. Anyone know the escape code to make it actually revert to what it was before instead of just making an assumption about what color is being used?

Hide Commandline Input One of the first things I looked up when I started this project today was how to hide user input from the command line. I sure as hell didn't want people typing their passwords for UWACE on screen and having it actually display. It turns out you can do this by temporarily telling your TTY to stop echoing what you type. The command for this is "stty -echo" and can be re-enabled using "stty echo". Below is how I implemented as part of the AngelAccess class to meet my needs.

1
2
3
4
5
6
7
8
9
10
11
 function Prompt($prompt_text,$hide = false) {
     echo $prompt_text;
     $input = "";
     if ($hide) {
         $input = trim(`stty -echo;head -n1;stty echo`);
         echo "\n";
     } else {
         $input = trim(fgets(STDIN));
     }
     return $input;
 }

As a complete side note, thanks to a boot-camped installation of Windows 7 (or at least I'm fairly sure that's the culprit,) my Macbook Pro is now stuck on Digital Out. This means I can't use the internal speakers on my computer under Mac OS X. Well... what I should say is that I can't use them without some annoying tricks. If I plug in my headphones, then tell my mac to use the input jack for audio input, then my internal speakers appear under the output options and let me use them. The speakers then work perfectly fine. They also work fine under Windows 7. A direct side effect of digital out being stuck on is a read light emanating from the audio jack.

The problem is apparently fairly common, unfortunately the only confirmed fixes for it are sending it back to Apple or wiggling a toothpick around in the audio jack. I had absolutely no luck with the toothpick, or precision screwdriver, or pen cartridge, or paintbrush handle. If anyone knows how to fix this problem, I would love to know. Otherwise, I'm just going to take it into the Apple store in Rideau some time this week and hope they can fix the problem. I really don't want to have to send my Mac in during my first week at Velocity.

Tagged as: , , , , , 3 Comments