Case in point: I want to use “find” to find files I’ve recently created.
man find (BSD edition):
-ctime n[smhdw]
If no units are specified, this primary evaluates to true if the difference between the time of
last modification time and the time find was started, rounded up to the next
full 24-hour period, is n 24-hour periods.
If units are specified, this primary evaluates to true if the difference between the time of
last modification time and the time find was started is exactly n units.
Please refer to the -atime primary description for information on supported time units.
Humane documentation FAIL! The precision here is all well and good to include somewhere, but unnecessary for most usages. Please, just tell me what I need to know and Don’t Make Me Think!.
What I wanted to see:
-mtime t
Include only files modified t days ago. You will typically want to specify a +/- sign. e.g. “-ctime +3″ for files created 3 or more days ago. To measure in another unit of time, you can append one of the following to t: s for seconds, m for minutes, h for hours, d for days, w for weeks, but note that “-ctime” unfortunately only works if the time is at least one day. For example, “find . -ctime 1d6h” will return files created in the past 30 seconds.
Technical detail: (the legalese stuff goes here. 99% of users will never need it and never read it.)
The improved version focuses on what the typical user needs to know, uses active voice, avoids the cross-reference (it’s documentation, not code, so embrace redundancy!), and most importantly, includes an example. (The man page does include examples at the bottom, but (a) they should be included against each component too; and (b) they still shy away from concrete values: “-newer ttt”!!!)
A lot of these man pages have been around for two decades or more, with minimal changes to my knowledge; I’d love to see someone like Ubuntu sponsor an effort to bring them up to date. Plain English without dumbing down.

Tags: SoftwareDev
November 13th, 2008 · 3 Comments
Guid0.js
Guid0 is a GUID library for Javascript. Okay, it doesn't yet do official, bona fide, 128-bit, GUIDs yet, mainly for API design reasons. But this is a library you might find useful if you want to generate a unique ID in your Ajax app.
Usage:
JAVASCRIPT:
guid = new Guid();
guid.generate(); // Returns a unique ID, e.g. "dkvagrkx1rt"
With options:
JAVASCRIPT:
guid = new Guid(
{
chars: Guid.constants.base85, // or you could say "abc" if you only wanted those chars to appear
epoch: "June 1, 2003",
counterSequenceLength: 2, // a counter field appended to the end
randomSequenceLength: 2 // a random field appended to the end
}
)
The demo:

The demo generates a bunch of GUIDs. They look almost the same because most of the GUID is just a time representation in Base N (where N is the number of characters in the GUID's configured charset).
I made Guid0 in conjunction with TiddlyWiki work. Within a store, tiddlers are keyed on their title. In the typical case, the user has entered a title to describe the content. But when we get into application territory - using TiddlyWiki as an application framework - there are reasons why we want the more familiar database approach of automagically generating the primary key. These are several reasons for this:
- Tiddlers with no meaningful title. Sometimes, tiddlers are just containers for text someone has entered. A perfect example is the Comments Plugin I've been working on (separate blog post pending). A comment is a tiddler. When you have a blog or forum or whatever with comments, you usually don't invite users title their comment...it's not very enticing. So in this case, the comment is the tiddler text and the title must be auto-generated so we can put it in the store.
- Renaming. As with the usual motivation for auto-generated IDs over meaningful IDs, renaming support is sometimes required. In one case, I have a user submitting a first cut of something, and an admin coming along later and cleansing it. We can't expect the user to get the name right the first time, and there are several tiddlers referencing the initial tiddler (via custom fields) by the time it might be renamed.
- Can't ensure uniqueness. With multiple users, you don't always want to force them into choosing different titles for each tiddler. If the comments plugin did include titles for instance, you wouldn't want a uniqueness constraint. Using GUIDs, you could support multiple titles with the same display name.
The library is generic - not TiddlyWiki-specific - but I've wrapped it into a small TiddlyWiki plugin. In the future, we may expand the plugin. For example, each time a new tiddler is created, the plugin may intercept the call and give the tiddler a GUID title, and stick the title in a "name" field.
I'll update this post when proper 128-bit GUID is supported.
Tags: SoftwareDev
October 21st, 2008 · 5 Comments
I just did some tinkering with offline sound and it turns out you can embed an audio clip in an HTML file, and play it without using Flash. I could have demo'd this in a raw HTML file, but it was just as easy to stick it in a Tiddlywiki file. So I made a TiddlyWiki called JinglyWiki. Click on the button and it will play a sound. If you grab the file (safest using a tool like Curl or wget, as the browser will sometimes Save As something different), you can run it offline and it will still play the sound.

JinglyWiki started after an office conversation yesterday. We had a flaky wifi connection and were pleased to be able to play a beat on http://instantrimshot.com to signify a re-connection. This got us thinking about playing beats in Tiddlywiki. Jeremy mentioned the possibility of data: URIs, and I thought back to Reinier's great effort in playing sound without Flash. I wondered if it would work with data: URIs and to my pleasant surprise, it did. At least in FF3, which is all I've tested so far. I also forgot how tiny the code is to play audio without Flash - you just add an element to the page.
The point of JinglyWiki is you can stick a 300K file on your local file system or a USB stick and play gratuitous sounds without being online. Your iPod cost you several hundred bucks, whereas JinglyWiki is entirely free. Free as in you can spend your money on beer instead. JinglyWiki may well be the best portable music player you never paid a penny for. Groovy.
It would be so much more useful with some code to dynamically generate WAVs, but that's a project for another day.
As for the name, it's a play on the much more important project Phil Hawksworth has initiated to build a JQuery
based Tiddlywiki framework: JigglyWiki. I think this nascent effort is going to produce some wonderful plugins for the JQuery community and be an important enough project to derive novelty joke names out of :), so I'm setting the trend here.
The data itself is 15KB for about a second of voice content.
Here's the plugin code. Trivial or wot?!!!
JAVASCRIPT:
config.macros.jingle = {}
config.macros.jingle.handler = function(place,macroName,params,wikifier,paramString,tiddler) {
button = document.createElement("button");
button.style.fontSize = "4em";
button.innerHTML = "Play Me! Play Me!"
button.onclick = function(ev) {
startWav(SOUND_URL);
}
place.appendChild(button);
// cancel dbl-click so we can follow our natural urge to click on the button incessantly
story.getTiddler(tiddler.title).ondblclick = function() {}
}
// non-flash sound handling adapted from http://www.zwitserloot.com/files/soundkit/soundcheck.html
var embedEl;
function startWav(uri) {
stopWav();
embedEl = document.createElement("embed");
embedEl.setAttribute("src", uri);
embedEl.setAttribute("hidden", true);
embedEl.setAttribute("autostart", true);
document.body.appendChild(embedEl);
}
function stopWav() {
if (embedEl) document.body.removeChild(embedEl);
embedEl = null;
}
// To make a new sound, cut and paste into hixie's handy Data URI Kitchen
// http://software.hixie.ch/utilities/cgi/data/data.pl
var SOUND_URL="data:audio/x-wav,RIFF%17%1C%00%00WAVEfmt%20%10%00%00%00%01%00%01%00%40%1F%00%00%40 ........................" // snipped
Tags: SoftwareDev
October 20th, 2008 · 5 Comments

Chrome now has Greasemonkey support. The Chromium patch came from Aaron Boodman, who is at once a Google employee and the brains behind the original Firefox Greasemonkey extension.
It makes me wonder if this is the plan for Chrome add-ons. Forget about anything like Firefox's add-on mechanism and just rely on Greasemonkey. With the right APIs, it's all you need.
For a long time, I have been confused and disturbed by the disparity between Greasemonkey and Firefox extensions. Creating a Greasemonkey extension is dead simple for any Ajax developer; creating a bona fide Firefox extension is more complicated, and involves writing the kind of meta-descriptions and JARs that most Ajax folk avoid. (The kind of simplicity mantra that has made JQuery king of the hill for now.)
You might recall I automagically ported the domain teleporter Greasemonkey script to a Firefox extension a while back. That this was possible, and easy, demonstrates that the Firefox extension mechanism could be made a lot simpler. I thought there was talk of doing it for FF3, but it didn't happen.
What do Firefox extensions do that Greasemonkey can't? Nothing Greasemonkey can't get around.
- Extended access - manipulating the Browser Object Model, accessing local file system, etc. All of this could be possible from a Greasemonkey script with the right APIs available. There are security implications, of course, but as long as users are aware of who can do what, it's no different from what we have now. It may be even better, due to Greasemonkey's built-in wildcard-based URL filtering, so that certain apps might only be limited to certain domains.
- Metadata - certain metadata is present in an extension. This could just as easily be part of Greasemonkey's metadata.
It's my hope that Google's vision for Chrome plugins is Greasemonkey on Steroids, and that this unleashes a whole new ecosystem of powerful add-ons that have until now required too much effort to build.

Tags: SoftwareDev
New York Times has a popular article about an important topic: getting locked out of your webmail account:
LOGGING on to Gmail or other e-mail service has become a routine of daily life, completed without a thought. What would you do, however, if you woke up tomorrow, plugged in your user name and password as you always do, but then received an unfamiliar message: “User name and password do not match”?
If you’re a Gmail user, what you’ll want to do after a few more unsuccessful, increasingly frantic attempts is to speak with a Google customer support representative, post haste. But that’s not an option. Google doesn’t offer a toll-free number and a live person to resolve the ordinary user’s problems.
The gist is, if you want GMail with the assurance you won't get locked out, pay up $50 a year for support.
$0/year is very reasonable, but there's a way you can do it for free, and quite simply. You just sign up for Google Apps for Your Domain (note: I'm not a shareholder nor an affiliate, just a fanboy). The catch is you have to own a domain, but (a) they are damn cheap, around $7/year for .coms; (b) it doesn't even have to be a .com; some other endings like spam-infested .biz and .info are even cheaper; (c) you may already own a domain anyway. (A friend recently showed me a great little website some had put together for his business, with its own domain, but the email was a yahoo! address - more professional to match it to the website ne?)
With Google Apps for Your Domain, you point your DNS server's MX at Google. If you're locked out, you can point your MX at another mail server, perhaps your SNS registrar provider as most of them provide some rudimentary support. And you're unlikely to be locked out anyway, because you can post a special message on a website on your domain, to prove you control it, which will reset the domain admin password. This is all offered free of charge.
Admittedly, this is not a mom-and-pop solution. It's obviously requires some tech knowledge to own a domain and point its MX somewhere or post a message to it. But certainly doesn't require hardcore geek-fu either, just a little savvy and willingness to try things out and follow some instructions. If you already own a domain, you may as well go this route over just using a plain GMail/Yahoo account. it's great piece of mind to know that you, and only you, are the master of your own domain!
Tags: SoftwareDev

I can't let the current credit crunch / financial crisis / Wall St meltdown pass without mentioning the Sarbanes-Oxley Act, aka SOX.
I feel compelled to do so because I haven't seen it mentioned once in the mainstream media during the past fortnight of turbulence, and yet it should have at least played some role in reducing the likelihood and impact of an event like this. Otherwise, it was a waste of effort.
Searching Google News for "Sarbanes-Oxley" just now yielded about a half-dozen results. One is from 2006, one is a letter, one is about Sarbanes' son's bailout vote. Not much. The only relevant article I found:
The pain felt in middle America was so intense that Congress enacted legislation to clamp down on such errant behaviour. The Sarbanes-Oxley Act of 2002 imposed stricter levels of disclosure on public company boards, management and accounting firms. It was hailed at the time as a breakthrough in regulating errant corporate behaviour. But it should come as no surprise that about a year ago, during the height of the most recent boom, US regulators were coming under intense pressure to dilute parts of the legislation.
Sarbanes-Oxley, the argument went, had cost Wall Street its coveted position as the world's financial hub. The high cost of compliance with the legislation had seen international focus shift to London.
The article goes on to explain why it might be not so relevant to the current situation, which is completely dominated by the banks:
The latest crisis has emerged from a different area - the lax prudential regulation of America's banks. Housing loans were pushed on to people who had a history of default. That's the definition of subprime.
So it's not a case of "this is exactly the kind of thing SOX was meant to prevent". It's more subtle than that - SOX is only public companies, and not all banks are public; SOX covers all types of companies, not banks which have particularly complex financial characteristics; SOX is about control and reporting, and does not place specific constraints on levels and forms of credit risk.
Nevertheless, many banks are public companies and public companies must comply with SOX (even if the system is developed in the UK...as long as it operates in the USA, it must comply, that's my legally dunce understanding of the matter). Sarbanes still applied in banks from around 2003. I was working on one project where "pulling up your SOX" was a constant non-functional force lurking in the background of many major design decisions. So, for example, if we were to choose an in-memory database, what would happen to the auditing facility in the event of a sudden crash, would this cause a violation of SOX?
Another system I was looking at working on involved the treasury operation of a prominent American bank, where SOX was a big driver for them to streamline the performance of the system that comes out with a single, very important number: the bank's overall position.
It's vastly beyond the scope of this blog to explain away the crisis or even SOX's (non) effect on it. What I can say, though, from a software perspective is that it feels like yet another standard that's complex enough, and enforced enough, to drive substantial effort, while being high-level enough to not necessarily be very useful, at least not in cases where the intent was already there.
Alistair Cockburn wrote to the effect, "show me the methodology, and I'll show you the methodologist's fears". We might well apply this to standards and regulations too.
SOX can be very closely tied back to Enron and related collapses and the fear of a repeat incident. However well-intentioned, there are two problems with standards that emerge from fear: (a) forcing someone to not follow the same strategy as that which led to a collapse...is no way to guarantee a similar collapse won't take place again, for there are many alternative strategies they may take; if you retrospectively try to do what would have prevented recent incidents, you can expect your standard to be gamed hard by those using alternative strategies; (b) even if you can prevent a repeat incident, at what cost? Many times, the constraints you place on creativity and the degree to which your standard crushes human spirit and consequently inhibits progress, these costs may well outweigh the benefits.
Whether these problems were causes by SOX is a topic for debate. But as the world readies itself for a whole new set of controls - many of which will affect your daily work and mine, dear software reader - one can only hope there is big ups on some fair dincum contemplation and ixnay on the knee jerk, eh.
Tags: HumansAndTech
September 28th, 2008 · No Comments
My fellow Osmosoftie Paul Downey made this bodacious sketch when I ran through my @Media Ajax presentation on OpenSketch:

If you haven't seen his handiwork before, he has a great talent for this distinctive style of text. Check them out. He also created The Web Is Agreement (I made a little remix of it into a full page version.)

Tags: HumansAndTech · SoftwareDev
September 21st, 2008 · 5 Comments
I've recently begun working on a project with Osmosoft, which I'll announce Real Soon Now, and have got my hands dirty with TiddlyWiki to the point where I'm now able to make at least some useful functionality. You effectively get an MVC framework for free with TiddlyWiki, so as a power developer, I can see how it could let you build a certain type of app quite rapidly. Even without too much knowledge, you could use it for prototyping quite easily, just by knowing the key extension points. I figured it would be worth capturing my reflections to date.
There's a lot of documentation around on TiddlyWiki, and also some good support resources in the form of Groups and IRC. What I'd like to see in addition to that is a guide for people writing "verticals" - web apps building on TiddlyWiki, rather than incremental enhancements. And also it would be good to see a cookbook or pattern collection covering the main types of plugins.
The other issue I've had, while I'm brain-dumping, is that plugin exceptions are caught at some point, with an error message shown, and not propagated, so they don't turn up in Firebug. I need to look into this more as I think there are ways to get better diagnostics. I would also like to get a better understanding of the startup and shutdown lifecycle. As explained in my last post, there are some techniques you can use to hook in at certain stages, though no direct support.
I'll have an initial stab here at the kind of thing I'd like to see in a developer guide, and refine it massively at a time when I'm less of a green Tiddler, maybe on a wiki. I'm really not qualified to say too much at this stage, but I want to capture it while it's fresh on my mind. Note there's already a lot of good material along these lines on the TiddlyWiki wiki.
Development Process
The simplest way to work is directly inside the TiddlyWiki. Locate shadow tiddlers under the "more" tab and edit them. And create new tiddlers, tag them as "systemConfig", and stick your plugin code inside them. Each time you change it, hit reload. That's a nice, simple, way to start off.
For serious development, there are better options. (Which I'm about to start learning.)
Extending TiddlyWiki into a Custom Web App
The way to extend TiddlyWiki is not to take a TiddlyWiki and start hacking the source. You can do anything you want to do via the following techniques:
- Edit Shadow Tiddlers Shadow tiddlers are special tiddlers used to configure the TiddlyWiki. When you open a shadow tiddler and edit it, it saves as a regular tiddler. The original shadow tiddler remains, mainly as a safeguard, but becomes irrelevant. (I mention this because you might think there's a cascading effect, where the regular tiddler is run before or after the shadow. In fact, the regular tiddler simply replaces its shadow from the perspective of configuration.
- Make Plugins A plugin is a tiddler tagged "systemConfig" and containing some code. The code will be executed when the wiki loads, since TiddlyWiki's built-in startup sequence looks for tiddlers marked SystemConfig and executes their content.
- Include Plugins Include plugins from elsewhere if they are useful. You import a plugin via the PluginManager tool, accessible from Backstage. Or by cutting-and-pasting into a new "systemConfig" tiddler.
- Change Options Options such as Auto-Save also affect your application's behaviour. You can set them programatically using config.options at startup. Alternatively, if you have retained the options control in the sidebar, set options there and save the page.
In addition, you may find you need more than one TiddlyWiki file to build up your web app. You might end up with a separate file for each key functional area. (I haven't seen this done, but a guide could explain how to pull in plugins and tiddlers from a common place. Possibly building on TiddlyWeb.)
Which Shadow Tiddlers to Customise?
Here's a list of shadow tiddlers you might want to customise for your app:
- SiteTitle - the contents of this tiddler are used in the header. This is an example of an uber-simple shadow tiddler. When you begin to build a vertical, you will want a header that reflects the name of your app. Similarly, you can set SiteSubtitle and SiteURL tiddlers.
- StyleSheet - the "StyleSheet" tiddlers lets you add some CSS rules to enhance or redefine the existing CSS based look and feel. This is a slightly more complex form of appearance customisation than the previous point. You probably don't want your app to look like a carbon copy of the original TiddlyWiki, so use these tiddlers to theme it. There are some other style-related tiddlers, like StyleSheetColors and StyleSheetLayout, but it's not recommended that you change them, because if you ever upgrade the TiddlyWiki core, any new styling will be ignored. So if there are things you want to change in those tiddlers, just create the CSS rule inside StyleSheet and it will take precedence. There is also a ColorPallette tiddler referenced by StyleSheetColors, which you *can* modify safely, and it lets you change the color scheme. In general, you won't need to override StyleSheetColors directly - ColorPallette should be sufficient.
- PageTemplate - the HTML for the entire page. An even more complex way to customise your app, by changing the raw page structure. Note the way this tiddler "pulls in" content other tiddlers. You can therefore change the appearance not just by changing PageTemplate, but by changing those included tiddlers. We've already met a couple of them - SiteTitle and SiteSubtitle - which simply contain a word or few in most cases. Others you'll noticed here are MainMenu and Sidebar to reflect further options which are always present in your app.
- DefaultTiddlers - a list of the initial tiddlers that show up when the page is loaded. In a web app, this would typically be a blurb, maybe embedding a video or image, and links to other tiddlers. The kind of thing you'd see in any web app, really. In this sense, TiddlyWiki provides you with a basic, customisable, layout scheme.
- etc.
What Kind of Plugins to Create?
Here are some examples of plugin styles:
- Macro - Your plugin defines a macro. Users include the macro as <<macroname>> inside a tiddler, and your macro is invoked, and it typically spits out some content. You can easily make your macro apply inside all tiddlers by including it in ViewTemplate.
- Hijacking (aka Monkey Patching) - changing the behaviour of some code that's already in the application - either core TiddlyWiki code or another plugin you've imported. (Could expand this with specific things that are changed)
- Startup behaviour - Some code executed on startup.
Architectural Principles
- Reuse - where a plugin already exists, don't reinvent the wheel. Reuse it. Likewise for core TiddlyWiki components. If possible, hijack (aka monkey patch) to extend it rather than directly hacking it. (Open-Close Principle).
- Modularity - Plugins build on each other. Don't write a single "big bang" plugin for your entire app. Break things down into logical units.
- Flexibility - keep the app open to further customisation from users. For example:
- Content inside special tiddlers - Instead of hard-coding values, consider pulling them in from special Tiddlers, just like the way SiteTitle and SiteSubtitle shadow tiddlers are used. This way, a power user could easily change the value by modifying the tiddler. If it's content to be included somewhere, you would usually want to run wikify(tiddler.text) against the tiddler content, so the user can include TiddlyWiki markup. A useful concept here is "slices" - this mechanism lets you include content from just part of a tiddler, not the whole thing. See how StyleSheetColors uses ColorPallette for an example.
- Javascript inside special tiddlers - Most apps have critical algorithms which power users - if sufficiently authorised - might like to update ("strategy pattern" type modules). Isolate such code into special tiddlers, so someone can change those critical parts of your code without having to dive into the whole thing. If your core code has the right functions available, the tiddler content might be a kind of internal domain-specific language.
- Favour macros over plugins which just charge in and change stuff. For example, if you were writing a comments plugin. The brute force approach would be to bolt on a comments area to every tiddler. But you could achieve the same thing by creating a comments macro, and then updating ViewTemplate to run the macro (ie adding < > to ViewTemplate). Power users could then have more flexibility in several ways: (a) they could remove comments or alter where they appear; (b) they could use a plugin like TaggedTemplateTweak to ensure comments only appear for certain tiddlers; (c) they could customise the way comments are handled using parameters to the comments tag (assuming your macro accepted parameters).
Key Classes and Functions
Here's a guide to the most important classes (
(More complete guide on TiddlyWiki internals).):
- Tiddler - the data model for a single tiddler - its title (tiddler.title), content (tiddler.text), last modifier, etc.
- TiddlyWiki (~aka "store") - a collection of tiddlers. Typically, there is just one TiddlyWiki on the page containing all Tiddlers, called "store". Due to certain hard-codedness, it's not worth creating a separate TiddlyWiki - just use "store" to create, retrieve, update, and delete Tiddlers (the "CRUD" functions).
- Story (~aka "story") - a view showing zero or more tiddlers. The main display area you see on the standard TiddlyWiki page is a Story called "story". So use "story" to add and remove tiddlers being viewed.
- (possibly others)
- window - for completeness sake, I'll note that there are certain "global" (i.e. window) functions worth knowing about.
Let's look at how those classes give our web app a model and view.
First, the model. How is CRUD handled?
Tiddlers are the atomic model unit in TiddlyWiki. You can inspect the contents using tiddler attributes:
- tiddler.title, tiddler.text, tiddler.fields, tiddler.tags. These are the title (which also acts as ID), content, custom fields map, and tags for a tiddler. To access slices, use getTiddlerSlice(). Note that shadow tiddlers aren't real instances of "Tiddler", so use getTiddlerText() to retrieve them and inspect their text. (There are also properties tracking creation, modifier, etc.)
- tiddler.set()
-update several features of a tiddler at once.
So the "U" in CRUD - Updating - is handled primarily by setting its values.
As for creation, reading, and deleting - these go against the collection of tiddlers on the page, viz. the "store" object (an instance of TiddlyWiki). The key functions are:
You persist these changes by calling:
- saveChanges() - save changes to disk (remember, TiddlyWiki runs on a file:/// URL - using cunning manipulations normally exclusive to file:/// URLs, it modifies itself with the updated data)
Next, the view. This is mainly handled by manipulating the "story" global (as well as customising general structure and look-and-feel using the many appearance-related shadow tiddlers). You will probably want to show and hide tiddlers dynamically:
Some important global functions:
- wikify() - converts a string of marked-up TiddlyWiki content to HTML. (e.g. wikify(''xyz'') becomes <b>xyz</b>.)
- createTiddlyElement - just a generic utility function to help create DOM elements (notTiddlyWiki-specific, but appears a lot if you're creating content via DOM manipulation).
Cookbook
- Introducing a New Tiddler
- Using Slices
- Running Code on Startup
- Turning Auto-Save on
- etc etc
Testing
Using JSpec, building a test vertical etc.
Tags: SoftwareDev
September 17th, 2008 · 1 Comment
Tiddlywiki plugins load on startup, early on in the whole boot sequence. I was wondering how to detect when elements are on the page and got some good advice in #tiddlywiki.
Turns out there's no hooks, but a kind-of-hook is macros' init() function. I didn't want to use this, since I'm not creating a macro, though it would have been possible to create a "fake" macro - ie one that's not intended to be called, but just does something in its init(). However, I went for the more general solution - hijacking (monkey-patching) restart():
JAVASCRIPT:
var origRestart = restart;
window.restart = function() {
origRestart();
... some code which can assume elements are on the page ...
}
mmahemoff: hi, i'm writing a plugin that needs to load as soon as the page is ready...is there an event handler for that?
mmahemoff: specifically, my PageTemplate contains an element and I want my plugin to do document.getElementById("element")
Ace_NoOne: mmahemoff: well, there's a ticket for those kinda hooks - but no implementation so far AFAIK
Ace_NoOne: a hacky way would be to write a macro that's hidden in (executed by) some PageTemplate element
jayfresh: mmahemoff: there is this:
jayfresh: var startingUp = false;
jayfresh: that's in the global space and is true during main()
jayfresh: and false the rest of the time
Ace_NoOne: FWIW, http://trac.tiddlywiki.org/ticket/484
Ace_NoOne: has some links
Ace_NoOne: specifically: http://www.tiddlywiki.org/wiki/Dev:Startup_Phases
mmahemoff: great tips, thanks
Ace_NoOne: mmahemoff: macros' init function run after refreshDisplay
mmahemoff: ok, that ought to do it in my case
mmahemoff: in the more general case, it sounds like hijacking restart() is the typical pattern?
Ace_NoOne: mmahemoff: saqimtiaz1 probably knows best
saqimtiaz1: mmahemoff: standard practice is to hijack restart. Not pretty but the best we have right now
(Snipped some discussion related to a separate thread.)
Tags: SoftwareDev
September 16th, 2008 · 3 Comments
In the questions after my @media ajax talk, Simon Willison asked about frame busting. If gadgets sit inside iframes, what's to stop them from busting the frame, i.e. replacing the container with another website. I notice he made a similar comment when OpenSocial came out. If a gadget can cause iGoogle to go away in place of another website, it could for example launch a phishing attack by presenting a mock iGoogle login page ("iGoogle has timed out. Please re-enter your username and password.").
At a technical level, there is actually nothing to prevent this. There's no magic in the container. IFrames are about as good as it gets in modern browser for taming the gadgets, but there are still problems with that model, and one of those is the ability for iframes to bust out. I decided to create a demo of this. The gadget is here. You can drop it into iGoogle and see for yourself. Video below:
(Parenthetically, the video is vertical. Why are videos always horizontal on the internets? It's a computer, not a TV! It should be just as easy to embed an dodecahedron video if that's what I fancy at the time.)
At this stage, there's no technical way around this. One possibility would be for the container to do something in the rarely-used onexit() method, which runs just before the new page is loaded. However, as I learned with WebWait, which is also vulnerable to frame-busting, there's nothing you can really do at that stage, and you can't determine if the exit is happening because of a frame-busting event as opposed to the user just typing in a new URL. I suppose onexit() could still be used to log info to the server - if you knew all the times the container exits and which gadgets were present at that time, you might find certain (malicious) gadgets were present more times than you'd expect if they were present randomly. Although, I'm not sure about how reliable it is to make an Ajax call in the onexit(). (In this case, though, it would only need to work some of the time.)
In the future, the technical solution is Caja, if it proves to be production-ready. Caja ensures a safe subset of Javascript, so a container like iGoogle would only ever serve a gadget if it was verified to be safe.
Until then, we have to rely on "social" mechanisms. i.e. user comments in the catalogue and manual checking by container staff. A while ago, iGoogle made it harder to add a gadget directly by URL - you basically have to use the catalogue unless you're a developer. So the catalogue is effectively acting as a whitelist - once found to be malicious, a gadget could be removed. This isn't simple though - gadgets are dynamic and the catalogue is effectively just a list of URLs. A malicious author could have their gadget added to the catalogue and then change it, so the gadgets need constant review - a highly ineffective process.
I also mentioned in the presentation that "html" type gadgets are more recommended than "url" gadgets. This is partly because with html gadgets, the container at least has some idea of what's happening inside the gadget - though not entirely, since the code can still reference external scripts and services. With "url" gadgets, what happens is entirely controlled by an external server.
Tags: SoftwareDev