Thursday, October 16, 2008

Fun With Cloud Calculators

The fifth and final example of cloud calculators is the Bushulator. Previous examples of cloud calculators included the piulator, the large type calculator, the Spanish calculator and the calculadora Inglés. The Bushulator, like the previous examples uses the same underlying JavaScript to perform the calculations. In this case though the user interface is modified such that the calculator becomes a form of political expression.

Software divergence is subtle.



So let's start with that JavaScript code. First write the core code, something like:


var cumulativeValue = 0;
var decimalUsed = false;
var newNumber = false;
var nextOperation = "";

function updateData(myValue) {
if (newNumber) {
document.f1.theData.value = myValue;
newNumber = false;
}
else {
if (document.f1.theData.value == "0") {
document.f1.theData.value = myValue;
}
else {
document.f1.theData.value += myValue;
}
}
}

function updateDecimal() {
if (newNumber) {
document.f1.theData.value = "0.";
newNumber = false;
}
else {
if (!decimalUsed) {
document.f1.theData.value += ".";
}
}
decimalUsed = true;
}

function clearEntry() {
document.f1.theData.value = 0;
newNumber = true;
decimalUsed = false;
}
function Clear() {
cumulativeValue = 0;
nextOperation = "";
clearEntry();
}

function doComputation(myOperation) {
if (newNumber && nextOperation != "=");
else {
newNumber = true;
if (nextOperation == '+') cumulativeValue += parseFloat(document.f1.theData.value);
else if (nextOperation == '-') cumulativeValue -= parseFloat(document.f1.theData.value);
else if (nextOperation == '*') cumulativeValue *= parseFloat(document.f1.theData.value);
else if (nextOperation == '/') cumulativeValue /= parseFloat(document.f1.theData.value);
else cumulativeValue = parseFloat(document.f1.theData.value);
}
document.f1.theData.value = cumulativeValue;
nextOperation = myOperation;
decimalUsed = false;
}



Save this to a file, say cloudcalculator.js and put the file in a /static sub-directory, say js so that this javascript for cloudcalculator.js is in /static/js. Next add the python page handler to your app-engine code. This page will be the CSS to skin the above JavaScript. For the Bushulator it looks something like this:


#
# Bushulator
#
class bushulatorPage(webapp.RequestHandler):
def get(self):
self.response.headers['Content-Type'] = 'text/html'
self.response.out.write('')
self.response.out.write('')
self.response.out.write('<html><body>');
self.response.out.write('<head>');
self.response.out.write('<script language="JavaScript" src="/js/cloudcalculator.js">');
self.response.out.write('</script>');
self.response.out.write('</head>');
self.response.out.write('</html>');
self.response.out.write(\
"""
<form name="f1" action="">

<input type="text" size=30 name="theData" align="right" style="font-size:72px; width:315px;" value="0"><p>
<table>
<tr>
<td><div id="b1" style="background-image:url('/bh/bh1.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b2" style="background-image:url('/bh/bh2.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b3" style="background-image:url('/bh/bh3.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b4" style="background-image:url('/bh/bh4.gif'); margin:1px; width:75px;
height:75px;" onClick="doComputation('+')"></div></td>
</tr>
<tr>
<td><div id="b5" style="background-image:url('/bh/bh5.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b6" style="background-image:url('/bh/bh6.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b7" style="background-image:url('/bh/bh7.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b8" style="background-image:url('/bh/bh8.gif'); margin:1px; width:75px;
height:75px;" onClick="doComputation('-')"></div></td>
</tr>
<tr>
<td><div id="b9" style="background-image:url('/bh/bh9.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b10" style="background-image:url('/bh/bh10.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b11" style="background-image:url('/bh/bh11.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b12" type="button" value="" style="background-image:url('/bh/bh12.gif'); margin:1px; width:75px;
height:75px;" onClick="doComputation('*')"></div></td>
</tr>
<tr>
<td><div id="b13" style="background-image:url('/bh/bh13.gif'); margin:1px; width:75px;
height:75px;" onClick="updateDecimal()"></div></td>
<td><div id="b14" style="background-image:url('/bh/bh14.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b15" style="background-image:url('/bh/bh15.gif'); margin:1px; width:75px;
height:75px;" onClick="updateData(0)"></div></td>
<td><div id="b16" type="button" value="" style="background-image:url('/bh/bh16.gif'); margin:1px; width:75px;
height:75px;" onClick="doComputation('/')"></div></td>
</tr>
<tr>
<td><div id="b17" style="background-image:url('/bh/bh17.gif'); margin:1px; width:75px;
height:75px;" onClick="doComputation('=')"></div></td>
<td><div id="b18" style="background-image:url('/bh/bh18.gif'); margin:1px; width:75px;
height:75px;" onClick="Clear()"></div></td>
<td><div id="b19" style="background-image:url('/bh/bh19.gif'); margin:1px; width:75px;
height:75px;" onClick="clearEntry()"></div></td>
<td><div id="b20" style="background-image:url('/bh/bh20.gif'); margin:1px; width:75px;
height:75px;" onClick="window.open('http://www.boldlentil.com/','mywindow','toolbar=yes,location=yes,
directories=yes,status=yes,menubar=yes,scrollbars=yes,copyhistory=yes,resizable=yes'
)"></div></td>
</tr>
</table>

</form>


Now a couple things to note in the previous python. Unlike the previous cloud calculators the Bushulator uses div's instead of buttons. Next the div's reference gif files stored in the /static/bh directory (without us he's just president bh). Be sure to update your app.yaml file with the two new directories:


- url: /js
static_dir: static/js

- url: /bh
static_dir: static/bh


OK that's it. That's all there is to a cloud calculator. Well OK you have to use your app-engine account to upload it to appspot.com but once it's uploaded then it's a cloud calculator. In this case the cloud functionality is not in the code itself but how the code hosted elsewhere. The final step is to pull the Bushulator out of the cloud and add it to a specific blog post. Fortunately this is pretty simple with blogger. Simply add an iframe and voila the Bushlator appears:


<iframe src="http://1boldlentil.appspot.com/bushulator" height="550"
width="500" frameborder="0">
Apologies, it looks like your browser doesn't support iFrames.
</iframe>


Does that mean anyone can embed the Bushulator into their blogger blog post using the above iframe? Yes it does. Ay caramba does that mean this blog post needs a terms of use? I'd rather it was just linkware. Oh wait there's a bl button on every calculator. That means the top requirement is structural. Easy peasy.

As for software divergence it's now possible to start from a page of JavaScript and to re-skin this core code from the mathematical, to the useful, to the multi-lingual and even to the political. And it's everywhere. We'll everywhere that's online.