Archive for the 'Programming' Category

Designing Fiddle Code Storage

Feb 17 2012 Published by under Fiddle Salad,Programming,Python Fiddle

I just had an aha! insight 5 minutes ago when working on the design to be implemented next month. The previous storage format used string splitting and joining. Everyone who’s worked with it recognizes the mistake immediately, though the solution didn’t come until I spent a bit of time designing the system.

Previously, get_code and set_code belonged to the abstract factory. Looking at the way things are used, it may better facilitate the implementation of the local history feature if a code storage class was used. I took a snapshot when I got the idea for the JSON format, so things are still a bit disorganized:

The realization is that this design doesn’t require the back-end to store all the different languages used in the fiddle. It allows both PythonFiddle, which stores only Python, and FiddleSalad, which mixes languages, to use the same storage backend. They already do, but I’m getting ready to go to the next stage. The /python/ and /coffeescript/ URL structure is still good for SEO and linking purposes.

No responses yet

Course Planner Authentication Libraries

Feb 11 2012 Published by under CourseTree,Programming

Just working on this project yesterday, I discovered the Facebook login was no longer working. I noticed from my other projects Facebook changed their API and the library needed to be upgraded.  Back in 2009, the best library available was socialauth. Now I’m using social_auth in my newer projects. There’s more documentation at first glance. Although problems showed up from time to time, upgrading always fixed them. So I would recommend social_auth.

It turns out I could use an independent login module, already a part of the shared codebase for 2 other projects, at a cost. The cost is to add the login button to keep the logic flow the same. Later, I used a dependent observable to automatically save after the authentication state changes. Simply pass the load or save function as an argument to the login decorator (Python term, same concept in JavaScript):

loginRequired: function (action) {
        if (viewModel.authenticated()) {
            return false;
        } else {
            viewModel.setMessage(loginPrompt, 'warning');
            viewModel.afterLogin = action;
            return true;
        }
    },

The save function begins by checking if the user is logged in:

save: function () {
        if (viewModel.loginRequired(viewModel.save)) return;

afterLogin is called in the observable:

ko.dependentObservable(function() {
    if (viewModel.authenticated() && viewModel.message() == loginPrompt) {
        viewModel.setMessage('');
        viewModel.afterLogin();
    }
});

After a hectic few minutes of upgrading the site with about 3 different kinds of server errors and many email debug messages, I finished upgrading the database and the settings file.

Maybe next time I will use if DEBUG statements in my settings file so it can be copied straight to server. But the main reason I opted not to was because of the facebook, twitter, and google keys which had to be set differently. On the other hand, those can be in a conditional debug statement, too.
Overall, it was a thrill to work with the project again, bring back the gifts from more recent projects, and see the brilliantly written code.

No responses yet

Coursetree Libraries Upgraded

Feb 10 2012 Published by under CourseTree

Compatibility with the old API means a library can be upgraded without affecting the codebase. I recently upgraded these libraries used in coursetree:

jQuery UI <1.8.14 -> 1.8.17

Raphaël 1.5 -> 2.0.2

In the case of  Raphaël, the size was reduced from 151 kB to 86 kB. However, the JIT and Knockout libraries did not maintain compatibility, because I was an early adopter of the canvas and MVC libraries. Regardless, there is a speed improvement for new visitors because I combined many small JavaScript files into larger ones.

No responses yet

jQuery Scrolling Menu

Jan 30 2012 Published by under CourseTree

When implementing the scrolling menu for Chrome and Firefox, I prototyped the menu using fiddlesalad’s LESS CSS editor. Then, I copied the compiled CSS and started coding with a straight forward procedural approach.

function displayMenu() {
    var selected = [$('#menu ul:first li.selected'), $('#menu ul:eq(1) li.selected')];
    if (selected[0].length) $('#menu div:first').scrollTo(selected[0]);
    if (selected[1].length) $('#menu div:eq(1)').scrollTo(selected[1]);
    $('#menu ul:first').parallax({
        takeoverFactor: .2,
        mouseport: $('#menu ul:first').parent(),
        xparallax: false
    });
    $('#menu ul:eq(1)').parallax({
        takeoverFactor: .2,
        mouseport: $('#menu ul:eq(1)').parent(),
        xparallax: false
    });
    $('#menu ul:first li').click(function () {
        window.location.assign(ajax_url + 'calendar/' + $(this).text() + '/');
    });
    $('#menu ul:eq(1) li').click(function () {
        var course = $(this).text().split(' ');
        window.location.assign(ajax_url + 'calendar/' + course[0] + '/' + course[1] + '/');
    });
}

$('#menu ul:first li.last').livequery(displayMenu);

Later, I noticed that the performance can be improved by caching jQuery results. Also, many lines of code were repetitive. Before moving onto the more challenging part of the menu design, scrolling to the current location, I made it object oriented using plain JavaScript.

function Menu(selector) {
    this.selector = selector; // #menu ul:first
    this.$list = $(this.selector);
    this.$container = this.$list.parent();
    this.display = bindMethod(this, function () {
        var selected = this.$list.find('.selected').prev(),
            prevCount = 0;
        var prev = selected.prev();
        while (selected.length && prevCount++ < 3)
            selected = selected.prev();
        // only course pages have enough height, otherwise the courses at the top cannot be reached
        if (selected.length && window.location.pathname.split('/').length == 5)
            this.$container.scrollTo(selected);
        this.$list.parallax({
            takeoverFactor: .2,
            mouseport: this.$container,
            xparallax: false
        });
    });
    this.$list.find('.last').livequery(this.display);
    this.scrollTop = bindMethod(this, function () {
        if (this.activated)
            this.$container.scrollTo(this.$list.find('li:first'));
    });
    this.$container.mouseenter(bindMethod(this, function () {
        this.activated = true;
    }))
    this.width = function () {
        return this.$container.width();
    }
}

Writing classes in JavaScript brings unexpected quirks, such as this being set to an HTML Element. However, using an additional helper, bindMethod, this problem is avoided. I used the scrollTop method to scroll to the top of the menu:

var deptMenu = new Menu('#menu ul:first'), courseMenu = new Menu('#menu ul:eq(1)');
var $deptTop = $('#menu').prev().find('div:first'), $courseTop = $('#menu').prev().find('div:eq(1)');
$deptTop.width(deptMenu.width());
$courseTop.width(courseMenu.width());
$deptTop.hover(deptMenu.scrollTop);
$courseTop.hover(courseMenu.scrollTop);

 

No responses yet

Coursetree Bugfixes

Nov 30 2011 Published by under CourseTree

Most bugs in the system are now edge cases, while others are produced by aging.

  • External links to online courses from the OpenCourseWare initiative (mostly MIT) are once again available due to the search service being down for several months
  • Twitter social auth back to working after upgrading the package
  • Fixed bug where the splash had a z-index of 1, blocking interaction with the page. This only happened when loading or saving and the splash wasn’t played. Due to the splash being disabled for development, this bug could only be found in production.
  • Added exception catching when student doesn’t exist in model

No responses yet

AJAX Callbacks and Function Closures

Nov 30 2011 Published by under CourseTree

Working with JavaScript closures in an asynchronous context (callbacks) was a memorable experience when I first wrote the code for course links. Now I had a chance to look at it again after restoring the functionality during a recent bugfix.

A look under the hood of the fourth nested AJAX call:

  • postCORS is a function that provides cross browser cross origin POST requests. XDomain request is used for IE, while the usual jQuery.post is used for othe browsers.
  • because each callback needs to have an associated site dictionary from the previous callback, they need to have their own scope. Otherwise, a global variable would be overwritten each time through the loop in the parent closure.
  • g simply returns whatever is passed to it. This is one way of creating an independent scope. A related way is to call new on a function that is a constructor.

No responses yet

PythonFiddle introduces Python scripting for the web

Nov 18 2011 Published by under Python Fiddle

The initial release of PythonFiddle attracted a lot of attention due to an article on SlashDot, one of the best places to post general technology news. Although the first version featured cutting edge technology that would run a Python interpreter in the browser, the general consensus is that it’s good for sharing Python code on the web, but not much else. With some afterthought (or maybe forethought, because this was the original intention), I made a new version for web development.

The new PythonFiddle aims to solve problems with JavaScript by offering Python as a replacement. Developers  prefer class based inheritance to JavaScript’s prototypal inheritance, mostly because it’s mainstream. Writing applications with classes built into the language is helpful in large projects, along with the removal of global scope. For small projects, Python’s pseudo-code like syntax is preferable to the ancient C syntax.

The large collection of third-party tools in JavaScript is not overlooked, as in the case of Google’s Dart programming language. JavaScript libraries such as jQuery can be used directly, others can be added as external resources. With PythonFiddle, web developers who use Python server-side are now able to use the same language client-side. Besides the Python to JavaScript compiler, other advantages PythonFiddle offer include live reloading of the page, Less, and Zen Coding.

No responses yet

Several Thousand Visitors Second Day Launch

Aug 30 2011 Published by under Python Fiddle,Singularitarian

A recent site I launched received a lot of attention. It may have been the only way to get the momentum going, since Google wouldn’t index a site with no content.

Fortunately, I spent a week before launch optimizing the page loading, serving static files from Amazon, and fixing usability bugs. So the result is a very smooth launch, even when serving many visitors per second. Some users who experienced slow loading issues may have been waiting for the browser to download a 1.3 or 2.0 MB file, which could have caused a traffic jam on a static file server. The technique used here was to serve files that are already compressed with lzma and gzip, respectively. Due to htaccess configuration not being available on Amazon, it was decided to serve these from another server.

The most surprising effect was that Google seemed to have picked up the link as soon as it appeared, along with other sites that mirror content.

No responses yet

Coursetree: the Epilogue and Return

Aug 23 2011 Published by under Programming

The sign the adventure is over is always a return to the starting point after traveling to the other side of the world. In the early days when I wrote the crawler for courses, I gathered faculty links from a table by writing a small scraper for the links. The exact method is not clear, but it could have also been done in numerous other ways. Later, I found only those links when I came back to the project after several months. One reason I may not have recorded the method may be that there were duplicates in them, such as 100’s and 200’s referring to the same page.

At the end of this journey, I have many pages of documentation on the system. However, the system still lacked a way of handling new course pages. Now the system is complete, with only a few lines of code, which would have been impossible without the journey:

from urllib import urlopen
html = urlopen("http://ugradcalendar.uwaterloo.ca/page/Course-Descriptions-Index").read()
from BeautifulSoup import BeautifulSoup, SoupStrainer
import re, cgi
from urlparse import urlparse
linksToCourses = SoupStrainer('a', href=re.compile('courses.aspx'))
links = [tag['href'] for tag in BeautifulSoup(html, parseOnlyThese=linksToCourses)]
faculties = list(set([cgi.parse_qs(urlparse(link)[4])['Code'][0] for link in links]))
faculties
[u'CIVE',
u'ARBUS',
u'ECON',
u'INTEG',
u'JS',
u'REES',
u'WS',
u'DUTCH',
u'CHEM',
u'AVIA',
u'PSYCH',
u'SPD',
u'SPCOM',
u'CROAT',
u'CHE',
u'HRM',
u'ENBUS',
u'SCBUS',
u'PACS',
u'SYDE',
u'KIN',
u'LAT',
u'STAT',
u'INDEV',
u'SMF',
u'CMW',
u'FINE',
u'PORT',
u'GER',
u'KOREA',
u'SCI',
u'BUS',
u'SWREN',
u'HIST',
u'AMATH',
u'PD',
u'RUSS',
u'OPTOM',
u'AFM',
u'COOP',
u'ECE',
u'MSCI',
u'NATST',
u'GRK',
u'ME',
u'INTTS',
u'RS',
u'GERON',
u'ITALST',
u'HLTH',
u'JAPAN',
u'MATH',
u'PLAN',
u'FR',
u'PHIL',
u'ENGL',
u'ISS',
u'ITAL',
u'PDENG',
u'SOCWK',
u'REC',
u'ARTS',
u'MTHEL',
u'NE',
u'BIOL',
u'APPLS',
u'EARTH',
u'CLAS',
u'CO',
u'CM',
u'ACTSC',
u'POLSH',
u'DRAMA',
u'COMM',
u'CS',
u'SPAN',
u'SI',
u'PSCI',
u'CHINA',
u'WKRPT',
u'SE',
u'HUMSC',
u'ERS',
u'ARCH',
u'EASIA',
u'DAC',
u'PMATH',
u'LS',
u'GEOE',
u'GEOG',
u'PHYS',
u'PDPHRM',
u'IS',
u'SOC',
u'STV',
u'MUSIC',
u'ANTH',
u'ESL',
u'MTE',
u'ENVS',
u'INTST',
u'PHARM',
u'GENE',
u'ENVE']

This gets a list of faculties from the table by returning a set.


import MySQLdb
db = MySQLdb.connect(user='', db='', passwd='', host='')
cursor = db.cursor()
cursor.execute('SELECT faculty FROM faculties ORDER BY faculty')
db_faculties = [row[0] for row in cursor.fetchall()]
db.close()
set(faculties) - (set(faculties) & set(db_faculties))
set([u'BUS', u'COOP', u'PD', u'PDPHRM'])

By subtracting the intersection of faculties in the database from the faculties in the table, the set of new items are found. The new items may be added to the database. I leave it to the reader.

Not only is this the first step when updating the database, it is a miniature model of the entire application. Thus it wraps everything up in a way that serves a purpose.

No responses yet

Javascript LZMA Decompression

Aug 13 2011 Published by under Linux,Programming

In modern browsers, g-zip compression is a standard feature. The typical compression ratio for a plain text file is 30%, reducing the download time of web content by 70% and making it load 2-3 times faster. In spite of the speed up, g-zip is an old algorithm based on LZ77. Since then, newer algorithms have been invented, with LZMA being the standard. On Linux, LZMA typically produces files half the size compared to g-zip. This tutorial will show you how to use an LZMA compressed file produced by the standard lzma command on Unix machines directly in a client side web application. The rest of the post assumes you have the JavaScript libraries for LZMA and binary AJAX set up.

First, Make a Compressed File

echo "Hello, world." | lzma -3 > hello.lzma

Next,  Read Binary Data

<script src="../src/jquery-1.4.4-binary-ajax.js"></script>
<script src="../src/jdataview.js"></script>
<script>
function unzip(data) {
    // Make a view on the data
    var view = new jDataView(data);

    var int_arr = new Array;

    while (view.tell() < view.length) {

       int_arr.push(view.getUint8(view.tell()));

   }
   console.log(int_arr.length);
   console.log(int_arr);

}

// Download the file
$.get('hello.lzma', unzip, 'binary');
</script>

This is a pretty simple step, except the while loop counter may be unintuitive. getUint8 increments the file pointer, though it wasn’t documented in the API specification. I spent an hour or so comparing the output in hex. One of the problem was that

5d 00 00 08 00 0d 00 00 00 00 00 00 00 00

is the same as

5d 00 00 08 00 0d ff ff ff ff ff ff ff ff

in little Endian. You can try it in the decompressor, just replace the bytes in the hello world lzma on compression level 3. However, I figured out the problem as soon as I compared view.length and int_arr.length. They were multiples of 2! That always has significance in computing, in this case it meant I was reading every other byte. After correcting the while loop, I moved onto decoding the binary.

Third, Enjoy the Decoding

Yes, this is a rather boring thing to do while waiting, but do enjoy it.

    lzma.decompress(int_arr, function(result) {
        $('body').append($('<textarea></textarea>').val(result));
    })

Benefits

Using LZMA compression rather than g-zip, I was able to reduce a g-zipped file to 2/3 of its size, reducing the download time by 33%. The LZMA decompression algorithm could be improved to use an array to store results, joining them at the end, rather than appending to a string. It is not recommended to use this method unless you have large files. The libraries themselves take up about 50kb with g-zip. Furthermore, it is unsuitable for downloads where files are sent directly to the user, without being used by the application, since the user would have the decompression utilities.

One response so far

« Prev - Next »