Designing Fiddle Code Storage

Feb 17 2012

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

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

Recycle Bin Alias on Windows

Feb 11 2012

While working with the command line and SQL, I accidentally discovered a shortcut for the recycle bin on Windows. That is, the $  Recycle Bin(ary).

Yes, that means everything resides in the recycle bin. Literally, /* means everything under the root. All things under the root are being continually recycled. Coincidentally, I am recycling lots old code. Throwing stuff away and putting the new parts in.

The other observation is that */ is here. Everything leads here.

No responses yet

Coursetree Libraries Upgraded

Feb 10 2012

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

EAP Study Guide Updated

Jan 31 2012

The Engineering as a Profession question and answer sheet was made about 3 years ago. Last time I changed the URL to make it more relevant in searches. However, I was still surprised to see more answer submissions this time. Today, I added those answers and fixed character issues that appeared since I converted files to UTF-8.

It definitely makes answering those questions on the exam easier. I developed and used it myself, with the goal of spending minimal amount of time on it. Separate files stored questions from the PDF study guide and the answers from Word, which are combined using a simple PHP program.

No responses yet

jQuery Scrolling Menu

Jan 30 2012

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

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

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

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

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

« Newer - Older »