Category Archives: Web

SimpleAB

I’ll be the first to admit that my dad did my SAT book’s website (www.satessayace.com); I did nothing but proofread and offer wordsmithing suggestions. As part of the website design process, my dad and I decided that we should do some “AB” testing of website sales copy, meaning that we would display one of two possible websites to our users at random.

My dad complained to me that most of the existing AB testing solutions were either too difficult to use or were far too complex for the simple act of choosing a page to show to a user. I decided to fix that: I wrote a jQuery plugin called SimpleAB that would switch views in and out. And it only switches views in and out.

The premise is simple: add the class “simpleab-#” (where # is a natural number) to all the elements that you wish to switch in and out with SimpleAB. Elements with the same number will be shown together. That way, you can separate the text and structure of your elements of the page and only AB test the parts you want to.

SimpleAB also has some other nice features:

  • You can choose whether or not to “persist” a view. That is, SimpleAB will set a cookie that will cause the user to always see the same view.
  • You can customize the SimpleAB class name, so that if “simpleab-#” doesn’t float your boat, you can use “mycoolwebsite-#” instead!
  • Even if you persist views, the “flip” feature lets you make sure that all your views look beautiful by iterating through the views as you refresh your SimpleAB page.

Want to see more? SimpleAB is MIT licensed! Check it out on my GitHub: https://github.com/parsonsj/SimpleAB

Reason for my Absence: Freshman Fall

The good news is that I’m done with school until February; I’ve been on break since the middle of December; everything has gone very well since I left. Still, I feel as though I should update my blog–even during the school year–from now on. I learned tons and tons of interesting things this fall, and I’d love to share them!

Oh yeah, and one of my friends (my neighbor, in fact) has started blogging, and I would never want to miss out on the fun. The difference is that he’s writing his own blogging platform, and I’m lazy and running WordPress.

Maybe I’ll do something cool with Django someday.

In the meantime, it’s good to be authoring some content again. I’ll start posting a lot more regularly (no, really, I will this time), especially since I’ll be authoring lots of cool software in 6.01 (Intro to Electrical Engineering and Computer Science I) next semester. Here’s what I’ve done since I left:

Wrote a Book

A long time ago, I started authoring (and nearly published) a blog post about how one could beat the SAT essay. I expanded that rough post into a much longer handbook that I lovingly call The SAT Essay Ace Template. You can get your own copy at http://satessayace.com. Kindle and print (!) versions are forthcoming on Amazon!

Almost Released Hawgrade GradeSolve

As I reread my blog, I realized that I hadn’t given any of my last summer’s work nearly as much love as it deserved. I released a beta version (that I redesigned and am almost ready to release) of a web application remake of Hawgrade that I call GradeSolve. Learn more at GradeSolve‘s website.

Joined a Fraternity

Or, as my girlfriend’s father calls it, a franerdity. I’m a pledge-member of Phi Kappa Sigma at MIT. Hopefully, I’ll post that I am a brother within a few weeks.

Lived Through Freshman Year

I did well, even with Pass/No Record taken out of the picture. I’m proud of how I did.

Started Writing More Software

I’m working with a friend to expand GradeSolve into something even more useful. I’ll probably be posting a lot of code snippets from my work.

Speaking of code snippets, I’ve been working with updating Django model data with user input from ModelForms. This would normally be trivial, except I’m getting my data via AJAX: I cannot simply render a ModelForm with data in a GET request, and I don’t think it’s necessary for all relevant fields to be present in the POST data for the update.

In other words, I want to update what a user tells me to update, and leave everything else alone. Simply specifying a model instance for a ModelForm does not work. Luckily, you can create a new dictionary to which to bind the ModelForm for validation. The dictionary contains the data supplied by the user, and form fields left blank are automatically populated from the model instance. Here’s the method:

def edited_form_data_merge(post_data, model_instance, form_fields):
	data = { }
	for field in form_fields:
		if field in post_data:
			data[field] = post_data[field]
		else:
			data[field] = getattr(model_instance, field)
 
	return data

The method should be invoked like so (Subject is a model, SubjectForm is a ModelForm for Subject):

from x.y.z import Subject, SubjectForm, edited_form_data_merge
# ...
subject = Subject.objects.get(id = subject_id)
frm_data = edited_form_data_merge(request.POST, subject, SubjectForm._meta.fields)
form = SubjectForm(frm_data, instance = subject)
# ...

The form will always validate (assuming correct user input), and will reflect only changes: if data is not specified by a user, then data from the model is used instead.

One very interesting part of this is SubjectForm._meta.fields. This collection contains a string list of fields that makes it very easy to create the new data dictionary.

It’s good to be back!

Easy SQL Query Counting in Django

I’ve become somewhat of a Django ninja during my time as GradeSolve’s developer (okay, a Django hacker…). One of the things that I have noticed as I have written several thousand lines of Django code is that SQL queries tend to be made pretty regularly–often, a little too regularly. Some of GradeSolve’s pages were loading a little slowly for my tastes, so I decided to do some basic SQL profiling to see where the trouble was.

The issue there was that django-debug-toolbar didn’t want to play nice, and I lacked the motivation to try to get it working. Instead, I re-invented the wheel a little bit and write a simple piece of middleware to print out the SQL execution time and number of SQL queries made for a particular request. Obviously, this is going to go away in the production version of GradeSolve (which is being released in eight days!), but for the time being, I like the extra information on my debug console.

Anyway, here’s the middleware class. Stick this in one of your project’s files:

from django.db import connection
class SqlPrintMiddleware(object):
    def process_response(self, request, response):
        sqltime = 0 # Variable to store execution time
        for query in connection.queries:
            sqltime += float(query["time"])  # Add the time that the query took to the total
 
        # len(connection.queries) = total number of queries
        print "Page render: " + unicode(sqltime) + "sec for " + unicode(len(connection.queries)) + " queries"
 
        return response

Now, in your settings.py file, add the path to the middleware class. For example, if your project’s name is gradesolve and your file’s name is middleware.py, your middleware classes setting would end up looking like:

MIDDLEWARE_CLASSES = (
    # ...
    'gradesolve.middleware.SqlPrintMiddleware',
    # ...
)

Happy (very simple) profiling!

How to Keep Unoconv + Apache From Making You Sad

Server-side conversion of documents is a fairly common task. On Linux/Apache, doing so should be easy: you should just be able to run LibreOffice or OpenOffice in headless mode. If you’re really adventurous, you can install unoconv, which makes document conversion better[citation needed]. Anyway, you’ll be delighted to know that you can invoke any of those programs from your terminal. You won’t be delighted to know that they will return error code 77 when Apache tries to invoke them to actually convert a document. That means your server will probably return a 500 error to your users, and that means you’ll get a phone call at 3:00 in the morning from a crying user. Nobody wants to get a 3 AM phone call from a crying user.

To save yourself from such punishment, there is actually a very simple fix. First, create a new home directory for your Apache user (www-data):

sudo mkdir /home/www-data && sudo chown www-data /home/www-data

Then, you’ll need to edit your /etc/passwd file (scary stuff, right) to change the Apache user’s home directory and default shell. Doing so magically gets rid of your error code 77 troubles (I can’t explain further than that).

sudo nano /etc/passwd

Scroll down to the line that starts with “www-data.” It will look something like “www-data:x:[a number]:[a number]:[a string]:[user's home directory]:[path to user's default shell].” Obviously, we only care about the last two parts. Change the default directory to /home/www-data and then change the default shell to /bin/bash. You may need to move some of your website’s files around–I’m not sure because I use Django with mod_wsgi for GradeSolve so my files are stored elsewhere and I’m still an Apache noob.

Good luck.

Quick and Dirty Word Counting in JavaScript

Here’s an interesting problem that came up today during my Gradesolve development: counting the number of words in a particular div. It’s remarkably simple to do so (approximately), efficiently, and correctly. I pass this method the results of a $(“#myelement”).text() call to jQuery:

function wordCount(bodyText){
	var split = bodyText.split(/ |\n|-/);
	var count = 0;
	for (var i = 0; i < split.length; i++){
		if (split[i] != "") count++;
	}
	return count;
}

This returns a result very close to that returned by LibreOffice. It also runs in O(n) (and Θ(n) and Ω(n)). On my hyperthreading-enabled, 3.6GHz Pentium 4 test PC, it took about 0.76ms to count the words in a 400-word document. That means counting the words in a 100,000-word novel would take 190ms or so (not including any memory allocation time) even on a relatively old machine. In other words, it’s quick!

Saving Massive IE Headaches

It shouldn’t surprise you that I’m still working on Hawgrade–now called “Gradesolve.” I’ve been making a huge amount of progress with it. Well, I suppose I should say “was making a huge amount of progress.” Today was my dreaded IE day: I’ve been testing everything in Internet Explorer.

Most of my time has been spent with the heart of the Gradesolve experience, the “Magic Editor JavaScript Engine (from Hell),” which I have lovingly named magic_editor.js. A surprising amount of the code has worked flawlessly; most of the changes resulted in something that was better in every browser (A big one was updating some jQuery .css() calls to use .offset()). My updates were coming with relative ease (read: I do not enjoy making my code cater to imaginary standards) until I hit a major snafu with the Twitter Bootstrap modal.

The problem was simple: it didn’t work. Not working, however, is easy to fix. The bigger problem was that the modal worked in the Bootstrap documentation. I was at a loss; I spent hours digging through my code, making messy tweaks, and was on the brink of throwing out the comment editing functionality when I finally decided to look at what was going on with the browser standards inside the iframe in which the magic editor does its magic.

I’ll give those of you who’ve had to go through this the doctype of the page that was inside the iframe (generated by an outside source):

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">

Yep. WHEN I USED IE VERSION 8 OR OLDER, THE DOCUMENT MODE WAS SET TO IE5 QUIRKS. That’s the rough equivalent of trying to run an iOS app on MS-DOS. It’s not going to work.

Luckily, the fix is relatively easy. I added this to the head of my page (it is not feasible to change the doctype of the served page):

<meta http-equiv='X-UA-Compatible' content='IE=edge'>

That forces IE to render in whatever the latest and greatest document mode for the browser mode is.

Creating Profiles with Django-registration

As part of developing Hawgrade, I’m learning the Django framework. That seemed like a noble idea about a week ago, and I’m practically competent already, but I have run into several snags so far. Major snags. Hair-pulling snags. One of the big ones was how to create a profile while simultaneously registering a user with django-registration 1.0 (FYI: I am using Python 2.7.4 with Django 1.5.1 on Ubuntu 13.04 “Raring Ringtail” x86). I’ve decided to do this post because I saw about a million questions about this topic on StackOverflow. This tutorial assumes that you have already installed django-registration and have included it in your urls.py file such that you access the django-registration app in your accounts/ url:

urlpatterns = patterns('',
    # ...
 
    url(r'^accounts/', include('registration.backends.default.urls')),
 
    # ...
)

We’re going to do the following:

  1. Define a model for our profile.
  2. Define a registration form that inherits from registration.forms.RegistrationForm.
  3. Attach to the django-registration user_registered signal so we know when the user registers. We save the user’s profile in the callback.
  4. Modify urls.py to use our custom registration view.

And now, we get to the Python! We’ll start in models.py. Our example profile stores whether or not a user is human.

class ExUserProfile(models.Model):
    user = models.ForeignKey(User, unique=True)
    is_human = models.BooleanField()
 
    def __unicode__(self):
        return self.user

Next, we need the custom registration form. If you don’t already have a file named forms.py in your app, make one. You’re going to make a custom form.

from registration.forms import RegistrationForm
from django import forms
 
class ExRegistrationForm(RegistrationForm):
    is_human = forms.ChoiceField(label = "Are you human?:")

After the form, we need to attach to the user_registered signal. This is easily accomplished. We’re going to put the method in our models.py file, because, well…I’m new to this…the Django documentation says so!

from registration.signals import user_registered
 
def user_registered_callback(sender, user, request, **kwargs):
    profile = ExUserProfile(user = user)
    profile.is_human = bool(request.POST["is_human"])
    profile.save()
 
user_registered.connect(user_registered_callback)

The last step is the simplest one: editing the urls in urls.py so that users can actually access your cool new registration form. It is REALLY IMPORTANT to put your new entry BEFORE the django-registration include entry.

from YOUR_APP.forms import ExRegistrationForm
from registration.backends.default.views import RegistrationView
 
urlpatterns = patterns('',
 
    # ...
 
    url(r'accounts/register/$', 
        RegistrationView.as_view(form_class = ExRegistrationForm), 
        name = 'registration_register'),
 
    url(r'^accounts/', include('registration.backends.default.urls')),
 
    # ...
)

This code should be fairly extensible–even if you’re not very familiar with Django. One thing I have noticed is that the documentation is very thorough. Good luck!

Hawgrade: Coming soon to a school near you?

I’m sitting in my new office at RMC, writing this post with Ubuntu 13.04 on monitor #2 (I had to bring in my own NVidia GeForce GTS 250 to get two monitors to work; some gamers may note that the GTS 250 is a beefy card). I think it’s only right that I update my blog a log more frequently this summer, since it was RMC that gave rise to this blog in the first place.

OOOVVVEEERRRRKKIILLLLLL!!!

OOOVVVEEERRRRKKIILLLLLL!!!

So what am I working on? For one thing, probably fewer C# tutorials. I’m working on learning Python and the Django framework. To do so, I’m porting Hawgrade to Python/Django. The best part is that RMC is paying me to do so; I’m going to try to get a marketable product by the end of the summer. Right now, the process is going surprisingly well:

Looks a lot like the current version of Hawgrade, huh? I need a graphic designer...

Looks a lot like the current version of Hawgrade, huh? I need a graphic designer…

[Much more frequent] updates will continue. For now, I have a backend to finish!

It serves!

Writing a Working Web Server in Under 100 Lines of Code

UPDATE 12/30/12: You must run the compiled executable as an administrator on systems with UAC. Otherwise, the program will crash and exit.

I was reading some coding blogs last night and I happened across a guy who had written a minuscule web server in C# over his lunch break. I knew right away that I had to have one, too. A server like this one serves little practical purpose; it does not support any sort of server-side scripting (though adding a BASIC interpreter to it would be extremely cool). It does, however, serve a wide variety of documents (and will detect their MIME type prior to serving them.

The first thing I did was write a Log method to make console output look fancy:

static void Log(string message)
{
    Console.WriteLine("[{0}]: {1}", DateTime.Now, message);
}

That was quick. Next was to create an actual server method, which would continuously loop and be started asynchronously by the Main() method.

static void RunServer(int port)
{
    HttpListener listener = new HttpListener();
    listener.Prefixes.Add(string.Format("http://+:{0}/", port)); // Where to listen
    listener.Start(); // Fire up the server
    while (true)
    {
        HttpListenerContext context = listener.GetContext(); // Get a connection
        Log("Requested: " + context.Request.Url);
 
        if (context.Request.RawUrl.EndsWith("/")) // Just asking for index; redirect
        {
            context.Response.StatusCode = 301;
            context.Response.StatusDescription = "301 Moved Permanently";
            context.Response.RedirectLocation = context.Request.RawUrl + "index.html"; // Just send browser to index.html
            context.Response.Close();
            Log("Redirected client to /index.html.");
        }
        else
        {
            byte[] retVal;
            try
            {
                retVal = File.ReadAllBytes("www" + context.Request.RawUrl); // Give the client the requested page
            }
            catch
            {
                context.Response.StatusCode = 404; // File not found; tell the client.
                context.Response.StatusDescription = "404 Not Found";
                Log("404: " + context.Request.RawUrl);
                context.Response.Close();
                continue;
            }
            string mime = GetMimeType(context.Request.RawUrl);
            context.Response.Headers.Add(HttpResponseHeader.ContentType, mime); // Give response a MIME type
 
            Stream respStream = context.Response.OutputStream; // Response stream we'll write to
            respStream.Write(retVal, 0, retVal.Length);
 
            context.Response.StatusCode = 200;
            context.Response.StatusDescription = "200 OK"; // Let client know stuff is okay
 
            respStream.Close();
            context.Response.Close();
            Log("Served: " + context.Request.RawUrl + " as " + mime + ".");
        }
    }
}

There’s quite a bit going on here; I’ll try to explain it all. The beginning of this method configures an HttpListener to wait for connections and starts it. It then starts an infinite loop (the user can stop the server by closing the console window) of continuously waiting for and serving requests (listener.GetContext() blocks until something makes a request). A client can ask for three things in this simple server (since we’re not running server-side scripts):

  1. A page that exists (e.g. /index.html)
  2. A page that doesn’t exist (e.g. __++++_____-sdasfash1234.abcdf)
  3. A directory root that may or may not exist (e.g. /mysite/)

The first thing we check for is the directory root case. We check the URL to see if it ends in a slash. If it does, we redirect the client to whatever the path is, plus “index.html.” We could simply serve the “index.html” off the bat, but we’re (poorly) code golfing right now! That would take more code and accomplish essentially the same thing!

If the RawUrl does not end in a slash, we’re serving a page! Anyway, the server stores all its files in a “www” folder that lives in the same directory as the executable. Fetching “www” plus the raw path with File.ReadAllBytes gets the data of the file we are looking for. The try statement is used in the event we can’t find the file. If an exception does get raised, the server returns a “404 File Not Found” error to the client. If this server were fancy, it would also serve a 404 error page.

If the server can find the file, it determines the MIME type through a simplistic process I will detail in a moment, sets the MIME type in the header, writes the data to the client stream, gives the client a “200 OK” (I am not sure if the order matters for all this, or if all the data simply gets flushed when the HttpResponse gets closed, but this code worked fine in Chrome and IE 9), and closes the connection.

The last thing is to determine the MIME type of the file. Rather than using WIN32 interop calls, I decided to write a simplistic method of my own based on the file extension being served.

static string GetMimeType(string fileName)
{
    // Fast way of determining if the lowercase file name ends with something
    Func<string, bool> fendw = new Func<string, bool>(inp => fileName.ToLower().EndsWith(inp));
 
    // Use our function to figure out the mime type
    if (fendw(".htm") || fendw(".html")) return "text/html";
    else if (fendw(".ico")) return "image/vnd.microsoft.icon";
    else if (fendw(".png")) return "image/png";
    else if (fendw(".jpg") || fendw(".jpeg")) return "image/jpeg";
    else if (fendw(".gif")) return "image/gif";
    else if (fendw(".js")) return "text/javascript";
    else if (fendw(".css")) return "text/css";
    else return "application/octet-stream";
}

This method wouldn’t be very interesting were it not for the Lambda Expression (remember those things I love?). The Lambda Expression takes as a string as an argument and returns a Boolean of whether the lowercase version of the provided file name ends with the specified text. In other words, it checks to see if the file has whatever extension you pass to it and ignores case. The “fendw” name, although cryptic, is short for “file ends with;” it prevented me from having to type fileName.ToLower().EndsWith(…) over and over again!

That’s it. The web server works — we just need to add a Main() method:

static void Main(string[] args)
{
    Console.WriteLine("On what port should the server run?:");
    int port = int.Parse(Console.ReadLine());
 
    Task server = new Task(() => RunServer(port)); // Start the server async
    server.Start();
    Log("Server started on port " + port.ToString() + ". Close this window to stop it.");
 
    while (!server.IsCompleted) ; // Wait infinitely
}

The first part of this method gets the port the user wants to run the server on. I used 2013, since it’s almost New Year’s! Next, it creates an asynchronous task (using a Lambda Expression again!) to run the server on, then fires it up and blocks indefinitely. The use of the Lambda expression is unnecessary here (since the thread Main() runs on will just loop forever), but if you wanted to listen on more ports, you could create more tasks to run new instances of the server on. It makes the code more extensible, right?

It serves!

It serves!

Serving a real web page from a website I built for a charity organization last year!

Serving a real web page from a website I built for a charity organization last year!

If you desired, you could actually open a port in your router and let your friends connect to your cool new server. I should probably warn you that doing so would be a terribly risky idea, even if you only have the port open for a short while. You wouldn’t run through wolf-infested woods with a steak or swim at the Great Barrier Reef with a gaping leg wound for ten minutes, so why would you do the same on the Internet? In other words: this code is provided “AS-IS” with no express or implied warranty, especially since I do not really know how secure this server is. My guess is that it isn’t. Still, it’s hard to go wrong with a 100-line server!

A Brainf**k Interpreter in JavaScript

Brainf**k (I bet you can guess what the asterisks are covering…) is a tiny, esoteric programming language. It is classified as Turing-complete, but its practical use is very limited (if not nonexistent). BF is an interesting challenge because it is so simple. Many devoted developers spend lots of time creating the smallest, fastest BF interpreters and compilers they can. One user on Codegolf created a BF implementation that was only 106 bytes long. That’s pretty impressive.

BF has eight commands (which will be discussed in a moment). Every program has access to a series of memory blocks that can have any range of values. When a BF program loads, all the “cells” in the memory (really just an array) are initialized in value to zero. BF programs can switch between different blocks of memory (change the array index that they are accessing), increment the values of specific blocks, decrement the values of specific blocks, print a character representation of a block to the screen, or put a character’s value into a block. Programs can also loop. They are executed command-by-command from left to right.

There is no official language specification for BF, so many details are left up to the individual implementation. However, the following standards are pretty common (and were implemented in my BF interpreter):

  • Using bytes for memory. My BF interpreter limits values in cells to [0, 255].
  • Allowing overflows. Blocks overflow when their value goes outside the permissible range of [0, 255]. That is, when a program tries to make a block’s value -1, its value becomes 255, and when a program tries to make a block’s value 256, its value becomes zero.
  • 30,000 blocks (29.3kb) of available memory.
  • Non-command characters are ignored.

The eight commands:

  •  + increases the value of the current block by one.
  • - decreases the value of the current block by one.
  • > increases the block index by one.
  • < decreases the block index by one.
  • . prints the block to the screen as an ASCII character.
  • , gets an ASCII character and puts it in the current block.
  • [ opens a loop. It will jump to the end of the loop if the current block’s value is zero.
  • ] closes a loop. It will jump to the beginning of the loop if the current block’s value is not zero. If it is zero, the program will continue.

I’m not going to teach you how to write BF programs in this post; I’m hardly a maestro of it myself. If you want to learn more about BF, Google is an awesome resource.

My interpreter is pretty simple. The first task was to create a crash-reporting function, since I figured that would probably happen a lot. For future reference, “output” is the ID of the part of the page where BF script output goes.

function crash(reason, at){ // When the program dies
	$("#output").text("CRASHED: " + reason + " ( at char index " + at + ")");
}

The actual interpreter starts out with the declaration of a run function and all sorts of BF-related variables.

function run(data){ // Runs the BF program. Data: program to run.
	var mem = []; // Program memory
 
	// Initialize all the memory
	for(var i = 0; i < 30000; i++){
		mem[i] = 0;
	}
 
	var pointer = 0; // Pointer to memory
 
	$("#output").text(""); // Clear output field

Next, it loops through each character in the program (specified to the function as data) and if it is BF-legal, the required action is performed. The simple ones (that aren’t loops) are self-explanatory.

for(var i = 0; i < data.length; i++){ 	
        if(data[i] === ">"){ // Right one cell
		if(pointer < 30000) pointer++;
		else{
			crash("There are only 30,000 usable cells of memory. Sorry.", i); // Trying to use too many cells.
			return;
		}
	}
	else if(data[i] === "<"){ // Left one cell 		
                if (pointer > 0) pointer--;
		else {
			crash("Cannot decrement pointer when pointer is at first cell.", i); // Trying to go below cell zero.
			return;
		}
	}
	else if(data[i] === "+"){ // Increment cell value
		mem[pointer]++;
		if(mem[pointer] > 255) mem[pointer] = 0; // Overflow
	}
	else if(data[i] === "-"){ // Decrement cell value
		if (mem[pointer] > 0) mem[pointer]--;
		else {
			mem[pointer] = 255; // Overflow back to 255
		}
	}
	else if(data[i] == "."){ // Put character to screen
		var memChar = String.fromCharCode(mem[pointer]);
		if (memChar == "\n") memChar = ""; // Turn newlines into breaks
		$("#output").append(String.fromCharCode(mem[pointer])); // Log the correct character from its code
	}
	else if(data[i] == ","){
		mem[pointer] = window.prompt("Please enter one character.").charCodeAt(0); // Set memory to char code
	}

Next come loops. There are loads of elegant ways of going about loops; a stack storing the start indices of loops could be used to avoid all the searching my implementation does. However, simplicity was on my mind when I wrote this program: it suffices to say I took the slow, not-so-elegant way out. When the interpreter encounters the start of a loop (a [), it checks to see if the value of the current cell is zero. If it is not, it just continues along. If it is, things get more interesting. The interpreter loops through the program until it finds the corresponding end of the loop so that the program can continue executing properly.

The task is not as simple as incrementing i (the “instruction pointer,” so to speak) until data[i] is a ]. Other loops could be in the way. The solution is shockingly simple: keep track of the number of newly open loops as the program searches for the end of the original loop. I used a counter to keep track of the loop openings. Every [ increments it; every ] decrements it. When the counter gets to zero and the program finds a ], the index has been found. All that is left is to change the “instruction pointer” to the new location in the program.

The ] routine works in the exact opposite way. It keeps track of ]s instead of [s but is otherwise very similar. Here’s what it looks like:

else if(data[i] == "["){
	if(mem[pointer] != 0) continue;
	else{ // Search for corresponding ]
		var openCount = 0; // # of open loops
		for(var j = i; j < data.length;j++){ // Loop through more characters
			if(data[j] === "[") openCount++; // Another open loop
			else if(data[j] === "]"){ // A closing of a loop
				openCount--; // Decrement open count
				if(openCount === 0){ // If we're at zero, we're done.
					i = j; // Move the program forward
					break; // Stop looping
				}
			}
		}
		if(openCount != 0){
			crash("Open loop.", i);
			return;
		}
	}
}
else if(data[i] === "]"){
	// Same deal as [ except going backwards
	if(mem[pointer] != 0){
		var closeCount = 0; // We use close count on this one because it makes more sense (since we're doing the opposite from before!)
		for(var j = i; j >= 0; j--){
			if(data[j] === "]") closeCount++;
			else if(data[j] === "["){
				closeCount--;
				if(closeCount === 0){
					i = j;
					break;
				}
			}
		}
		if(closeCount != 0) {
			crash("Too many loop closings.", i);
			return;
		}
	}
}

That’s all there is to it. The rest of the page that contains the interpreter, which you can find here, is instructions and a textbox to let you put a program in.

Here’s what the finished product looks like:

It's not as pretty as TextRacer but it gets the job done.

The interpreter running a ROT13 cipher example I found on Wikipedia.

Overall, I was surprised with how quickly I managed to get my interpreter working. I was also glad I went with the architecture I did; though it would have been possible to convert the BF to JavaScript and then eval() it, the program would have lost most of its charm. This program could certainly use some refining but overall, it gets the job done! Happy BFing!