JavaScript for everyday scripting

By Stephen Holdaway

25 Oct, 2012

Though JavaScript tends to cop a lot of flak, I find it’s actually a pretty useful thing to know. No matter how much you may dislike JavaScript, the fact is that it’s part of almost every web browser since 1996, and it’s the only major, cross-browser client-side scripting option for the web (though Dart is looking to join that rank). While I fully agree that writing large systems in JavaScript can be a pain, I can’t say the same thing about what’s in the name: scripting. I’m not talking about scripting in the sense of writing small programs, rather scripting the way you operate a command line; short, contextual snippets of code to get stuff done.

Every now and then, I find myself popping open the JavaScript console in Google Chrome and writing a few lines of JavaScript to accelerate something I’m doing. While situations that warrant this are rare, there have been a few occasions where the JavaScript console has saved me huge amounts of menial clicking labour. It’s arguable that if you have to write code to do something on the web, then the creator(s) of the page you’re battling with didn’t do a good enough job. In reality however, most of the things I’ve accomplished with the JavaScript console have been far outside the scope of what the target pages were intended to do. So much to the point that only once have I used the JavaScript console to work around a real usability issue.

Essentially, this all boils down to the fact that the data on every page is right there in your web browser, and in a highly accessible form at that. Why waste time doing things manually when you can automate?! It’s exactly the reason projects like Greasemonkey exist.

Here’s a list for you to ponder:

  • Every component of a web page is accessible with JavaScript (ignoring a few cross-domain nuances with iframes).
  • You don’t just get access to the raw data of a page; you get a highly organised hierarchy (the DOM).
  • The page is on your computer, so you can do whatever you like to it. No-one can stop you (except maybe with some preemptively written defensive JavaScript, but that’s a bit silly).

As a crude example, lets say you wanted to open every link on a page in a new window/tab. You could achieve that like this:

// Get all the anchor (link) elements on the page
var links = document.getElementsByTagName('a');

// Loop through the array of links, opening each one
for( var i=0, c=links.length; i<c; i++){
    window.open(links[i].href);
}

Note that any half-decent pop-up blocker will stop this working (you easily can disable your pop-up blocker if you really want to try it out).

Mining Bebo with JavaScript

In one of my furious efforts to digitally archive everything relevant in arms reach, I decided it would be a good idea to take some old conversations I had on Bebo. To save myself the effort of manually retrieving pages, I wrote an email to Bebo’s support asking for a dump of all comments to and from my account, and a few hours later I received this rather helpful response:

Dear Bebo User:

Thank you for your feedback. We always enjoy hearing from our users.

Jordan

I definitely wouldn’t have done what I did next for the likes of Facebook or twitter (not that it would be necessary with their public APIs), however Bebo wasn’t exactly rocketing through the inter-sky and I didn’t want to lose two years of conversation with my partner because someone pulled the plug on a failing social network. I wrote back kindly pointing out that Jordan hadn’t in-fact attempted to answer my question at all, and soon received this curt reply:

That is not a service that we offer.

With the easy option off the table, I set out to harvest my comment wall from Bebo, and I did. Very successfully. With less than 100 lines of JavaScript, I turned pages and pages of old Bebo comments into 697 rows in a MySQL table on my server in about 5 minutes flat.

The harvesting code

I used an iframe as a viewport and ran snippets of JavaScript in the window to retain state above page changes. Once a small loop had loaded every page and scraped their comments, I packaged everything up in an XMLHttpRequest POST request and fired it off to a script on my local server for database insertion. The key component in this operation was the iframe:

document.body.innerHTML = '<iframe width="100%" height="1000px" src="'+window.location+'"></iframe>';

The browser allowed me to access the contents of this iframe with JavaScript because I created it inside a page on Bebo’s own domain, and it’s content was also from Bebo’s domain. This line of code essentially moves the current page into an iframe on it’s own page, retaining the context of the original page as far as the browser is concerned (Inception-frame?). After this trick, the rest of the code I ran through the console was fairly straight forward:

// Get all comment elements
var comment_elements = window.frames[0].document.getElementById('comment-list').getElementsByTagName('LI');

for (var i=0; i&lt;comment_elements.length; i+=10) {
    var el = comment_elements[i],
        comment = {};

    // Ignore a specific type of comment
    try {
        comment.from = el.childNodes[3].innerHTML;
        if(comment.from.search(/^&lt;/) != -1)
            comment.from = el.childNodes[5].innerHTML;
    } catch(e) {
        console.log("Ignored Moble");
    }

    comment.date = el.getElementsByClassName('comment-timestamp')[0].innerHTML;
    comment.text = el.getElementsByClassName('comment-text')[0].innerHTML;

    if(comment.from == "Steph" || comment.from == "Stephen"){
        comments.push(comment);
    }
}

Once I had the data I wanted, sending cross-domain requests was a breeze. While I could have added a few headers to my server’s response to stop the browser complaining about and ‘blocking’ cross-domain requests, I didn’t need to do anything more than send the requests. The browser complained away, however because it needed to send my requests to read the cross-domain permission headers in the first place, my server happily digested the incoming data and I didn’t care about the discarded response.

While I could have gathered this data using any old language by downloading the HTML pages, the requirement for a logged-in session to view the pages I wanted was a whole other can of worms. In the end, running JavaScript in the context of an authenticated session in a browser made life a lot easier.

Update, August 2013: My concerns about losing this data were well founded: the old Bebo is now inaccessible. Apparently some data will be available in the future after Bebo gets refurbished, but I’m still glad I got this stuff off when I did.

And with that…

I don’t think that everyone should have JavaScript under their belt, but it has certainly been invaluable to me. If you’re interested in learning JavaScript, the Mozilla Developer Network is an excellent resource, and you could always pop open the JavaScript console in your browser.



Avoiding nested conditionals in your code

By Stephen Holdaway

1 Sep, 2012

Deeply nested code can be a pain to work with, especially when it’s unnecessary. To combat nasty nesting situations, I’m in the habit of doing something pretty straightforward: invert your if statements.

(Birds-)nested code

Take the following block of nested if statements for example:

function doLoginWithDetails(username, password)
{
    if(isSessionValid()){
        if(userExistsInDatabase(username)){
            if(isUserAllowedToLogin(username)){
                if(isPasswordCorrectForUser(username, password)){
                    // Successful login
                } else {
                    // Incorrect password
                }
            } else {
                // User not allowed to log in
            }
        } else {
            // User not in database
        }
    } else {
        // Session not valid
    }

}

The target code is in the middle here and has a nice path up to it, however connecting the dots for the else conditions isn’t quite as clear. While this code might be understandable in the heat of writing, if you decided later that userOwnsCat() needed to be true for a user to log in, and you wanted a specific error condition for it…things get messy, quickly. Essentially, this code is not maintainable.

There’s no issue with the logic in this nested example – it’s just badly organised. The very same logic can be written in such a way that it only ever goes one level deep, and there’s not much to it either.

Cleaning up the nest

Bird’s nests have no place in code, so it’s time to eradicate this one. Instead of using if statements to handle the desired condition, use them to handle the exceptional one:

function doLoginWithDetails(username, password)
{
    if(!isSessionValid()){
        // Session not valid
    }

    if(!userExistsInDatabase(username)){
        // User not in database
    }

    if(!isUserAllowedToLogin(username)){
        // User not allowed to log in
    }

    if(!isPasswordCorrectForUser(username, password)){
        // Incorrect password
    }

    // Successful login

}

This version is easier to read, hence more maintainable, and adding that userOwnsCat() check probably won’t be such a mission now!

A little extra flow control inside the if blocks is required to make this code behave the same as the nested version, but it’s nothing that can’t be handled by throwing an exception or returning from the function.

This no-nesting strategy only requires a small change in code structure, but it can make a big difference to readability when you otherwise might be dealing with some form of multi-level-soup. Use at your own discretion.



Game Concept: ‘Impact’

By Stephen Holdaway

14 Mar, 2011

This concept was written for the Advanced Computer Game Design (MDDN343) at Victoria University in 2011. I’d love to see it realised!

Vehicle simulation with an arcade core, but with a distinctive lack of sprites. Impact fuses together arcade-style challenge and scoring with intensely real vehicle simulation, a bit of humour, and some serious underlying themes for those who like greater meanings. Not a fan of racing games? – Good, because this game is all about crashing.

Real-to-life, dynamic vehicle crash simulation is at the driving heart of this concept, though scoring systems and a variety of challenges keep it in the realm of games over ‘serious physics simulations’. In Impact, the player pilots a vehicle in a three-dimensional, semi-open environment where they must ultimately crash the vehicle to earn points and achieve goals. Points are awarded for the extent of damage to different vehicle components and can also be awarded for completing bonus objectives. Short, separate challenges or ‘levels’ are built-up using a variety of constraints, obstacles and goals, and slot over the simulation framework allowing for almost infinite iterations of tightly-woven player experiences. As the player’s primary point of interaction and the foundation of the scoring system, accurate vehicle crash simulation is the cornerstone of Impact.

While the term ‘accurate vehicle simulation’ suggests a mighty-complex physics model and a lot of heavy computation, accuracy in the context of this game is about satisfying the player – not a scientist. As long as collisions and visual damage are believable and satisfying to the player, the underlying skeleton of the simulation can be an array of box-model estimations and triggers representing a vehicles main components. This pseudo-complexity simplifies the simulation model to a sensible game level and richens gameplay with increased dynamic possibilities. Playable as a stand-alone entity, the vehicle and crash simulation of Impact relies on a solid scoring system driven by crash data to make the step from interactive physics demonstration to game.

Equally as important as its core simulation mechanic, Impact’s scoring system gives worth to collisions and creates a further framework for levels and challenges to perch on. A workable array of floating-points representing the damage of each simulated vehicle component is fed into the scoring system, where it is further refined, and returned to the player as points (score) and short written messages. Each vehicle component is assigned a worth in points primary based on ease of destruction, and any damage reported by the simulation is awarded as a factor of component damage (0. – 1. ) and component value. It is undecided whether points should be awarded cumulatively (where each time a damage value changes the new factor is added to the current score, and a component can give many times its value in points) or relatively (where a part can only give the total value it has been assigned, and score is calculated from the current damage of every component with every change).

Relatable information is given to the player by segmenting component damage (as 0. - 1. ) into several stages and alerting the player when damage has reached a segment. For example, “unharmed” (0.), “scratched”( > 0. & < 0.1), “damaged” ( > 0.1 & < 0.4), “critically damaged” ( > 0.4 & < 0.8), and “obliterated” ( > 0.8) could give an on-screen message like: “Front Bumper Obliterated”. Reaching certain damage segments on any component or specific components could also result in additional fixed-value rewards. Each segment adjective could be exchanged for a more appropriate alternative if necessary (i.e. a tire being “scratched” doesn't sound right) or randomly taken from a pool of generic alternatives to reduce monotony - “disintegrated”, “shredded” “vaporised”, and “destroyed” could be variations of “obliterated”. This text-based feedback creates a simple point of reference between challenges and allows the player to quickly understand the scoring system and the result of their collision. As many different components could simultaneously send text feedback in a collision, it would be wise if feedback was separated on the player's HUD into an area for important messages and a smaller, dimmed stream for everything else. Each message could also be assigned a priority, so that minor messages would show in the important stream until higher priority messages push them to the general stream.

In addition to the attribution of individual component damage to score, multiple components can be analysed as groups to define broader levels of damage and bonus objectives. As the most relatable form of feedback over that of any individual component, bonuses like “Fatal Impact +1000” (for killing the driver) are not only emotive and rewarding, but present an extra layer of challenge and incentive to the player on top of what a level demands. Bonus objectives and point awards can similarly be triggered from data besides component damage: vehicle speed, angle of impact, and speed of impact to name a few. A scoring system of points, individual component damage, and bonus objectives bind to the raw simulation of Impact to put in the realm of 'game', but also provide a solid framework for levels and challenges to expand upon.

Levels and challenges are the interchangeable icing on the cake that is Impact, giving direction to the game and player through sets of defined goals and constraints. Goals power the game from the top up – giving a reason to play, and using the game's systems to make play possible and rewarding.

With a firm scoring system underfoot, challenges can easily be created by taking possibilities of the scoring framework and marking them as goals or events that must not occur (constraints). To win a player must achieve all goals while keeping within constraints. Challenges can be presented raw (i.e. “Achieve more than X points without damaging Y”) or as a scenario where additional non-standard features may be added. For example: “A masked gunman has entered your vehicle and is sitting in the front passenger seat ordering you to drive. You must kill the gunman by crashing, but make any obvious moves and he'll shoot! You must survive as there's pizza waiting for you at home”. In this scenario the goal is to kill the front-seat passenger and the constraints are that the driver must survive, and a custom meter (probably based on latitudinal g-force and steering delta) must not be maxed-out. Without a defined challenge the game defaults to a 'crash to earn maximum points' goal. An enormous number of goal and constraint combinations can be blended to offer different types of challenge within the same gameplay model, but without an engaging and relevant environment, the gameplay falls to pieces.

Environment plays an important roll in both setting the theme of the game and allowing physical difference between challenges. Impact is set at a crash testing facility where arenas designed for different outcomes – a long narrow track for high-speed impact for example – exist in a single environment. Challenges can isolate the player to an arena with location constraints, and the placement of themed objects like highway barriers, cones, ramps and poles, as well as unreal objects like large vertical wedges, spikes, and tank-busters can provide physical points of difference between challenges. The environment substantial enough that it is not dependant on challenge defined objects to create variation, but object placement allows a greater number of challenge possibilities.

Challenge variation is topped off with sprinkles in the form of multiple vehicle choices. A range of generic, classed vehicles adds depth to the game by giving the player multiple interactions to master. Though all vehicles would use the same control scheme, differences in handling, power, physical structure, strength and vehicle specific crash bonuses provide different experiences. A single generic vehicle from each of the following classes might be available: car (sedan, hatch-back, wagon, and convertible), 4x4, van, city/delivery truck, and semi-truck. All things considered, a rich array of challenges, and a rewarding and relatable scoring system move Impact firmly to the 'game' category, but is there more to it than meets the eye?

Impact relies on real-to-life vehicle collision simulation and analysis of damage incurred to report to the player, amongst other things, fatalities. While it may seem politically-incorrect to simulate and even challenge a player to crash a vehicle killing its occupants, the game is not intended to be violent – more of a demonstration; educational if you will. All characters in Impact including the player are crash-test dummies (mannequins), and they're just doing their jobs. Scoring and bonus feedback encourages players to explore what is possible, and assist to educate the player that it doesn't take much to make a totally fatal or catastrophic vehicle accident. If a player crashes at 160KP/h in Impact, the result should mirror a real life crash at 160KP/h; no Hollywood physics.

Collision at 160KP/h into steel wall. From Mythbusters S08E08.

The core simulation interaction and scoring mechanics of Impact bind together to form a solid platform for expandable, challenge based gameplay. This concept could be developed as a one vehicle, one arena, 'get high-scores' type game or as a large sequential series of challenges with an range of environments and vehicles, both using the same foundation and employing the same core mechanics. Either way, this is a game I personally want to play. It's not a racing game, it's a crashing game: it's Impact.

This is a backdated post. The publish date reflects when the it would have been posted originally, however the actual publish date was later. This post was last modified 2 Oct, 2012.



[Solved] SLI with different VRAM on each card

By Stephen Holdaway

20 Oct, 2010

[This post has been migrated from my old site. It was re-published August 8, 2012]

When I bought a second NVIDIA GTS250 mid 2010 to take advantage of my new X58 motherboard’s SLI capibilities, I thought I would be up and running in no time – a standard plug-and-play gig.

At the time I bought the second card, my original blower style XFX 1GB GTS250 was no longer on sale, and the only 1GB GTS250 I could get was ugly as hell (plus it wasn’t a blower type design). Luckily for me, EVGA offered blower style GTS250 – the only catch being there was no 1GB model. After doing a lot of research, I concluded that I would be able to run SLI on different brand cards with different amounts of memory; so I went ahead and ordered the 512MB EVGA card.

When I got the card home the next day and connected everything…nothing. Both cards (1GB and 512MB) were working fine and there were no problems with other components, but no matter how hard I tried, NVIDIA Control Panel wouldn’t give me any SLI options. I won’t go into details, but it took me about a week of research and failed attempts (it was uni holidays) before I stumbled upon the simplest solution in the universe: one tiny registry edit that made everything click. I can’t remember what forum I stumbled into this on, but this fix is in a few places (with the right keywords).

Symptoms

The main thing you’re likely to notice is the lack of a Set SLI and PhysX configuration menu option your NVIDIA Control Panel. Normally this option would show up immediately once your cards are connected, and a balloon would pop up on first run saying something along the lines of “Your system is SLI compatible. Click here to enable SLI”.

For reference, this is what the NVIDIA Control Panel looks like when SLI is detected (and working) properly:

Nvidia SLI control panel

If you aren’t seeing the SLI menu option or the balloon pop-up, and you are confident your hardware is set up correctly, it’s time to fix the problem.

Fixing the problem

A simple registry edit is all you need to make SLI detect properly. Before I begin I’d like to point out that this tweak will NOT enable NVIDIA SLI if

  • your computer uses a crappy integrated graphics processor,
  • you only have one graphics card,
  • your graphics card(s) do not support SLI mode,
  • your graphics card(s) are not NVIDIA.

This is not some miracle tweak that will magically make your computer shoot jets of flames and attract beautiful women; this will merely force NVIDIA Control Panel to detect your SLI compatible hardware (although it could be argued that NVIDA SLI does the aforementioned things). Secondly, editing the registry can seriously screw up your computer if you mess around. I take no responsibility for damage or loss of data that comes from editing registry values. This isn’t a lesson on registry editing so there are only basic pointers of how to apply this fix. If you seriously don’t know what you’re doing, I’ve created a .reg file that will do it all for you (you must restart your computer after applying this edit. SLI with not work until you do).

The target registry entry for today is a 32-bit DWORD called CoolBits. Open the registry editor (click start and type regedit, then press enter) and navigate to:

HKEY_LOCAL_MACHINE\SOFTWARE\NVIDIA Corporation\Global\NVTweak

When I did this initially, there was no CoolBits entry, so I had to create one. If you don’t have a CoolBits entry create a new DWORD (32-bit) value called “CoolBits”, otherwise you can skip to the next step.

Once you’ve got a CoolBits entry, the next step is to set it’s value to 18 by opening the entry and changing the “Value data” field to 18. You should now have something that looks like this:

Coolbits set in the registry

If you want to have all this done automatically, download and run this .reg file. The file contains the following:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SOFTWARE\NVIDIA Corporation\Global\NVTweak]
"CoolBits"=dword:00000018

The final step in the process is restarting your computer. If everything went ok, you should see the “Enable SLI” balloon when Windows loads again, and the SLI menu option in NVIDIA Control Panel.

This is a backdated post. The publish date reflects when the it would have been posted originally, however the actual publish date was later. This post was last modified 26 Apr, 2013.