65 |
66 | {% if site.google_analytics %}
67 |
68 |
78 | {% endif %}
79 |
80 |
81 |
--------------------------------------------------------------------------------
/_posts/2010-11-17-mechanize-and-uwace-downloader.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Mechanize and UWAce Downloader
4 | tags: []
5 |
6 | status: publish
7 | type: post
8 | published: true
9 | meta:
10 | _edit_last: "1"
11 | _edit_lock: "1290224986"
12 | _wp_old_slug: ""
13 | ---
14 | A while ago I made something in php that would let you download things form UW-Ace (the University of Waterloo's course management system) from the command-line. Michael Chang had the excellent idea of making something that would simply download everything available to you from Ace so you could have a local copy of everything.
15 |
16 | His solution was an extension of my php solution.
17 |
18 | Because I wanted to make the product easier to distribute and because I wanted to make use of Mechanize, I rewrote the solution in ruby and packaged it as a gem.
19 |
20 | UWAce Downloader
21 | ============
22 | The new version looks like this:
23 |
24 | 
25 |
26 | To get it running, you'll need a copy of RubyGems, which you can get here: [Download RubyGems][]. It's a simple package management and distribution system for ruby, which is used by more or less every ruby project you can think of.
27 |
28 | Once you have that set up, just run
29 |
30 | sudo gem install uwace
31 |
32 | Wait for it to finish installing, then run
33 |
34 | uwace
35 |
36 | Which will prompt you for a username and password.
37 | Of course, I wouldn't release anything that asks for your password without releasing source, so here it is:
38 |
39 | * [uwace gem @ github][]
40 | * [uwace gem @ RubyGems][]
41 |
42 | [uwace gem @ github]: https://github.com/phleet/UWAngel-CLI
43 | [uwace gem @ RubyGems]: https://rubygems.org/gems/uwace
44 | [Download RubyGems]: http://rubygems.org/pages/download
45 |
46 | Mechanize
47 | =======
48 |
49 | This version of the downloader is written in ruby with the aid of Mechanize for ruby.
50 | Mechanize is a set of tools for automating webpage interactions and retrieving data. It can identify links and forms on a page, fill them in, submit them and grab any data you want. Perfect for this task.
51 |
52 | There's a simple guide on github here: [Getting Started with Mechanize][]
53 |
54 | To demonstrate how simple form interaction is, here's the method for login:
55 |
56 | lang:ruby
57 |
58 | def login
59 | @username ||= ask("Username: ")
60 | @password ||= ask("Password: ") {|q| q.echo = '*'}
61 |
62 | say "Logging in ..."
63 |
64 | login_page = angel_get 'home.asp'
65 | form = login_page.form_with(:name => "frmLogon")
66 | form.username = @username
67 | form.password = @password
68 |
69 | login_submit_page = @agent.submit form
70 |
71 | if login_submit_page.uri.to_s.include? 'authenticate.asp'
72 | raise InvalidLogin
73 | end
74 | rescue InvalidLogin
75 | say 'Invalid Username/Password'
76 | exit
77 | end
78 |
79 | While I've only used the Mechanize bindings for ruby, there bindings for many other languages:
80 |
81 | * [Python's Mechanize](http://wwwsearch.sourceforge.net/mechanize/)
82 | * [Perl's WWW::Mechanize](http://search.cpan.org/dist/WWW-Mechanize/lib/WWW/Mechanize/Cookbook.pod) - This was actually the original Mechanize
83 |
84 | [Getting Started with Mechanize]: https://github.com/tenderlove/mechanize/blob/master/GUIDE.rdoc
85 |
--------------------------------------------------------------------------------
/_posts/2010-03-09-learn-source-control-with-git.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Learn Source Control with Git
4 | tags:
5 | - git
6 | - hg
7 | - mercurial
8 | - revision control
9 | - source control
10 | - svn
11 | - Tools
12 | status: publish
13 | type: post
14 | published: true
15 | meta:
16 | _edit_lock: "1274333057"
17 | _edit_last: "1"
18 | ---
19 |
20 |
21 |
22 |
23 |
24 | One of the gaps among my tech skills upon entering university was source/revision control.
25 |
26 | 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.
27 |
28 | 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.
29 |
30 | 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.
31 |
32 | 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.
33 |
34 | You can see a summary of source control options here: Comparison of revision control software @ Wikipedia
35 |
36 | 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.
37 |
38 | 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).
39 |
40 | In order to learn how to use git, I can recommend two sources of information.
41 |
42 | 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.
43 |
44 | 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.
45 |
46 | For those of you more interested in learning Mercurial (Hg), Zameer Manji has recommended the following
48 | guide: Hg Init: a Mercurial tutorial by
49 | Joel Spolsky.
50 |
51 | 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.
52 |
--------------------------------------------------------------------------------
/_posts/2010-01-07-tools-ideone-regexr-jitouch-2-opengnome-open-ditaa.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "Tools: ideone, RegExr, jitouch 2, open, ditaa"
4 | tags:
5 | - ditaa
6 | - ideone
7 | - jitouch
8 | - mac os x
9 | - open
10 | - regexr
11 | - regular expressions
12 | - Tools
13 | status: publish
14 | type: post
15 | published: true
16 | meta:
17 | _edit_last: "1"
18 | _edit_lock: "1274332878"
19 | ---
20 | Through reading proggit and hearing about new technology from classmates, every
21 | once in a while, I build up a list of tools which I plan on checking out and see
22 | whether they're useful enough to add to my regular routine. The first four on
23 | this list fall into that category, and I may eventually find a use for the last.
24 |
25 | ideone
26 | ======
27 |
28 | ideone is an in-browser, syntax-highlighted
30 | code editor complete with interpreters and compilers. Basically, if you've ever
31 | wanted to try out a language but really didn't feel like installing it on your
32 | system, this is the perfect place to start. The site even runs Brainf**k.
33 |
34 | There's another site which accomplishes the same task, but less elegantly: Codepad. This site is so much less elegant that I
36 | wasn't originally planning on posting it, but decided to once I saw there was a
37 | Codepad vim
38 | plugin. There's also emacs integrations.
39 |
40 | RegExr
41 | ======
42 |
43 | Regexr is an online tool, implemented in
45 | Adobe Flex, to test out regular expressions in real time. If you haven't learned
46 | about regular expressions yet, go
47 | learn right now. They're just about the most powerful text matching, user
48 | verification and error correction tool in existence. They're also implemented in
49 | nearly all languages now in some form or another. Before I saw this site, I
50 | would test out all my regular expressions just using vim, but found it
51 | frustrating when the expressions needed to be changed to be compatible with php.
52 | So I'm likely going to start using RegExr instead.
53 |
54 | jitouch 2
55 | =========
56 |
57 | Jitouch 2 is an application expanding on the
59 | multi-touch gestures available to MacBook Pro users who want to do more with
60 | just the touch pad. The two big things that this enables me to do that I love
61 | are opening links in new tabs using only taps on the keypad, and switching tabs
62 | using a gesture equivalent to ctrl-tab to switch tabs. I actually saw this
63 | reading Randal Munroe's blag.
64 |
65 | Mac OS X/Gnome open
66 | ===================
67 |
68 | open & gnome-open are terminal
69 | commands in Mac OS X and gnome respectively, but they do the same thing.
70 | Whenever you double click on a file in Finder or Nautilus, the operating system
71 | has a database of which extensions are opened by which applications. You can
72 | leverage that database by calling `open`. Examples:
73 |
74 | open "Office Space.avi"
75 |
76 | Open up Office Space in your default viewer.
77 |
78 | open http://www.jamie-wong.com
79 |
80 | Visit my website from the commandline, opening in your default browser
81 |
82 | open -a "Adobe Photoshop CS3"
83 |
84 | Launch Photoshop. `open -a` opens files with an application.
85 |
86 | ditaa
87 | =====
88 |
89 | ditaa is a tool for converting ASCII
91 | art diagrams into graphical diagrams. This is pretty well illustrated in the
92 | picture to the left. I haven't actually found much of a use for this yet, but
93 | some of you might.
94 |
95 |
96 |
--------------------------------------------------------------------------------
/_posts/2009-12-01-game-of-life.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Game of Life
4 | tags:
5 | - conway
6 | - gif
7 | - gifsicle
8 | - life
9 | - optparse
10 | - Projects
11 | - python
12 | status: publish
13 | type: post
14 | published: true
15 | meta:
16 | _edit_lock: "1265429990"
17 | _edit_last: "1"
18 | ---
19 | For my latest project, I'm implementing Conway's Game of Life in python into animated GIFs.
20 |
21 | Before I even explain what Conway's Game of Life is, be amused by the below, generated animation:
22 |
23 |
24 |
25 |
26 |
27 | As always, the code I'm using here is open source: Game Of Life @ Github.
28 | In addition to the source code, there's also a few animation demos such as the one above.
29 |
30 | Conway's Game of Life is a cellular automaton following very simple rules, as outlined in the Wikipedia article. It is a zero player game played on a 2 dimensional grid of squares, each holding either a state of dead or alive. The state of any cell is dependent on the state of the 8 cells neighbouring it in the previous generation. There are only 4 rules.
31 |
32 | From the Wikipedia article Conway's Game of Life:
33 |
34 | > 1. Any live cell with fewer than two live neighbours dies, as if caused by
35 | > underpopulation.
36 | > 2. Any live cell with more than three live neighbours dies, as if by
37 | > overcrowding.
38 | > 3. Any live cell with two or three live neighbours lives on to the next
39 | > generation.
40 | > 4. Any dead cell with exactly three live neighbours becomes a live cell.
41 |
42 | The colours you see in the above animation represent the alive status of each cell and also how many neighbours that cell has if it's alive.
43 |
44 | This project is my first time making use of two utilities: optparse in python, and gifsicle.
45 |
46 | optparse is a python library designed to make the creation of command line application much simpler. Specifically it's targeted towards making application with many possible flags easy to maintain. lifeImage.py falls into this category. From the commandline, you can control the source of input, the colour scheme, the number of generations to output, the scaling of the image and various other things to produce the exact animation or image you want.
47 |
48 | You can take a look at optparse here: optparse @ docs.python.org.
49 | The tutorial included there was enough for me to create this application.
50 |
51 | gifsicle is a command line application for the creation and modification of animated gifs. It can create gifs out of a sequence of images, convert an image into a sequence of images, or even modify replace a single frame of an animated gif with an external image.
52 |
53 | You can see and download gifsicle here: Official Gifsicle Page
54 |
55 | Why did I use gifsicle instead of the much more universal convert in
56 | ImageMagick? Simply put: gifsicle is faster. If someone would like to do a
57 | benchmark to (dis)prove this, I'd be happy to post the results, but from simple
58 | experimentation, it seemed obvious to me that gifsicle took less time to make
59 | the animation.
60 |
61 | What's Next?
62 | ============
63 |
64 | Now that I have a working command line utility, my next goal is to make an AJAX
65 | powered web interface for the thing. This might explain why I have `ProcMonitor`
66 | in the github for Game of Life. The web interface was another key motivator
67 | behind using gifs for the output medium. People may want to use these things for
68 | avatar, and they're simply easier to share and move around than a java applet,
69 | or a flash swf, or some database stored simulation. It also helps that gifs are
70 | designed for palette based images, which works out nicely for optimizing the
71 | file size of these animations. The first 1000 generations of acorn is 2.5 MB as
72 | it is.
73 |
74 | Another thing I want to do is make `lifeImage.py` read the `.cells` format from
75 | the Life Lexicon. This
76 | would save me a lot of time having to code all the states myself. This will be a
77 | very straightforward process, as the `.cells` files are simply plaintext with 2
78 | lines of header.
79 |
80 | Suggestions/bug fixes for my implementation of Game of Life are welcomed.
81 |
82 | I'm almost 100% sure that some combination of the command line flags of
83 | `lifeImage.py` don't work nicely together, and would like to know what they are.
84 |
--------------------------------------------------------------------------------
/_posts/2009-11-08-spoj-problem-1.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: SPOJ Problem 1
4 | tags:
5 | - bash
6 | - c++
7 | - c99
8 | - java
9 | - pascal
10 | - perl
11 | - php
12 | - prime
13 | - python
14 | - ruby
15 | - SPOJ
16 | status: publish
17 | type: post
18 | published: true
19 | meta:
20 | _edit_lock: "1258154416"
21 | _edit_last: "1"
22 | ---
23 | When I saw that Thor had done solutions to the first few problems of Project Euler in many many languages, I thought "Hey! That's a good idea!" but didn't want to copy exactly.
24 |
25 | So instead I'm doing solutions to some problems on SPOJ.
26 | SPOJ is an online judge system full of algorithmic problems. This is one of the things that Hanson Wang did to get as good as he is. The solutions I'll be providing here are going to be very simple problems, so don't expect any magic. The beautiful thing about SPOJ is the sheer number of languages it will judge. I figured this was the perfect playground to make sure my code worked in all the languages I try.
27 |
28 | Problem: Life, the Universe, and Everything
29 |
30 |
31 | Your program is to use the brute-force approach in order to find the Answer to Life, the Universe, and Everything. More precisely... rewrite small numbers from input to output. Stop processing input after reading in the number 42. All numbers at input are integers of one or two digits.
32 |
33 | Solutions - In order of frequency that I use the language
34 |
35 | C++
36 |
37 | lang:cpp
38 |
39 | //TEST AC - CPP (g++)
40 | #include
41 | using namespace std;
42 |
43 | int main() {
44 | int n;
45 | while(1) {
46 | cin >> n;
47 | if (n == 42) break;
48 | cout << n << endl;
49 | }
50 | return 0;
51 | }
52 |
53 | C99
54 |
55 | lang:c
56 |
57 | //TEST AC - (gcc C99)
58 | #include
59 | int main() {
60 | int n;
61 | while(1) {
62 | scanf("%d",&n);
63 | if (n == 42) break;
64 | printf("%d\n",n);
65 | }
66 | return 0;
67 | }
68 |
69 | php
70 |
71 | lang:php
72 |
73 |
74 | //TEST AC - PHP
75 | while(1) {
76 | fscanf(STDIN,"%d",$n);
77 | if ($n == 42) break;
78 | print "$n\n";
79 | }
80 | ?>
81 |
82 | Python
83 |
84 | lang:python
85 |
86 | #TEST AC - Python
87 | while 1:
88 | num = input()
89 | if (num == 42):
90 | break
91 | print num
92 |
93 | Bash
94 |
95 | lang:bash
96 |
97 | #!/bin/bash
98 | # TEST AC - BASH
99 |
100 | while true; do
101 | read n
102 | if [ $n -eq 42 ]; then
103 | break
104 | fi
105 | echo "$n"
106 | done
107 |
108 | Ruby
109 |
110 | lang:ruby
111 |
112 | #TEST AC - Ruby
113 | while 1
114 | n = gets.to_i
115 | if n == 42
116 | break
117 | end
118 | puts n
119 | end
120 |
121 | Java
122 |
123 | lang:java
124 |
125 | //TEST AC - Java
126 | import java.io.*;
127 | import java.util.*;
128 |
129 | public class Main {
130 | public static void main(String[] args) {
131 | Scanner in = new Scanner(System.in);
132 |
133 | while(true) {
134 | int n = in.nextInt();
135 | if (n == 42) break;
136 | System.out.println(n);
137 | }
138 | }
139 | }
140 |
141 | Perl
142 |
143 | lang:perl
144 |
145 | #TEST AC - Perl
146 | while (1)
147 | {
148 | $n = ;
149 | if ($n == 42) {
150 | last;
151 | }
152 | print $n
153 | }
154 |
155 | C#
156 |
157 | lang:csharp
158 |
159 | //TEST AC - C# (gmcs + Mono)
160 | using System;
161 | class WelcomeCSS {
162 | static void Main() {
163 | while(true) {
164 | int n;
165 | n = int.Parse(Console.ReadLine());
166 | if (n == 42) break;
167 | Console.WriteLine(n);
168 | }
169 | }
170 | }
171 |
172 | GNU Pascal
173 |
174 | lang:pascal
175 |
176 | {TEST AC - GPC Pascal}
177 |
178 | program TEST;
179 |
180 | var n:integer;
181 |
182 | begin
183 | while true do
184 | begin
185 | readln(n);
186 | if n = 42 then begin
187 | break;
188 | end;
189 | writeln(n);
190 | end;
191 | end.
192 |
193 | You can see Thor's Project Euler solutions here: Derek Thurn's Website - Project Euler
194 |
--------------------------------------------------------------------------------
/_posts/2010-07-07-flexactionscript-3-debug-output-to-console.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "Flex/Actionscript 3: Debug Output to Console"
4 | tags:
5 | - actionscript
6 | - flex
7 | - flixel
8 | - trace
9 | - Tutorials
10 | status: publish
11 | type: post
12 | published: true
13 | meta:
14 | _edit_last: "1"
15 | _edit_lock: "1278565881"
16 | _wp_old_slug: ""
17 | ---
18 | 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.
19 |
20 | [Flixel]: http://flixel.org/
21 | [FLex]: http://www.adobe.com/products/flex/
22 |
23 | The first problem is capturing _any_ debug output. For whatever reason, I was unable to output traces to anywhere useful.
24 | 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.
25 |
26 | [De MonsterDebugger]: http://demonsterdebugger.com/
27 |
28 | print_r style output in actionscript
29 | -----------------------------
30 |
31 | I found a good starting point [here][base86], but the output of this wasn't exactly what I wanted. I messed around with it until I got something more familiar to me.
32 |
33 | [base86]: http://dev.base86.com/solo/47/actionscript_3_equivalent_of_phps_printr.html
34 |
35 | lang:actionscript
36 |
37 | package learning {
38 | import org.flixel.*;
39 |
40 | public class Debugger {
41 | public static function pr(obj:*, level:int = 0, output:String = ""):* {
42 | var objtype:String = typeof(obj);
43 | if (objtype == "boolean" || objtype == "string" || objtype == "number") {
44 | return obj;
45 | }
46 |
47 | var tabs:String = "";
48 | for(var i:int = 0; i < level; i++) {
49 | tabs += "\t"
50 | }
51 |
52 | output += "{\n";
53 | for(var child:* in obj) {
54 | output += tabs +"\t["+ child +"] => ";
55 |
56 | var childOutput:String = pr(obj[child], level+1);
57 | if(childOutput != '') output += childOutput
58 |
59 | output += "\n";
60 | }
61 | output += tabs + "}\n";
62 |
63 | return output;
64 | }
65 |
66 | public static function log(obj:*):void {
67 | FlxG.log(pr(obj));
68 | // This is a flixel thing. If you're not using flixel
69 | // Just use trace(pr(obj));
70 | }
71 | }
72 | }
73 |
74 | Example output
75 |
76 | {
77 | [0] => {
78 | [tile] => 4
79 | [rule] => {
80 | [0] => xxx
81 | [1] => x1x
82 | [2] => x1x
83 | }
84 | }
85 | [1] => {
86 | [tile] => 8
87 | [rule] => {
88 | [0] => x1x
89 | [1] => x1x
90 | [2] => xxx
91 | }
92 | }
93 | }
94 |
95 | trace output to console
96 | --------------------
97 |
98 | This, fortunately, was much less of a hassle for me to get working.
99 |
100 | Reference: [Configuring the debugger version of Flash Player][Flex 3 Reference]
101 |
102 | **Step 1**
103 |
104 | Locate/create your `mm.cfg` file. For me this was in `~/mm.cfg`. See [reference][Flex 3 Reference].
105 |
106 | Stick this in it: `TraceOutputFileEnable=1`
107 |
108 | Or, in one command:
109 |
110 | lang:bash
111 |
112 | echo "TraceOutputFileEnable=1" > ~/mm.cfg`
113 |
114 | **Step 2**
115 |
116 | Locate the location of the log file. Mine is in
117 |
118 | ~/Library/Preferences/Macromedia/Flash Player/Logs/flashlog.txt`
119 |
120 | See [reference][Flex 3 Reference].
121 |
122 | You don't want to type this in every time you want to view the log, so add a function to your `.bash_profile`
123 |
124 | This is what I have:
125 |
126 | lang:bash
127 |
128 | flashlog() {
129 | tail -f $* ~/Library/Preferences/Macromedia/Flash\ Player/Logs/flashlog.txt;
130 | }
131 |
132 | [Flex 3 Reference]: http://livedocs.adobe.com/flex/3/html/help.html?content=logging_04.html
133 |
134 | **Step 3**
135 |
136 | Start debugging!
137 |
138 | lang:bash
139 |
140 | $ flashlog -100
141 | Warning: 'flash' has no property 'prototype'
142 | Warning: 'flash' has no property 'prototype'
143 | flixel v2.35 [debug]
144 | ----------------------------------------------------
145 | {
146 | [0] => {
147 | [tile] => 4
148 | [rule] => {
149 | [0] => xxx
150 | [1] => x1x
151 | [2] => x1x
152 | }
153 | }
154 | [1] => {
155 | [tile] => 8
156 | [rule] => {
157 | [0] => x1x
158 | [1] => x1x
159 | [2] => xxx
160 | }
161 | }
162 | }
163 |
--------------------------------------------------------------------------------
/_posts/2009-12-27-uwangel-cli.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: UWAngel-CLI
4 | tags:
5 | - CLI
6 | - curl
7 | - php
8 | - Projects
9 | - stty
10 | - UWAce
11 | - UWAngel
12 | status: publish
13 | type: post
14 | published: true
15 | meta:
16 | _edit_lock: "1265430002"
17 | _edit_last: "1"
18 | ---
19 |
20 |
21 |
22 |
23 | Near the end of the semester, I was getting kind of tired of navigating UW-ACE
24 | so frequently through my browsing and opening all the different tabs to grab all
25 | the files I wanted. While all the pretty graphics make for a decent user
26 | interface, it reduces the speed of the service.
27 |
28 | But aside from that, I like being able to do as much as I possibly can from the
29 | console.
30 |
31 | So I made a Command Line Interface (CLI) for UW-ACE in php using cUrl. I built
32 | in on my Macbook Pro in Snow Leopard, but it should work just fine on any *nix
33 | machine, and possibly in Cygwin or other emulators.
34 |
35 | As always, source is available on github: UWAngel-CLI @ Github.
37 |
38 | Since I always like to post snippets of code from my projects that may be
39 | universally useful, I'll do that here too.
40 |
41 | CLI Colour in PHP
42 | -----------------
43 |
44 | `cli_colours.php` included in the UWAngel-CLI source is just a collection of
45 | constants which allow you to print out colours in your CLI scripts.
46 |
47 | lang:php
48 |
49 |
50 | $COLOR_BLACK = "\033[0;30m";
51 | $COLOR_DARKGRAY = "\033[1;30m";
52 | $COLOR_BLUE = "\033[0;34m";
53 | $COLOR_LIGHTBLUE = "\033[1;34m";
54 | $COLOR_GREEN = "\033[0;32m";
55 | $COLOR_LIGHTGREEN = "\033[1;32m";
56 | $COLOR_CYAN = "\033[0;36m";
57 | $COLOR_LIGHTCYAN = "\033[1;36m";
58 | $COLOR_RED = "\033[0;31m";
59 | $COLOR_LIGHTRED = "\033[1;31m";
60 | $COLOR_PURPLE = "\033[0;35m";
61 | $COLOR_LIGHTPURPLE = "\033[1;35m";
62 | $COLOR_BROWN = "\033[0;33m";
63 | $COLOR_YELLOW = "\033[1;33m";
64 | $COLOR_LIGHTGRAY = "\033[0;37m";
65 | $COLOR_WHITE = "\033[1;37m";
66 | $COLOR_DEFAULT = "\033[0;37m";
67 |
68 | echo <<< EOT
69 | One fish,
70 | two fish,
71 | {$COLOR_RED}red{$COLOR_DEFAULT} fish,
72 | {$COLOR_BLUE}blue{$COLOR_DEFAULT} fish.
73 |
74 | EOT;
75 |
76 | The only gripe I have about this is that `COLOR_DEFAULT` it's the same colour as
77 | I have on by default in iTerm. Anyone know the escape code to make it actually
78 | revert to what it was before instead of just making an assumption about what
79 | color is being used?
80 |
81 | Hide Commandline Input
82 | ----------------------
83 |
84 | One of the first things I looked up when I started this project today was how to
85 | hide user input from the command line. I sure as hell didn't want people typing
86 | their passwords for UWACE on screen and having it actually display.
87 |
88 | It turns out you can do this by temporarily telling your TTY to stop echoing
89 | what you type. The command for this is `stty -echo` and can be re-enabled using
90 | `stty echo`. Below is how I implemented as part of the AngelAccess class to meet
91 | my needs.
92 |
93 | lang:php
94 |
95 |
96 | function Prompt($prompt_text,$hide = false) {
97 | echo $prompt_text;
98 | $input = "";
99 | if ($hide) {
100 | $input = trim(`stty -echo;head -n1;stty echo`);
101 | echo "\n";
102 | } else {
103 | $input = trim(fgets(STDIN));
104 | }
105 | return $input;
106 | }
107 | ?>
108 |
109 | As a complete side note, thanks to a boot-camped installation of Windows 7 (or
110 | at least I'm fairly sure that's the culprit,) my Macbook Pro is now stuck on
111 | Digital Out. This means I can't use the internal speakers on my computer under
112 | Mac OS X. Well... what I should say is that I can't use them without some
113 | annoying tricks. If I plug in my headphones, then tell my mac to use the input
114 | jack for audio input, then my internal speakers appear under the output options
115 | and let me use them. The speakers then work perfectly fine. They also work fine
116 | under Windows 7. A direct side effect of digital out being stuck on is a read
117 | light emanating from the audio jack.
118 |
119 | The problem is apparently fairly common, unfortunately the only confirmed fixes
120 | for it are sending it back to Apple or wiggling a toothpick
122 | around in the audio jack. I had absolutely no luck with the toothpick, or
123 | precision screwdriver, or pen cartridge, or paintbrush handle. If anyone knows
124 | how to fix this problem, I would love to know. Otherwise, I'm just going to take
125 | it into the Apple store in Rideau some time this week and hope they can fix the
126 | problem. I really don't want to have to send my Mac in during my first week at
127 | Velocity.
128 |
--------------------------------------------------------------------------------
/_posts/2009-11-14-omegle-voyeur-multiple-connections.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Omegle Voyeur - Multiple Connections
4 | tags:
5 | - AJAX
6 | - javascript
7 | - omegle
8 | - php
9 | - Projects
10 | - prototype
11 | status: publish
12 | type: post
13 | published: true
14 | meta:
15 | _edit_lock: "1259218981"
16 | _edit_last: "1"
17 | ---
18 | In case you haven't read the post about all my projects, here's a description of what Omegle Voyeur is:
19 |
20 | Omegle is a website where you are connected to a stranger for a chat. It is dominated mostly by trolls whose primary purpose is to coerce you into a cyber session and then switch genders or to make you lose the game. Talking to these people is a rather tiresome endeavour, but seeing exactly what happens in these conversations is interesting. Omegle Voyeur is a way of watching a conversation which you aren't part of. What Voyeur does is form two simultaneous connections and then pass the input of one to the output of the other. This sets you up as a conversation proxy, allowing you to watch. Currently, this is exclusively a "sit and watch" program. Later I intend to add functionality to add more than 2 people into a conversation, automatically name the participants so it will be obvious that there are more than 2 people in the conversation, and allow the ability to interfere (mute participants/say things yourself) with a conversation. This concept was spawned during discussion (read: boredom) at CCC Stage 2, 2009.
21 |
22 |
23 | In terms of technology, Omegle Voyeur is primarily one big Javascript Prototype class. Prototype is a Javascript Framework which makes the creation and maintenance of classes, conversion of data into JSON for transfer, and sending AJAX requests much, much easier.
24 |
25 | There's also a very small bit of code in php which is able to be so short because it uses the incredible program cUrl. cUrl is a command line utility for grabbing data from websites using their URL. libcurl facilititates the use of curl in php without having to write your own wrapper.
26 |
27 | Below is some php code I use to make curl even easier than it already is. simple_get($url) will return the HTTP GET result from the url specified. simple_post works similarly, but delivers data using the payload.
28 |
29 | lang:php
30 |
31 |
32 | // Simple cUrl
33 | // Simple get and post requests
34 | function simple_get($url) {
35 | $c = curl_init();
36 | curl_setopt($c, CURLOPT_URL, $url);
37 | curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
38 | $result = curl_exec($c);
39 | curl_close($c);
40 | return $result;
41 | }
42 |
43 | function simple_post($url,$payload) {
44 | $c = curl_init();
45 | curl_setopt($c, CURLOPT_URL, $url);
46 | curl_setopt($c, CURLOPT_POST, true);
47 | curl_setopt($c, CURLOPT_POSTFIELDS, $payload);
48 | curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
49 | $result = curl_exec($c);
50 | curl_close($c);
51 | return $result;
52 | }
53 | ?>
54 |
55 | When I started working on this project today (well, I suppose that would be last night now... wonder if I'll see the sunrise) I figured it would be a good time to get used to using git, so I made a repository using github.
56 | So far I'm enjoying git. Everything seems to act pretty much the way you'd expect to, and I already had to do a revert once I realized my logic was wrong for the way I was structuring my code.
57 |
58 | You can see the github for Omegle Voyeur here: http://github.com/phleet/Omegle-Voyeur
59 | Feel free to design your own stuff with the all the code there - just be sure to link back here, or to the github page.
60 |
61 | In any case, the thing the majority of the people reading this are probably interested in are the result.
62 | Things I've updated since last time are primarily aesthetic and behind the scenes, but I did add the ability to connect one person to more than one other person, and the connections don't have to be mutual. In the first 3 way conversation example, 1 can only speak to 2, 2 can only speak to 3 and 3 can only speak to 1. It leads to some rather confused people.
63 |
64 | You can see the current running version here: Omegle Voyeur.
65 | EDIT: It seems that after being posted on reddit, omegle has (manually?) IP blocked me. The source should still work, so feel free to try it out yourself.
66 | You can go grab XAMPP to run it locally.
67 | For the time being, you can view it here: Omegle Voyeur
68 |
69 | A quick note on how I figured out the Omegle communication protocol.
70 | The entire code governing the process is conveniently kept here: http://omegle.com/static/omegle.js?27
71 | Unless you enjoy reading 1000s of characters on a single line, you can use the JS Beautifier to clean it up to a readable state.
72 |
--------------------------------------------------------------------------------
/_posts/2010-02-05-jobmine-improved-greasemonkey-jquery.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Jobmine Improved (Greasemonkey & jQuery)
4 | tags:
5 | - greasemonkey
6 | - jobmine
7 | - jquery
8 | - Projects
9 | status: publish
10 | type: post
11 | published: true
12 | meta:
13 | _edit_lock: "1285900502"
14 | _edit_last: "1"
15 | ---
16 |
17 |
18 |
19 |
20 | _I will no longer be supporting this script, there's a much better version
21 | called [Jobmine Plus](http://userscripts.org/scripts/show/80771) maintained by
22 | Matthew Ng._
23 |
24 | I, like many (most) Waterloo Co-op students, am forced to use Jobmine and am
25 | extremely dissatisfied with its functionality. So I decided to kill three birds
26 | with one stone: improve Jobmine, learn Greasemonkey and learn jQuery all at the
27 | same time.
28 |
29 | The result is, unsurprisingly, a Greasemonkey script written using jQuery that improves on some features of Jobmine.
30 |
31 | Features
32 |
33 |
Table sorting - all major tables are now sortable (Interviews, Job Short List, Applications)
34 |
Improved navigation - no more Student -> Use ridiculousness
35 |
No more frames - you can refresh and it will stay on the same page!
36 |
Colour highlighting for tables - pictured above, you see the applications page with various statuses highlighted. Selected is green, not selected is red.
37 |
No more spacers - the Jobmine page is riddled with spacer images just sitting there, stealing screen real estate
38 |
39 |
40 | How to Install
41 | You'll either need Firefox & Greasemonkey, or a recent build of Chrome (Windows only?).
42 | You can get Greasemonkey here: Greasemonkey @ addons.mozilla.org
43 |
44 | Once you've done that, navigate to the script and click install.
45 | You can get the script here: Jobmine Upgrade @ userscripts.org
46 |
47 | Now for the part where I explain the tech I used.
48 |
49 |
Greasemonkey
50 | 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).
51 |
52 |
jQuery
53 | 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).
54 |
55 | lang:js
56 |
57 | // Standard Javascript method:
58 | var tables = document.getElementsByTagName("table");
59 | for (var i = 0; i < tables.length; i++) {
60 | var rows = tables[i].tBodies[0].rows;
61 | for (var j = 0; j < rows.length; j++) {
62 | var rowColor;
63 | if (j % 2 == 1) {
64 | rowColor = "#eef";
65 | } else {
66 | rowColor = "#fff";
67 | }
68 |
69 | var cells = rows[j].cells;
70 | for (var k = 0; k < cells.length; k++) {
71 | cells[k].style.backgroundColor = rowColor;
72 | cells[k].style.borderBottom = "1px solid #ccc";
73 | }
74 | }
75 | }
76 |
77 | // jQuery way:
78 | $("td").css("border-bottom","1px solid #ccc");
79 | $("tr:even > td").css("background-color","#fff");
80 | $("tr:odd > td").css("background-color","#eef");
81 |
82 | 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.
83 |
84 | 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
85 |
86 | 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.
87 |
88 | 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)
89 |
--------------------------------------------------------------------------------
/_posts/2010-08-14-javascript-dependency-loading-jquery-atreq.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "Javascript Dependency Loading \xE2\x80\x93 jquery.atreq"
4 | tags:
5 | - javascript
6 | - jquery
7 | status: publish
8 | type: post
9 | published: true
10 | meta:
11 | _edit_last: "1"
12 | _edit_lock: "1287294623"
13 | _wp_old_slug: ""
14 | ---
15 | 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.
16 |
17 | [jquery.atreq @ github](http://github.com/phleet/jquery.atreq)
18 |
19 | 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.
20 |
21 | jquery.atreq
22 | ============
23 |
24 | jquery.atreq loads your javascript dependencies asynchronously.
25 |
26 | How to use
27 | ----------
28 |
29 | First, include your main application file with `$.atreq`
30 |
31 | lang:html
32 |
33 |
34 |
35 |
38 |
39 | Then inside your application.js and any other required files, place a require statement in the comments.
40 |
41 | lang:js
42 |
43 | // application.js
44 | // @require 'lib/lib1.js'
45 | // @require 'lib/lib2.js'
46 |
47 | Library1Function();
48 | Library2Function();
49 |
50 | **NOTE**: While `//@require` "blocks", `$.atreq` does not. This means the following will not work:
51 |
52 | lang:js
53 |
54 | $.atreq('lib/lib1.js');
55 | Library1Function();
56 |
57 | Relative Require Paths
58 | ----------------------
59 |
60 | Unless the require paths begin with a `/`, they're assumed to be relative to the location of the file they're in.
61 |
62 | 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.
63 |
64 | Each of the library files can also have their own dependencies, and `$.atreq` will make sure they're run in the correct order.
65 |
66 | lang:js
67 |
68 | // lib/lib1.js
69 | // @require `dep/libdep.js`
70 |
71 | function Library1Function() {
72 | alert('Awesome!");
73 | }
74 |
75 | Redundant or Duplicate Requires
76 | -------------------------------
77 |
78 | Duplicate requires of the same file will neither request nor run the same file twice.
79 | This is true even if the relative path is different from files. This means that:
80 |
81 | lang:js
82 |
83 | // lib/lib2.js
84 | // @require '../shared/shared.js'
85 |
86 | and
87 |
88 | lang:js
89 |
90 | // lib/lib3.js
91 | // @require '../shared/shared.js'
92 |
93 | will only make one request out to `shared/shared.js`.
94 |
95 |
96 | Alternatives and How They're Different
97 | --------------------------------------
98 |
99 | ### $.include
100 |
101 | 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
102 |
103 | It even has the ability to load dependencies for included scripts like so (taken from his blog post):
104 |
105 | lang:js
106 |
107 | $.include(
108 | // URL
109 | 'js/my-script.js',
110 | // will be loaded after this script
111 | $.include(baseURL+'js/my-other-script.js')
112 | );
113 | $.include('js/src/behaviors.js',
114 | // dependencies can also be an array
115 | [
116 | $.include('js/src/jquery-metadata.js'),
117 | $.include('js/src/jquery.form.js')
118 | ]
119 | );
120 |
121 | This is great, except that it requires all the dependencies to be loaded from the same file.
122 | This means you won't get useful behaviour if one of the files you're including has internal dependencies.
123 |
124 | See: [$.include() @ tobiasz123.wordpress.com](http://tobiasz123.wordpress.com/2007/08/01/include-script-inclusion-jquery-plugin/)
125 |
126 | ### $.require
127 |
128 | 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.
129 |
130 | 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.
131 |
132 | The require paths in this script are relative to the inclusion point (the HTML file), not the script itself.
133 |
134 | Comparison of load times for the following dependency tree:
135 |
136 | application.js
137 | |--- 1.js
138 | | |--- 1a.js
139 | | |--- 1b.js
140 | | \--- shared.js
141 | \--- 2.js
142 | |--- 2a.js
143 | |--- 2b.js
144 | \--- shared.js
145 |
146 | 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.
147 |
148 | $.atreq:
149 |
150 | 
151 |
152 | $.require:
153 |
154 | 
155 |
156 | Note the difference in the load order - there's no reason why 1.js and 2.js shouldn't load at the same time.
157 |
158 |
159 | See: [$.require @ plugins.jquery.com](http://plugins.jquery.com/project/require)
160 |
161 | **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.
162 |
--------------------------------------------------------------------------------
/_posts/2009-12-12-manual-sorting.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Manual Sorting
4 | tags:
5 | - algorithm
6 | - cards
7 | - sorting
8 | status: publish
9 | type: post
10 | published: true
11 | meta:
12 | _edit_lock: "1261898946"
13 | _edit_last: "1"
14 | ---
15 |
16 |
17 |
18 |
19 | The basis for this post is the following question: what is the fastest algorithm for sorting a deck of cards by hand?
20 |
21 | TL:DR advisor - skip to the end of the post for a challenge.
22 |
23 | In terms of algorithmic complexity, merge sort and quick sort are two of the fastest widely used sorting algorithms - both running at an average case of O(n log n). But if you've ever sorted a deck of cards, ordering primarily by suit and secondly by number, I doubt you used either of these algorithms. You might unknowingly be doing bucket sort, dividing the cards into 4 "buckets" - one for each suit, then sorting each suit using a different algorithm and joining all the suits together at the end.
24 |
25 | If I had a deck of cards in my room right now, I would be inclined to take videos of me sorting them using various different algorithms and comparing the time required. I have a feeling that the fastest algorithm would involve drawing out a 4x13 grid on a big piece of paper with each cell labeled with the exact card that fits there, then running through the deck, placing all the cards on their grid cell and just picking them up in order at the end. Of course, this could be accomplished without the grid but requires a spacial sense which I simply do not possess.
26 |
27 | As a followup, I have another question: what if the cards were labeled with a number system you've never seen before? Assume you have some visual reference allowing you to understand the system, but also assume that the number system is not intuitive. Does your approach change? Of course, the fastest approach here depends on what I'm really asking by "fastest". Given enough time and practice, you would be able to become familiar enough with the numeral system to use any approach you would with regular cards or regular decimal numbers. When I say "fastest", I'm asking how you would minimize the time between receiving the cards and the visual reference and the cards being sorted. In terms of computation, the introduction of this numeral system has drastically increased the time for a comparison or enumeration while not affecting the time for movement or swapping at all. The reverse would be to use the standard deck of cards but make them orders of magnitude larger - say 1 meter wide each. In this case a move or a swap is extremely costly, but a comparison is very cheap.
28 |
29 | A more realistic scenario in which the cost of comparison is drastically increased comes about when the criteria used for sorting is not an absolute. Example: sort these pictures by aesthetic appeal. Even by yourself this may be a long process, as you second guess your original decision about the relative appeal of a picture. In the world of web 2.0 though, it's a much much longer process. Sorting by crowd-sourced opinion is the basis of many websites, such as bash.org and reddit. Most of these systems work by providing users with the ability or increase or decrease the item's value by small amounts. Is there some better way of ensuring that the articles which will be the most valuable to the readers will show up at the top?
30 |
31 | Returning to the point of manual sorting, I have 2 more things to say.
32 |
33 | The first is an idea - competitive sorting. I'm sure this sounds nerdy as hell, but I think I'd still find it fairly entertaining. Groups of people would be given sets of objects and told to sort by some criteria, the fastest group being the victor, with penalties dished out for people falsely claiming their list is sorted. The criteria could be size, weight, volume, buoyancy, color saturation, retail price, alcohol content, power consumption or even something as obscure as average salary of a worker for the company manufacturing the product. Given that I'm at Waterloo, I feel that organizing such a competition isn't all that unlikely. Anyone feel like coming up with a plan for making this actually happen?
34 |
35 | The second is a challenge. I challenge everyone reading this to make a video of them sorting a deck of 52 cards (no jokers) as fast as they can, then post the video in the comment section. As soon as I actually get a deck of cards, I'll take part in this challenge myself.
36 |
37 | Rules.
38 |
39 |
The video must be all in one take
40 |
The deck must be shuffled thoroughly on screen, then fanned towards the camera to demonstrate the randomized order of the cards.
41 |
Once the cards have been fanned towards the camera, you can have a maximum of 10 seconds of review time looking through the cards before the sorting starts. All cards must stay in contact and in order during this review time.
42 |
The timer starts the second a card is separated from the rest of the deck.
43 |
The timer stops when the deck has been reassembled into a single sorted deck.
44 |
A deck is considered sorted if the cards are primarily ordered by suit in the order diamonds, clubs, hearts, spades, and secondarily ascending numerically.
45 |
You must fan the deck towards the camera after it is sorted.
46 |
You are allowed any setup you want before starting to sort (e.g. the grid I talked about above,) provided that the setup does not contain moving parts - no robots.
47 |
You must be the only one handling the cards - no team efforts.
48 |
49 |
50 | That's all. I fully expect to receive no responses to this challenge, but would love to see the things people come up with if someone does try it.
51 |
52 | EDIT: Woohoo! Someone attempted!
53 | Timothy Armstrong Sorting
54 |
55 | Also, the claimed record according to this page is 36.1 seconds.
56 |
--------------------------------------------------------------------------------
/_posts/2010-04-19-ajax-method-callbacks-and-omegle-voyeur-update.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: AJAX Method Callbacks and Omegle Voyeur Update
4 | tags:
5 | - AJAX
6 | - callbacks
7 | - jquery
8 | - method
9 | - omegle
10 | - omegle voyeur
11 | - Projects
12 | status: publish
13 | type: post
14 | published: true
15 | meta:
16 | _edit_lock: "1274333018"
17 | _edit_last: "1"
18 | ---
19 | I finally got back around to updating Omegle Voyeur with the ability to
20 | interfere, and decided to re-implement the whole thing in jQuery while I'm at
21 | it. Since jQuery doesn't come with a built-in method of building classes, I used
22 | lowpro for
23 | jQuery. It's a port of a class building scheme from Prototype. It doesn't do
24 | everything I could have hoped for, but it served most of my needs.
25 |
26 | The other thing I implemented was a way of knowing when Omegle is blocking
27 | requests. They have a more robust form of detection now - it isn't just manual
28 | IP ban. Once you request too many things from them too fast, they start
29 | requesting a captcha. Locally, this isn't a problem - I simply embed an iframe
30 | with Omegle in it and provide instructions to the user. Hosted, this is a more
31 | troublesome problem, since the captcha is directed towards an IP, so it must be
32 | responded to from that IP. I have no solution to this problem at the moment, but
33 | I'm going to look into implementing the whole thing using Greasemonkey so this
34 | isn't an issue at all.
35 |
36 | For now, you can see the latest version here: Omegle Voyeur.
38 | Don't be surprised if it's down, and please go grab your own copy: Omegle-Voyeur @ github.
40 |
41 | Now on to the customary technical concept to go along with my own self promotion.
42 |
43 |
AJAX Method Callbacks
44 | While passing functions as arguments is a pretty standard thing among almost
45 | all languages, attempting to pass methods of specific instances as arguments in
46 | JavaScript presents an interesting problem. Consider the following:
47 |
48 | lang:js
49 |
50 | function car(price) {
51 | this.price = price;
52 |
53 | this.setPrice = function(price) {
54 | this.price = price;
55 | };
56 | }
57 |
58 | function pass666(func) {
59 | func(666);
60 | }
61 |
62 | var redcar = new car(2000);
63 | alert(redcar.price);
64 | redcar.setPrice(123);
65 | alert(redcar.price);
66 | pass666(redcar.setPrice);
67 | alert(redcar.price);
68 |
69 | As you might expect, the first two alerts will say 2000 and 123 respectively.
70 | But the last one also says 123. Why?
71 |
72 | It all has to do with what `this` refers to. Both in the initialization of
73 | `redcar` and the modifier call `redcar.setPrice`, "this" refers to the instance
74 | of the function car given the identifier name `redcar`. In the `pass666`
75 | version, `this` refers to the function `pass666`. As a result, it does nothing
76 | to modify the properties of the car because it isn't told anything about
77 | `redcar`.
78 |
79 | One way to fix this is to use a placeholder variable. I used "self". Change the
80 | definition of car to the following yields the desired result.
81 |
82 | lang:js
83 |
84 | function car(price) {
85 | this.price = price;
86 |
87 | var self = this;
88 | this.setPrice = function(price) {
89 | self.price = price;
90 | };
91 | }
92 |
93 | In this example, it's difficult to see why you would ever want to use this in
94 | the first place. The reason I encountered this problem is my need to use
95 | instance methods as callback functions for AJAX calls. Here's an excerpt of the
96 | jQuery version of Omegle Voyeur to see what I'm talking about.
97 |
98 | lang:js
99 |
100 | sendQuery: function(target,respFunc) {
101 | // Send a query to the omegle server
102 | //log('sending');
103 | var self = this;
104 | if (respFunc == null) {
105 | respFunc = function(self,data) {}
106 | }
107 | $.ajax({
108 | url: 'omegle.php?'+target,
109 | type: 'GET',
110 | dataType: 'json',
111 | success: function(data) {
112 | respFunc(self,data);
113 | }
114 | });
115 | },
116 |
117 | Sending a request to the Omegle server is a very common task in Omegle Voyeur,
118 | so I wanted all the AJAX requests leaving from the same method. This means I
119 | have to accept the callback function as a parameter. I've written all the
120 | callback methods to accept a parameter `self` which will refer to the instance
121 | of interest.
122 |
123 | This aspect is one of the many things that makes Prototype's class system
124 | superior to jQuery's. However, since jQuery makes a lot of other things nicer
125 | and the two libraries don't play together very well, I decided to port over to
126 | jQuery nonetheless. In Prototype, there's a function called bind (not to be confused
128 | with jQuery's bind which does
129 | something completely different,) which solves this problem elegantly.
130 |
131 | To fix the redcar problem with the aid of Prototype without having to use a
132 | placeholder variable, you can use bind like so:
133 |
134 | lang:js
135 |
136 | function car(price) {
137 | this.price = price;
138 |
139 | this.setPrice = function(price) {
140 | this.price = price;
141 | };
142 | }
143 |
144 | function pass666(func) {
145 | func(666);
146 | }
147 |
148 | var redcar = new car(2000);
149 | alert(redcar.price);
150 | redcar.setPrice(123);
151 | alert(redcar.price);
152 |
153 | pass666(redcar.setPrice.bind(redcar));
154 |
155 | alert(redcar.price);
156 |
157 |
158 | The line `pass666(redcar.setPrice.bind(redcar));` is what makes this work out.
159 | We're explicitly saying that we want `setPrice` executed from the scope of the
160 | instance.
161 |
162 | If I ever have to hire someone for a web development job, I'll be sure to ask
163 | something about this.
164 |
--------------------------------------------------------------------------------
/_posts/2010-10-16-dfas-and-graphviz-dot.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: DFAs and Graphviz DOT
4 | tags:
5 | - cs241
6 | - dot
7 | - graphviz
8 | - ruby
9 | - school
10 | status: publish
11 | type: post
12 | published: true
13 | meta:
14 | _edit_lock: "1287296820"
15 | _edit_last: "1"
16 | _wp_old_slug: ""
17 | ---
18 | As is usually the case with CS assignments, I tend to focus on reducing debugging time as much as possible by spending time coding things to make my life (and hopefully yours) easier.
19 |
20 | On the latest assignment we are required to describe DFAs (Deterministic Finite Automatas) in a [format][] with very low human readability, I knew immediately that I was going to write something to allow me to write my DFAs in a more human readable format so that I could sanely debug them. So instead of this:
21 |
22 | 2
23 | 0
24 | 1
25 | 5
26 | start
27 | zero
28 | 0mod3
29 | 1mod3
30 | 2mod3
31 | start
32 | 2
33 | zero
34 | 0mod3
35 | 8
36 | start 0 zero
37 | start 1 1mod3
38 | 1mod3 0 2mod3
39 | 1mod3 1 0mod3
40 | 2mod3 0 1mod3
41 | 2mod3 1 2mod3
42 | 0mod3 0 0mod3
43 | 0mod3 1 1mod3
44 |
45 | I can do this in Ruby:
46 |
47 | lang:ruby
48 |
49 | dfa = {
50 | :alphabet => %w(
51 | 0
52 | 1
53 | ),
54 | :states => %w(
55 | start
56 | zero
57 | 0mod3
58 | 1mod3
59 | 2mod3
60 | ),
61 | :initial => 'start',
62 | :final => %w(
63 | zero
64 | 0mod3
65 | ),
66 | :transitions => {
67 | 'start' => [
68 | ['0','zero'],
69 | ['1','1mod3']
70 | ],
71 | '1mod3' => [
72 | ['0','2mod3'],
73 | ['1','0mod3']
74 | ],
75 | '2mod3' => [
76 | ['0','1mod3'],
77 | ['1','2mod3']
78 | ],
79 | '0mod3' => [
80 | ['0','0mod3'],
81 | ['1','1mod3']
82 | ]
83 | }
84 | }
85 |
86 | For those of you not familiar with ruby, `%w(one two three)` is equivalent to `['one','two','three']`. Just a bit of syntactic sugar.
87 |
88 | You can generate the DFA format required by Marmoset with the following function:
89 |
90 | lang:ruby
91 |
92 | def dfa_output(dfa)
93 | lines = []
94 | lines << dfa[:alphabet].length.to_s
95 | dfa[:alphabet].each {|c| lines << c.to_s}
96 |
97 | lines << dfa[:states].length.to_s
98 | dfa[:states].each {|s| lines << s.to_s}
99 |
100 | lines << dfa[:initial].to_s
101 |
102 | lines << dfa[:final].length.to_s
103 | dfa[:final].each {|f| lines << f.to_s}
104 |
105 | transitions = []
106 | dfa[:transitions].each do |start,pair_array|
107 | pair_array.each do |(sym,targ)|
108 | if sym.is_a? String
109 | transitions << "#{start} #{sym} #{targ}"
110 | else
111 | sym.each do |s|
112 | transitions << "#{start} #{s} #{targ}"
113 | end
114 | end
115 | end
116 | end
117 |
118 | lines << transitions.length.to_s
119 | lines += transitions
120 |
121 | return lines.join("\n")
122 | end
123 |
124 | And then invoking with
125 |
126 | lang:ruby
127 |
128 | puts dfa_output(dfa)
129 |
130 | I designed the function with ranges and multiple transition tokens in mind, so you can do stuff like this:
131 |
132 | lang:ruby
133 |
134 | 'start_state' => [
135 | [%w(one that other),'end_state'],
136 | [1..9,'X']
137 | ]
138 |
139 | Now, this makes fixing problems, once discovered, much much simpler than trying to locate the error in the DFA format, but it still doesn't help much by way of identifying problems in the DFA itself. Probably the easiest way to look at a DFA is as a picture. Thankfully, there exists a set of tools perfect for this task known as [Graphviz][].
140 |
141 | Graphviz DOT
142 | ========
143 | 
144 |
145 | Graphviz is a collection of utilities used for visualizing graphs. The tool of interest for this post is DOT.
146 | It produces the kind of thing you can see above - which is the same graph described by the ruby code and the DFA format above.
147 |
148 | The syntax of DOT is very simple, and is better explained by [the DOT language wiki entry][dotwiki] than by the official documentation.
149 | The DOT description of the above graph is as follows:
150 |
151 | digraph dfa {
152 | "" [shape=none]
153 | "start" [shape=circle]
154 | "zero" [shape=doublecircle]
155 | "0mod3" [shape=doublecircle]
156 | "1mod3" [shape=circle]
157 | "2mod3" [shape=circle]
158 |
159 | "" -> "start"
160 | "1mod3" -> "2mod3" [label="0"]
161 | "1mod3" -> "0mod3" [label="1"]
162 | "0mod3" -> "0mod3" [label="0"]
163 | "0mod3" -> "1mod3" [label="1"]
164 | "2mod3" -> "1mod3" [label="0"]
165 | "2mod3" -> "2mod3" [label="1"]
166 | "start" -> "zero" [label="0"]
167 | "start" -> "1mod3" [label="1"]
168 | }
169 |
170 | And this is the ruby code to generate that output using the `dfa = { ... }` format at the beginning of the post.
171 |
172 | lang:ruby
173 |
174 | def dot_output(dfa)
175 | lines = []
176 | lines << "digraph dfa {"
177 |
178 | lines << %(\t"" [shape=none])
179 |
180 | dfa[:states].each do |state|
181 | if (dfa[:final].include? state)
182 | lines << %(\t"#{state}" [shape=doublecircle])
183 | else
184 | lines << %(\t"#{state}" [shape=circle])
185 | end
186 | end
187 |
188 | lines << ''
189 | lines << %(\t"" -> "#{dfa[:initial]}")
190 |
191 | dfa[:transitions].each do |start,pair_array|
192 | pair_array.each do |(sym,targ)|
193 | if sym.is_a? String
194 | lines << %(\t"#{start}" -> "#{targ}" [label="#{sym}"])
195 | else
196 | lines << %(\t"#{start}" -> "#{targ}" [label="[#{sym.collect(&:to_s).join(',')}]"])
197 | end
198 | end
199 | end
200 |
201 | lines << "}"
202 |
203 | return lines.join("\n")
204 | end
205 |
206 | Once you've installed Graphviz, you can generate a PNG of the graph by running
207 |
208 | lang:bash
209 |
210 | dot -Tpng < graph.dot > graph.png
211 |
212 | Enjoy CS241 A5.
213 |
214 | [dotwiki]: http://en.wikipedia.org/wiki/DOT_language
215 | [Graphviz]: http://www.graphviz.org/
216 | [format]: http://www.student.cs.uwaterloo.ca/~cs241/dfa/DFAfileformat.html
217 |
--------------------------------------------------------------------------------
/_posts/2011-01-12-hacker-cup-qualification-round-solutions.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Hacker Cup Qualification Round - Solutions
4 | tags: []
5 |
6 | status: publish
7 | type: post
8 | published: true
9 | meta:
10 | _edit_lock: "1294822476"
11 | _edit_last: "1"
12 | _wp_old_slug: ""
13 | ---
14 | Overall, I was fairly disappointed with the organization and general structure of hacker cup qualification round. Hopefully the next round will be better, but for now - here are the solutions to the three questions. Unfortunately it seems the questions themselves have been taken down. I did manage to score 3/3, so I can be fairly sure that these are correct to the spec of the questions Facebook wrote.
15 |
16 | Squares
17 | =====
18 |
19 | **Problem**: For each given z, Find the # of pairs (x,y) such that x <= y and x^2 + y^2 = z.
20 |
21 | **Solution**: Pre-generate the set of perfect squares. Iterate through this set. Check to see if z - x^2 is also in this set, where x is the current perfect square.
22 |
23 | **Implementation**:
24 |
25 | lang:cpp
26 |
27 | #include
28 | #include
29 | #include
30 | using namespace std;
31 |
32 | typedef long long unsigned int llu;
33 | set squares;
34 |
35 | int main() {
36 | for (int i = 0; i < 50000; i++) {
37 | llu i2 = i*i;
38 | if (i2 > 2147483647L * 2L) {
39 | break;
40 | } else {
41 | squares.insert(i2);
42 | }
43 | }
44 |
45 | int N;
46 | cin >> N;
47 |
48 | for (int i = 0; i < N; i++) {
49 | int num;
50 | cin >> num;
51 | int ans = 0;
52 | for(set::iterator it = squares.begin(); it != squares.end(); ++it) {
53 | llu first = *it;
54 | if (2 * first > num) break;
55 | if (squares.count(num - first)) {
56 | ans++;
57 | }
58 | }
59 | cout << ans << endl;
60 | }
61 | }
62 |
63 | Students
64 | ======
65 |
66 | **Problem**: For a given set of words (sequences of lowercase letters), find the the lexicographically lowest string result from the concatenation of these words in any order.
67 |
68 | **Solution**: I'm fairly sure simply sorting the words then concatenating them would suffice, but I was having issues string comparison yielding the same results at Facebook's output. Since the constraints were so low - maximum of 9 words per set, I simply did it exhaustively. This finishes easily within the 6 minute time limit since 9 factorial is relatively small.
69 |
70 | **Implementation**:
71 |
72 | lang:python
73 |
74 | from itertools import permutations
75 |
76 | def doit():
77 | words = raw_input().split()[1:]
78 |
79 | best = ""
80 |
81 | for x in permutations(words):
82 | concatted = "".join(x)
83 | if best == "" or concatted < best:
84 | best = concatted
85 |
86 | print best
87 |
88 | n = input()
89 |
90 | for z in range(n):
91 | doit()
92 |
93 | Pegs
94 | ===
95 |
96 | **Problem**: Given a peg board in the format like this:
97 |
98 | x.x.x
99 | x.x
100 | x.x.x
101 |
102 | defined by the number of rows and cols of pegs, except with a few pegs missing, like this:
103 |
104 | x.x.x.x.x
105 | x...x.x
106 | x...x.x.x
107 | x.x...x
108 | x.x.x.x.x
109 |
110 | Determine the optimal location to drop a ball in order to maximize the probability of the ball landing in a specific slot in the bottom row. The probability of the ball going to either side of a peg is 0.5.
111 |
112 | **Solution**: There's no real trick to this one - you just create an array of the probabilities that the ball reaches each available cell given which pegs are missing. This one is more of a coding problem than anything else.
113 |
114 | I'm sure I could have written a more elegant solution to this problem, but I just wanted to get it done.
115 |
116 | **Implementation**:
117 |
118 | lang:cpp
119 |
120 | #include
121 | #include
122 | #include
123 | #include
124 | using namespace std;
125 |
126 | void doit() {
127 | int R, C, K, M;
128 | cin >> R >> C >> K >> M;
129 | set > missing;
130 | for (int i = 0; i < M; i++) {
131 | int ri, ci;
132 | cin >> ri >> ci;
133 | missing.insert(make_pair(ri,ci));
134 | }
135 |
136 | int best_pos = 0;
137 | long double best_prob = 0;
138 | for (int cur_pos = 0; cur_pos < C-1; cur_pos++) {
139 | long double probs[R][C];
140 | for (int r = 0; r < R; r++) {
141 | for (int c = 0; c < C; c++) {
142 | probs[r][c] = 0.00;
143 | }
144 | }
145 | probs[0][cur_pos] = 1.00;
146 |
147 | for (int r = 1; r < R; r++) {
148 | if (r % 2 == 1) { // odd row
149 | for(int peg = 0; peg < C-1; peg++) {
150 | if (missing.count(make_pair(r,peg))) {
151 | if (r+1 < R) probs[r+1][peg] += probs[r-1][peg];
152 | } else {
153 | if (peg == 0) {
154 | probs[r][peg] += probs[r-1][peg];
155 | } else if (peg == C-2) {
156 | probs[r][peg-1] += probs[r-1][peg];
157 | } else {
158 | probs[r][peg] += 0.5 * probs[r-1][peg];
159 | probs[r][peg-1] += 0.5 * probs[r-1][peg];
160 | }
161 | }
162 | }
163 | } else { // even row
164 | for(int peg = 1; peg < C-1; peg++) {
165 | if (missing.count(make_pair(r,peg))) {
166 | if (r+1 < R) probs[r+1][peg-1] += probs[r-1][peg-1];
167 | } else {
168 | probs[r][peg] += 0.5 * probs[r-1][peg-1];
169 | probs[r][peg-1] += 0.5 * probs[r-1][peg-1];
170 | }
171 | }
172 | }
173 | }
174 |
175 | long double cur_prob = probs[R-1][K];
176 | if (cur_prob > best_prob) {
177 | best_prob = cur_prob;
178 | best_pos = cur_pos;
179 | }
180 | }
181 |
182 | printf("%d %.6Lf\n", best_pos, best_prob);
183 | }
184 |
185 | int main() {
186 | int z;
187 | cin >> z;
188 | while(z--)doit();
189 | }
190 |
--------------------------------------------------------------------------------
/_posts/2010-06-29-commandline-tips-and-tricks.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Commandline Tips and Tricks
4 | tags:
5 | - bash
6 | - commandline
7 | - shell
8 | status: publish
9 | type: post
10 | published: true
11 | meta:
12 | _edit_last: "1"
13 | _edit_lock: "1287294635"
14 | ---
15 | 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.
16 |
17 | I forget where I discovered this, but commandlinefu.com
19 | is an awesome site.
20 |
21 | 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.
22 |
23 | Here are some of the more useful ones from the site and a few I learned at work and elsewhere.
24 |
25 |
101 | $ cds ..
102 | -bash: cds: command not found
103 |
104 | $ ^s
105 | cd ..
106 |
107 |
List your last n commands
108 |
109 | lang:bash
110 |
111 | $ history 10
112 | 522 locate mysqld
113 | 523 sudo /Library/StartupItems/MySQLCOM/MySQLCOM start
114 | 524 sudo /Library/PreferencePanes/MySQL.prefPane/Contents/MacOS/MySQL
115 | 525 sudo mysqld_safe
116 | 526 sudo /usr/local/mysql/bin/mysqld_safe
117 | 527 mysql
118 | 528 history
119 | 529 history | awk '{a[$2]++}END{for(i in a){print a[i] " " i}}' | sort -rn | head
120 | 530 history
121 | 531 history 10
122 |
123 |
Edit and run a previous command
124 | From: Edit the last command line in an editor then execute @ commandlinefu.com
125 |
126 | This one requires a bit of explanation. The `fc` command will, by default, open
127 | your last command in the console editor you specify (emacs by default).
128 | If you want it to be vim, stick this in your `.bash_profile` to just run
129 | it when you want to use it.
130 |
131 | lang:bash
132 |
133 | export EDITOR=vim
134 |
135 | Then run `fc`, and it will open up your editor with your last command in it.
136 | Save and exit (`:wq`) to run that command.
137 | If you just want to execute it immediately, use `fc -s`.
138 |
139 | lang:bash
140 |
141 | $ history 5
142 | 86 cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf
143 | 87 echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf "
144 | 88 history 10
145 | 89 echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf "
146 | 90 history 5
147 |
148 | $ fc -s 87
149 | echo "cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf "
150 | cat /etc/apache2/passenger_pane_vhosts/searchgraph.local.vhost.conf
151 |
152 | If you don't care to look up the history number but happen to remember that it
153 | was the command you executed two lines ago, you can use negative history numbers
154 |
155 | $ echo hello
156 | hello
157 |
158 | $ echo world
159 | world
160 |
161 | $ fc -s -2
162 | echo hello
163 | hello
164 |
165 |
Follow new output to a log
166 | This one comes from my coworkers
167 |
168 | lang:bash
169 |
170 | $ tail -f ~/code/searchgraph/log/development.log
171 |
172 |
173 | Processing HomeController#bp (for 127.0.0.1 at 2010-06-23 22:19:27) [GET]
174 | Rendering home/bp
175 | Completed in 6ms (View: 5, DB: 0) | 200 OK [http://searchgraph.local/bp]
176 |
177 |
178 | Processing HomeController#bp (for 127.0.0.1 at 2010-06-23 22:20:46) [GET]
179 | Rendering home/bp
180 | Completed in 9ms (View: 7, DB: 0) | 200 OK [http://searchgraph.local/bp]
181 |
182 | Then if I go open up searchgraph.local, my console window will get updated on
183 | its own
184 |
185 |
Copying and pasting from files
186 |
187 | The pbcopy and pbpaste commands copy and paste from your clipboard.
188 |
189 | lang:bash
190 |
191 | $ echo test > test.txt
192 |
193 | $ pbcopy < test.txt
194 |
195 | $ pbpaste
196 | test
197 |
198 | And if you want to paste content you have in your clipboard to a file, just
199 | redirect, with
200 |
201 | lang:bash
202 |
203 | $ pbpaste > output.txt
204 |
205 | That's all for now - I'll write more down as I find them.
206 |
--------------------------------------------------------------------------------
/_posts/2012-04-16-declarative-programming-and-autosubscribe.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Declarative Programming and Autosubscribe
4 | tags:
5 | - javascript
6 | - api
7 | ---
8 |
9 | While I was watching the [Meteor screencast]() (if you haven't already seen it,
10 | go watch it), I paused around 1:35. They had just said "There's no callbacks, no
11 | bindings, and no controllers. It just works." after showing off the code
12 | something like the following:
13 |
14 | lang:javascript
15 |
16 | Template.color_list.colors = function() {
17 | return Colors.find({}, {sort: {likes: -1, name: 1}});
18 | }
19 |
20 | along with a [handlebars][] template kind of like this:
21 |
22 | {% raw %}
23 |
24 | lang:html
25 |
26 |
27 | {{#each colors}}
28 |
29 |
30 | {{ name }}
31 |
32 |
33 | {{/each}}
34 |
35 |
36 | {% endraw %}
37 |
38 | From an application developer's perspective, I thought "Wow. That is really
39 | amazing". This is a perfect example of how incredible working with declarative
40 | programming can be. Meteor itself focuses on reactive programming, but it
41 | facilitates declarative style in its live templates.
42 |
43 | From working on my own libraries and frameworks, I thought "Wow. How the hell
44 | did they get that to work?" More on this later.
45 |
46 | [Meteor screencast]: http://meteor.com/screencast
47 | [handlebars]: http://handlebarsjs.com/
48 |
49 | Declarative Programming (The What)
50 | ==================================
51 |
52 | Whenever you're trying to make anything, you want to spend your time figuring
53 | out _what_ you want in your application, not _how_ to get it there. Declarative
54 | programming tries to shift the focus from control flow to logic and state.
55 |
56 | A prime example of this is the divide between the creation and updating of views
57 | in imperative style. For example, consider a simple view that wraps an `h1`
58 | that reflects some data stored in a model.
59 |
60 | Ultimately the goal here is to have an `h1` that says "Salutations, NAME", where
61 | NAME is always synchronized with the model.
62 |
63 | Imperative Creation and Update
64 | ------------------------------
65 |
66 | If you were to write it in this style, you would probably do it with jQuery or
67 | some similar DOM manipulation library, so that's what we'll use here.
68 |
69 | lang:javascript
70 |
71 | var HelloView = function() {
72 | this.h1 = $('');
73 |
74 | var self = this;
75 | model.bind('update', function() {
76 | self.update();
77 | });
78 | self.update();
79 | };
80 |
81 | HelloView.prototype.update = function() {
82 | this.h1.text("Salutations, " + Model.get('name') + "!");
83 | }
84 |
85 | Mentally, I had to translate the original task into "create an element,
86 | listen for any updates to the model, then update the view to match the model".
87 | This isn't so bad, and is definitely better than the model knowing about the
88 | view, but there's room for improvement.
89 |
90 | Namely, it's very apparent that the creation of the elements and the
91 | synchronization of the data exist as two distinct tasks, when they really don't
92 | need to.
93 |
94 | Declarative Creation and Update
95 | -------------------------------
96 |
97 | Here's the same example written in Meteor style declarative programming.
98 |
99 | The template code:
100 |
101 | {% raw %}
102 |
103 | lang:html
104 |
105 |
106 |
Salutations, {{ name }}!
107 |
108 |
109 | {% endraw %}
110 |
111 | And the JavaScript:
112 |
113 | lang:javascript
114 |
115 | Template.hello_view.name = function() {
116 | return Model.get('name');
117 | }
118 |
119 | In this style, we aren't manually wiring up synchronization at all. We aren't
120 | thinking in a "when this, then that" kind of mindset. We just say "this is how
121 | it always should be". As a side effect, the mental separation between create and
122 | update becomes unnecessary. You don't need to consider what happens when the
123 | model changes - the view just _always_ reflects the model.
124 |
125 | While the amount of code isn't significantly different between these two
126 | examples, I believe that as applications become more complex, the savings in the
127 | declarative style will increase, and the logic will be easier to follow.
128 |
129 | Autosubscribe (The How)
130 | =======================
131 |
132 | I've done a bunch of JS development by now, and this is one of the first things
133 | I've tripped over in a long time thinking "How is this possible?". I'm not
134 | talking about how the task was algorithmically complicated, I'm talking about
135 | how it looked like there was something essential _missing_ from the code.
136 |
137 | In particular, I couldn't understand how the views knew when to update, since
138 | there was no event binding anywhere.
139 |
140 | The solution comes from Meteor's concepts of "autosubscribe".
141 |
142 | The basic idea is to establish a global context that things are currently
143 | running in and check this whenever any mutable data is accessed. If the accessor
144 | notices that a global context is active, it will subscribe that context to be
145 | re-run when that data changes.
146 |
147 | A basic implementation would look something like this:
148 |
149 | lang:javascript
150 |
151 | var Magic = {
152 | context: null
153 | autosubscribe: function(cb) {
154 | Magic.context = cb;
155 | Magic.context();
156 | }
157 | };
158 |
159 | var Model = function() {
160 | this.props = {};
161 | };
162 |
163 | Model.prototype.get = function(prop) {
164 | if (Magic.context != null) {
165 | // An autosubscribe context is active, so subscribe it to future
166 | // changes to the property
167 | this.bind('change:' + prop, Magic.context);
168 | }
169 | return this.props[prop];
170 | }
171 |
172 | Model.prototype.set = function(prop, val) {
173 | this.props[prop] = val;
174 | this.trigger('change: ' + prop);
175 | }
176 |
177 | // Implementations of bind and trigger omitted, but they would act exactly
178 | // like Backbone's
179 |
180 | Then it could be used like this - no manual event binding!
181 |
182 | lang:javascript
183 |
184 | var person = new Model();
185 | person.set('name', 'Odeen');
186 |
187 | Magic.autosubscribe(function() {
188 | $('h1').text('Salutations, ' + person.get('name'));
189 | });
190 |
191 | person.set('name', 'Estwald');
192 |
193 | While Meteor did not invent the concept of live templates, this method of
194 | dodging event binding seems the most powerful. While the idea of client-side
195 | access to the database seems a little scary, and it might end up hairier than
196 | normal client-server architecture if you want security, there are some ideas
197 | from Meteor that I think are a definite step in the right direction.
198 |
--------------------------------------------------------------------------------
/_posts/2011-06-25-complex-asynchronous-queries-in-javascript.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: Complex Asynchronous Queries in JavaScript
4 | tags:
5 | - AJAX
6 | - asynchronous
7 | - javascript
8 | - Karma
9 | status: publish
10 | type: post
11 | published: true
12 | meta:
13 | _edit_lock: "1309066702"
14 | _edit_last: "1"
15 | _wp_old_slug: ""
16 | ---
17 | Over the past couple of weeks, I finally got around to working on personal projects at an event I decided to create with the help of my housemates which we call [SEHackDay][]. The first and only project I worked on over the 3 nights was [Karma][], a Facebook App which gives you statistics about your posts and how they stack up against your friends.
18 |
19 | While it has not been remotely as successful as [The Wub Machine][] by one of my housemates, [Peter Sobot][], it did make me think about how to make complex asynchronous queries in JavaScript.
20 |
21 | While I was actually dealing with `FB.api` calls to the Facebook API, I'll use the example of jQuery AJAX queries for the purposes of this blog post, since they are more common. Before we delve into the complex examples, let's take a look at the basics.
22 |
23 | [Karma]: http://myfriendkarma.heroku.com/
24 | [SEHackDay]: http://www.sehackday.com/
25 | [The Wub Machine]: http://the.wubmachine.com/
26 | [Peter Sobot]: http://www.petersobot.com/
27 |
28 | Asynchronous Callbacks
29 | ---------------------
30 | *If you already understand AJAX, skip to the complex queries below*.
31 |
32 | JavaScript is, by nature, an asynchronous language. A few of the language's built-in constructs use callbacks, including `setTimeout` and `addEventListener`. The basic principle of a callback is this:
33 |
34 | **When something happens, do this, but keep doing other things while you're waiting.**
35 |
36 | Here's a simple example:
37 |
38 | lang:js
39 |
40 | window.setTimeout(function() {
41 | console.log("Three");
42 | }, 1000);
43 |
44 | console.log("One");
45 | console.log("Two");
46 |
47 | Run that with Firebug, Chrome Developer Tools or whatever other console logging tools you work with and you'll see that the numbers come out "One", "Two" and then finally "Three" after a one second delay.
48 |
49 | A more useful example is retrieving data in jQuery through AJAX from the server. AJAX (for those unfamiliar) allows you to retrieve information on a web page from the server without necessitating a full page reload. A query typically looks something like this:
50 |
51 | lang:js
52 |
53 | $.ajax({
54 | url: '/records.php',
55 | success: function(data) {
56 | console.log(data);
57 | }
58 | });
59 |
60 | Which says roughly: **Send an HTTP GET request to the path `/date`. When the server responds, log the response body to the console.**
61 |
62 | *For those of you reading this and unfamiliar with complex JavaScript, you should probably stop here, fiddle around with asynchronous callbacks and AJAX, and then consider continuing.*
63 |
64 | Sequential Requests with a Callback
65 | ------------------------------
66 |
67 | **Scenario**: I want to request a series of documents, one after another, then run a callback after they've all completed. A common example is running through paginated data when you don't know how many pages there are.
68 |
69 | **Solution**: Make the call recursive, keeping track of the data retrieved, then run the final callback when the last request completes.
70 |
71 | For example, let's assume a page `records.php` returns the latest 10 records in a database as JSON, with a parameter `offset`, specifying how many records from the front to skip. We'll assume if it returns fewer than 10 results, there are no more. The coded solution will look something like this:
72 |
73 | lang:js
74 |
75 | function allRecords(callback, offset, data) {
76 | if (typeof offset === 'undefined') {
77 | offset = 0;
78 | }
79 | if (typeof data === 'undefined') {
80 | data = [];
81 | }
82 | $.ajax({
83 | url: 'records.php',
84 | data: {offset: offset},
85 | success: function(dataChunk) {
86 | data = data.concat(dataChunk);
87 | if (dataChunk.length < 10) {
88 | callback(data);
89 | } else {
90 | allRecords(callback, offset + 10, data);
91 | }
92 | }
93 | });
94 | }
95 |
96 | And since there's a check for the `undefined` state of the second two parameters, they can be omitted when the function is actually called, like so:
97 |
98 | lang:js
99 |
100 | allRecords(function(allData) {
101 | console.log(allData);
102 | });
103 |
104 | And this callback will be called only after the last request finishes. Assuming there are 47 records, it would make the following requests in series, then run the callback with the concatenated arrays of data.
105 |
106 | records.php?offset=0
107 | records.php?offset=10
108 | records.php?offset=20
109 | records.php?offset=30
110 | records.php?offset=40
111 |
112 | Note that this solution ensures that the records are returned in order.
113 |
114 | Parallel Requests with a Callback
115 | ----------------------------
116 |
117 | **Scenario**: I know exactly which documents I need, but I can't get them all at once, and I want to run a callback after all of them have been retrieved. A common use case is when you know exactly how many records there are, but for whatever reason (usually API limits), you can't get them all at once.
118 |
119 | While a simple modification of the above solution would work, it's inefficient. We can send more than one AJAX response at a time, so we might as well wait on more than one at a time. Chances are we can send at least the second request while we're waiting for the first to return.
120 |
121 | **Solution**: Send all the requests at once, noting how many were sent. Then count the responses as they come back. Once the count equals the number of requests sent, run the callback. Note that this does nothing to preserve order (and usually we don't care).
122 |
123 | Assuming the same general rules as above, let's say we want to retrieve the most recent n records.
124 |
125 | lang:js
126 |
127 | function nRecords(n, callback) {
128 | var nCallsNeeded = Math.ceil(n / 10);
129 | var nCallsFinished = 0;
130 | var data = [];
131 | for (var i = 0; i < nCallsNeeded; i++) {
132 | $.ajax({
133 | url: 'records.php',
134 | data: {offset : i * 10},
135 | success: function(dataChunk) {
136 | data = data.concat(dataChunk);
137 | nCallsFinished += 1;
138 | if (nCallsFinished == nCallsNeeded) {
139 | callback(data.slice(0,n));
140 | }
141 | }
142 | });
143 | }
144 | }
145 |
146 | So if I want the latest 23 records, I would get them like so:
147 |
148 | lang:js
149 |
150 | nRecords(23, function(allData) {
151 | console.log(allData);
152 | });
153 |
154 | If you have suggestions on ways to improve these solutions, I'm all ears.
155 |
156 | Also, if you are interested in what your highest rated post or just generally want to see your own statistics on pretty graphs, please check out [Karma][].
157 |
--------------------------------------------------------------------------------
/_posts/2012-08-14-khan-academy-computer-science.md:
--------------------------------------------------------------------------------
1 | ---
2 | layout: post
3 | title: "Khan Academy Computer Science: Instant Gratification and Bragging Rights"
4 | tags:
5 | - mercurial
6 | - arcanist
7 | - khan-academy
8 | ---
9 |
10 | 
11 |
12 | When I was 6 years old, my mom asked me what kind of summer camp I wanted to go
13 | to. I excitedly exclaimed "LEGO!" She laughed it off a little then asked me to
14 | choose some other options, so I picked a couple sports camps and trampoline
15 | camp.
16 |
17 | A few weeks later, she found a Science and Technology camp called [Virtual
18 | Ventures][1] which actually did have playing with LEGO as part of the camp
19 | activities. But it was even better than that -- it was LEGO robotics!
20 |
21 | I went to that camp for the first time in 1998. In the 11 years that followed, I
22 | spent almost every full summer there, first as a camper, then as a volunteer,
23 | then 3 summers as an instructor. (I played with LEGO almost every week of it.)
24 | The life changing thing I got out of it was a fascination with programming.
25 |
26 | When I started there, I was saving HTML files to 3.5" floppies showing off my
27 | talent with `
Comments
42 | 43 | 51 | 52 | blog comments powered by Disqus 53 | {% endif %} 54 |