micmath blog
RecentRunning A Personal SVN Server on Mac Snow Leopard
I love version control. I use it more than is probably appropriate to be honest. For personal projects that don't warrent their own page on github or google projects I like to use a quick and simple svn repo right on my laptop. I have Apple's Time Machine running on there and full weekly snapshots saved to an external hard drive, so I'm not too concerned about the repo itself getting hosed.
I do however want it to be easy to make frequent commits to files I'm working on. And I specifically don't want to run svn with apache -- that is simply overkill for my personal usage. Finding decent instructions on how to set that up on Snow Leopard is difficult, so here's how I did it:
1. If you haven't already done so, download the installer for the excellent My Subversion-1.5.5 Package. It's simply a double click job and you then have an svn server and client all ready to go.
2. Create a folder to hold your repo. Adjust the filepaths to match your own system, obviously:
mkdir /Users/michael/svn
3. Start the svn server, pointing it at the repository directory you just created:
svnserve -d -r /Users/michael/svn
4. Create a new repository:
svnadmin create /Users/michael/svn/projects
5. Set up users for that new repository. This may be the most complicated step, but even this is very straight forward if you can edit an ini file:
bbedit /Users/michael/svn/projects/conf/svnserve.conf
It's just an ini type of file and has loads of useful comments (so read them). You'll want it to say this:
[general]
anon-access = read
auth-access = write
password-db = passwd
realm = projects
That means anonymous users can only read, while authenticated users can read and write. Also the password file is going to be in conf/passwd. So let's edit that now:
bbedit /Users/michael/svn/projects/conf/passwd
Again, a very simple ini type of file. Add yourself to it and save.
[users]
michael = secretpassword
6. Checkout your repository:
cd ~/Workarea
svn co svn://localhost/projects
7. Make changes, commit:
cd ~/Workarea/projects
bbedit README.txt
svn add README.txt
svn commit README.txt -m 'Initial commit.'
8. Finally, you can always stop the svn server, if you want to save a little battery juice:
killall svnserve
JavaScript Constructors and Factories
One of JavaScript's peculiarities is the 'new' expression: when a function invocation is included in that expression that function behaves like a constructor. But the function, by itself, is not intrinsically a "constructor," it's still just a function, and as such any function intended to be called with new can just as easily be called without new. Of course if you, the function's author, are relying on the side-effects provided by new things may not work as intended when those effects are missing. There are however many built-in examples of functions which work equally well, if perhaps slightly differently, when invoked as a constructor or as an ordinary function:
Objects are created by using constructors in new expressions; for example, new String("A String") creates a new String object. Invoking a constructor without using new has consequences that depend on the constructor. For example, String("A String") produces a primitive string, not an object. -- ECMAScript Language Specification, 4.2.1 Objects
Constructors are not the only way to build objects, there is a similar pattern that involves a function, called a "factory." The difference is that a factory is not called with new and factories don't return their this value, as constructors do. You could say that String is an example of a function that can be invoked as a constructor to return a String object, or as a factory to return a string primitive. This design blurs the distinction between factories and constructors. What can we do in this blurry area?
One thing we can do is to create a wrapper for an existing constructor, where we add on our own extensions:
function ArrayPlus() {
var self = Array.prototype.slice.call(arguments);
self.last = function() {
if (this.length) return this[this.length-1];
};
return self;
}
var a1 = new ArrayPlus(1, 2, 3); // like a constructor
var a2 = ArrayPlus(1, 2, 3); // like a factory
// the result is the same, arrays that can last()
alert( a1.push(4), a1.last() ); // alerts 4
alert( a2.push(4), a2.last() ); // alerts 4
When we call ArrayPlus as a factory it returns an instance of an Array with an extra method added on. However the same thing happens when we call ArrayPlus as a constructor, how is that possible?
Typically when a function is invoked as a constructor it automatically returns the constructor's own this value, however in ArrayPlus we are returning our own object, named self. This is allowed under the rules of the ECMAScript Language Specification (section 13.2.2), but it is important to know what the difference is: self is an instance of an Array, not an ArrayPlus. In essense we are overriding the typical behavior of a constructor and forcing ArrayPlus to always behave like a factory, whether it is called with or without new.
I referred to the ECMAScript Language Specification a moment ago, and it does indeed allow arbitrary objects to be returned from constructors, but there is a caveat worth knowing related to this: a constructor (called with new) cannot return a non-object. For example:
function MyNumber(value) {
var self = new Number(value); // an object
return self;
}
var one = new MyNumber(1);
function Three(value) {
var self = 3; // a primitive
return self;
}
var three = new Three();
alert(one); // alerts 1
alert(three); // alerts "[object Object]"
What happened? The rules of ECMAScript say that if a constructor returns an object, as MyNumber does, then proceed as expected. But if a constructor returns a non-object, as Three does, then ignore the return statement entirely and instead return whatever the constructor's this value is. In the case of Three the this value is an instance of Three; in any case it is not the number 3, as you might think it is.
HTML DOM Manipulation with PHP
When discussing HTML DOM (Document Object Model) manipulation it is common to think JavaScript, but there are cases where you might want to do this on the server.
You, if you're like me, might think that HTML, or at least XHTML, is a job for simplexml. Loading and parsing an XHTML file is certainly possible with simplexml_load_file and you can easily use the various simplexml methods to maanipulate the DOM. You will however encounter a small problem if you need to output HTML. As simplexml is designed to deal with XML, it sees nothing wrong with outputting compacted empty tags. In other words if you give it an empty textarea, like so:
$xml = simplexml_load_string('<textarea></textarea>');
and a little while later try to get that string back again, you will find that it's taken some liberties:
echo $xml->asXML(); // <textarea />
This is perfectly fine XML but as HTML it breaks at least a few browsers. If you want to avoid this you'll need to start thinking up clever ways to circumvent what simplexml wants to do.
Or we can just not use simplexml.
The DOMDocument class is, perhaps not unsurprisingly, more feature-rich than the its simpler little brother. For example it has a a way to preserve opening and closing tags:
echo $dom->saveXML($dom, LIBXML_NOEMPTYTAG); // <textarea></textarea>
But even more usefully, it has a loadHTMLFile method and a saveHTML method, which treat HTML more like, well HTML.
Here's a quick example, we're looking to get the names of any required textareas:
$dom = new DomDocument();
$dom->loadHTMLFile($myHtmlFile);
$requireds = array();
$nodes = $dom->getElementsByTagName('textarea');
foreach ($nodes as $node) {
if ($node->hasAttribute('required')) {
array_push($requireds, $node->getAttribute('name'));
}
}
Understanding Variable Instantiation
Quick, just from examining this code (no fair testing it), what will the following alert?
var f = 1;
function f() { }
alert(f);
The fact that I consider this code intersesting (or at least instructive) may tip you to what the answer will be: it's 1. Surprised? If you are you're likely suffering from the common misconception that your JavaScript code is executed in the order you wrote it. If that were true the variable named f would first be declared, then assigned the value 1. Next the function named f would be declared, replacing that existing f and finally the alert would show us the function. But we know that's not what happens.
What really happens is explained in section 10.1.3 of the ECMAScript specification, entitled "Variable Instantiation". If you imagine there is a Variable Object and the JavaScript engine is adding properties to it based on your source code, the specification defines the following distinct steps and the order in which they must happen:
- Function declarations
- Variable declarations
- The rest
Note that when you write var f = 1; you are really doing two things together: declaring a variable named f and then assigning the value of 1 to it. So, putting all that together, effectively the code in our previous example is the same as this:
function f() { } // function declarations first
var f; // variable declarations next
f = 1; // the rest
alert(f);
Is Lightbox the New Popup Window?
Web-based advertising has always been the unloved stepson of web development. Well I say unloved but actually there are lots of people who feel a sort of passion about things like "branding", "click-through rates" and "return on investment". The fact that these things personally bore me doesn't change the fact that there has always been an understanding in this business that if we want to have free-to-view web pages, we must then have a load of ad banners all over those pages. I'm going to concede that point, at least for the sake of my bigger argument.
And I'm conceding the point even though I have no personal experience to base it on: I myself have been using the World Wide Web from it's first days and can safely say I have never, not once ever, clicked on a single web ad. Not even one. Am I living this lifestyle to make some socio-political point? Nope, I'm just still waiting to see a web ad that is interesting enough to click on.
The ad mongers obviously know about uncooperative potential-customers like me, but when they analyze the problem of "he's still waiting to see a web ad that is interesting enough to click on" they come to the wrong conclusion that the solution is to make their uninteresting ads easier to see. If the blinking banners aren't appealing, they reason, then waving a popup window about in front of the content will surely make him want to click; it's worth a try anyway, right? I mean what's the harm?
So here's the harm: Since 2004 every major web browser has had an option to "block popup windows" built-in. And if that's not enough, users can choose from a wide variety of addons and plugins to do the same. If you, wayward web developer, have ever put an uninteresting ad in an popup window, you have helped to practically remove the popup window feature from every modern web browser. Well done, I hope you're proud of yourself.
But in the arms race for greater "CPMs" and "ROIs" there can be no surrender. If the user has developed an immunity to popup windows then there are other fronts to attack.
Now, based on the title of this blog entry, you might guess that I'm suggesting that Lightbox style ads are the latest front, and you'd be right. But I don't intend to criticize the technique used by JavaScript Lightbox implementations, they are no more evil than popup windows were ten years ago. Lightboxes don't annoy people, but annoying Lightboxes do. And here we are standing at the start of yet another very predictable path: how long before we see advice on how to disable JavaScript Lightboxes?
The problem is that a JavaScript Lightbox is not as distinct and self-contained as a popup window. Probably the most practical way to disable all JavaScript Lightboxes will be to disable JavaScript. This is a race back to the 1990's in terms of web development and it should be a concern to all of us.
But it's hard to know who to address this point to: I don't have the illusion that aggressive web advertisers, working for financially-desperate companies are going to suddenly develop a long-view ethos about this issue based on my warnings. In-your-face, hard-sell, intrusive web advertising will always be around but maybe it's up to all of us to enforce a new social contract, if these offenses are offered up by people who speak in terms of dollars and "clicks", then we can give our answer: don't click on those damned things. In fact add those products to your own blacklist of bad members of our web community. Avoid the hosting web sites altogether if possible. This is a campaign for us, if you're a web developer you may be helping yourself in the long run.
Mysterious At-Sign: Extended Attributes in Mac Files
I was attempting to run an old perl script today, and doing a quick ls -la to check the permissions revealed a mysterious at-sign @ in the permissions.
-rw-r--r--@ 1 michael michael 467 8 May 13:16 cvsToSql.pl
Hi there little at-sign. What are you doing in there?
And do you know how hard it is to google the meaning of an at-sign in ls -la? Not easy. I did learn that a filename with a trailing at-sign can indicate a symbolic link on Linux. But this is Mac OS X Leopard and the at-sign is in the permissions. More googling....
The best answer is from dev.netcetera.org and Jeff Seitz’s Blog, and it is that the at-sign indicates that the file has extended file attributes. Hmmm... I want to get rid of those I think. Step one is to find out the name of the extended attribute.
$ xattr -l cvsToSql.pl
com.apple.FinderInfo:
0000 54 45 58 54 52 2A 63 68 00 00 00 00 00 00 00 00 TEXTR*ch........
0010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 ................
Okay, so my file has some extra data attached to the "com.apple.FinderInfo" attribute. I suppose there is some important nerd-reason for that being there but I'm not interested: step two is to get it off.
$ xattr -d com.apple.FinderInfo cvsToSql.pl
And no more at-sign! All that files attributes are now of the non-extended variety.
Microsoft Mime Types
I had a problem with some more recent Microsoft document formats not being recognized when downloaded from an Apache server. Ironically it was the IE 8 having the problem -- I think it was trying to be secure -- while FireFox knew what to do just fine. Any way, here's an .htaccess addition that will help our IE 8 friends out (with thanks to mcupples):
AddType application/vnd.ms-word.document.macroEnabled.12 .docm
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.document docx
AddType application/vnd.openxmlformats-officedocument.wordprocessingml.template dotx
AddType application/vnd.ms-powerpoint.template.macroEnabled.12 potm
AddType application/vnd.openxmlformats-officedocument.presentationml.template potx
AddType application/vnd.ms-powerpoint.addin.macroEnabled.12 ppam
AddType application/vnd.ms-powerpoint.slideshow.macroEnabled.12 ppsm
AddType application/vnd.openxmlformats-officedocument.presentationml.slideshow ppsx
AddType application/vnd.ms-powerpoint.presentation.macroEnabled.12 pptm
AddType application/vnd.openxmlformats-officedocument.presentationml.presentation pptx
AddType application/vnd.ms-excel.addin.macroEnabled.12 xlam
AddType application/vnd.ms-excel.sheet.binary.macroEnabled.12 xlsb
AddType application/vnd.ms-excel.sheet.macroEnabled.12 xlsm
AddType application/vnd.openxmlformats-officedocument.spreadsheetml.sheet xlsx
AddType application/vnd.ms-excel.template.macroEnabled.12 xltm
AddType application/vnd.openxmlformats-officedocument.spreadsheetml.template xltx
