01.28.07
Posted in Coding at 7:44 pm by David Kellogg
The n-squared catastrophe (Metcalfe’s Law) occurs while messaging many other nodes in a cluster. I knew this math since 5th grade at West Elementary.
1 0
2 1
3 3
4 6
50 1225
This is also a game of connect the dots. How many lines are required to connect all dots to all others? n*(n-1)/2.
If there are 4 students in a class they need to pass 6 pairs of notes to each other to communicate. With 50 students, 1225 pairs of notes must trade hands. This is getting out of hand. Soon, instead of performing important tasks, the entire school day is taken up by note-passing. Surely there is a better way.
Computer programmers are slow to learn this lesson. This is mainly a lesson of a multi-node setup. Most coders like to think of complex problems in terms of a single application. A multi-node setup is never like a single application due to the above scaling law. Consider the code.
int count = 0; // a global
That’s all. It’s a global. In a single application, you would not dream of attempting to sync multiple variables, count1, count2, etc. Why would you do this with multiple nodes? The obvious choice in an application is to create a global or static variable. The obvious choice in a multi-node setup is to use a single centralized database. The n-squared catastrophe will kill you otherwise.
Dave
Permalink
Posted in POW at 7:38 pm by David Kellogg
POW 0.0.9 preview is available. It is there if you want to see any next-gen features. Rewrite rules were added. Rewrite rules allow you to rewrite urls on the fly. Most server admins know this through ‘.htaccess’. Here is the new functionality in action.
// htdocs/system/startup.sjs
<?sjs
pow_server.REWRITE_RULES =
[
[ "dog/?(.*)$", "/cat.sjs?q=$1" ],
[ /^\/Jason\/?(.*)$/i, "/cat.sjs?q=$1" ]
];
?>
This results in dog.html pointing to /cat.sjs?q=.html. This cleans up the problem of linking many fake directories to a single script.
Permalink
01.23.07
Posted in POW at 9:49 am by David Kellogg
POW 0.0.8 is live today. The great new feature for this version is Infinilink. Infinilink allows you to use my humble server for redirects to you ever-moving home server. Your problem and mine is that your ISP gave you a non-static IP. Infinilink gives you a static link through davidkellogg.com that redirects to your content.
Sound complicated? It’s not. Click on the infinilink link at localhost:6670 and follow the instructions. Please use port 6670, since that’s the way I set it up.
What’s next? Email your friends to show them your brand new static server.
Other new features include
* startup.sjs file — invoked on server startup
* cron jobs — SJS code run every minute, hour or whenever
These are documented.
Dave
Permalink
01.21.07
Posted in Coding at 8:27 pm by David Kellogg
Javascript continuations are are intriguing for AJAX (remote scripting) applications. Here I will show you how to do it.
First what is a continuation? A continuation saves the current state of a program and allows the coder to restart it at any time. A good example (though a poorly scalable one) is a login. Once you attempt to click on a link that requires a login, you go to a separate login page, then proceed to the intended page. If you used a continuation on the server side, you could save the current state of the user, then return him to that state as if the login jump had not occurred. This often presents the constraint that the user must return to the same server, a usual no-no for medium-sized startups. It also wastes memory or a database call that should be used for something else.
On the client side, though, the browser and user remain in place. Client-side continuations still use up memory, but here we stick it to the user, not to your poor server. We can use continuations to make AJAX coding easier. The callback is implied. All calls to the server appear to receive data instantly. Then the code can act on the data on the next line.
Though not natively implemented, continuations can be created using Javascript’s own flexibility. It turns out that JS knows what function it is running, can save the call stack through closures, and has access to the source code it is invoking.
This turns out to be a fun experiment. Can we save the entire environment, then pick up where we left off? We do below with a bit of PHP and Javascript. The tail of the function with the continuation is saved. It all appears synchronous, even when it is not.
Thanks to Steve Yen for inspiration on this.
<?php
if($_GET['AJAX'] == 'true') {
if($_GET['function'] == 'date') {
echo "{'date': '".date('h:i:s A')."'}";
}
exit();
}
?>
<html>
<head>
<title>Continuations</title>
</head>
<body>
<form method="GET" action="#Oops" onsubmit="get_remote_date(); return false;">
<input type="submit" value="Get Server Time">
</form>
<div id="changeme">
Text to change.
</div>
<script language="javascript">
/*
* Called by pressing the button.
* The tail of function and context are saved in the
* closure function 'tail_fun'
*
*/
function get_remote_date() {
var tail = get_tail(arguments);
var tail_fun = function(response_text) { eval(tail); }
var response_text = remote_request(tail_fun,
"continuation.php?AJAX=true&function=date");
if(!response_text) {
return;
}
eval("response_obj = "+response_text);
var changeme = document.getElementById("changeme");
changeme.innerHTML = response_obj.date;
}
/*
*
* This accepts the callback function and
* makes the correct request.
* 'handle_success()' then checks whether
* data is ready and calls the callback.
*
*/
function remote_request(callback_fun, url) {
var req = false;
if (window.XMLHttpRequest) {
req = new XMLHttpRequest();
} else {
req = new ActiveXObject("Microsoft.XMLHTTP");
}
if (!req) {
return false;
}
req.onreadystatechange = function() {
handle_success(req, callback_fun);
};
req.open('GET', url, true);
req.send(null);
return req.responseText;
}
/*
*
* handle_success takes the XHR object
* and the callback to be used upon reply.
*
*/
function handle_success(req, callback_fun) {
if (req.readyState == 4) {
if (req.status == 200) {
callback_fun(req.responseText);
} else {
alert('There was a problem with the request.');
}
}
}
/*
*
* get_tail() finds the function name
* and parses the function to find the
* last lines after the return. Evaling
* this function allows the continuation.
*
*/
function get_tail(arguments) {
var source = arguments.callee.toString().
replace(/(.|\r|\n)*return;.*(\n|\r)*.*}/,"");
return "{ " + source;
}
</script>
</body>
</html>
Permalink
01.06.07
Posted in Coding at 2:47 pm by David Kellogg
- alert() is a native method
- alert() is part of window
- alert() is part of this
- alert() can be rewritten
- alert() can be saved and reused
alert() is a dull function, useful for debugging and annoying users with messages that their password must contain at least one non-alphanumeric character. Let’s spice things up a bit while we find the true essence of this old companion.
1. Alert is a native method. It is not made up simply of other Javascript. This can be confirmed by typing javascript:alert(alert.toString()) into the location bar. We want to rewrite this, but luckily, the native code part will not stop us.
2. Alert is a function of window.
window.alert(”hello!”);
is the same as the non-window.alert() version.
3. alert() is part of ‘this’.
this.alert(”alert from this”);
This agrees with window being at the top level.
4. alert() can be rewritten.
function alert(message) {
document.writeln(message+”<br>”);
}
5. alert() can be saved and reused.
Sometimes while writing extensions, I want to dump some data through alert, but I want to limit the number of times alert can be called. Here is how to do this.
var temp_alert = alert;
alert = function(msg) {
if(alert.count++ < alert.max_alerts) {
temp_alert("Note from alert "+alert.count+": "+msg);
} else {
document.writeln("Max alerts reached!");
}
}
alert.count=0;
alert.max_alerts = 2;
alert("dude");
alert("dude");
alert("dude");
alert("dude");
Result:
Max alerts reached!
Max alerts reached!
Permalink