Oh the Irony. Oh the sadness. \n\nWhile plugging an NVR to backup my main computer (as my main computer wasn't backed up at all until then) I accidently switched off my computer. Well, Linux just isn't resistant to power switching off.\n\n81 days, 18:04:43. That was its uptime. Do you have any idea how long it's going to take for it to get such at uptime again? 81 days, 18:04:43, that's how long.
Yesterday I worked my last day at CS. I spent almost exactly three years there. I left mostly because I couldn't get a raise, and someone else contacted me and offered me more. As soon as I resigned, I was offered more money. I wish employers would just pay people to start with. Now I feel like I should have resigned years ago (well, presumably less than three years ago).\n\nThe "someone else" is Altran, which is a huge service company. It's going to be a totally different job (no more development, but high-level specification and analysis), which worries me and excites me. Will I like it? I'll let you know.
"Your cat fell off the balcony," kids coming up the stairs told us. "What? No, he's right over here." "No, he's down there he fell off!" Our cat comes over to see what's going on. "See, he's right here." "Oh." "Oh, //a// cat fell off the balcony".\n\nSure enough, we could see it down there on the floor, laying and looking around. We went downstairs to see if we could help.\n\n\nIt was the cat from the neighbours upstairs, a small, young cat that was into extreme acrobatics. One afternoon I found him in front of our door, and he escaped into our flat. I spent ten minutes trying to get him, as he jumped from the balcony to the office window (we're on the sixth floor) and balanced on the railing, all that in high wind.\n\nOn that sunny Sunday, he was laying on the floor, in the corner of a garage door, just under the balconies. He was looking around as we approached. Blood was coming out of his mouth and eyes. After a minute not knowing what to do, Narelle went back up to see if she could find the owners, or call or a vet, or something.\n\nI stayed with him and laid my hand on his neck. He cried blood. He was fighting to breathe for all the blood in his mouth and windpipe and lungs. I felt powerless and sad. I could hear the gurgle of the blood down in his throat. He'd pooed himself. That's the smell of death, a mixture of blood and shit.\n\nLater the owners came and I moved the cat in its carrier. I didn't think he stood a chance after that fall from the 7th floor down on to concrete, but you've got to do what you've got to do.\n\nThat night the neighbours came around to let us know the vet gave him morphine, then found he had perforated lungs, perforated palate. He was put to sleep.\n\nShit.\n\n
This is my second post. I have actually moved to ccTiddly, which saves data in MySQL (well that does not make me happy) and allows for remove editing, among many other things.\n\nI do wonder if this is suitable for a purely bloggy-type usage. If it's not, I may have use for my old Nanoblogger.\n\nRight, I think I've enable RSS generation. Without a feed, this would be mostly useless as a blog. Let's see.\n\nI like that whenever you press 'New Journal' it just opens the post for today. That would consolidate journals into one entry per day. On the other hand if you're posting on different subjects, it's not the right thing anymore. Oh well.
I installed a BlogPlugin I found on the internet, which automatically creates a blog-like first page: it displays a list of the most recently modified tiddlers. So from now on you'll see the recent changes automatically without having to look up the timeline.\n\nThe next step, I guess, is to find out how to let readers comment. ccTiddly has a whole access control system, so this might help.\n\nI also installed a SplashScreenPlugin to tell people the site is loading, but somehow I screwed it up and it wouldn't go pas the splash screen. Suddenly, you can't edit the wiki anymore. So you can't remove the splash screen. Oops. Luckily a bit of phpmyadmin to erase the splash screen did the trick. I'll have to look into it a bit more...\n\nRight, we're now off to the countryside for a bit of barbequeuing up and a bit of voting.\n\n7.15pm. I'm pretty sure that a method to allow anonymous comments is described on [[this forum|http://groups.google.com/group/PrinceTiddlyWiki/browse_thread/thread/1c3c13068a3c3934/f0f2e4ef9826e48f#f0f2e4ef9826e48f]]. I'm so happy.\n\nIn other news, it seems no one documented the fact that you should set up a SiteUrl tiddler for RSS generation to work properly. Otherwise, the RSS links go to tiddlywiki.com, which really isn't what you want.
There is a funny little hack out there called [[sslh|http://search.cpan.org/~book/Net-Proxy-0.07/script/sslh]], which lets one accept both https and ssh connection on the same, one port. It lets me connect from inside my corporate proxy, which allows outbound connections on port 443, using Putty, while still being able to serve Web pages over https.\n\nThere are two problems with sslh:\n* It's in Perl. That means it's pretty RAM hungry, and probably not very fast.\n* It doesn't manage privilege dropping, which is rather questionnable.\n\nThe obvious solution to both problems was to re-implement it in C, because that's what geeks do. I give you [[sslh.c|http://www.rutschle.net/tech/sslh.c]]. Use it wisely.\n\nThis also makes for a good example of network programming.\n\nEDIT: sslh now has its own [[page|http://www.rutschle.net/tech/sslh]] on my site, and was accepted by [[Freshmeat|http://freshmeat.net/projects/sslh/]].
It's not actually new at all, it's been around for several years. However, I just recently heard of it when Scott Adams (of [[Dilbert|http://www.dilbert.com]] fame) wrote about it on his [[blog|http://dilbertblog.typepad.com/the_dilbert_blog/]]\n\nIt's called [[Basic Instructions|http://basicinstructions.net/]]. Most of it is hilarious. And to top it off, there's several years' worth of archives. Now that's not going to be as bad as [[UserFriendly|http://www.userfriendly.org]] in terms of productivity loss, but that's mostly because I have no productivity left to speak off.
Someone on the Debian-User-French mailing list asked what people thought about the [[Ubuntu|http://www.ubuntu.com]] distribution, and here is my answer (in French -- I may translate that some day):\n\nA l'avantage d'être basée sur Debian, que je connais bien: un debianniste est à la maison sur une Unbuntu (contrairement à une Mandrake par ex. basée sur Redhat). Ça veut dire qu'on retrouve les mêmes fichiers de configs aux mêmes endroits, etc. \n \nA l'avantage sur Debian d'être actualisée plus souvent, ce qui est intéressant pour au moins 2 raisons: \n* Applications bureautiques plus récentes (bon, je dois avouer que personnellement je m'en fous un peu, je suis content avec une vt100 -- mais si j'avais un parc à gérer, ça entrerait sans doute en ligne de compte). \n* Meilleur support du matériel récent. \n \nA également la propriété (là ça n'est pas forcéement un avantage :) ) d'être plus souple sur la licence, donc d'intégrer des drivers propriétaires, flash, et autre: la distrib est plus utilisable de base. \n \nPar contre, ces choses sont parfois aussi des inconvénients: sur un serveur, je ne veux *pas* que mes applications soient mises à jours tous les 6 mois, je veux qu'elles ne bougent plus du tout quand elles marchent, pour aussi longtemps que possible. Sur un serveur (et sur ma machine personnelle) ça m'embête d'avoir du code propriétaire: le jour où ça ne fait pas ce que je veux, c'est foutu, je ne peux pas y toucher. Et finalement, dans mon cas personnel, les 'vieilles' applis me conviennent bien dans la plupart des cas. \n \nDonc pour synthétiser, je pense qu'Ubuntu est une bonne distribution, et je l'utiliserais sans doute sur un parc de machines de bureau, mais que Debian me convient bien pour mon utilisation personnelle (plus proche de l'utilisation serveur). \n
<<option chkGenerateAnRssFeed>> GenerateAnRssFeed\n<<option chkOpenInNewWindow>> OpenLinksInNewWindow\n<<option chkSaveEmptyTemplate>> SaveEmptyTemplate\n<<option chkToggleLinks>> Clicking on links to tiddlers that are already open causes them to close\n^^(override with Control or other modifier key)^^\n<<option chkHttpReadOnly>> HideEditingFeatures when viewed over HTTP\n<<option chkForceMinorUpdate>> Treat edits as MinorChanges by preserving date and time\n^^(override with Shift key when clicking 'done' or by pressing Ctrl-Shift-Enter^^\n<<option chkConfirmDelete>> ConfirmBeforeDeleting\nMaximum number of lines in a tiddler edit box: <<option txtMaxEditRows>>\nFolder name for backup files: <<option txtBackupFolder>>\n<<option chkInsertTabs>> Use tab key to insert tab characters instead of jumping to next field\nDAV-URL: <<option txtDAVURL 50>>
I already discussed what I think about [[CAPTCHA|PHPBB2 and Anti-spam]] and how I can't see it work, ever. Instead I suggested [[Textual Confirmation|http://bbantispam.com/tc/]] which sounds more sane to me. \n\nA [[recent story|http://news.bbc.co.uk/1/hi/technology/7067962.stm]] shows that things are worse for CAPTCHA than I thought: not only can you program computers to recognise the letters, but you can also just carry the CAPTCHA to other sites for humans to solve for you. We've known about the possibility for a while now, and it's been done for sure.\n\nThis has implications about Textual Confirmation, too: our questions could also be taken and asked to someone else. However, we can defend against that: we simply need to only ask questions that are related to our site, instead of generic questions. That way, 'porting' the question to a different site doesn't work anymore, as the context surrounding the question has changed.\n\nFor example, 'what is the capital city of France' is a bad question: anyone can answer that (with or without the help of Wikipedia :-) ). On the other hand, 'what is the name of the forum's founder', 'in which city do we meet?' are questions that only make sense in the context of a specific Web site.\n
People who actually use computers need the Control key all the time, because it allows you to map functions to keys: 's' inserts 's', 'ctrl-s' saves your document. It's much faster than taking the mouse, clicking File, clicking Save.\n\nA long time ago, computers were built by people who used computers for people who used computers: therefore, they made the control key easy to type: old keyboards would have the control key between the 'tab' and the 'shift' key on the left-most column. Then bad things happened, and somehow the capslock key was invented. Not only does it serve no obvious purpose (one should never be writing all caps, it's ugly, hard to read and it's just rude to shout all the time), it bumped the control key at the bottom of the left-most column. Suddenly, the control key became hard to reach.\n\nThe obvious solution is to remap your keyboard. In Windows, the easiest way to do that is a little program called [[AutoHotKey|http://www.autohotkey.com/]]. Simple, and you don't need to be admin to install and run it. Just create a default script and add:\n\n{{{\nCapsLock::Ctrl\n}}}\n\n
// //''Name:'' Blog\n// //''Version:'' 0.1\n// //''Author:'' [[Anshul Nigham|http://yavin4.anshul.info]] (adapted from an earlier plugin by [[ClintChecketts|http://www.checkettsweb.com/]]) \n// //''Type:'' Plugin\n// //''Description:'' Posts the most recently edited tiddlers when the TiddlyWiki is opened, similar to a blog.\n// //''Syntax:'' Change the daysOrPosts and numOfDaysOrPosts variables below\n// // If daysOrPosts variable is "days", tiddlers from the past numOfDaysOrPosts dates will be displayed\n// // If daysOrPosts variable is "posts", the past numOfDaysOrPosts tiddlers will be displayed \n\n// // ''Tested against:'' Tiddlywiki 2.1.3\n\n// // ''HOWTO:'' Simply copy this entire tiddler and paste it into a new tiddler in your own tiddlywiki.\n// // Tag it with systemConfig, and also with systemTiddlers if you don't want it to appear within the blog views. Name it anything you like\n\n// // History:\n// // 28MAY2007\n// // * Sort by 'created' date rather than 'modified' date, to be more blog-like (YMMV)\n// // * copy function into config object to work with Haloplugin, which turned out to not be useful, but now it'd done\n// // * made code to fit in a pretty block.\n\n//{{{\nvar daysOrPosts = "posts";\nvar numOfDaysOrPosts = "10";\n\nconfig.macros.blogplugin = {};\nconfig.macros.blogplugin.displayTopTiddlers = function ()\n{\n if(window.location.hash) daysOrPosts = "";\n if(daysOrPosts == "posts")\n {\n var tiddlerNames = store.reverseLookup("tags","systemTiddlers",false,"created");\n if (tiddlerNames.length < numOfDaysOrPosts)\n numOfDaysOrPosts = tiddlerNames.length;\n for(var t = tiddlerNames.length-numOfDaysOrPosts;t<=tiddlerNames.length-1;t++)\n story.displayTiddler("top",tiddlerNames[t].title,DEFAULT_VIEW_TEMPLATE,false,false);\n }\n if (daysOrPosts == "days"){\n var lastDay = "";\n var tiddlerNames = store.reverseLookup("tags","systemTiddlers",false,"modified");\n var t = tiddlerNames.length -1;\n var tFollower = 0;\n for(t;t>=0;t--) if(numOfDaysOrPosts >= 0){\n var theDay = tiddlerNames[t].created.convertToYYYYMMDDHHMM().substr(0,8);\n if(theDay != lastDay){\n numOfDaysOrPosts = numOfDaysOrPosts -1;\n lastDay = theDay;\n tFollower = t;\n }\n }\n\n for(tFollower = tFollower+1; tFollower < tiddlerNames.length;tFollower++){\n displayTiddler("top",tiddlerNames[tFollower].title,'ViewTemplate',false,false);\n }\n }\n}\n\nwindow.original_restart = window.restart;\nwindow.restart = function()\n{\n window.original_restart();\n config.macros.blogplugin.displayTopTiddlers();\n}\n//}}}
Here's a list of books I wish I had time to read. Hopefully this will serve as a notebook and I'll work my way through them slowly.\n\n* Technical books (of course)\n** [[Structure and Interpretation of Computer Programs|http://mitpress.mit.edu/sicp/full-text/book/book.html]]\n** [[ANSI Common Lisp|http://www.paulgraham.com/acl.html] and [On Lisp|http://www.paulgraham.com/onlisp.html]]\n** [[The Operating Systems Handbook|http://www.snee.com/bob/opsys.html]]\n\n* Management\n** [[The Peter Principle|http://en.wikipedia.org/wiki/Peter_Principle]]\n\n* Fantasy\n** Discworld\n\nThink there is something else I should read? Let me know! \n\n
Cats always land on the floor.
I recently started using CenterICQ as a Jabber client, mainly because [[imcom|http://wiki.jabberfr.org/ImCom]] has a bug in its presence reporting code (basically it never sets the user as 'online'), and it is a bit inconvenient when chatting to several contacts at once.\n\nThe interface is slightly disturbing at first, but not for long.\n\nThe biggest problem of CenterICQ is its total lack of documentation. Here I'll record the result of stuff I had to look into the _code_ to find.\n\n* Keys can be changed in ~/.centericq/keybindings\n* First key to change (for me) was \scx to <enter> for send_message. I see little point in multiple line messages.\n* Contrary to what the documentation says, not all commands are in that file. bind editor \scn next_chat to jump from one active chat window to the next one. (There is also a prev_chat command, which I have not yet mapped).\n\nNext I'll look into remapping some more keys: I want to use j and k to move in the contact list.
This morning Exim complained about ClamAV daemon not being present. Upon inspection it turns out that ClamAV was complaining that its databases were broken. This may be linked to all the restarts we made yesterday to test various combinations of programmes and see what made X crash. Anyway, removing the databases in {{{/var/lib/clamav/}}} then running {{{freshclam}}} (which takes a while, as the entire database has to be re-loaded) fixed the problem. \n\nIt's unclear whether e-mail gets bounced or simply delivered without scanning when the malware ACL fails.\n
<div class='toolbar' macro='toolbar +saveTiddler -cancelTiddler deleteTiddler wikibar'></div><div class='title' macro='view title'></div><div class='editor' macro='edit tags' style='display:none;'></div><div class='GuestSign' >Your Name: <span macro='option txtUserName'></span>(NickName)<br />Comments:</div><div class='editor' macro='edit text'></div>
So, I'd already installed [[comments|Comments are here!]], but the links wouldn't appear under the title. I think the problem was related to HaloscanMacro not being defined when BlogPlugin would create the first page, and then failing to update those tiddles.\n\nWell, I've got a solution at last: I copied the integrality of HaloscanMacro directly into the original tiddlywiki source, so it gets defined at startup, and now it works.\n\nI hope that'll get me more comments than I've been getting lately. It's lonely on here.
I found the HaloscanMacro plugin which uses Haloscan as support for comments in blogs. You can now leave comments everywhere, using the 'Comments' button that's available on each tiddler, after the post date.\n\nThere is just a little problem: it doesn't work smoothly with the BlogPlugin, so the tiddlers opened on the first page don't have that button (yet -- I'll look into it). If you want to leave a comment or see if there are any comments on a tiddler that was opened automatically at start-up, you'll need to close it and open it again.\n\nThat's all for now. Go forth and comment.
Type the text for 'New Tiddler'I got a big screen and a graphics card for Christmas, so now I can play [[FlightGear|http://www.flightgear.org/]]. However Debian stable has an old, old version and [[FlightGear|http://www.flightgear.org/]] has made huge progress in rendering, so it's a shame to run the old version. Here's what I did to compile it on Debian stable:\n\n{{{\napt-get install build-essential git cmake libsvncpp-dev libboost-dev libgl1-mesa-dev libopenal-dev libopenscenegraph-dev libudev-dev libapr1-dev libplib-dev libxi-dev libxmu-dev libjpeg-dev libxinerama-dev libpng12-dev libxft-dev libalut-dev\n\nget flightgear-2.8.0 and simgear-2.8.0 and OpenSceneGraph-3.0.1.zip\nwget ftp://flightgear.wo0t.de/ftp/Shared/FlightGear-data-2.8.0.tar.bz2\n\n\nunzip OpenSceneGraph-3.0.1.zip\ncd OpenSceneGraph-3.0.1\n./configure\nmake\n#make coffee, this takes a while\nsudo make install\n# It all goes in /usr/local/lib and /usr/local/include\ncd ..\n\nmkdir sgbuild\ncd sgbuild\ncmake ../simgear-2.8.0\nmake\nsudo make install\ncd ..\n\nmkdir fgbuild\ncd fgbuild\ncmake ../flightgear-2.8.0\nmake\nsudo make install\ncd ..\n\n\ntar jxvf FlightGear-data-2.8.0.tar.bz2\nfgfs --fg-data=./data\n# Enjoy!\n\n# Now get custom_france, it's really worth it\nwget http://www.mguillaud.net/fg/custom-scenery-france-v1.tgz\nfgfs --fg-data=./data --fg-scenery=./custom_france --airport=LFBO\n# Interesting airport ICAO codes: LFLG: Grenoble LFBO: Toulouse LFPG: CDG)\n\n# Now get Aircraft-2.8 to fly UFOs, and unpack in ./data\nfgfs --fg-data=./data --fg-scenery=./custom_france\n\n}}}\n
Right, I looked for that once already and didn't write it down. Always post, that's what I say.\n\n{{{\nxmodmap -e "keysym Meta_L = Multi_key Meta_L"\n}}}\n\nThis turns the left Alt key of my keyboard into a key that's both Multi (aka Compose) to compose accentuated characters like é à and others and still Meta for my window manager.\n\nEDIT: Actually, there is a problem with this setup: the Alt key appears to be 'sticky', which means that after I used it to changed frames in ION (with Alt-W) it's switched to //Compose// mode. Instead, I now use my right Alt key, which I have never used.\n\n{{{\nxmodmap -e "keysym Meta_R = Multi_key"\n}}}\n
At the moment I have no CD drive in my main Linux computer. As a result I can't use my favourite CD ripping program (which is //jack//, for the record). I have a CD drive on my work laptop which unfortunately runs WinXP, so it can only produce WMA.\n\nSo, I use Windows Media Player to extract the tracks to lossless WMA, then I copy them over to the Linux server and convert them as such:\n\n{{{\n for i in * ; do mplayer -ao pcm "$i"; mv audiodump.wav "$i.wav"; done\n oggenc *.wav\n rm *.wma *.wav\n rename s/.wma// *\n}}}\n\nand I'm left with the same files as OGG instead of WMA. Straightforward, almost.\n
Here is a good article that explains how to create SSL certificates that are applicable to several domain names.\n\nhttp://www.hsc.fr/ressources/breves/ssl_virtualhosts.html.fr\n\nUnfortunately it's in French ;) I need to look at it anyway so I'll translate the parts I used to do that. For now, consider this port a bookmark for brain-challenged rabbits.\n\nOtherwise, creating a self-signed certificate + key goes:\n{{{\nopenssl req -nodes -x509 -new -out cert -pubkey\n}}}
Here's a new, more complicated version of an old game where you had to help a shepherd, a wolf and a sheep cross a river on a barge that could only old two at once.\n\n[[In this Japanese version|http://freeweb.siol.net/danej/riverIQGame.swf]], we have a family in which adults can't stand the opposite-gender kids, along with a policeman and a prisoner. So, here are the rules:\n\n* Only two people at once on the barge\n* The father can't stay alone with one of the daughters if the mother isn't also there\n* The mother can't stay alone with one of the sons if the father isn't also there\n* The prisoner can't stay with any member of the family without the policeman\n* Only the adults (the father, the mother and the policeman) can operate the barge.\n\nHere's my [[solution|Crossing the river: my solution]]
Here is my solution for the [[problem|Crossing the river]] I posted earlier.\n\nPol: Policeman; Pris: Prisoner; b: boy; g: girl.\n\nPol + Pris\nPol\nPol + b\nPol + Pris\nfather + b\nfather\nfather + mother\nmother\nPol + Pris\nfather\nfather + mother\nmother\nmother + g\nPol + Pris\nPol + g\nPol\nPol + Pris\n\nNow, is this the shortest solution?
[[This| http://www.info-sectes.org/roles/cartes.htm]] would be funny if it wasn't sad.\n\nShort summary: We're informing you about the dangers of cults. In particular, be wary of role playing games like //Dungeon and Dragon//, and of collectible cards like //Pokemon// and //Magic: The gathering//. They'll turn your children away from Jesus.\n\nIt's even worse than the 'mainstream' criticism against role playing games. Usually, players are pointed at because they immerse themselves into imaginary worlds, to the point where they lose touch with the real world, and then act all nutty in real life when something happens in the imaginary world. Like, committing suicide because their character has died.\n\nThis type of criticism has mostly moved on away from role playing games (role playing games are old news now, and too many people have played them for the rumor to keep going) to move to on-line games such as //World of Warcraft// and //Second Life//.\n\nThis point of view about Pokemon and Magic will appear laughable to anyone who actually plays, or has played, those games.\n\nOf course, there //are// some players who go overboard and sacrifice their lives (figuratively usually). In other times they'd have read too many books ([[Werther|http://en.wikipedia.org/wiki/The_Sorrows_of_Young_Werther#Cultural_Impact]] anyone?), or been too far in the practice of whatever. The point is that these are a tiny minority.\n\nFor most players, games are just that: games. Just like books are just that: books. And Harry Potter is just that: an imaginary character.\n\nBut the ironic part is that it's not what is being reproached to all these things here. This article doesn't point to Magic or Harry Potter because they send their users to imaginary worlds. They point to them because they feel like players and readers are being put in touch with a part of the //real// world that should be left alone, namely witches, witchcraft and, of course, Satan.\n\nMost players know perfectly well where the real world starts and where it ends. It takes some religious nut who has already lost grip with those boundaries to come up with stuff like that. It's even more ironic when you think that religions are pretty much the same as cults, except they have become socially acceptable. And religions have //directly// caused much suffering and the death of millions.\n\nIndeed, you'll notice that this Web site attacks anything that isn't Catholicism: Mormons are a cult, Islam is a cult. Of course the author forgets that Catholicism is a cult as well. And that he's lost touch with reality, as there really is no such thing as magic, witches, spells or devil.\n\nOn a related note, [[Gary Gygax|http://en.wikipedia.org/wiki/Gary_Gygax]], the inventor of Dungeon and Dragon, passed away a couple of days ago. Now that's sad.
A pretty little restaurant in Arnaud-Bernard: the room sits about 20 to 30 people. The walls are all bricks and Garonne stones. Service is informal and friendly, and the food comes from Lyon: escargots, boudin, quenelles and so on, all excellent. Dinner will cost you about 25EUR a head.\n\nDalle et Pepie, 31, rue de la chaine, Toulouse, 05 61 21 55 33
France is almost done electing its next president. It'll have been six blissful months of constant arguing, debating, personal attacks, slurs, and so on. Well, you know what politicians are like.\n\nWhat bothers me in the whole thing is that politicians all seem to be in it for similar reasons, which are either attraction to power (in which case what they really need is to see a psychiatrist, for they have unresolved issues) or personal gain (in which case they should go to jail). You'll have to agree that these are hardly good reasons to govern a country. Good reasons should be selfless, such as making your country a better place, making life for the citizens better, etc. Well, all the things that politicians actually say, all the while they're thinking about all the personal gain and power they'll get.\n\nI remember reading a book, which may or may not have been fiction, where there was an easy way to ensure that the elected chief was a selfless servant of the people. The chief was elected for seven years, and then he'd be sacrificed to the spirits and eaten by the rest of the tribe to assimilate his wisdom.\n\nNow that may sound stupid, but I think it's a really good idea. If the president gets killed at the end of their mandate, then there is no incentive for personal gain, as you won't be able to take advantage of it later on. Those that are just after power, will probably think twice and may actually try to help their country by seeking professional help. You'll only be left with candidates that are genuinely -- and literally -- ready to die for their country. And we the people won't get the same faces in power over and over again. It's really a win-win scenario.\n\nOn the other hand, population in France is 60 million, so I strongly suggest you vote for the biggest candidate if you want anything to eat.\n
I just read a [[very interesting article|http://globalpublicmedia.com/node/461]] about the inability of the human mind to comprehend exponentials. Exponential growth happens whenever there is a constant growth rate mentioned. So, when you hear about a '5% growth a year', that's actually an exponential growth: it grows faster and faster. So fast in fact that our minds fail to measure how fast it grows.\n\nThe article gives easy tips to estimate the exponential computation:\n\n* 7% growth per year means doubling every 10 years. Doubling your electricity consumption every 10 years means that if you have one nuclear station today, you'll need 32 in 50 years.\n* Over 70 years (about one life-time) an increase of x%/year results in a growth by a factor 2^^x^^ (which is 2 multiplied by itself, x times: 2^^8^^ is 2x2x2x2x2x2x2x2 which is 256). So a tame 4% growth rate means multiplying everything by 16 over 70 years.\n\nThe author then explains what should be self-evident: anything that's based on continuous growth is doomed to stop some day. That applies to the population on earth, power consumption and so on. The only point I disagree with is that this does not actually apply to inflation or GDP, which are abstract values that can actually grow boundlessly: with 100% inflation a year, life can go on happily for decades, it's just pretty bad for my savings.\n\nOn the other hand, overpopulation is a real problem, because, as the author says, "we can debate whether we like zero population growth or don't like it, it's going to happen". Either through war, famine, and disease, or through drastic birth control.\n\nAnd our lack of understanding of exponentials also means that things are probably much more urgent than we think. He imagines a model of bacteria growing in a bottle. Each minute, each bacteria splits and the population doubles. You start the experiment at 11:00, and at 12:00 the bottle is entirely full. At what point do the bacteria start to think they're running out of space? 5 minutes before 12:00, they're only using 3% of the bottle. With 97% of the known universe to fill, surely they're fine? 5 minutes later, fighting starts over that last spot on the head of a pin.\n\nNow, how many humans do we think the earth can comfortably sustain? How many can it sustain at all? How many minutes have we got left?\n\n\n
There is a [[funny story|http://www.brisbanetimes.com.au/articles/2007/11/18/1195321589275.html]] in Sweden, where women are requiring to be able to go topless to beaches and public swimming pools. Apparently this is a problem for some. Now the terrible thing is that the movement is powered by feminists, who want to act that way so as to remove the sexual trait that breasts have.\n\nDamn them. We men want breasts to be erotic, dammit!\n\nWhat's next? Total nudity so that we lose interest in their entire body? I say, bring eroticism back and cover women with a burka!\n
These are the navigation extensions I currently use, for later reference...\n\nFirefox has memory leaks. You need to restart it once in a while. That's a drag, because you'll lose all the tabs you still had to read. Enter [[Session Manager|https://addons.mozilla.org/en-US/firefox/addon/2324]], which saves the state of your tabs and restores them when you restart. The default behaviour is to only restore after crashing, so don't forget to customise in Tools->Session Manager.\n\nKeyboard navigation:\n\nI love my keyboard. Mice are mostly designed for leisurly tasks. Some day I'll write a post on user interfaces. And I love Vim. It's the only editor I use, all the time. So naturally when I found \n[[Vimperator|https://addons.mozilla.org/fr/firefox/addon/4891]], a plugin that makes Firefox behave like Vim, I was happy. The plugin still has some rough edges, but it's fantastic, it's really the best thing since Hit-a-Hint (see further).\n\nI also use [[mozex|http://mozex.mozdev.org/]] lets you set external programs for some actions. In particular, this lets you set a shortcut to edit a form's textarea with the editor of your choice (Vim is of course mine). Alleluia!\n\n\nI used to use those extensions as well, but they are pretty much all obsoleted by Vimperator:\n\n[[Hit a Hint|http://hah.mozdev.org/]]: select a link with your keyboard. In the process, find hidden links that you'd never see with your mouse. HaH suggests another extention named surfkey, which I'm not fond of. YMMV.\n\n[[Keyconfig|http://forums.mozillazine.org/viewtopic.php?t=72994]]: Change keys. With [[Functions for keyconfig|https://addons.mozilla.org/en-US/firefox/addon/1537]], you can now use your keyboard properly, and have h,j,k,l navigate in the page.\n\nA note to Firefox developers: get all the plugins to be configured the same way, will ya? Some create a menu entry in Tools, others are configured through the plug-in manager... it's a mess!\n\n
Olivier had posted something about TiddlyWiki, and it looked quite interesting. So here I am trying it out. There is a good chance that this replaces my blog, as it seems to have all the blog features (well, that's really only dated posts isn't it) and then some: easy to update, more interactive, and closer to a 'real' Web site in that you can have actual links.\n\nFor I have to say, one of the motivations for me to start a blog was to have some sort of a notepad to store recipes like 'how to burn a dvd' and whatnot. A wiki really is a better place for that.\n\nAnyway, I'll probably post on here from now on, and if it proves satisfactory I'll slowly import over the interesting articles from my blog.
Bugs crawls all over the place, they sneak into places you don't want them to sneak, they poo in places you don't want them to poo, they laugh at you from places you don't want them to laugh at you, they bite you in places you don't want them to bite you. And, they make your programs misbehave.\n\nI hate bugs.\n\nI do, however, like Hubert. \n\n[img[Hubert at 19:25|/cp/hubert_0607_1.jpg]]\n\nSo, here's [[Hubert being fed a firebug|/cp/hubert_0607.avi]].\n\nHubert is a Venus Fly Trap (aka "VFT", or //dionaea miscipula//). VFT's have sensitive hair in the middle of their trap: after one hair has been triggered twice, the trap closes within half a second or so. The delay and the repetition is designed so that false positives, such as a drop of rain falling, do not trigger the flat.\n\nAfter the trap starts to close, there is an additional delay before it closes completely: first, it traps the bug inside, then it 'checks' that the bug is still moving inside the trap, even though the trap is only half-closed. This allows very small bugs to escape, in which case the flat re-opens in the following hours: digestion is very expensive in terms of energy, so the VFT only spends it on a large enough bug.\n\nIf the bug is big enough to be trapped, it will keep moving inside the trap, ensuring its doom: the trap seals slowly over the next hour:\n\n+5min: \n\n[img[Closing 2|/cp/hubert_0607_3.jpg]]\n\n+9min: \n\n[img[Closing 3|/cp/hubert_0607_4.jpg]]\n\n17min: \n\n[img[Closing 4|/cp/hubert_0607_5.jpg]]\n\n37min:\n\n [img[Closing 5|/cp/hubert_0607_6.jpg]]\n\nThe trap will then remained sealed for about a week before opening again. All that is left of the bug is its exoskeleton. Unfortunately we're going on holiday soon and Hubert has been moved to a pond in the suburbs, so the re-opening of the trap will be shown another day.\n
I'll be throwing links to articles and descriptions of rating systems for Go, and maybe some other games, in here, as I run into them. I find rating systems morbidly interesting.\n\nhttp://sabaki.org/RatingSystem.htm\n\nAnd, not at all related, is the problem of tournament pairing algorithms. I'm collecting that because I'm planning on writing a pairing program, because the ones that exist are either non-free (McMahon by Gerlach) or Windows-only (Gotha by Vannier), neither of which is acceptable for me.\n\nhttp://www.ap76.com/LV/gotournaments/gotha.htm\nhttp://www.cgerlach.de/macmahon.html\nhttp://ourworld.compuserve.com/homepages/AccelRat/PairAlg.htm\n\nWho said every piece of software worth writing exists on CPAN:\nhttp://search.cpan.org/~reid/Games-Go-GoPair-1.001/\nhttp://search.cpan.org/~reid/Algorithm-Pair-Best-1.010/Best.pm
I have lots of ideas for businesses, which I usually have no intention of following up (because of lack of ambition, laziness and so on). I'll give them to the world. If you make a fortune using my ideas, consider giving me a bottle of wine or something.\n\n* Breakfast delivery route: Most people are too busy/lazy to get up in the morning and get fresh bread rolls or croissants from their local bakeries (this is a problem in France -- other countries may not even have bakeries at all). The idea is to get a delivery service to bring fresh croissants to people in the morning. Basically this is the same as the old milk delivery or paper routes. Milk deliveries have disappeared not so much because it's too expensive, but because the availability of fridges has made them useless. Although bread machines do exist, they don't make croissants, and a good baker makes better bread (well, that's not true everywhere -- a scary number of bakers make bread that's worse than supermarkets). I reckon it would work.\n\n* Wine bank: You bought all that very nice wine from Bordeaux, and you were told it's best to age it another three to ten years. Wine matures best at constant temperature of about 17C, preferably with high humidity. Clearly you can't keep those bottles in your flat (it's clutter, and temperature in flats tend to vary drastically), and so-called wine fridges are not a real solution (you're not going to buy a 100-bottle fridge, put that in your bar, and fill it with bottles you can't touch for three years) (okay, maybe you //are// going to do that, in which case my service won't interest you). The solution is to take your wine to the bank: it's just like a safe deposit box, you pay a small fee per bottle and per year kept and the temperature and humidity is guaranteed.
//Removes hidden tiddlers from lists. Hopefully this code will be included in the core TW soon.//\n//{{{\nTiddlyWiki.prototype.getTags = function()\n{\n var results = [];\n this.forEachTiddler(function(title,tiddler) {\n if(tiddler.tags.find('excludeLists')===null)\n {\n for(var g=0; g<tiddler.tags.length; g++){\n var tag = tiddler.tags[g];\n var taggingTiddler = store.fetchTiddler(tag);\n if(!taggingTiddler || !taggingTiddler.tags || taggingTiddler.tags.find('excludeLists')===null){\n var f = false;\n for(var c=0; c<results.length; c++){\n if(results[c][0] == tag){\n f = true;\n results[c][1]++;\n }\n }\n if(!f){\n results.push([tag,1]);\n }\n }\n }\n }\n });\n results.sort(function (a,b) {if(a[0].toLowerCase() == b[0].toLowerCase()){ return(0);} else {return (a[0].toLowerCase() < b[0].toLowerCase()) ? -1 : +1;} });\n return results;\n};\n\nTiddlyWiki.prototype.getOrphans = function()\n{\n var results = [];\n this.forEachTiddler(function (title,tiddler) {\n if(this.getReferringTiddlers(title).length === 0 && tiddler.tags.find('excludeLists')===null){\n results.push(title);\n }\n });\n results.sort();\n return results;\n};\n//}}}
I recently found some films on the internet that come as a 4.7GB stack of VOB files. They're DVD images, that can be burnt following the simple process:\n\n{{{\nmkdir -p dvd/VIDEO_TS\nmv * dvd/VIDEO_TS\nmkisofs -dvd-video -udf -o dvd.iso dvd/\ngrowisofs -Z /dev/cdrom=dvd.iso\n}}}\n\nNow, what do we do when we find 8GB DVD images? The easy way out is probably to buy 8GB DVDs and the appropriate burner. The other way is to shrink the DVD.\n\nWindows has a nice utility called DVDShrink. But it's for Windows only. Linux has vamps. It's better. Vamps will resize a VOB file by any factor, thus letting you shrink the DVD image. Supposing we need to shrink the DVD to half its size, the previous commands become:\n\n{{{\nmkdir -p dvd/VIDEO_TS\nfor f in `ls *.VOB`; do vamps -e 1.5 < $f > dvd/VIDEO_TS/$f; done\ncp -u * dvd/VIDEO_TS\nmkisofs -dvd-video -udf -o dvd.iso dvd/\ngrowisofs -Z /dev/cdrom=dvd.iso\n}}}\n\n
This always amazes me: the record and movie industry is once again going on about their losses because of [[illegal copying|http://www.lemonde.fr/cgi-bin/ACHATS/acheter.cgi?offre=ARCHIVES&type_item=ART_ARCH_30J&objet_id=1025364]]. The theory goes that every time someone downloads a movie illegally, that's one DVD that they should have sold, I guess.\n\nOf course this is complete crap. It always amazes me that no-one links dropping DVD sales with [[raising food prices|http://www.lemonde.fr/archives/article/2008/02/24/les-prix-des-produits-alimentaires-ont-flambe-entre-novembre-et-janvier_1015129_0.html]] and mad real-estate prices. Logically, people spend their money on food and shelter first. Clothes second. Entertainment last.\n\nWe watch quite a few series which we download. However, where they not available, we would not buy them, simply because we couldn't afford them. We'd end up watching TV (or reading books, more likely).\n\nI guess corporation end up just fighting over our limited income: if food prices raise, entertainment budget goes down and that industry gets hurt. If food prices decrease, entertainment budget goes up, but farmers are sad. Either way, I earn the same and it's a zero-sum game. And how many movies I download actually doesn't appear in that equation.
\n\nList of [[restaurants]] I like to go to, in and around Toulouse.\n\nPosts about <<tag politics>>.\n\nMy <<tag blog>>.\n\nAnd, most important, <<tag tech>>!\n\n<html><a href="javascript:generateSEOFiles();">Generate SEO files</a></html>
Etch includes an NZB downloader called hellanzb, but I don't seem to manage to get it to work. Nevermind.\n\nIt's now easy to use SABnzbd: you just need to\n{{{\naptitude install python-cherrypy python-elementtree python-cheetah\n}}}\nand fill in your SABnzb.ini as usual.
A few days ago in a group conversation, there was a discussion on a number of bad things about France, and in particular on how it was a scandal that landlords had such a hard time getting rid of tenants that don't pay. I kind of put a damper on the conversation when I said that financially weak people should not invest in real estate, prompting questions on whether I considered people who are capable of buying a flat are financially weak. Although I felt I knew exactly what I meant, my arguments weren't ready. They are now.\n\n!!Investment\nThe foundation of investment is to keep some of your money and lend it to someone else in order to make a profit. The capital you invest may get lost or go down in value, so investors associate a risk with any investment, and ask for higher yields for higher risk investments.\n\nFor example, investing in government-guaranteed bonds has a low risk of your capital disappearing, and has a low yield (in the order of 2% in France at the moment). Speculative investing in the Asian stock market can yield phenomenal returns (15%, sometimes more) but with a high risk of losing some of your capital (50% from 2000 to 2001 for example).\n\nOne of the basic rules of investing in the stock market (i.e. riskier investments) is that //you should only invest money you can afford to lose//. These words were actually //literaly// said by an investment advisor I met a long time ago during the dot-com boom. It sounds like reasonable advice.\n\n!!Investing in Real estate\nThere is no reason to treat investing in real-estate any differently. This means that before investing in a flat, you need to assess your risk:\n* You may not find a tenant (reducing your ROI to 0%)\n* The tenant may not pay its rent (reducing your ROI to 0%)\n* The tenant may leave and cause extensive damage to the\n* flat (sending your ROI in the negative)\n\nIt is true that French law is strongly in favour of the tenants. However this is known ahead of time by prospective landlords, and should not come as a surprise.\n\nAccording to my investment advisor, you should only invest what you can afford to lose. This means that:\n* if you can't find a tenant, it shouldn't be a problem,\n* if your tenant doesn't pay rent, it shouldn't be a problem,\n* if your tenant damages your flat, it shouldn't be a problem.\n\nBasically it means that //you can afford to lose the mortgage repayment//. Otherwise you're exposing yourself to unacceptable risk (it's like borrowing money to invest in the Asian stock market). Being exposed to unacceptable risk is what I meant by being financially weak.\n\n
Article in French:\nhttp://www.lemonde.fr/web/article/0,1-0@2-3220,36-898659@51-894554,0.html\n\nIt'll probably be published somewhere in English as well; basically, it's the World Bank, one of the big pillars of today's capitalist world (other 2 being the World Trade Organisation and the International Monetary Fund), saying that maybe it makes sense for states to intervene on their own markets. In other words, free market economy does not always yield the best results, as was previously assumed by those organisations.
A funny thing about TiddlyWiki is that it seems to be mostly undocumented.\n\nI don't like the default style where text is not justified on the right. It violates typographical rules.\n\nLike many settings in the wiki, the styles are actually very simple to edit: they're contained in the shadow tiddler StyleSheetLayout. Edit that tiddler and add "text-align: justify" to the .viewer class, and you're done.
Sometimes you want to kill a process, and {{{kill}}} doesn't work, and {{{kill -9}}} doesn't work either.\n\nI think this can happen when a process is blocked in kernel mode waiting for some event.\n\nWhat is sure is that a zombie cannot be killed. Zombie processes are already terminated, and appear in the output of {{{ps}}} as {{{<defunct>}}} (in Linux, anyway). The system keeps zombies around because their parent process is supposed to be able to receive their return value using {{{wait(2)}}} or {{{waitpid(2)}}}, so the PID cannot be re-used until the parent calls one of these functions.\n\nJust as in movies, you cannot kill a zombie but you can kill the zombie master: using {{{pstree -p}}} you can find the parent of the zombie, and that's the one you need to kill. As soon as the parent process dies, all zombie processes that it spawned will disappear.\n\nYou shouldn't feel too bad about killing the parent: leaving zombies is a sign that the application is malfunctionning anyway.\n \n
This is one of the very few creperies in Toulouse. We went there with all of 10 people one night.\n\nThe decoration is very "sailory", with ropes and fishing nets and wooden ornaments everywhere. Unless I'm mixing up with another restaurant (ok, the reason I'm writing this is because Narelle is tidying up and found their business card -- we ate there like a year ago).\n\nThe choice of crepe was standard, with their quality being "good but not wonderful." One of us thought his bacon crepe was too salty. In other words, one might be able to do as good at home.\n\nI have no recollection about the price range. The smoking posed no problem, although I don't remember if it's all non-smoking or what.\n\nL'Embarcadère, 11 rue de la Bourse, 05 61 21 03 58.\n
This is a paradise for the oyster lover: set directly in the production place, a few tables are set under a big vine and you'll get your pick of locally produced oysters. The people there are very nice, and you can see the work of the oyster farm while enjoying them with a glass of white and bread and butter. Among the oysters we tried around Arcachon, theirs also seem to be the best: clear, healthy-looking, appetizing. And cheap. And goooooood.\n\nLa Cabane de l'Aiguillon\nBoulevard Pierre Loti\n33120 Arcachon\n05 56 54 88 20
La Forge is a restaurant from another world. It's a restaurant set in a pretty red brick building in a small village twenty minutes out of Toulouse. The tables are set around a huge fireplace. It's altogether a rather nice place.\n\nCooking is very traditional southern French: Expect foie gras, duck, and so on (their foie gras in particular is excellent). Prices are very reasonable, with dinner set menus around 20EUR.\n\nIt's only open on friday night, saturaday lunch and dinner, and sunday lunch. Cards are not accepted, so come with cheque books or cash.\n\nLa Forge: Lavalette. 05 61 84 76 00
La Paniolade is a pizza restaurant. It's a pretty good one for Toulouse (we have been thoroughly unimpressed by the general quality of pizza around here, to the point that we usually make our own instead of going out). A pizza will set you back about 10 to 15EUR, service is informal but friendly (and waitresses usually wear very short skirts, which ain't bad). \n\nThe indoor non-smoking section isn't as separated as one might like. In summer, the restaurant opens a large terrace as well.\n\nLa Paniolade: 146 bd Suisse, 05 61 13 00 72
Found the business card for a restaurant I went to with Olivier a couple of weeks ago: La table de belvédère.\n\nThat one's high up in a building overlooking the Garonne river, with many large windows. It is a very pretty place, despite the landscape being littered by many ugly buildings from the 60's.\n\nThe food errs on the fancy side, with the lunchtime meal at about 18EUR, and the dishes being very carefully presented.\n\nAltogether, more of a special occasion restaurant than a day-to-day restaurant, but it's definitely worth a try if only for the view.\n\nEDIT: forgot a pretty important detail: it's entirely non-smoking.\n\nLa table du belvédère: 11 Bd des Récollets, 8e étage, 05 62 26 69 14.
We went to 'Le Bon Vivre' with Narelle's conversation group last night. Right on place Wilson, it's of the fancier sort: fabric table cloth and serviettes and all. The service is nice though strangely amateurish for a place like that (I get prejudiced based on the serviettes). First price menu for dinner is 22EUR, we ended at about 40EUR a head after wines and coffees were added.\n\nThe food is very French and all very nice, although the cassoulet does not beat [[Le canard sur le toit]] in Tournefeuille.\n\nIt's not non-smoking, but the waiter assured us that very few people smoked. We had bad experience with this sort of judgement before, but in this case it was true: probably about 3 cigarettes were smoked over the evening, that is, from 7pm to 10pm: perfectly bearable.\n\n[[Le Bon Vivre|http://www.lebonvivre.com]]: 15b, place du Pt Wilson, 05 61 23 07 17
Tonight we accidently went to the Djerba, a Tunisian restaurant. Nice place, nice staff, nice food, very reasonnably priced (52EUR for our 2 couscous, a bottle of wine, dessert and tea). To top it all off, the whole place was smoke-free the entire night. Only downside is, it's not actually non-smoking: we were just lucky.\n\n(The interesting thing about the smoke is that there were smokers, but they went outside. Strange things are happening in France, let me tell you.)\n\nLe Djerba: Place Esquirol Impasse St Geraud, 05 61 21 80 12
Landreau is a pasta factory in Tournefeuille near Toulouse. In 2006 they opened a restaurant which main theme is pasta.\n\nThe lunch menu will set you back 12.50EUR, for which you'll get starters and dish of the day, or dish of the day and dessert of the day. The evening or set meals are much more expensive and we've never really tried them. For 12.50, you get a reasonnably-sized portion that's generally rather nice (think meat in sauce and pasta and you won't be far from a standard dish of the day -- Yesterday's was seafood lasagna. (Homer voice) Hmmmm, lasagna.)\n\nThe room is nice, although usually a bit on the cool side. You get real napkins and tablecloth. It's all non-smoking.\n\nLe Landreau: 25 avenue François Verdier, Tournefeuille. 05 34 52 01 88
Le Progrès ("The Progress") is apparently a historical place for Airbus workers, in that it's been a canteen for them for a long time. And for good reason.\n\nSomehow, I went there today for the first time ever, even though I have been hearing from it for more than two years.\n\nThe restaurant is located in Saint-Martin, a twenty minute walk from the Saint-Martin Airbus factory. It's a non-assuming bistro-looking place. Decoration is non-important (but it's not disgusting).\n\nBasically this is a one-menu, one-price place: the price is 11.50, and the menu is 4 courses, including cheese platter and wine **at will**. This is important to know, as, if you're just a tad compulsive as I am, you'll have to take in account that the afternoon will be pretty much lost on you. The food isn't fancy but it's nice, home-style cooking.\n\nService is informal and friendly. The place is not non-smoking, but it has high ceilings and it didn't seem to bother me at the time. Maybe that's got to do with how much wine I had, though.\n\nLe Progrès: 185 rte Bayonne, 05 61 49 22 75\n
Narelle has been to this one and says it's good. I can't comment any more than that.\n\nLe Zouave, 13 rue Docteur Coste, Collioure. Tel: 04.68.82.00.71\n
This is a place for finer cooking, which also means it's more expensive: the average dish is between 15 to 25EUR, 19EUR for a cassoulet. It is, in fact, the best cassoulet I've had around Toulouse so far.\n\nThe venue is set in an old red brick house, which gives it a nice atmosphere. It'd probably be a nice place for weddings and stuff. \n\nThe restaurant has a fully non-smoking room.\n\nLe canard sur le toit: 58 chem Salvetat, Colomiers, 05 61 30 37 83\n
I was telling Narelle about [[Linutop|http://www.linutop.com/linutop2/index.en.html]] computers and how they were pretty cool, but too expensive for they are when you can get a big computer for 350EUR, and that Linutop's pretty much force you to have a server of some kind anyway. She came up with an interesting idea: with an external USB disc, you actually have a full computer.\n\nI'll track my research on the topic of 'superlight, super-silent' computers here.\n\n\nLinutop 1 considered too small (256Mb not really enough for Firefox (what about FF3?))\nLinutop 2: 333EUR incl VAT\n\nIDE-USB enclosure: [[20USD|http://www.xpcgear.com/usbenclosure.html]] or [[14EUR|http://www.amazon.fr/APM-Boitier-Alu-Externe-pour/dp/B000TJ4TC2/ref=sr_1_12?ie=UTF8&s=electronics&qid=1208859337&sr=8-12]] or a better one at [[20EUR|http://www.amazon.fr/EW-Link-SATA-External-Hard-Enclosure/dp/B0010VGQJM/ref=sr_1_11?ie=UTF8&s=electronics&qid=1208859337&sr=8-11]]\nDisc: 500GB for [[100EUR|http://www.amazon.fr/Disque-dur-interne-3-5-Hitachi-DeskStar/dp/B0013YL5WY/ref=pd_sxp_grid_pt_0_2]]\n\nOr:\n500GB USB disc: [[100EUR|http://www.amazon.fr/Iomega-Disque-externe-500Go-USB2/dp/B000SKLNRG/ref=sr_1_1?ie=UTF8&s=electronics&qid=1208859247&sr=8-1]] or [[93EUR|http://www.amazon.fr/Western-Digital-WD5000KS-interne-SATA-300/dp/B000JFGI16/ref=pd_sxp_grid_pt_1_2]]\n\nAn alternative to the USB enclosure would be to actually get a dedicated disc server such as [[this Quad-disc NAS|http://www.amazon.fr/Lindy-Bo%C3%AEtier-Quad-HDD-noir/dp/B0012GHXCY/ref=pd_sbs_ce?ie=UTF8&qid=1215509132&sr=8-1]]. What's interesting here is the ability to scale: get one NAS with 500GB then several Linutops working off the same storage.\n\nEDIT 13SEP2008: An alternative would be a [[FitPC|http://www.fit-pc.com/new/]] which has an internal disc for a similar price range.\n
[[This Aussie story|http://www.news.com.au/story/0,23599,22813265-401,00.html]] relates how MS Explorer is "said to be dogged by maintenance woes": it has "maintenance problems and missing [...] plans".The story also reports that "safety measures were also criticised". Upon inspection, "problems with [MS Explorer's] safety record were immediately highlighted [...]". That lack of plans means that "we're not quite sure what the prognosis is yet." "But the specialist Lloyds List [...] publication said the Explorer had five "deficiencies" at its last inspection".\n\n\nThat's just for Australia, but it's not the only country to have issue with that dodgy MS Explorer: "Chilean inspectors also found six deficiencies during an inspection in Puerto Natales in March, including two related to navigation matters". \n
[[Index]]\n
<!--{{{-->\n<link rel='alternate' type='application/rss+xml' title='RSS' href='index.xml'/>\n\n<style type="text/css">\n#contentWrapper {display:none;}\n</style>\n\n<div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:White; font-size: 28px; font-family:Tahoma; background-color:Navy;">\nWhiteRabbit's brain is being dumped<blink> ...</blink>\n<br><br>\n<span style="font-size: 14px; color:red;">Requires Javascript.</span>\n</div>\n\n<!--}}}-->
One of the advice I'll happily provide to anyone who wants to hear it (and some who don't) is to choose one text editor and learn it well. If you think about it, text editing is one of the things you do most on your computer: e-mail, letters and whatnot. The rest of your time is probably mostly spent in your Web browser.\n\nSo, pick one text editor, and a good one, and learn it well.\n\nNow the problem is, browsers, for some strange reason, seem to have that strange idea that they should re-implement their own editor. It's especially a problem when you use Webmails: the text edit tool of browsers is usually totally broken.\n\nEnter [[mozex|http://mozex.mozdev.org]]. Now you can link an editor to the {{{textedit}}} action, with a hotkey, and your favourite editor is just one {{{ctrl-e}}} away.\n\nEDIT: I now have a list of the [[extensions|Firefox extensions]] I use.\n
This is so simple I want to cry.\n\nYou know when you need to sort a list following several critiria? "Sort the files by type, then sort those that have the same type by name, then by size".\n\nPerl's //sort// and comparison operators (//cmp// and //<=>//) come in handy:\n\n{{{\n @sorted = sort { $a->type cmp $b->type or $a->name cmp $b->name or $a->size <=> $b->size} @list;\n}}}\n\nAssuming of course the objects in //@list// have //type//, //name// and //size// methods available.\n\nThis reads litteraly as //"compare //a// and //b//'s types, and if they're the same then compare their names, and then compare their sizes"//.\n\nOf course you should never compare file sizes, because size doesn't matter.
Last week, I rebooted my machine to upgrade its hardware. I took advantage of that to also see about upgrading its window manager. I had been using [[ION2|http://en.wikipedia.org/wiki/Ion_%28window_manager%29]] for basically a decade, and just had no idea what was happening in the rest of the world (except some noise about Gnome 3 being crap.)\n\nION was a miracle for me. I remember when I first saw Windows coming from DOS, I wondered what the point of displaying several windows might possibly be. And GUIs just sucked compared to the ease of keyboard shortcuts. I was vindicated when I first stepped in a research lab where they used Unix (Solaris, I guess): here's an enormous screen, but basically all it's displaying is... xterms. So the only point of X was the ability to display several //text// applications at once.\n\nI spent the following years suffering through Windows 3, Windows 95, SunOS and Solaris, thinking the UI was useless. In particular, feeling like I spent way too much time arranging windows myself, which I never had to do under DOS.\n\nThen ION came out. It was efficient (used the entire screen and arranged the windows for you), intuitive (it worked basically the same way that emacs or Vim splitting works), and integrated perfectly with mostly-text applications. I've used only ION2 on Unix ever since it came out.\n\nRecently I heard of //[[awesome|http://awesome.naquadah.org/]]//, which was supposed to be better and more modern. So I tried it for a week, which I will acknowledge is not enough to discover all its feature, but which I hope is long enough to get a good idea of how it works.\n\nThe biggest difference between //awesome// and ION is that //awesome// is dynamic. The idea is to have a the screen divided into a main working area and a //stacking// area. The window into which work happens (e.g. your editor) occupies the main area, while other windows get relegated into the stacking area. You can quickly move to the stacking area for simple tasks (e.g. compile), or easily move a window from the stacking area to the main area, in which case the main window gets moved to the stacking area. And opening a new window automatically moves it to the main area, and moves the current main window to the stacking area. The windows in the stacking area get automatically mashed down little by little.\n\nSounds confusing? Yeah, it is a bit, and that's really my biggest problem with //awesome// in the end. Typically, I'll have an editor window, a compile terminal an a run terminal, and maybe also a mail client terminal. Because the stacking area is dynamic, I'm never really quite sure where my terminals are, and they may be moving around as new window appear. And if too many windows open, they become uselessly small.\n\nCompare to ION's static, tabbed layout: a window is always in the same geographic place, unless I move it myself. In the end, I wished //awesome// had tabbing and I didn't like the dynamism of it. Now don't get me wrong: my spending 10 years with ION probably shaped my way of interacting with the window manager, and I can understand some will prefer the dynamic windowing. However, if you're currently using a floating window manager and consider moving to something more efficient, I'd advise giving both //awesome// and ION a week's try each to see which is best suited to the way your brain works.\n\n\nOn the other hand, //awesome//'s default keybindings all use the Windows key. I wonder why I never thought of that, and I wonder why ION's default bindings don't use that as well instead of ALT, which conflicts with some applications. \n\nSo I'm now upgrading to [[notion|http://notion.sourceforge.net/]], the successor to ION, and seeing about simplifying the key bindings: my goal is to bind all common operations to a simple //Win+1 key// instead of the current ALT+K + operation. More on that in a later post.\n\n
This refers to //O'Sushi Bar// in town, we haven't tried any of the others, as it seems this actually is a chain.\n\nWe had high hopes for O'Sushi when it opened: it was small, and was the first Japanese restaurant that didn't emphasise sushi (which is a small part of Japanese cooking) or skewers (which we're not sure even exists in Japanese cooking :) ). We could get ramen, tonkatsu and few other traditional dishes at very affordable prices.\n\nA year down the line, the restaurant has become quite big, raised its prices on all dishes, and now does a lot more sushi. It's got a cute sushi train that's actually done by boats floating on running water in a gully. Unfortunately, that kind of sushi is only available in a "all you can eat" formula, and is very, very average.\n\nAltogether we've been disappointed.\n\nO Sushi Bar, 30 r Gambetta, 05 61 21 98 64
The French education minister got a new, brilliant idea to tackle the French' abysmal level of English (and foreign languages in general): let's start teaching children in kindergarten, from age 3. The rationale has been heard many times before: everyone knows that children are just like sponges, they learn extremely quickly and can just pick up foreign languages in a couple of days. In fact, it's known that we should also just teach them advanced mathematics and quantum theory. Logically, the next minister should try to out-do the current minister, and propose //in utero// English introduction courses (which will give the "introduction" a whole new meaning.)\n\nClearly this does not pass the [[mockability test|http://dilbert.com/blog/entry/mockability_test/]]. Many things bother me in this theory: children are supposed to learn a language easily, yet French kids are taught French in school for 10 years, and after that many are still not very good (as in, can't write a coherent cover letter that's not littered with grammar and spelling mistakes.) In the past I met a German guy who grew up in Brazil for a few years. He did in fact learn a lot of Portuguese. He left Brazil by the age of 6 or so, and when I met him in Germany as he was 35 he could not speak or understand a word of Portuguese. A lot of things that children are taught at a very early age are just forgotten if the teaching is not continuous.\n\nAnd then there is the assumption that adults just can't learn new languages. I think that's a convenient position adults like to corner themselves in: they suck at languages, but what can they do about it, it's the fault of their teaching system that didn't start on them early enough, and now they're 30 and it's too late and they'll just suck at languages forever no matter how hard they try, so why bother. Well, that's just all bullshit: I know from personal experience that I started English in school at the age of 14, I absolutely sucked at school until I was about 20, discovered the Internet and started using English as a communication tool and became bilingual within a few years, to the point that native English speakers often can't tell I'm not in fact a native. I went on to become fluent in German as well, a language at which I sucked even more than English at school.\n\nI think the biggest problem with the French language teaching system is a problem of goal (and this may apply to some other language teaching systems, but I can't vouch for them). English teachers tend to see themselves, I guess, as English literature teachers. As long as they don't start regarding themselves as //communication// teachers, their efforts are doomed. There is no point reading Marting Luther King when you can't order food at a restaurant. There is no point knowing how to describe a picture when you can't ask for directions to the nearest hospital. There is no point teaching English as a abstract subject without showing to kids that it can serve them to connect to the world, which is something that the Internet actually makes possible today (I do pity language teachers from the time of my youth, when the only easily available resources were Time Magazine and the Wall Street Journal.)\n\nIn a similar vein are the language teachers with an agenda. My wife teaches English in Engineering schools in France. She was once asked to teach an entire curriculum about the place of women in society and in the industry in particular. Way to go to bore 20 year-old engineering boys who would like nothing more than to have more girls in their classrooms, but have no idea why that's not the case. Meanwhile her fun class on creative use of technology was poo-pooed as pandering to the kids (I guess). Here's a teacher with the wrong agenda: her classroom is not the place to teach kids about feminism, it's supposed to be the place to teach them English, and the topics chosen should only matter insofar that they motivate the kids. Show them that understanding English enables them to understand Youtube videos about robots, and they'll actually go and seek them by themselves. Show them that English girls like Byron, and they may even get an interest in poetry.\n\nOn top of that problem of creating motivation (the carrot), there was a problem of lack of coercion (the stick). I remember being clearly told that in high school, it didn't really matter if I sucked at history, or biology, or languages, because I'd never have to do the year again as long as I was good enough at French and maths. Right, so I'm a 14 year old French boy, I see no point in learning any English because let's be honest, who the heck would want to live in Britain, and I won't get punished if I suck at English? Give me a break, I'd rather play video games. Uh-oh, that //D&D Pool of Radiance// is entirely in English. And that's how by the time I reached the end of high school, I could have taught English teachers about medieval weapons (in English, obviously). Still couldn't ask for direction to the nearest inn, though. That's the strength of motivation. This particular point might be slowly changing, with a raising number of Engineering schools making it mandatory to have a Cambridge certificate or a minimum TOIC score to obtain the degree. However, while that certainly should be motivating for Engineering students, there needs to be something similar earlier on that applies to all children (presumably, if you consider everyone should speak a little bit of English, which the minister's idea seems to entail.)\n\nSo there, another silly idea from a minister that probably doesn't know much about teaching, nor about languages. Luckily, there will be no funding for this idea and it'll stay where it is. Actually, want to bet that when they start finding it difficult and expensive to implement, they'll suddenly come across a study that explains that teaching kids languages at an early age achieves nothing?\n\n\n\n\n\n
Today we went to an old favourite of ours: Okini, a tiny Japanese "salon de the". Deep underground in a traditional Toulouse cellar, set up as a traditional Japanese tea salon, kick off your shoes and enjoy some nice tea or the dish of the day (at very affordable prices: 7 EUR for today's chicken special).\n\nThat one is completely non-smoking.\n\nOkini: 19 rue des Tourneurs, 05 61 32 69 56
See, English is an imprecise language: you have no idea whether I'm going to be talking about parts for old computers or old parts for computers.\n\nThat'll be about the former: This [[site|http://www.impactcomputers.com/toshiba-satellite-pro-420cds-parts.html]] has got parts for my old (more than 8 years) Toshiba laptop. They also have parts for the Toshiba T1000, which just blows my mind: the damn thing is twenty years old!\n\nNow, maybe that means I can fix ''my'' Toshiba T1000...
I am releasing today the first version of OmniComment. People can now leave comments not only on here, but also anywhere on my site. It'll now be obvious that I have no friends ;)\n\nIt's available here: [[OmniComment|http://www.rutschle.net/tech/omnicomment.shtml]]\n\nOld comments that had been posted on Haloscan will be re-installed soon.\n\nIn terms of installation, all the details for OmniComment are in the tar ball for the server side. On the client side and for TiddlyWiki integration, you'll need OmniPlugin, which works fine but doesn't yet have all the meta-data that TiddlyWiki suggests. It should be as simple as copying OmniPlugin in your TiddlyWiki, and adding a line in ViewTemplate to add the comment link. You will however need to change something in //omni.cgi// (search for "ugly hack", it'll be obvious what you need to do).
[[OmniComment]] now supports RSS. I mean, ATOM. You can subscribe to the comments on this blog by going to any page of the site and subscribing there, as I haven't done what is requred on Tiddly wiki.\n\nYou can also [[download|http://www.rutschle.net/tech/omnicomment.shtml]] it.
// Interface Tiddly with OmniComment to get a comment page for each Tiddler.\n\n// {{{\nvar cgi_path = "/cgi/omni.cgi";\nvar server = "http://" + window.location.hostname;\n\nconfig.macros.omni = {};\n\nconfig.macros.omni.handler = function (place,macroName,params,wikifier,paramString,tiddler){ \n \n var id = story.findContainingTiddler(place).id.substr(7);\n var hs_search = new RegExp('\s\sW', 'gi');\n id = id.replace(hs_search, "_");\n\n xh = new XMLHttpRequest();\n xh.open("GET", server + cgi_path + "?count=1&filename=wiki_" + id, false);\n xh.send(null);\n\n commentsLabel = "Comments (" + xh.responseText + ")";\n var commentsPrompt = "Comments on this tiddler";\n var commentsHandler = function(e) { \n window.location=server + cgi_path + "?filename=wiki_"+id;\n return false;\n };\n var commentsButton = createTiddlyButton(place, commentsLabel, commentsPrompt, commentsHandler);\n\n}\n\n\n// }}}
In a recent job interview, my personality was assessed by the interviewer, using a pretty boring 90-question test. Turns out that the profiling of my personality seemed pretty accurate after all, unless this works the same as astrology, which mostly works by being general enough to please everyone.\n\nOne interesting thing in my profile was a big 0 for respect and support of my hierarchy. That sounds about right. My point of view is that there is no point supporting your hierarchy if they're doing something stupid or wrong.\n\nThen I remembered Narelle and I arguing with Narelle's mum about how one should soft-boil eggs, and how laundry should be hung. Basically Narelle has developped a fairly complicated timing process for egg cooking, while her mum sticks by the 3 minute rule. Meanwhile, I was hanging laundry in a way that used half as many pegs as her method, and she argued it wouldn't dry as fast. In both cases, her main argument was that that was the way she'd done it for 40 years, so it can't be bad. In both cases, she's wrong: eggs are bigger these days, and 3 minutes in boiling water won't cook the white. Underwear doesn't need to be all lined up to dry.\n\nThis brings me to my point: respect for authority hinders innovation. By definition, to innovate, one must put old assumptions in the bin in the hope of building something better. This involves criticising your elders' knowledge. The strange thing is that it should be a natural process: obviously if we'd always listened to our elders and trusted their experience without ever questionning it, we'd still be painting hands on cave walls. (caves? what caves? Back to the tree!).\n\nThis has implications in the business world. An engineer that does not question its hierarchy's views will not be able to innovate: at best he'll implement his manager's vision. So a company that is looking for innovative people, should actually look for people who do not respect authority.\n\nNow, there might be an interesting development of this in that the bigger companies are built with a stronger emphasis on authority (it becomes harder to procure stuff, it becomes harder to just set up a small server on the side, basically everything becomes forbidden). The amount of innovation that happens in a big company is usually a fraction of that that happens in a small company, which has a more relaxed, flexible approach to authority. \n\nDon't believe me: you'd be thinking under my authority!\n
[[A good article|http://www.souslestoits.net/blog/index.php/post/ogm]] from a genetician commenting on the fears about GMO. Very moderate and reasonable. Except for the fact that it's in French.\n
We have recently moved to the suburbs of Toulouse. At our housewarming party a friend mentionned that my blog wasn't up to date. I guess he meant I said nothing about the move. So there: our new address is 82.235.147.6. Of course if you use DNS, you don't need to know that.
Your may remember that I once installed [[eXtreme Antispam|http://www.rutschle.net/blog/archives/2006/12/17/T20_01_07/]] and later reported I was [[very happy with it|http://www.rutschle.net/blog/archives/2007/03/08/T20_54_44/]].\n\nThen I upgraded to Etch, Debian's last release. And sure enough, we started getting phony users again: oops, the upgraded process erased the modifications that made eXtreme work. Now the really funny thing is, the link I had for it now points to another Phpbb mod that has nothing to do with spam. No matter how much I scoured the Internet, it appears that it's nowhere to be found. Crap.\n\nSo after ah-ing and em-ing and wondering if I could maybe rewrite the code needed, I ended up finding a different mod that's basically exactly the same, except without pictures: [[Textual Confirmation|http://bbantispam.com/tc/]] simply ask one question among many that the administrator can set, and expects the right answer. Simple, accessible, wonderful. Really one of those should be in the stock Phpbb configuration instead of the pointless letter salad they insist on using.\n
[[Free.fr|www.free.fr]]'s set top box, the "Freebox", lets one play videos from a remote computer, provided said computer runs a [[VLC|http://www.videolan.org/vlc/]] server.\n\n[[YouTube|http://www.youtube.com]] has a lot of funny videos, but sometimes it'd just be nicer to watch them on TV, wouldn't it?\n\nWell, you can actually download Youtube videos to your computer using, for example, [[this Firefox plugin|https://addons.mozilla.org/en-US/firefox/addon/3242]]. It'll save a 'flv' file, a Flash Video format. You can either try to transcode it with mencoder:\n\n{{{\nmencoder video.flv -ovc copy -oac copy -o video.avi\n}}}\n\nor simply rename it as .avi: that way, the Freebox will see the file, and VLC will magically convert it on-the-fly.\n\nNow go try it out on this hilarious video about [[Achmed the dead terrorist|http://www.youtube.com/watch?v=1uwOL4rB-go]]
You may remember I had an awkward method to redirect a port (i.e. upon TCP connection to a port, forward it to another address and port) using [[netcat|http://www.rutschle.net/blog/archives/2007/03/29/T14_49_41/]].\n\nYesterday I really needed a 'tranparent proxy': something that would allow me to look at the traffic going through a network connection, without doing anything else. You could use monitoring tools like tcpdump, but unfortunately you have to have administrative rights to run such tools, which isn't always possible.\n\nThe other method is to go through a transparent proxy: connect to the proxy, which will dump all the data in a file while also forwarding to a different port. Note it's almost exactly while netcat does.\n\nClearly I didn't understand the netcat manual, so I wrote a little transparent proxy from scratch. Twice. Once in Perl and once in C.\n\nThen today I realise that:\n* netcat can dump the traffic going through it using option {{{-o}}}\n* my hack is very awkward; to redirect a port all one needs to do is:\n{{{\nnc -l -p 5000 -c "nc smtp.free.fr 25"\n}}}\nwhich reads "listens for connections on port 5000, and when that happens connect the connection to another connection to smtp.free.fr, port 25. Now a telnet to localhost:5000 goes to smtp.free.fr:25.\n\nAnd with just one more option, we get a transparent proxy:\n{{{\nnc -l -p 5000 -c "nc -o dump smtp.free.fr 25"\n}}}\n\nAll that's really missing in the dump is a dating field, which really has nothing to do with Meetic.\n
So, recently we ran into a problem at englishintoulouse.com: we have over 500 members, and our ISP, which I used as a smarthost, objects to our sending more than 200 e-mails a day. So, sending a newsletter becomes a two-day job, with the last people on the list getting the newsletter a lot later than they should.\n\nI went through the pain of setting up my own outgoing SMTP server. It was simple 10 years ago when all SMTP servers just accepted your e-mail: thanks to spammers, it's become much harder and your setup needs to be a lot more precise if you want large ISPs to accept mail from your.\n\nHere are the changes I made.\n\n! SPF\n\nSPF (Sender Policy Framework) is a DNS record that documents who has the right to send e-mail for your domain. In our case, the IP address documented as A and MX record are allowed to send e-mail for us.\n\nFor MaraDNS, you add a line like this:\n{{{\n% spf 'v=spf1 a mx ~all'\n% txt 'v=spf1 a mx ~all'\n}}}\n\nMore details about SPF, including a script that builds the SPF record for you, are available on the [[SPF Web site|http://www.openspf.org]].\n\n! ISP setup\n\nSeveral large ISP (e.g. AOL) filter incoming mail depending on the emitting IP address. \n\nConfigure a reverse DNS with your ISP, so the RDNS is consistent with your domain (I am not sure this is totally useful).\n\nRemove your residential IP from [[SpamHaus|http://www.spamhaus.org]] PBL: , link "Remove IP Address". This lets most serious ISPs (Yahoo, Gmail, ...) receive your e-mail. Some other ISPs use a blacklist from [[Trend Micro|http://www.mail-abuse.com/]]. You'll also need to request being taken off their list.\n\nAOL still won't listen, so use your ISP as smarthost just for them, adding to /etc/exim4/hubbed_hosts:\n{{{\naol.com: smtp.free.fr\n}}}\n\nAOL also lets you set up a spam feedback loop, but I am not done with that yet.\n\n\n! Check your DNS setup\n\nAnother goal I had was to pass all of zonecheck(1) tests. This can be either run from their [[Web site|http://www.zonecheck.com]] or installed under Debian {{{apt-get install zonecheck}}}.\n\nIt pointed out that my DNS setup was klunky at best. So, what I need to do is tell my registrar that each of my domains has two nameservers, ns1.% and ns2.%, with the appropriate addresses. The registrar transmits that to the registry. The thing is, this will only work properly if your DNS is consistent with the registry, i.e. you have ns1.% and ns2.% A and NS records set up. In MaraDNS:\n{{{\n% NS ns1.%\n% NS ns2.%\n\nns1.% 80.68.89.183\nns2.% 82.235.147.6\n}}}\n\nThen zonecheck insists that my servers should also serve TCP requests. In MaraDNS, in {{{/etc/mararc}}}:\n{{{\ntcp_convert_acl = "0.0.0.0/0"\ntcp_convert_server = "80.68.89.183"\n}}}\n(with the appropriate IP address of course), and restart zoneserver (not maradns!).\n\nAnother pretty, Web-based, DNS tool that you can use is [[DNSCheck|http://dnscheck.iis.se/]], which has the advantage of giving you an external view of your setup even if you do not have access to a machine outside your network.\n\n! Misc\n\nYou can test your e-mail system with \n{{{\ntelnet relay-test.mail-abuse.org\n}}}\nThis runs a series of security tests on the IP you're coming from and tells you the results. Ideal to find if you're accidently set up as an open relay.\n\n\n
Well, sensei RMS came to [[Toulouse|http://www.toulibre.org/rms2007]]. I went. I didn't see. I didn't conquer. It was actually so crowded I couldn't get in.\n\nI can only hope there'll be another time. RMS is, I'd say, one of the ten most influencial computer people in the last twenty years (with Bill Gates, Steve Jobs, Linus, Larry Wall, Rasmus Ledorf and a few others. Actually, maybe he'd make top five).\n
You know how you always open too many tabs in Firefox for deferred reading, and then you end up with a thousand tabs because you're not getting around to reading them, and then Firefox crashes and then you lose them all? Plus, it's rather unmanageable.\n\nEnter [[Read it later|http://readitlaterlist.com/]]. Now you can just add the tab to a reading list, and close it. Later on when you have time, you can come back to your reading list.\n\nBut wait, there's more. You can open an account with Read It Later, and then you can synchronise your reading list between all your Firefoxes.\n\nBut wait, there's more. You can get [[Calibre|http://calibre-ebook.com/]] to use your reading list as a news source (in the "unknown" section of Scheduled News) and Calibre will download your entire list, make it into a periodical entry, and send it to your Kindle. Now how's that for cool (and non-straightforward)?\n\nOk, so to get to that point I ran into a number of problems. Read It Later does not work with Vimperator, and I have no idea why. I discovered that there is now a branch of Vimperator called Pentadactyl (which is actually a funny name), which is compatible with Read It Later, and seems to have some new functions over Vimperator too. But Pentadactyl requires Firefox 3.6, which is not in Debian yet. I discovered Mozilla provides a tar of Firefox that just unpacks and somehow works directly on Debian stable. Problem solved: with Firefox 3.6, I can have Pentadactyl, which lets Read It Later works happily. And that's how wanting one little extension makes you upgrade half of your computer.\n\nAnd on top of that, I add a file {{{readitlater.js}}} in {{{~/.pentadactyl/plugins}}} containing:\n\n{{{\ncommands.addUserCommand(['readitlater'], "Read Later",function(){RIL.addCurrent();RIL.addedFromLocationBar();});\ncommands.addUserCommand(['markasread'], "Mark as Read", function(){RIL.markCurrentAsRead();});\ncommands.addUserCommand(['readsomething'], "Read Something", function(){RIL.readSomething();});\n}}}\n\nThat way, I have new commands: {{{:readitlater}}} and {{{:markasread}}}, to set my reading list, and {{{:readsomething}}} to open the reading list. The next step will be to integrate the reading list properly the same way as it is done in Pentadactyl.\n\n
Yesterday I was listening to the radio and heard some goon of the pope talk about his highness' philosophical greatness. Apparently the pope is visiting France and that's worth ignoring all the pledges of laicity written in French law.\n\nSo, what's the summary of his highness [[Palpatine|http://frafilm.blog.kataweb.it/files/2007/10/pope_palpatine.jpg]]? He seems to be trying to reconcile reason and faith. He reasons that Pure Reason, i.e. reason without faith, leads to scientism and corruption of everything, with, like, the atomic bomb and genetic engineering (and abortion, presumably). Holy crap, isn't that "Science sans conscience n'est que ruine de l'ame" (Rabelais, five centuries ago)? Way to go, thinker!\n\nAnd at the other end of the spectrum, is Pure Faith, which is also bad because that's what those evil islamists are doing. Lucky catholics don't believe too much, eh?\n\nThe argument of reason is laughable. Anyone who exercises reason should see that the atomic bomb is not a good thing, and among the reasons to avoid GMO, none are religious and all are related to actual, reasonable reasons (which are not linked to profit: just because it's outside the scope of capitalist reason, doesn't means it's outside of the scope of Reason).\n\nIt just blows my mind that this sort of argument is still going around. Faith, by definition, has nothing to do with reason, and vice-versa: the minute I uncritically believe something that is told to me, I stop using reason. I guess that's just too hard to reconcile in the head of a pope.\n\n
I very recently started using [[Remember The Milk|http://www.rememberthemilk.com]], a TODO list manager. It's quite good: you can set up various lists, target dates, submit tasks by e-mail, and then some.\n\nThe biggest downside I saw was the absence of a command line tool to access the task lists. That means that before I can see which tasks I have to do, I need to start up my browser. But let's face it, as soon as you start up a browser, it's suddenly time to go home (or to bed, if you're at home) when you realise you've spent all day (or evening) reading Wikipedia.\n\nSo I scratched my hitch (as they say) and wrote [[rtm|http://www.rutschle.net/rtm]], which enables me to just type:\n\n{{{\nrtm --show\n}}}\n\nto see what I have to do, without further delays.\n\nThe agent class RTMAgent on which rtm is built is an interesting example of one of Perl's strengths: there is a mechanism that allows the object to catch a call to an undefined method, which lets the object's user just call any of RTM's API methods, catch them, and turn them into a web access.\n\nSo I can write:\n{{{\n$tasks = $useragent->tasks_getList;\n}}}\n\ntasks_getList doesn't actually exists, but the useragent objects transforms it into a request to rtm.tasks.getList, sends the request to http://www.rememberthemilk.com/services/rest, parses the response and returns that. The only downside is that the response isn't as abstract or synthetic as one might like.\n
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">\n<html>\n<head>\n<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">\n<title>SITE_TITLE: TIDDLER_TITLE</title>\n<meta name="description" content="SITE_SUBTITLE">\n<meta name="keywords" content="TIDDLER_KEYWORDS">\n<script language="JavaScript" type="text/javascript">\nlocation.href = 'TIDDLER_URL';\n</script>\n<base href="TIDDLER_URL">\n</head>\n\n<body>\n<noscript>\n<a href="TIDDLER_URL">TIDDLER_TITLE</a>\n</noscript>\nTIDDLER_CONTENT\n</body>\n</html>
function generateSEOFiles()\n{\n // last update: 2007-02-14 by Fabrice Proudhon\n // http://www.superphysique.net#%5B%5BSEO%20TiddlyWiki%20Plugin%5D%5D\n var originalPath = document.location.toString();\n if(originalPath.substr(0,5) != "file:") \n {\n alert(config.messages.notFileUrlError);\n if(store.tiddlerExists(config.messages.saveInstructions))\n story.displayTiddler(null,config.messages.saveInstructions);\n return;\n }\n var y = [];\n var g = [];\n var localPath = getLocalPath(originalPath);\n var c = store.getTiddlerText("SEOTiddlyWikiConfig");\n var su = store.getTiddlerText("SiteUrl");\n var st = wikifyPlain("SiteTitle");\n var sbt = wikifyPlain("SiteSubtitle");\n var htmlPath = localPath.substr(0,localPath.lastIndexOf("/"));\n var tiddlers = store.getTiddlers("modified","excludeSearch");\n g.push('<url><loc>' + su.htmlEncode() + '</loc></url>');\n y.push(su.htmlEncode());\n for (var t=0; t<tiddlers.length; t++) {\n var content = c;\n var filename = tiddlers[t].title.htmlEncode();\n filename = filename.toLowerCase();\n filename = filename.replace(/ |\s/|@/gi, '-');\n filename = filename.replace(/(-)\s1+/gi, '$1');\n content = content.replace(/SITE_TITLE/gi, st.htmlEncode());\n content = content.replace(/SITE_SUBTITLE/gi, sbt.htmlEncode());\n content = content.replace(/TIDDLER_TITLE/gi, tiddlers[t].title.htmlEncode());\n content = content.replace(/TIDDLER_URL/gi, su.htmlEncode() + '#' + String.encodeTiddlyLink(tiddlers[t].title));\n content = content.replace(/TIDDLER_KEYWORDS/gi, tiddlers[t].tags.join(',').htmlEncode());\n content = content.replace(/TIDDLER_CONTENT/gi, wikifyStatic(tiddlers[t].text,null,tiddlers[t]).htmlEncode());\n content = content.replace(/</gi, '<');\n content = content.replace(/>/gi, '>');\n content = content.replace(/"/gi, '"');\n var d = tiddlers[t].modified.getFullYear() + '-';\n if (tiddlers[t].modified.getMonth() + 1 < 10) d = d + '0';\n d = d + (tiddlers[t].modified.getMonth() + 1) + '-';\n if (tiddlers[t].modified.getDate() < 10) d = d + '0';\n d = d + tiddlers[t].modified.getDate();\n for (var ta=0; ta<tiddlers[t].tags.length; ta++) {\n var tag = tiddlers[t].tags[ta].toLowerCase();\n g.push('<url><loc>' + su.htmlEncode() + escape(tag) + '/' + escape(filename) + '.htm' + '</loc><lastmod>' + d + '</lastmod></url>');\n y.push(su.htmlEncode() + escape(tag) + '/' + escape(filename) + '.htm');\n displayMessage(htmlPath + '/' + tag + '/' + filename + '.html', '');\n saveFile(htmlPath + '/' + tag + '/' + filename + '.html', convertUnicodeToUTF8(content));\n }\n }\n saveFile(htmlPath + '\s\surllist.txt', convertUnicodeToUTF8(y.join('\sn')));\n saveFile(htmlPath + '\s\ssitemap.xml', '<?xml version="1.0" encoding="utf-8"?><urlset xmlns="http://www.google.com/schemas/sitemap/0.84">\sn' + convertUnicodeToUTF8(g.join('\sn')) + '</urlset>');\n displayMessage('SEO files created', '');\n}\n
// //''Name:'' Save Changes To DAV plugin\n// //''Version:'' <<getversion saveChangesToDAV>> (<<getversiondate calendar "DD MMM YYYY">>)\n// //''Depends on:'' YATWA http://www.rumsby.org/yatwa/\n// //''Author:'' PeterSuschlik <peter-tiddly //at// suschlik //dot// de>\n\n// //''Syntax:'' \n// //<< {{{saveChangesToDAV}}} >>\n\n// //''Description:'' \n// //This plugin allows you to upload your changes to a webserver via WebDAV (at the moment only the methods {{{GET}}} and {{{PUT}}} are implemented)\n// //It should be add to SideBarOptions.\n// //Addionally, add << {{{option txtDAVURL 50}}} >> to AdvancedOptions.\n\n// //''WebDAV Apache Setup Example''\n// // Wiki-URL: http://{{{host}}}/wiki/\n// // DAV-URL: http://{{{host}}}/wiki/dav/index.html\n// // * setup WebDAV for {{{host}}} as usual\n// // * symlink /wiki/index.html to /wiki/dav/index.html\n\n// //''Notes on XMLHttpRequest restrictions''\n// //Due to security reasons there are some restrictions on connection to a webserver via XMLHttpRequest\n// //The wiki and the upload WebDAV directory must live on the same host\n\n// //''TODO''\n// // * some documentation/comments\n\n\n// //''Configuration:''\n// //Modify {{{txtDAVURL}}} option at AdvancedOptions.\n// //For setup see above.\n\n// //''Code section:''\n// (you should not need to alter anything below here)//\n\n/*\n{{{\n*/\n\nfunction isHttp() {\n return document.location.toString().search(/https?:\s/\s//) != -1;\n}\n\nfunction DAVSaver() {\n this.uploading = false;\n}\n\nDAVSaver.prototype = {\n xmlhttprequest: function() {\n try {\n return new XMLHttpRequest();\n return new ActiveXObject("Msxml2.XMLHTTP");\n return new ActiveXObject("Microsoft.XMLHTTP");\n } catch(e) {}\n alert("Could not construct XmlHttpRequest Object!");\n },\n reset: function() {\n this.uploading = false;\n return null;\n },\n loadLocal: function() {\n var originalPath = document.location.toString();\n var hashPos = originalPath.indexOf("#");\n if(hashPos != -1) originalPath = originalPath.substr(0,hashPos);\n var localPath;\n if(originalPath.charAt(9) == ":") // pc local file\n localPath = unescape(originalPath.substr(8)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file://///") == 0) // FireFox pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(10)).replace(new RegExp("/","g"),"\s\s");\n else if(originalPath.indexOf("file:///") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(7));\n else if(originalPath.indexOf("file:/") == 0) // mac/unix local file\n localPath = unescape(originalPath.substr(5));\n else // pc network file\n localPath = "\s\s\s\s" + unescape(originalPath.substr(7)).replace(new RegExp("/","g"),"\s\s");\n displayMessage('Loading locally: ' + localPath, localPath);\n var original = loadFile(localPath);\n if (original == null) {\n displayMessage('Loading locally failed: ' + localPath, localPath);\n return;\n }\n this.doUpload(original);\n },\n loadRemote: function() {\n var xml = this.xmlhttprequest();\n xml._uploader = this;\n displayMessage('Loading remotely: ' + this.url, this.url);\n xml.onreadystatechange = function() {\n if (xml.readyState != 3)\n displayMessage("Download-State " + xml.readyState);\n if (xml.readyState == 4) {\n if (xml.status == 200) {\n displayMessage('Downloaded ' + xml.responseText.length + ' bytes');\n xml._uploader.doUpload(xml.responseText);\n } else {\n displayMessage('Upload failed ' + xml.status, xml._uploader.url);1\n xml._uploader.reset();\n }\n }\n }\n xml.open('GET', this.url, true);\n xml.send('');\n },\n loadAndUpload: function() {\n if (isHttp()) {\n this.loadRemote();\n } else {\n this.loadLocal();\n }\n },\n upload: function() {\n if (readOnly) return;\n if (this.uploading) {\n displayMessage("Upload in progress - please wait");\n return;\n }\n this.url = config.options['txtDAVURL'];\n if (this.url == null || this.url == "") {\n alert("No DAV URL specified in AdvancedOptions!\sn\sn" +\n"Maybe you need to add the following line to AdvancedOptions:\sn" +\n"DAV-URL <<option txtDAVURL 50>>");\n return;\n }\n this.uploading = true;\n this.loadAndUpload();\n },\n doUpload: function(content) {\n if (content == null) return;\n content = this.reviseStore(content);\n displayMessage("Uploading " + content.length + " bytes to " + this.url);\n var xml = this.xmlhttprequest();\n xml._uploader = this;\n xml.onreadystatechange = function() {\n displayMessage("Upload-State " + xml.readyState);\n if (xml.readyState == 4) {\n if (xml.status == 201 || xml.status == 204) {\n displayMessage("Uploaded", this.url);\n } else {\n displayMessage("Upload failed " + xml.status, xml._uploader.url);\n }\n xml._uploader.reset();\n }\n }\n if (!isHttp()) {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n }\n xml.open('PUT', this.url, true);\n xml.send(content);\n },\n reviseStore: function(original) {\n // Locate the storeArea div's\n var posOpeningDiv = original.indexOf(startSaveArea);\n var posClosingDiv = original.lastIndexOf(endSaveArea);\n if((posOpeningDiv == -1) || (posClosingDiv == -1)) {\n alert(config.messages.invalidFileError.format([localPath]));\n return;\n }\n var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + \n convertUnicodeToUTF8(allTiddlersAsHtml()) + "\sn\st\st" +\n original.substr(posClosingDiv);\n var newSiteTitle = store.getTiddlerText("SiteTitle","TiddlyWiki").htmlEncode();\n revised = revised.replace(new RegExp("<title>[^<]*</title>", "im"),"<title>"+ newSiteTitle +"</title>");\n return revised;\n },\n onClick: function() {\n clearMessage();\n this.upload();\n },\n}\nvar davSaver = new DAVSaver();\n\nversion.extensions.saveChangesToDAV = {major: 0, minor: 2, revision: 1, date: new Date(2005,09,09)};\n\nif (isHttp() && (config.options['txtDAVURL'] == null || config.options['txtDAVURL'] == "")) {\n config.options['txtDAVURL'] = document.location.href;\n}\n\nconfig.macros.saveChangesToDAV = {\n label: "save to dav",\n prompt: "Save all tiddlers to create a new TiddlyWiki to DAV"\n}\n\nconfig.macros.saveChangesToDAV.handler = function(place) {\n if(!readOnly)\n createTiddlyButton(place,this.label,this.prompt, function() { davSaver.onClick() });\n}\n\n/** Override */\n\nconfig.macros.option.handler = function(place,macroName,params)\n{\n var opt = params[0];\n if(config.options[opt] == undefined)\n return;\n var size = params[1] || 15; // configure size\n var c;\n switch(opt.substr(0,3))\n {\n case "txt":\n c = document.createElement("input");\n c.onkeyup = this.onChangeOption;\n c.setAttribute("option",opt);\n c.size = size; // configure size\n c.value = config.options[opt];\n place.appendChild(c);\n break;\n case "chk":\n c = document.createElement("input");\n c.setAttribute("type","checkbox");\n c.onclick = this.onChangeOption;\n c.setAttribute("option",opt);\n c.checked = config.options[opt];\n place.appendChild(c);\n break;\n }\n}\n\nfunction convertUnicodeToUTF8(s)\n{\n if(saveUsingSafari)\n return s;\n/* This does not work remotely!\n else if(window.Components)\n return mozConvertUnicodeToUTF8(s);\n*/\n else\n return manualConvertUnicodeToUTF8(s);\n}\n\n/*\n}}}\n*/
First problem: Debian stable's Firefox is old (2.x). Solution: install a //chroot// containing Sid, and install the latest version.\n\nThing is, it's a recurring problem in Debian; I had removed my chroot settings last time Sid turned to Stable, and I forgot how it was done. This time I'll document it.\n\nSecond problem: The Web browser is one of the most critical pieces of software you use. The main assets on a computer are its functions (the programs and servers you run) and your data.\n\nMy machine acts as a server, so it's got Apache: but Apache can only read files, not normally write to them. So a vulnerability in Apache alone won't compromise my system much.\n\nOn the other hand, my Web browser has the same rights as me, which means it can read or write any of my personal files. A vulnerability in Firefox is a threat to all my data.\n\nSolution: run Firefox under a different user ID which has access to nothing.\n\nSo, let's do it.\n\nI use //schroot// as a wrapper to //chroot//.\n\n{{{\n# Setup chroot\ndebootstrap sid sid\n\n# Use same users as main system\ncd sid/etc\nrm passwd; ln /etc/passwd .\nrm shadow; ln /etc/shadow .\nrm group; ln /etc/group .\nln /etc/hosts .\n\n# Install Firefox\ncd ..\nchroot .\napt-get update\napt-get install iceweasel\n}}}\n\nNow outside the //chroot// we add the user (which automatically gets added to the //chroot// as well) and install //schroot//:\n\n{{{\nadduser me_www\napt-get install schroot\nvi /etc/schoot/schroot.conf\n<< configure >>\n}}}\n\nFor some reason X forwarding won't work if the //chroot// doesn't share the same /tmp as the main system (this doesn't totally make sense to me) so we add this to {/etc/fstab}:\n\n{{{\n/home /root/chroot/sid/home/ none bind 0 2\n/dev /root/chroot/sid/dev none bind 0 2\n/tmp /root/chroot/sid/tmp none bind 0 1\n/sys /root/chroot/sid/sys none bind 0 1\n}}}\n\nDon't forget to mount all that ({mount -a}) then we can start Firefox, in the //chroot//, under the new user ID:\n\n{{{\nschroot -u me_www -c sid -- iceweasel --display $DISPLAY\n}}}\n\nSimple, innit?\n\n
I recently discovered that our Internet Service Provider, Free.fr, allowed us to send a Fax (by posting a PDF on the Web interface) or to receive a Fax (directly to our Free.fr number, the fax gets turned into a PDF and is mailed to an address of your choice).\n\nI then wondered if I could send (or ever receive?) SMS messages (which is redundant really: Short Message Service messages.)\n\nThere is a [[discussion|http://www.freenews.fr/forum/viewtopic.php?pid=470290]] on Freenewz that led me to a [[page|http://free.phonevalley.com/websms/free/]] that lets you send SMS.\n\nOnce you subscribe (3 second process, no verification of anything whatsoever) you can buy credit. The cool thing is that if you're logging in from your Free.fr connection, that is detected and automatically added to your Free.fr bill. The bad thing is, if you're at work and want to SMS your beloved, you can't buy credit and try out the service.\n\nOr... maybe... with a reverse proxy at home, logging in from work...\n\nNo, go home, you crazy rabbit.\n\nLater on, from home, I bought credit: you just need the Free.fr password and that's it.\n\nWell, that's all to simple I say. My next project will be to install asterisk and send them from Perl script. Or something.\n
<<search>><<closeAll>><<permaview>><<newTiddler>><<newJournal 'DD MMM YYYY'>><<saveChanges>><<saveChangesToDAV>><<slider chkSliderOptionsPanel OptionsPanel 'options »' 'Change TiddlyWiki advanced options'>>\n
English words from a French rabbit's brain
WhiteRabbit's braindump\n
http://www.rutschle.net/wiki/
\n/***\n\n''Inspired by [[TiddlyPom|http://www.warwick.ac.uk/~tuspam/tiddlypom.html]]''\n\n|Name|SplashScreenPlugin|\n|Created by|SaqImtiaz|\n|Location|http://lewcid.googlepages.com/lewcid.html#SplashScreenPlugin|\n|Version|0.21 |\n|Requires|~TW2.08+|\n!Description:\nProvides a simple splash screen that is visible while the TW is loading.\n\n!Installation\nCopy the source text of this tiddler to your TW in a new tiddler, tag it with systemConfig and save and reload. The SplashScreen will now be installed and will be visible the next time you reload your TW.\n\n!Customizing\nOnce the SplashScreen has been installed and you have reloaded your TW, the splash screen html will be present in the MarkupPreHead tiddler. You can edit it and customize to your needs.\n\n!History\n* 20-07-06 : version 0.21, modified to hide contentWrapper while SplashScreen is displayed.\n* 26-06-06 : version 0.2, first release\n\n!Code\n***/\n//{{{\nvar old_lewcid_splash_restart=restart;\n\nrestart = function()\n{ if (document.getElementById("SplashScreen"))\n document.getElementById("SplashScreen").style.display = "none";\n if (document.getElementById("contentWrapper"))\n document.getElementById("contentWrapper").style.display = "block";\n \n old_lewcid_splash_restart();\n \n if (splashScreenInstall)\n {if(config.options.chkAutoSave)\n {saveChanges();}\n displayMessage("TW SplashScreen has been installed, please save and refresh your TW.");\n }\n}\n\n\nvar oldText = store.getTiddlerText("MarkupPreHead");\nif (oldText.indexOf("SplashScreen")==-1)\n {var siteTitle = store.getTiddlerText("SiteTitle");\n var splasher='\sn\sn<style type="text/css">#contentWrapper {display:none;}</style><div id="SplashScreen" style="border: 3px solid #ccc; display: block; text-align: center; width: 320px; margin: 100px auto; padding: 50px; color:#000; font-size: 28px; font-family:Tahoma; background-color:#eee;"><b>'+siteTitle +'</b> is loading<blink> ...</blink><br><br><span style="font-size: 14px; color:red;">Requires Javascript.</span></div>';\n if (! store.tiddlerExists("MarkupPreHead"))\n {var myTiddler = store.createTiddler("MarkupPreHead");}\n else\n {var myTiddler = store.getTiddler("MarkupPreHead");}\n myTiddler.set(myTiddler.title,oldText+splasher,config.options.txtUserName,null,null);\n store.setDirty(true);\n var splashScreenInstall = true;\n}\n//}}}
/*{{{*/\n* html .tiddler {\n height: 1%;\n}\n\nbody {\n font-size: .75em;\n font-family: arial,helvetica;\n margin: 0;\n padding: 0;\n}\n\nh1,h2,h3,h4,h5 {\n font-weight: bold;\n text-decoration: none;\n padding-left: 0.4em;\n}\n\nh1 {font-size: 1.35em;}\nh2 {font-size: 1.25em;}\nh3 {font-size: 1.1em;}\nh4 {font-size: 1em;}\nh5 {font-size: .9em;}\n\nhr {\n height: 1px;\n}\n\na{\n text-decoration: none;\n}\n\ndt {font-weight: bold;}\n\nol { list-style-type: decimal }\nol ol { list-style-type: lower-alpha }\nol ol ol { list-style-type: lower-roman }\nol ol ol ol { list-style-type: decimal }\nol ol ol ol ol { list-style-type: lower-alpha }\nol ol ol ol ol ol { list-style-type: lower-roman }\nol ol ol ol ol ol ol { list-style-type: decimal }\n\n.txtOptionInput {\n width: 11em;\n}\n\n#contentWrapper .chkOptionInput {\n border: 0;\n}\n\n.externalLink {\n text-decoration: underline;\n}\n\n.indent {margin-left:3em;}\n.outdent {margin-left:3em; text-indent:-3em;}\ncode.escaped {white-space:nowrap;}\n\n.tiddlyLinkExisting {\n font-weight: bold;\n}\n\n.tiddlyLinkNonExisting {\n font-style: italic;\n}\n\n/* the 'a' is required for IE, otherwise it renders the whole tiddler a bold */\na.tiddlyLinkNonExisting.shadow {\n font-weight: bold;\n}\n\n#mainMenu .tiddlyLinkExisting, \n#mainMenu .tiddlyLinkNonExisting,\n#sidebarTabs .tiddlyLinkNonExisting{\n font-weight: normal;\n font-style: normal;\n}\n\n#sidebarTabs .tiddlyLinkExisting {\n font-weight: bold;\n font-style: normal;\n}\n\n.header {\n position: relative;\n}\n\n.header a:hover {\n background: transparent;\n}\n\n.headerShadow {\n position: relative;\n padding: 4.5em 0em 1em 1em;\n left: -1px;\n top: -1px;\n}\n\n.headerForeground {\n position: absolute;\n padding: 4.5em 0em 1em 1em;\n left: 0px;\n top: 0px;\n}\n\n.siteTitle {\n font-size: 3em;\n}\n\n.siteSubtitle {\n font-size: 1.2em;\n}\n\n#mainMenu {\n position: absolute;\n left: 0;\n width: 10em;\n text-align: right;\n line-height: 1.6em;\n padding: 1.5em 0.5em 0.5em 0.5em;\n font-size: 1.1em;\n}\n\n#sidebar {\n position: absolute;\n right: 3px;\n width: 16em;\n font-size: .9em;\n}\n\n#sidebarOptions {\n padding-top: 0.3em;\n}\n\n#sidebarOptions a {\n margin: 0em 0.2em;\n padding: 0.2em 0.3em;\n display: block;\n}\n\n#sidebarOptions input {\n margin: 0.4em 0.5em;\n}\n\n#sidebarOptions .sliderPanel {\n margin-left: 1em;\n padding: 0.5em;\n font-size: .85em;\n}\n\n#sidebarOptions .sliderPanel a {\n font-weight: bold;\n display: inline;\n padding: 0;\n}\n\n#sidebarOptions .sliderPanel input {\n margin: 0 0 .3em 0;\n}\n\n#sidebarTabs .tabContents {\n width: 15em;\n overflow: hidden;\n}\n\n.wizard {\n padding: 0.1em 0em 0em 2em;\n}\n\n.wizard h1 {\n font-size: 2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.4em 0em 0.2em 0em;\n}\n\n.wizard h2 {\n font-size: 1.2em;\n font-weight: bold;\n background: none;\n padding: 0em 0em 0em 0em;\n margin: 0.2em 0em 0.2em 0em;\n}\n\n.wizardStep {\n padding: 1em 1em 1em 1em;\n}\n\n.wizard .button {\n margin: 0.5em 0em 0em 0em;\n font-size: 1.2em;\n}\n\n#messageArea {\nposition:absolute; top:0; right:0; margin: 0.5em; padding: 0.5em;\n}\n\n*[id='messageArea'] {\nposition:fixed !important; z-index:99;}\n\n.messageToolbar {\ndisplay: block;\ntext-align: right;\n}\n\n#messageArea a{\n text-decoration: underline;\n}\n\n.popup {\n font-size: .9em;\n padding: 0.2em;\n list-style: none;\n margin: 0;\n}\n\n.popup hr {\n display: block;\n height: 1px;\n width: auto;\n padding: 0;\n margin: 0.2em 0em;\n}\n\n.listBreak {\n font-size: 1px;\n line-height: 1px;\n}\n\n.listBreak div {\n margin: 2px 0;\n}\n\n.popup li.disabled {\n padding: 0.2em;\n}\n\n.popup li a{\n display: block;\n padding: 0.2em;\n}\n\n.tabset {\n padding: 1em 0em 0em 0.5em;\n}\n\n.tab {\n margin: 0em 0em 0em 0.25em;\n padding: 2px;\n}\n\n.tabContents {\n padding: 0.5em;\n}\n\n.tabContents ul, .tabContents ol {\n margin: 0;\n padding: 0;\n}\n\n.txtMainTab .tabContents li {\n list-style: none;\n}\n\n.tabContents li.listLink {\n margin-left: .75em;\n}\n\n#displayArea {\n margin: 1em 17em 0em 14em;\n}\n\n\n.toolbar {\n text-align: right;\n font-size: .9em;\n visibility: hidden;\n}\n\n.selected .toolbar {\n visibility: visible;\n}\n\n.tiddler {\n padding: 1em 1em 0em 1em;\n}\n\n.missing .viewer,.missing .title {\n font-style: italic;\n}\n\n.title {\n font-size: 1.6em;\n font-weight: bold;\n}\n\n.missing .subtitle {\n display: none;\n}\n\n.subtitle {\n font-size: 1.1em;\n}\n\n.tiddler .button {\n padding: 0.2em 0.4em;\n}\n\n.tagging {\nmargin: 0.5em 0.5em 0.5em 0;\nfloat: left;\ndisplay: none;\n}\n\n.isTag .tagging {\ndisplay: block;\n}\n\n.tagged {\nmargin: 0.5em;\nfloat: right;\n}\n\n.tagging, .tagged {\nfont-size: 0.9em;\npadding: 0.25em;\n}\n\n.tagging ul, .tagged ul {\nlist-style: none;margin: 0.25em;\npadding: 0;\n}\n\n.tagClear {\nclear: both;\n}\n\n.footer {\n font-size: .9em;\n}\n\n.footer li {\ndisplay: inline;\n}\n\n* html .viewer pre {\n width: 99%;\n padding: 0 0 1em 0;\n}\n\n.viewer {\n line-height: 1.4em;\n padding-top: 0.5em;\ntext-align: justify;\n}\n\n.viewer .button {\n margin: 0em 0.25em;\n padding: 0em 0.25em;\n}\n\n.viewer blockquote {\n line-height: 1.5em;\n padding-left: 0.8em;\n margin-left: 2.5em;\n}\n\n.viewer ul, .viewer ol{\n margin-left: 0.5em;\n padding-left: 1.5em;\n}\n\n.viewer table {\n border-collapse: collapse;\n margin: 0.8em 1.0em;\n}\n\n.viewer th, .viewer td, .viewer tr,.viewer caption{\n padding: 3px;\n}\n\n.viewer table.listView {\n font-size: 0.85em;\n margin: 0.8em 1.0em;\n}\n\n.viewer table.listView th, .viewer table.listView td, .viewer table.listView tr {\n padding: 0px 3px 0px 3px;\n}\n\n.viewer pre {\n padding: 0.5em;\n margin-left: 0.5em;\n font-size: 1.2em;\n line-height: 1.4em;\n overflow: auto;\n}\n\n.viewer code {\n font-size: 1.2em;\n line-height: 1.4em;\n}\n\n.editor {\nfont-size: 1.1em;\n}\n\n.editor input, .editor textarea {\n display: block;\n width: 100%;\n font: inherit;\n}\n\n.editorFooter {\n padding: 0.25em 0em;\n font-size: .9em;\n}\n\n.editorFooter .button {\npadding-top: 0px; padding-bottom: 0px;}\n\n.fieldsetFix {border: 0;\npadding: 0;\nmargin: 1px 0px 1px 0px;\n}\n\n.sparkline {\n line-height: 1em;\n}\n\n.sparktick {\n outline: 0;\n}\n\n.zoomer {\n font-size: 1.1em;\n position: absolute;\n padding: 1em;\n}\n\n.cascade {\n font-size: 1.1em;\n position: absolute;\n overflow: hidden;\n}\n/*}}}*/
So the [[VP882 MP3 player]] works well. But it's haunted.\n\nI created a 'Flamenco' play list, which, as you could have guessed, contains mostly Flamenco. Well, once in a while, the MP3 player just spontaneously start to play that play-list, starting in the middle of a seemingly random song.\n\n\nOn a (not) totally unrelated note, a [[study|http://www.msnbc.msn.com/id/18684016/?GT1=9951]] hints that fruit flies have free will. Free will is a funny topic which biggest use is to get Scott Adam's [[blog|http://dilbertblog.typepad.com/the_dilbert_blog/]]'s readers worked up. Some people's opinion is that the world is all deterministic and all, so free will is an illusion. And yes, there is quantum physics that introduces randomness, but then you'd be arguing that your free will is the same as acting randomly. The other people's opinion is that we have freedom of choice.\n\nWell, as for me, I'll let the jury out until someone has properly defined what 'free will' means. 'The ability to make a choice' is only a valid answer if you define 'choice', and detail how alternatives are available to us, and how the brain decides between the alternatives.\n\nBack to that article: scientists put a fruit fly in a completely featureless room, expecting the fly to act randomly because it had nothing to base its choices on. Instead, the fly always goes flying around following a well-known algorithm. Somehow, the scientists (or the journalist) deduced that that meant even fruit flies have free will. I am too dim to understand the reasoning: apparently, following a known, predictable algorithm is the same as free will.\n\nNow the interesting thing is the very long argument about how, if a fly can spontaneously 'decide' to follow a strategy, it must have free will.\n\nWait. What was that about spontaneously? But... my MP3 player spontaneously plays stuff, without having been told, in an unpredictable way! I've created a machine that possesses free will! Go me!\n\nThat, or it's just haunted.
Those of you most familiar with the dumps of my brain will now that I believe there is a big speculative bubble on real-estate in most of the Western world, which is now starting to explode here and there. Here being America and there being Spain (with a bit in Oz as well -- we're still waiting for France and the UK to explode).\n\nThere's a good article in The Times called [[The gain in Spain goes mainly down the drain|http://www.timesonline.co.uk/tol/comment/columnists/guest_contributors/article1733681.ece]]. Here are some extracts (Emphasis are mine):\n\n<<<\nShares in property companies plunged after it became clear to investors that there is not a limitless supply of wide-eyed Brits [...] to soak up the //800,000 properties a year// being built in Spain.\n<<<\n\n<<<\nThose who have bought holiday homes in the country recently face losing money\n<<<\n\nI really like this one:\n<<<\nWhy can’t we enjoy going on holiday any more without thinking we have got to acquire a slice of real estate?\n<<<\nAnswer: because real estate is magic: it's tangible (as opposed to shared in a company), and people appear to think there is a shortage of it and therefore its value can only increase. So the sooner you buy, the richer you get. Well, that's the theory anyway.\n\n<<<\nBritons who think their Spanish villa was a sure-fire investment are about to be rudely awakened.\n<<<\n\nWell, I just hope that the south of France is next!\n
I read much concern about how our privacy is threatened by all sorts of companies, such as Google (who knows everything about your secret desires) and Facebook (who knows all of your friends' birthdays).\n\nMy biggest concern relating to all these services is externalisation, which comes at the price of loss of control over the service or your data, or both. What happens if tomorrow Facebook decides to charge you 5 euro a month for their service? Chances are there would be an uproar at first, then most users would consider that it's too small a price to pay to worry about it. Yet they'd never have joined in the first place, had the service not been free in the first place.\n\nSomething similar happened to me recently: I used Haloscan to manage comments on this blog. Haloscan was free, easy to integrate and convenient: it did everything magically, filtered spam out, provided RSS feeds for comments and so on. And then inevitably one day they ran out of resources and slashed their free offers. I no longer have comments on my blog.\n\nBlah blah.\n\nExternal services are like the dark side of the force: they are easier, faster, but ultimately not as powerful as doing things the right way, which is hosting everything for yourself. Only then do you //know// your service will surivive the stand of time. Well, as long as you pay for your ISP bill I guess.\n\nEben Moglen expressed somewhat similar thoughts (although mostly from the point of view of privacy, which is another facet to the control of your own data) in a very interesting, recent [[interview|http://www.h-online.com/open/features/Interview-Eben-Moglen-Freedom-vs-the-Cloud-Log-955421.html]].\n
The computer of Narelle's friend Fatima died a few days ago. She got pretty upset because she had all her family pictures on it, and, like most, didn't have any backups.\n\nHere is the tale of how we saved her life (there must be some white rabbit in shiny armour involved or something).\n\nAfter starting the computer under [[System Rescue|http://www.sysresccd.org/Index.fr.php]], I used dd_rescue to copy the entire disk over the network onto my computer. System Rescue doesn't start [[lockd]], so mounting NFS volumes is faster using the nolock option.\n\nI then found a little program called [[Findfile|http://linux.softpedia.com/get/System/Recovery/findfile-1433.shtml]] which goes through a raw disk dump to find series of bytes that look like a JPEG file. This returned a few photos, mostly of CD covers, which were not really useful.\n\nLooking more into it, I realised that what is usually known as JPEG is not very precise. Photo processing software usually produces files that follow a file format called JFIF, but cameras produce files in a slightly different format called EXIF, which has a different signature. So I patched Findfile to also find EXIF files (along with a couple other changes as Findfile didn't work for me out-of-the-tarball):\n\n{{{\ndiff -ur findfile-0.2.orig/error.c findfile-0.2/error.c\n--- findfile-0.2.orig/error.c 2004-03-18 18:44:35.000000000 +0100\n+++ findfile-0.2/error.c 2007-06-03 12:45:17.000000000 +0200\n@@ -14,7 +14,7 @@\n va_start(ap, format);\n (void)vfprintf(stderr, format, ap);\n va_end(ap);\n- fprintf(stderr, "errno=%d (if applicable)\sn", errno);\n+ fprintf(stderr, "errno=%d %s (if applicable)\sn", errno, strerror(errno));\n \n exit(EXIT_FAILURE);\n }\ndiff -ur findfile-0.2.orig/findjpeg.c findfile-0.2/findjpeg.c\n--- findfile-0.2.orig/findjpeg.c 2004-03-18 18:44:35.000000000 +0100\n+++ findfile-0.2/findjpeg.c 2007-06-03 23:39:11.000000000 +0200\n@@ -24,15 +24,31 @@\n if (usector[0] == 0xff &&\n usector[1] == 0xd8 &&\n usector[2] == 0xff &&\n- sector[5] == 'J' &&\n- sector[6] == 'F' &&\n- sector[7] == 'I' &&\n- sector[8] == 'F' &&\n- sector[9] == 0x00)\n+ sector[6] == 'J' &&\n+ sector[7] == 'F' &&\n+ sector[8] == 'I' &&\n+ sector[9] == 'F' &&\n+ sector[10] == 0x00)\n {\n return 0;\n }\n \n+ /* Also check for a EXIF header -- it's similar, and it's\n+ * what digital camera pass off as jpeg */\n+ if (usector[0] == 0xff &&\n+ usector[1] == 0xd8 &&\n+ usector[2] == 0xff &&\n+ usector[3] == 0xe1 &&\n+ sector[6] == 'E' &&\n+ sector[7] == 'x' &&\n+ sector[8] == 'i' &&\n+ sector[9] == 'f' &&\n+ sector[10] == 0x00)\n+ {\n+ return 0;\n+ }\n+\n+\n return -1;\n }\n \n@@ -41,13 +57,10 @@\n unsigned char *usector = (unsigned char *)sector;\n int loop;\n \n- for(loop=0; loop<length; loop++)\n+ for(loop=0; loop<length; loop+=2)\n {\n- if (usector[loop] == 0xff)\n- {\n- if (usector[++loop] == 0xd9)\n- return loop;\n- }\n+ if ((usector[loop] == 0xff) && (usector[loop+1] == 0xd9))\n+ return loop + 2;\n }\n \n return -1;\ndiff -ur findfile-0.2.orig/utils.c findfile-0.2/utils.c\n--- findfile-0.2.orig/utils.c 2004-03-18 18:44:35.000000000 +0100\n+++ findfile-0.2/utils.c 2007-06-03 13:19:23.000000000 +0200\n@@ -18,7 +18,7 @@\n \n (*index)++;\n \n- fd = open64(fname, O_WRONLY);\n+ fd = open(fname, O_WRONLY | O_CREAT, 0644);\n if (fd == -1)\n error_exit("Cannot create file %s\sn", fname);\n \n}}}\n\nAnd voilà: we were rewarded with 463 camera pictures. Fatima's life is now safe!\n\n
This morning I got to work to find my Thunderbird not working. It was telling me that it could'nt open my mailbox to write, and I should check if there was disk space available, and if I had the write rights. Thinking there was no reason the rights had changed, I started deleting stuff both in my mailbox and on my disk, as it was indeed quite full. After freeing up 900Mb, Thunderbird would still not start.\n\nSo I went to check the permissions, just in case a gnome went by during the weekend to change a few bits on my disk. Aha, I thought, the Inbox file is 2Gb big. Now, 2Gb is one of those fundamental constants we have in computer science, because it's the biggest number you can code on 31 bits. And, we have 32-bit machines at the moment, with the 32nd bit usually used for error states, so operating systems and applications tend to have trouble with files that are bigger than 2Gb. (Modern applications are written with 64 bit numbers, which pushes the limit much higher, so I guess either Thunderbird or Windows 2000 is the problem here).\n\nThat's when I noticed that deleting mails in the mailbox doesn't actually reduce the file size. Apparently, nothing reduces the file size. WTF? My colleague then helpfully suggests I use the 'Compact folders' button in the file menu. WTF is that? So apparently Thunderbird never actually erases emails until you ask it to (thrice: first, delete the e-mail, then, empty the trash can, then, compact the folder, whatever that means).\n\nNow, Thunderbird has just finished compacting, and, guess what, it's still not working: my file is still 2Gb and won't open for writing. So I copied all my e-mails to another mailbox (which adds to a whopping 11Mb: so Thunderbird has filled my disk with 2Gb of crap) and erased the Inbox file. Magic! It creates a new, clean Inbox upon the next startup, and I now have all my mail, with 2Gb free.\n\nShall I compare thee to bad design? Let me count the ways.\n# Obviously, the 2Gb limit is a programming problem that should never affect the user. Whether Thunderbird decides to split the files, use Maildir instead, is up to the programmer, but as a user I should never see it.\n# Removing e-mails should actually do something. I already have to delete it, then remove it from the trash can. Isn't that enough?\n# What's up with that folder compacting? This is a maintenance operation, which should obviously done in the background without asking the user. Besides, it doesn't appear to do anything anyway. This is as bad, or worse, as using Defrag under Windows.\n# Error reporting. The error message that Thunderbird gives in the case is just wrong.\nI guess I'll soon have to install mutt on Cygwin...\n
Apparently I'm going to save a sizable portion of my brain in MySQL. It's about time I looked at how to back up MySQL automatically.\n\nLook up tag system in Tiddly.\n
This weekend I upgraded to Debian 4.0, codenamed Etch. The process is actually easy enough that you can do most of it using drunken monkeys (trust me).\n\nThe only funnies I got were:\n\n* xterm disappearing. Well, one really shouldn't be upgrading from X, should one?\n* xfree86 disappearing. There was actually a note in the release notes to be careful about that. Just re-install xorg and you're fine.\n\n[EDIT]\n* batch no longer takes parameters.\n\nNow I'll be looking at moving services that I was running in a SID [[chroot]] to my main system.
!Options used by UploadPlugin\nUsername: <<option txtUploadUserName>>\nPassword: <<option pasUploadPassword>>\n\nUrl of the UploadService script^^(1)^^: <<option txtUploadStoreUrl 50>>\nRelative Directory where to store the file^^(2)^^: <<option txtUploadDir 50>>\nFilename of the uploaded file^^(3)^^: <<option txtUploadFilename 40>>\nDirectory to backup file on webserver^^(4)^^: <<option txtUploadBackupDir>>\n\n^^(1)^^Mandatory either in UploadOptions or in macro parameter\n^^(2)^^If empty stores in the script directory\n^^(3)^^If empty takes the actual filename\n^^(4)^^If empty existing file with same name on webserver will be overwritten\n\n<<upload>> with these options.\n\n!Upload Macro parameters\n{{{\n<<upload [storeUrl [toFilename [backupDir [uploadDir [username]]]]]>>\n Optional positional parameters can be passed to overwrite \n UploadOptions. \n}}}\n\n
/***\n|''Name:''|UploadPlugin|\n|''Description:''|Save to web a TiddlyWiki|\n|''Version:''|3.4.5|\n|''Date:''|Oct 15, 2006|\n|''Source:''|http://tiddlywiki.bidix.info/#UploadPlugin|\n|''Documentation:''|http://tiddlywiki.bidix.info/#UploadDoc|\n|''Author:''|BidiX (BidiX (at) bidix (dot) info)|\n|''License:''|[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D ]]|\n|''~CoreVersion:''|2.0.0|\n|''Browser:''|Firefox 1.5; InternetExplorer 6.0; Safari|\n|''Include:''|config.lib.file; config.lib.log; config.lib.options; PasswordTweak|\n|''Require:''|[[UploadService|http://tiddlywiki.bidix.info/#UploadService]]|\n***/\n//{{{\nversion.extensions.UploadPlugin = {\n major: 3, minor: 4, revision: 5, \n date: new Date(2006,9,15),\n source: 'http://tiddlywiki.bidix.info/#UploadPlugin',\n documentation: 'http://tiddlywiki.bidix.info/#UploadDoc',\n author: 'BidiX (BidiX (at) bidix (dot) info',\n license: '[[BSD open source license|http://tiddlywiki.bidix.info/#%5B%5BBSD%20open%20source%20license%5D%5D]]',\n coreVersion: '2.0.0',\n browser: 'Firefox 1.5; InternetExplorer 6.0; Safari'\n};\n//}}}\n\n////+++!![config.lib.file]\n\n//{{{\nif (!config.lib) config.lib = {};\nif (!config.lib.file) config.lib.file= {\n author: 'BidiX',\n version: {major: 0, minor: 1, revision: 0}, \n date: new Date(2006,3,9)\n};\nconfig.lib.file.dirname = function (filePath) {\n var lastpos;\n if ((lastpos = filePath.lastIndexOf("/")) != -1) {\n return filePath.substring(0, lastpos);\n } else {\n return filePath.substring(0, filePath.lastIndexOf("\s\s"));\n }\n};\nconfig.lib.file.basename = function (filePath) {\n var lastpos;\n if ((lastpos = filePath.lastIndexOf("#")) != -1) \n filePath = filePath.substring(0, lastpos);\n if ((lastpos = filePath.lastIndexOf("/")) != -1) {\n return filePath.substring(lastpos + 1);\n } else\n return filePath.substring(filePath.lastIndexOf("\s\s")+1);\n};\nwindow.basename = function() {return "@@deprecated@@";};\n//}}}\n////===\n\n////+++!![config.lib.log]\n\n//{{{\nif (!config.lib) config.lib = {};\nif (!config.lib.log) config.lib.log= {\n author: 'BidiX',\n version: {major: 0, minor: 1, revision: 1}, \n date: new Date(2006,8,19)\n};\nconfig.lib.Log = function(tiddlerTitle, logHeader) {\n if (version.major < 2)\n this.tiddler = store.tiddlers[tiddlerTitle];\n else\n this.tiddler = store.getTiddler(tiddlerTitle);\n if (!this.tiddler) {\n this.tiddler = new Tiddler();\n this.tiddler.title = tiddlerTitle;\n this.tiddler.text = "| !date | !user | !location |" + logHeader;\n this.tiddler.created = new Date();\n this.tiddler.modifier = config.options.txtUserName;\n this.tiddler.modified = new Date();\n if (version.major < 2)\n store.tiddlers[tiddlerTitle] = this.tiddler;\n else\n store.addTiddler(this.tiddler);\n }\n return this;\n};\n\nconfig.lib.Log.prototype.newLine = function (line) {\n var now = new Date();\n var newText = "| ";\n newText += now.getDate()+"/"+(now.getMonth()+1)+"/"+now.getFullYear() + " ";\n newText += now.getHours()+":"+now.getMinutes()+":"+now.getSeconds()+" | ";\n newText += config.options.txtUserName + " | ";\n var location = document.location.toString();\n var filename = config.lib.file.basename(location);\n if (!filename) filename = '/';\n newText += "[["+filename+"|"+location + "]] |";\n this.tiddler.text = this.tiddler.text + "\sn" + newText;\n this.addToLine(line);\n};\n\nconfig.lib.Log.prototype.addToLine = function (text) {\n this.tiddler.text = this.tiddler.text + text;\n this.tiddler.modifier = config.options.txtUserName;\n this.tiddler.modified = new Date();\n if (version.major < 2)\n store.tiddlers[this.tiddler.tittle] = this.tiddler;\n else {\n store.addTiddler(this.tiddler);\n story.refreshTiddler(this.tiddler.title);\n store.notify(this.tiddler.title, true);\n }\n if (version.major < 2)\n store.notifyAll(); \n};\n//}}}\n////===\n\n////+++!![config.lib.options]\n\n//{{{\nif (!config.lib) config.lib = {};\nif (!config.lib.options) config.lib.options = {\n author: 'BidiX',\n version: {major: 0, minor: 1, revision: 0}, \n date: new Date(2006,3,9)\n};\n\nconfig.lib.options.init = function (name, defaultValue) {\n if (!config.options[name]) {\n config.options[name] = defaultValue;\n saveOptionCookie(name);\n }\n};\n//}}}\n////===\n\n////+++!![PasswordTweak]\n\n//{{{\nversion.extensions.PasswordTweak = {\n major: 1, minor: 0, revision: 3, date: new Date(2006,8,30),\n type: 'tweak',\n source: 'http://tiddlywiki.bidix.info/#PasswordTweak'\n};\n//}}}\n/***\n!!config.macros.option\n***/\n//{{{\nconfig.macros.option.passwordCheckboxLabel = "Save this password on this computer";\nconfig.macros.option.passwordType = "password"; // password | text\n\nconfig.macros.option.onChangeOption = function(e)\n{\n var opt = this.getAttribute("option");\n var elementType,valueField;\n if(opt) {\n switch(opt.substr(0,3)) {\n case "txt":\n elementType = "input";\n valueField = "value";\n break;\n case "pas":\n elementType = "input";\n valueField = "value";\n break;\n case "chk":\n elementType = "input";\n valueField = "checked";\n break;\n }\n config.options[opt] = this[valueField];\n saveOptionCookie(opt);\n var nodes = document.getElementsByTagName(elementType);\n for(var t=0; t<nodes.length; t++) \n {\n var optNode = nodes[t].getAttribute("option");\n if (opt == optNode) \n nodes[t][valueField] = this[valueField];\n }\n }\n return(true);\n};\n\nconfig.macros.option.handler = function(place,macroName,params)\n{\n var opt = params[0];\n if(config.options[opt] === undefined) {\n return;}\n var c;\n switch(opt.substr(0,3)) {\n case "txt":\n c = document.createElement("input");\n c.onkeyup = this.onChangeOption;\n c.setAttribute ("option",opt);\n c.className = "txtOptionInput "+opt;\n place.appendChild(c);\n c.value = config.options[opt];\n break;\n case "pas":\n // input password\n c = document.createElement ("input");\n c.setAttribute("type",config.macros.option.passwordType);\n c.onkeyup = this.onChangeOption;\n c.setAttribute("option",opt);\n c.className = "pasOptionInput "+opt;\n place.appendChild(c);\n c.value = config.options[opt];\n // checkbox link with this password "save this password on this computer"\n c = document.createElement("input");\n c.setAttribute("type","checkbox");\n c.onclick = this.onChangeOption;\n c.setAttribute("option","chk"+opt);\n c.className = "chkOptionInput "+opt;\n place.appendChild(c);\n c.checked = config.options["chk"+opt];\n // text savePasswordCheckboxLabel\n place.appendChild(document.createTextNode(config.macros.option.passwordCheckboxLabel));\n break;\n case "chk":\n c = document.createElement("input");\n c.setAttribute("type","checkbox");\n c.onclick = this.onChangeOption;\n c.setAttribute("option",opt);\n c.className = "chkOptionInput "+opt;\n place.appendChild(c);\n c.checked = config.options[opt];\n break;\n }\n};\n//}}}\n/***\n!! Option cookie stuff\n***/\n//{{{\nwindow.loadOptionsCookie_orig_PasswordTweak = window.loadOptionsCookie;\nwindow.loadOptionsCookie = function()\n{\n var cookies = document.cookie.split(";");\n for(var c=0; c<cookies.length; c++) {\n var p = cookies[c].indexOf("=");\n if(p != -1) {\n var name = cookies[c].substr(0,p).trim();\n var value = cookies[c].substr(p+1).trim();\n switch(name.substr(0,3)) {\n case "txt":\n config.options[name] = unescape(value);\n break;\n case "pas":\n config.options[name] = unescape(value);\n break;\n case "chk":\n config.options[name] = value == "true";\n break;\n }\n }\n }\n};\n\nwindow.saveOptionCookie_orig_PasswordTweak = window.saveOptionCookie;\nwindow.saveOptionCookie = function(name)\n{\n var c = name + "=";\n switch(name.substr(0,3)) {\n case "txt":\n c += escape(config.options[name].toString());\n break;\n case "chk":\n c += config.options[name] ? "true" : "false";\n // is there an option link with this chk ?\n if (config.options[name.substr(3)]) {\n saveOptionCookie(name.substr(3));\n }\n break;\n case "pas":\n if (config.options["chk"+name]) {\n c += escape(config.options[name].toString());\n } else {\n c += "";\n }\n break;\n }\n c += "; expires=Fri, 1 Jan 2038 12:00:00 UTC; path=/";\n document.cookie = c;\n};\n//}}}\n/***\n!! Initializations\n***/\n//{{{\n// define config.options.pasPassword\nif (!config.options.pasPassword) {\n config.options.pasPassword = 'defaultPassword';\n window.saveOptionCookie('pasPassword');\n}\n// since loadCookies is first called befor password definition\n// we need to reload cookies\nwindow.loadOptionsCookie();\n//}}}\n////===\n\n////+++!![config.macros.upload]\n\n//{{{\nconfig.macros.upload = {\n accessKey: "U",\n formName: "UploadPlugin",\n contentType: "text/html;charset=UTF-8",\n defaultStoreScript: "store.php"\n};\n\n// only this two configs need to be translated\nconfig.macros.upload.messages = {\n aboutToUpload: "About to upload TiddlyWiki to %0",\n backupFileStored: "Previous file backuped in %0",\n crossDomain: "Certainly a cross-domain isue: access to an other site isn't allowed",\n errorDownloading: "Error downloading",\n errorUploadingContent: "Error uploading content",\n fileLocked: "Files is locked: You are not allowed to Upload",\n fileNotFound: "file to upload not found",\n fileNotUploaded: "File %0 NOT uploaded",\n mainFileUploaded: "Main TiddlyWiki file uploaded to %0",\n passwordEmpty: "Unable to upload, your password is empty",\n urlParamMissing: "url param missing",\n rssFileNotUploaded: "RssFile %0 NOT uploaded",\n rssFileUploaded: "Rss File uploaded to %0"\n};\n\nconfig.macros.upload.label = {\n promptOption: "Save and Upload this TiddlyWiki with UploadOptions",\n promptParamMacro: "Save and Upload this TiddlyWiki in %0",\n saveLabel: "save to web", \n saveToDisk: "save to disk",\n uploadLabel: "upload" \n};\n\nconfig.macros.upload.handler = function(place,macroName,params){\n // parameters initialization\n var storeUrl = params[0];\n var toFilename = params[1];\n var backupDir = params[2];\n var uploadDir = params[3];\n var username = params[4];\n var password; // for security reason no password as macro parameter\n var label;\n if (document.location.toString().substr(0,4) == "http")\n label = this.label.saveLabel;\n else\n label = this.label.uploadLabel;\n var prompt;\n if (storeUrl) {\n prompt = this.label.promptParamMacro.toString().format([this.toDirUrl(storeUrl, uploadDir, username)]);\n }\n else {\n prompt = this.label.promptOption;\n }\n createTiddlyButton(place, label, prompt, \n function () {\n config.macros.upload.upload(storeUrl, toFilename, uploadDir, backupDir, username, password); \n return false;}, \n null, null, this.accessKey);\n};\nconfig.macros.upload.UploadLog = function() {\n return new config.lib.Log('UploadLog', " !storeUrl | !uploadDir | !toFilename | !backupdir | !origin |" );\n};\nconfig.macros.upload.UploadLog.prototype = config.lib.Log.prototype;\nconfig.macros.upload.UploadLog.prototype.startUpload = function(storeUrl, toFilename, uploadDir, backupDir) {\n var line = " [[" + config.lib.file.basename(storeUrl) + "|" + storeUrl + "]] | ";\n line += uploadDir + " | " + toFilename + " | " + backupDir + " |";\n this.newLine(line);\n};\nconfig.macros.upload.UploadLog.prototype.endUpload = function() {\n this.addToLine(" Ok |");\n};\nconfig.macros.upload.basename = config.lib.file.basename;\nconfig.macros.upload.dirname = config.lib.file.dirname;\nconfig.macros.upload.toRootUrl = function (storeUrl, username)\n{\n return root = (this.dirname(storeUrl)?this.dirname(storeUrl):this.dirname(document.location.toString()));\n}\nconfig.macros.upload.toDirUrl = function (storeUrl, uploadDir, username)\n{\n var root = this.toRootUrl(storeUrl, username);\n if (uploadDir && uploadDir != '.')\n root = root + '/' + uploadDir;\n return root;\n}\nconfig.macros.upload.toFileUrl = function (storeUrl, toFilename, uploadDir, username)\n{\n return this.toDirUrl(storeUrl, uploadDir, username) + '/' + toFilename;\n}\nconfig.macros.upload.upload = function(storeUrl, toFilename, uploadDir, backupDir, username, password)\n{\n // parameters initialization\n storeUrl = (storeUrl ? storeUrl : config.options.txtUploadStoreUrl);\n toFilename = (toFilename ? toFilename : config.options.txtUploadFilename);\n backupDir = (backupDir ? backupDir : config.options.txtUploadBackupDir);\n uploadDir = (uploadDir ? uploadDir : config.options.txtUploadDir);\n username = (username ? username : config.options.txtUploadUserName);\n password = config.options.pasUploadPassword; // for security reason no password as macro parameter\n if (!password || password === '') {\n alert(config.macros.upload.messages.passwordEmpty);\n return;\n }\n if (storeUrl === '') {\n storeUrl = config.macros.upload.defaultStoreScript;\n }\n if (config.lib.file.dirname(storeUrl) === '') {\n storeUrl = config.lib.file.dirname(document.location.toString())+'/'+storeUrl;\n }\n if (toFilename === '') {\n toFilename = config.lib.file.basename(document.location.toString());\n }\n\n clearMessage();\n // only for forcing the message to display\n if (version.major < 2)\n store.notifyAll();\n if (!storeUrl) {\n alert(config.macros.upload.messages.urlParamMissing);\n return;\n }\n // Check that file is not locked\n if (window.BidiX && BidiX.GroupAuthoring && BidiX.GroupAuthoring.lock) {\n if (BidiX.GroupAuthoring.lock.isLocked() && !BidiX.GroupAuthoring.lock.isMyLock()) {\n alert(config.macros.upload.messages.fileLocked);\n return;\n }\n }\n \n var log = new this.UploadLog();\n log.startUpload(storeUrl, toFilename, uploadDir, backupDir);\n if (document.location.toString().substr(0,5) == "file:") {\n saveChanges();\n }\n var toDir = config.macros.upload.toDirUrl(storeUrl, toFilename, uploadDir, username);\n displayMessage(config.macros.upload.messages.aboutToUpload.format([toDir]), toDir);\n this.uploadChanges(storeUrl, toFilename, uploadDir, backupDir, username, password);\n if(config.options.chkGenerateAnRssFeed) {\n //var rssContent = convertUnicodeToUTF8(generateRss());\n var rssContent = generateRss();\n var rssPath = toFilename.substr(0,toFilename.lastIndexOf(".")) + ".xml";\n this.uploadContent(rssContent, storeUrl, rssPath, uploadDir, '', username, password, \n function (responseText) {\n if (responseText.substring(0,1) != '0') {\n displayMessage(config.macros.upload.messages.rssFileNotUploaded.format([rssPath]));\n }\n else {\n var toFileUrl = config.macros.upload.toFileUrl(storeUrl, rssPath, uploadDir, username);\n displayMessage(config.macros.upload.messages.rssFileUploaded.format(\n [toFileUrl]), toFileUrl);\n }\n // for debugging store.php uncomment last line\n //DEBUG alert(responseText);\n });\n }\n return;\n};\n\nconfig.macros.upload.uploadChanges = function(storeUrl, toFilename, uploadDir, backupDir, \n username, password) {\n var original;\n if (document.location.toString().substr(0,4) == "http") {\n original = this.download(storeUrl, toFilename, uploadDir, backupDir, username, password);\n return;\n }\n else {\n // standard way : Local file\n \n original = loadFile(getLocalPath(document.location.toString()));\n if(window.Components) {\n // it's a mozilla browser\n try {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n var converter = Components.classes["@mozilla.org/intl/scriptableunicodeconverter"]\n .createInstance(Components.interfaces.nsIScriptableUnicodeConverter);\n converter.charset = "UTF-8";\n original = converter.ConvertToUnicode(original);\n }\n catch(e) {\n }\n }\n }\n //DEBUG alert(original);\n this.uploadChangesFrom(original, storeUrl, toFilename, uploadDir, backupDir, \n username, password);\n};\n\nconfig.macros.upload.uploadChangesFrom = function(original, storeUrl, toFilename, uploadDir, backupDir, \n username, password) {\n var startSaveArea = '<div id="' + 'storeArea">'; // Split up into two so that indexOf() of this source doesn't find it\n var endSaveArea = '</d' + 'iv>';\n // Locate the storeArea div's\n var posOpeningDiv = original.indexOf(startSaveArea);\n var posClosingDiv = original.lastIndexOf(endSaveArea);\n if((posOpeningDiv == -1) || (posClosingDiv == -1))\n {\n alert(config.messages.invalidFileError.format([document.location.toString()]));\n return;\n }\n var revised = original.substr(0,posOpeningDiv + startSaveArea.length) + \n allTiddlersAsHtml() + "\sn\st\st" +\n original.substr(posClosingDiv);\n var newSiteTitle;\n if(version.major < 2){\n newSiteTitle = (getElementText("siteTitle") + " - " + getElementText("siteSubtitle")).htmlEncode();\n } else {\n newSiteTitle = (wikifyPlain ("SiteTitle") + " - " + wikifyPlain ("SiteSubtitle")).htmlEncode();\n }\n\n revised = revised.replaceChunk("<title"+">","</title"+">"," " + newSiteTitle + " ");\n revised = revised.replaceChunk("<!--PRE-HEAD-START--"+">","<!--PRE-HEAD-END--"+">","\sn" + store.getTiddlerText("MarkupPreHead","") + "\sn");\n revised = revised.replaceChunk("<!--POST-HEAD-START--"+">","<!--POST-HEAD-END--"+">","\sn" + store.getTiddlerText("MarkupPostHead","") + "\sn");\n revised = revised.replaceChunk("<!--PRE-BODY-START--"+">","<!--PRE-BODY-END--"+">","\sn" + store.getTiddlerText("MarkupPreBody","") + "\sn");\n revised = revised.replaceChunk("<!--POST-BODY-START--"+">","<!--POST-BODY-END--"+">","\sn" + store.getTiddlerText("MarkupPostBody","") + "\sn");\n\n var response = this.uploadContent(revised, storeUrl, toFilename, uploadDir, backupDir, \n username, password, function (responseText) {\n if (responseText.substring(0,1) != '0') {\n alert(responseText);\n displayMessage(config.macros.upload.messages.fileNotUploaded.format([getLocalPath(document.location.toString())]));\n }\n else {\n if (uploadDir !== '') {\n toFilename = uploadDir + "/" + config.macros.upload.basename(toFilename);\n } else {\n toFilename = config.macros.upload.basename(toFilename);\n }\n var toFileUrl = config.macros.upload.toFileUrl(storeUrl, toFilename, uploadDir, username);\n if (responseText.indexOf("destfile:") > 0) {\n var destfile = responseText.substring(responseText.indexOf("destfile:")+9, \n responseText.indexOf("\sn", responseText.indexOf("destfile:")));\n toFileUrl = config.macros.upload.toRootUrl(storeUrl, username) + '/' + destfile;\n }\n else {\n toFileUrl = config.macros.upload.toFileUrl(storeUrl, toFilename, uploadDir, username);\n }\n displayMessage(config.macros.upload.messages.mainFileUploaded.format(\n [toFileUrl]), toFileUrl);\n if (backupDir && responseText.indexOf("backupfile:") > 0) {\n var backupFile = responseText.substring(responseText.indexOf("backupfile:")+11, \n responseText.indexOf("\sn", responseText.indexOf("backupfile:")));\n toBackupUrl = config.macros.upload.toRootUrl(storeUrl, username) + '/' + backupFile;\n displayMessage(config.macros.upload.messages.backupFileStored.format(\n [toBackupUrl]), toBackupUrl);\n }\n var log = new config.macros.upload.UploadLog();\n log.endUpload();\n store.setDirty(false);\n // erase local lock\n if (window.BidiX && BidiX.GroupAuthoring && BidiX.GroupAuthoring.lock) {\n BidiX.GroupAuthoring.lock.eraseLock();\n // change mtime with new mtime after upload\n var mtime = responseText.substr(responseText.indexOf("mtime:")+6);\n BidiX.GroupAuthoring.lock.mtime = mtime;\n }\n \n \n }\n // for debugging store.php uncomment last line\n //DEBUG alert(responseText);\n }\n );\n};\n\nconfig.macros.upload.uploadContent = function(content, storeUrl, toFilename, uploadDir, backupDir, \n username, password, callbackFn) {\n var boundary = "---------------------------"+"AaB03x"; \n var request;\n try {\n request = new XMLHttpRequest();\n } \n catch (e) { \n request = new ActiveXObject("Msxml2.XMLHTTP"); \n }\n if (window.netscape){\n try {\n if (document.location.toString().substr(0,4) != "http") {\n netscape.security.PrivilegeManager.enablePrivilege('UniversalBrowserRead');}\n }\n catch (e) {}\n } \n //DEBUG alert("user["+config.options.txtUploadUserName+"] password[" + config.options.pasUploadPassword + "]");\n // compose headers data\n var sheader = "";\n sheader += "--" + boundary + "\sr\snContent-disposition: form-data; name=\s"";\n sheader += config.macros.upload.formName +"\s"\sr\sn\sr\sn";\n sheader += "backupDir="+backupDir\n +";user=" + username \n +";password=" + password\n +";uploaddir=" + uploadDir;\n // add lock attributes to sheader\n if (window.BidiX && BidiX.GroupAuthoring && BidiX.GroupAuthoring.lock) {\n var l = BidiX.GroupAuthoring.lock.myLock;\n sheader += ";lockuser=" + l.user\n + ";mtime=" + l.mtime\n + ";locktime=" + l.locktime;\n }\n sheader += ";;\sr\sn"; \n sheader += "\sr\sn" + "--" + boundary + "\sr\sn";\n sheader += "Content-disposition: form-data; name=\s"userfile\s"; filename=\s""+toFilename+"\s"\sr\sn";\n sheader += "Content-Type: " + config.macros.upload.contentType + "\sr\sn";\n sheader += "Content-Length: " + content.length + "\sr\sn\sr\sn";\n // compose trailer data\n var strailer = new String();\n strailer = "\sr\sn--" + boundary + "--\sr\sn";\n //strailer = "--" + boundary + "--\sr\sn";\n var data;\n data = sheader + content + strailer;\n //request.open("POST", storeUrl, true, username, password);\n try {\n request.open("POST", storeUrl, true); \n }\n catch(e) {\n alert(config.macros.upload.messages.crossDomain + "\snError:" +e);\n exit;\n }\n request.onreadystatechange = function () {\n if (request.readyState == 4) {\n if (request.status == 200)\n callbackFn(request.responseText);\n else\n alert(config.macros.upload.messages.errorUploadingContent + "\snStatus: "+request.status.statusText);\n }\n };\n request.setRequestHeader("Content-Length",data.length);\n request.setRequestHeader("Content-Type","multipart/form-data; boundary="+boundary);\n request.send(data); \n};\n\n\nconfig.macros.upload.download = function(uploadUrl, uploadToFilename, uploadDir, uploadBackupDir, \n username, password) {\n var request;\n try {\n request = new XMLHttpRequest();\n } \n catch (e) { \n request = new ActiveXObject("Msxml2.XMLHTTP"); \n }\n try {\n if (uploadUrl.substr(0,4) == "http") {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");\n }\n else {\n netscape.security.PrivilegeManager.enablePrivilege("UniversalXPConnect");\n }\n } catch (e) { }\n //request.open("GET", document.location.toString(), true, username, password);\n try {\n request.open("GET", document.location.toString(), true);\n }\n catch(e) {\n alert(config.macros.upload.messages.crossDomain + "\snError:" +e);\n exit;\n }\n \n request.onreadystatechange = function () {\n if (request.readyState == 4) {\n if(request.status == 200) {\n config.macros.upload.uploadChangesFrom(request.responseText, uploadUrl, \n uploadToFilename, uploadDir, uploadBackupDir, username, password);\n }\n else\n alert(config.macros.upload.messages.errorDownloading.format(\n [document.location.toString()]) + "\snStatus: "+request.status.statusText);\n }\n };\n request.send(null);\n};\n\n//}}}\n////===\n\n////+++!![Initializations]\n\n//{{{\nconfig.lib.options.init('txtUploadStoreUrl','store.php');\nconfig.lib.options.init('txtUploadFilename','');\nconfig.lib.options.init('txtUploadDir','');\nconfig.lib.options.init('txtUploadBackupDir','');\nconfig.lib.options.init('txtUploadUserName',config.options.txtUserName);\nconfig.lib.options.init('pasUploadPassword','');\nsetStylesheet(\n ".pasOptionInput {width: 11em;}\sn"+\n ".txtOptionInput.txtUploadStoreUrl {width: 25em;}\sn"+\n ".txtOptionInput.txtUploadFilename {width: 25em;}\sn"+\n ".txtOptionInput.txtUploadDir {width: 25em;}\sn"+\n ".txtOptionInput.txtUploadBackupDir {width: 25em;}\sn"+\n "",\n "UploadOptionsStyles");\nif (document.location.toString().substr(0,4) == "http") {\n config.options.chkAutoSave = false; \n saveOptionCookie('chkAutoSave');\n}\nconfig.shadowTiddlers.UploadDoc = "[[Full Documentation|http://tiddlywiki.bidix.info/l#UploadDoc ]]\sn"; \n\n//}}}\n////===\n\n////+++!![Core Hijacking]\n\n//{{{\nconfig.macros.saveChanges.label_orig_UploadPlugin = config.macros.saveChanges.label;\nconfig.macros.saveChanges.label = config.macros.upload.label.saveToDisk;\n\nconfig.macros.saveChanges.handler_orig_UploadPlugin = config.macros.saveChanges.handler;\n\nconfig.macros.saveChanges.handler = function(place)\n{\n if ((!readOnly) && (document.location.toString().substr(0,4) != "http"))\n createTiddlyButton(place,this.label,this.prompt,this.onClick,null,null,this.accessKey);\n};\n\n//}}}\n////===\n
!Goal\nI finally got around to digging a VP882 I have. The VP882 was IndigoVision's most powerful MPEG4 codec at the time I left in 2005. Today I want to use it for the following purposes:\n* My disc server is hidden in a room where it can be as noisy as it likes to be. I want the silent VP882 to be able to access my MP3/OGG collection and play it in the lounge. Bonus points for getting a nice interface like that of mpd.\n* Connect a camera to the VP882 and do at least picture capture, at best video streaming, probably using VLC, to have a cat-checking Web cam type thing. \n* Run all the servers from the VP882 so no-one can attack me using x86-based exploits. Ok that's not possible, the VP882 won't be enough to serve anything more than plain files.\nUnfortunately I won't be able to use the MPEG4 encode hardware, as I'd have to speak VBTP or something for that to work, and those protocols are Indigo property. Oh well.\n\n!Strategy\nWe'll install a full Debian on the x86 disc server, then the VP882 will chroot into it. We'll use mpd on the vp882, and phpmp on the file server, pointing to the vp882, saving our having a Web server there.\n\n\n!Recipe\n!!Installing Debian\nI gave up my previous method of using debootstrap: debootstrap's problem is that it doesn't work to build a system for a different architecture (e.g. ARM on a x86), and trying to run it directly from the VP882 won't work because it's missing some functions (e.g. printf), which I can't compile without a cross-gcc which I'd really prefer not to have to build.\n\nLuckily, a long time ago, installing Debian was dumber and simpler: Potato has a simple tarball called [[base2_2.tgz|http://archive.debian.org/debian-archive/dists/potato/main/disks-arm/current/base2_2.tgz]] which should correspond to what debootstrap would download.\n\nUntar that somewhere (as root, so device files get created correctly). Mount it from the VP882 (with {{{rw,hard,intr,nolock}}} as usual, or you'll wait forever). At best create a new NFS export for that directory and add {{{no_root_squash}}}, so that the VP882 has full access to its root file system. Chroot. Done. Careful: {{{no_root_squash}}} only works if you mount the exact export.\n\nE.g.:\n{{{\n# Stop the VideoBridge applications so we can access\n# /dev/dsp\n/etc/init.d/vbapp stop\n\nmkdir /tmp/rfs\nmount -o rw,hard,intr,nolock 192.168.0.250:/home/shared/arm/debianrfs /tmp/rfs\n\n# Before chrooting, insmod the loopback interface (for swap\n# over NFS)\ninsmod /tmp/rfs/lib/modules/loop.o\n\nchroot /tmp/rfs\n\n# Setup swap\nlosetup /dev/loop0 /tmp/swap\nswapon /dev/loop0\n}}}\n\nIt seems to be vitally important to put at least / and /proc in /etc/fstab, something like:\n{{{\n192.168.0.250:/home/shared/arm/debianrfs / nfs defaults 0 0\nproc /proc proc defaults 0 0\n}}}\nand even more important is to fix an old APT problem by adding to /etc/apt/apt.conf:\n{{{\nAPT::Cache-Limit "10000000";\n}}}\n\nUpgrade to more recent versions have to be done step by step: potato, woody, sarge, etch. Otherwise, it'll blow up. Be prepared for various problems as the upgrade goes, as the configuration isn't at all standard. At some point APT asked to remove essential packages, which it then complained weren't present anymore. You'll find the old versions of Debian on the Debian Archive site http://www.debian.org/distrib/archive. Old version aren't mirrored, so downloading will take a while as it must come from the mothership.\n\nLast touches :\n* Set {{{/etc/resolv.conf}}} to something that makes sense.\n* Update /etc/apt/sources.list (only upgrade one version at a time -- don't go jumping from Potato to Etch, will you?)\n* Create some swap (on NFS -- this is good):\n{{{\ndd if=/dev/zero of=/tmp/swap\nmkswap /tmp/swap\n}}}\n*Setup /etc/fstab:\n{{{\nproc /proc proc defaults 0 0\n192.168.0.250:/home /home nfs rw,intr,nolock 0 0\n}}}\n(That's an example only -- I like to have my homes shared).\n\n!Building Mpd\nThe Xscale processor has no floating point unit. This means all the pre-compiled audio software in Debian is essentially useless. We'll need to rebuild the software we want to use against integer-only libraries: libmad for MP3, and Tremor for Ogg.\n!!Install libmad\n{{{\naptitude install libmad0-dev\n}}}\n(You can also install madplay to test things out)\n\n!!Building tremor\nTremor isn't part of Debian at all so we need to build it from scratch.\n\n(Done that, didn't document it. Doh. Install it to /usr/local).\n\n!!Other dependencies\nWe don't have, nor want, ALSA support. Luckily mpd also supports libao which is fine for our purpose. OSS support may be enough, too (I coded the VP882 audio driver -- we didn't go for ALSA at the time because it was both too complicated and basically entirely undocumented. A recent look suggests it's not changed much.) \n\n{{{\naptitude install libao-dev\n}}}\n\n!!Building mpd\nWe'll build it light for now. We disable everything we don't have nor want, and tell where tremor is.\n{{{\napt-get source mpd\n./configure --enable-ao --disable-alsa --disable-shout --disable-sun --disable-pulse --with-tremor=/usr/local --with-mad\nmake\nsudo make install\n}}}\n\nMeanwhile we install phpmp and make it point to the vp882.\n\nA good trick is to install Debian's mpd, that way you get all the daemon infrastructure installed for you. Just edit {{{/etc/init.d/mpd}}} and {{{/etc/mpd.conf}}} accordingly: You'll need to change the bind_to_address setting so the file server can connect to mpd, and run {{{/usr/local/bin/mpd}}} instead of {{{/usr/bin/mpd}}}. \n\nIndexing the MP3's takes a //long// time, as the files are accessed through NFS. And then, it all works! We can now access Phpmp through the Apache server on the file server, which connects to the mpd running on the VP882, which in turns accesses the MP3 files through NFS on the file server.\n\nWe now have a fan-less music listening experience in the lounge!\n\nLeft as an exercise to the reader is writing a small script that does all the chroot setup and runs mpd upon startup.\n
<div class='toolbar' macro='toolbar -closeTiddler closeOthers +editTiddler permalink references jump'></div>\n<div class='title' macro='view title'></div>\n<div class='subtitle'><span macro='view modifier link'></span>, <span macro='view modified date [[DD MMM YYYY]]'></span> (created <span macro='view created date [[DD MMM YYYY]]'></span>)\n<div class='tagging' macro='tagging'></div>\n<div class='tagged' macro='tags'></div>\n<div class='viewer' macro='view text wikified'></div>\n<span class='comments' macro='omni'></span>\n</div>\n\n<div class='tagClear'></div>
One problem with TiddlyWiki is that it's all JavaScript. That is, the content is also embedded in JavaScript strings, which are then rendered to HTML by JavaScript contained in the wiki itself.\n\nTypically, this sort of content never gets parsed by Google, because Google just parses HTML (and PDF and a few other static content formats). And that's fair enough: we can't expect Google to execute our JavaScript to find out our content. However, this means that a Tiddly-based site just doesn't get indexed. If I do searches on my own blog, I'll find posts on my old blog (because Nanoblog actually only uses static pages -- it's good about that) and none on my new blog. This sucks.\n\nOf course I'm not the first one to enjoy Tiddly's flexibility and general sexiness. And of course I'm not the first one to wish my site would be indexed by Google. Among the several solutions that have been thought of by people, [[this one|http://www.superphysique.net/#%5B%5BSEO%20TiddlyWiki%20Plugin%5D%5D]] appeared the best to me: it actually creates a static, HTML-rendered replica of the wiki, one tiddler per page, with the static pages that redirect to the appropriate section of the wiki. This means Google happily indexes the static pages, and users going to the indexed pages end up on the wiki. All is well.\n\nBut for one problem: I was using ccTiddly, which is based on PHP and MySQL to provide for editing of the content over the Internet. I wasn't mad about that, and now it actually gets in my way: the afore mentioned plug-in won't work with that setup. Darn.\n\nSo I've back-pedalled to a somewhat more primitive, but I think more flexible and satisfying, solution: set up a WebDAV service on my Apache server, turn my wiki back into a single, normal TiddlyWiki file, and use the [[Save to DAV|http://peter.suschlik.de/wiki/#SaveChangesToDAV]] plug-in.\n\nI now have a 'reading' URL (http://www.rutschle.net/wiki/), a secure 'editing' URL (https://www.rutschle.net/dav/) and static files under the reading URL.\n\nIt all seems to be working now. I hope I haven't messed up the RSS feeds. There's been only one serious bug, in the Save to DAV plug-in: I had to explicitly add the txtDAVURL variable to the config.options table, in the source.\n\nOn the negative side, I think I lose the ability to generate the RSS when not at my computer (i.e. I need to open the file as 'file:///'), and I think the static generation only works locally as well. I can live with that. \n\nOn the positive side, I now have a normal, self-contained TiddlyWiki file, which should make integration of plug-ins more straightforward. \n\nEDIT: After setting this up, I went to the office and was disappointed to see that the 'save to dav' macro had disappeared. Turns out there is a checkbox in the AdvancedOptions to //Hide Editing Features when viewed over HTTP//, which is all well to not confuse the casual reader, but just gets in my way when using DAV. I'm a bit surprised this wasn't mentionned in the save-to-dav plug-in. Oh well. Anyway, this is posted from the office, so there.\n
A few months ago I started looking at the whole XML and friend technologies for my Goat project. I discovered that XML does not make a good database contained for anything but the most trivial things -- on the other hand, Perl's Data::Dumper is quite good at the job.\n\nAnd even if it were: what's the point of XSLT?\n\nIn case you haven't heard of it, XSLT is a Transformation Language: it's a specific-purpose programming language that's designed to take XML data, and turn it into something else. One typical example is to turn an XML document into an HTML representation of it, which can be viewed in a browser.\n\nAt first, one thing I found interesting about storing your data as XML, is that with the appropriate XSLT it's very simple to see the state of the application: you get a 'viewer' for free, so to speak.\n\nThing is, if your data is stored as XML, then you must have a set of functions to load it, parse it and turn it into data that's usable by your application (arrays and structs for C programmers, lists for Lisp programmers, and so on). That's code you can't avoid having, even if you can avoid writing it (there are plenty of XML parsing libraries around).\n\nSo I have XML data, and a library to read it in my favourite language. What do I need XSLT for? I can just output the HTML, or whatever else I would produce with XSLT, directly with my general-purpose language.\n\nI wrote a Perl filter to output the status of the application in HTML yesterday, which I was using XSLT for before. Turns out the Perl program is almost the same size as the XSLT program (50 lines in Perl, 53 lines in XSLT -- I am talking about 'fair' lines here, not obfuscated stuff).\n\nSo, what would I learn XSLT for? If a specific-purpose language isn't better than a generic language at its own task, I would tend to think it has no purpose at all.
WhiteRabbit is the author of this wiki. You should follow the WhiteRabbit.
Ok, after a recent problem on Narelle's computer that suddenly exhibited signs of madness due to the [[Windows XP Recovery|http://www.bleepingcomputer.com/virus-removal/remove-windows-xp-recovery]] virus, I thought it was about time I installed a proper backup system for it.\n\nMy basic requirements for a backup system are:\n* Must work automatically (because users always forget to backup, or will "do it a little later).\n* Must work over the network (because there is no point doing the backup in the same computer, and saving to discs and both inconvenient (see point 1) and expensive).\n* Should be based on //rsync// or equivalent, because bandwidth isn't infinite.\n\nIn this case the additional requirements are:\n* Must work for a Windows client\n* Must work for a Linux server\n* Should only attempt backups when the Windows client is located on the local network, as we don't want to be performing a backup through a slow public wifi from the other side of the world. Although if optionaly we //can// do that (if we're travelling for months or something) it //should// be possible.\n\nBecause, well, that's just the way things are.\n\nLast time I tried to solve this by installing [[Cygwin|http://www.cygwin.com/]], a little script that would heuristically determine if it was on the local network (based on the IP, the gateway, and the presence of the server at the expected address) and rsync over ssh. This solution kinds of works, but Cygwin tends to be a last resort solution and suffers from Windows' lack of correct //cron// implementation, so scheduling is a pain.\n\nThere is actually a much simpler solution: Install the stand-alone version of [[rsync|http://sourceforge.net/projects/backuppc/files/cygwin-rsyncd/2.6.8_0/]], configure it so //rsync// can access the //Document and Settings// folder and run it as a Windows service, then script everything from the server: a simple //cron// running every night, connects to the //rsyncd// service on the Windows client and retrieves the changed files. And then just feed that through the normal Unix backup you use (I use [[Backup2l|http://backup2l.sourceforge.net/]]).\n\nYou'll have to make sure the Windows computer inherits a fixed address from the DHCP server, if applicable, obviously.\n\nThis, combined with OpenVPN, could potentially be used to backup remotely (as in, over the Internet) as well; this is still to study, I'm just getting started with OpenVPN.\n
A small japanese restaurant. It's easy to get lost on the way, so make sure you have a map of Colomiers. The service is very slow, so don't plan to go to the movies afterwards. It's the best sushi we've tried in and around Toulouse. Budget about 35EUR a head.\n\nYakiyori: 14 r Prat, Colomiers, 05 61 15 79 21
This is a service name for NFS, which is the Networking File System. That's all Unix speak for network shares.\n\nWhatever.\n\nIt's not a typo.
Sometimes, you want to watch a DVD on a set-top box such as the //Freebox// (in a version that doesn't have a disc drive), or maybe you want to to watch an ISO...\n\nI used to have [[mplayer|http://www.mplayerhq.hu]] scripts to try and extract the right track, with the right audio and the right subtitles. Until I ran into the [[Conan|http://www.imdb.com/title/tt0082198/]] DVD ISO, which I just could not make sense of. Out of frustration, I set out to find a better solution. And here it is, Kevin!\n\nEnter [[makemkv|http://makemkv.com/]]. It'll read the structure of the DVD (from the drive, or from an ISO), and let you create a MKV file, while selecting which audio and which subtitles you want to include in the final file. And it'll do all that in just a few minutes.
I have a list of [[restaurants in Toulouse]], and there are some more on the side here for the cities where I don't have enough entries to warrant a category.\n\n
These are restaurants I have been to in and around Toulouse. I try to give a quick description of the place, type of food, price range and smoke level.\n\n
I have been using Debian's [[ejabberd|http://www.ejabberd.im/]] for quite some time now. Originally, I chose it because it could do Http Poll, which I don't think any other could. And then using something written in not-C, and that calls itself fault-tolerant and distributed, sounded cool.\n\nWell, today I replaced it for the more standard [[jabberd 1.4|http://jabberd.org/]]. For all it's fault tolerance, after our server's last reboot, ejabberd just didn't start up.\n\nI already had problems with ejabberd not starting, getting confused whether it had started or not, and leaving various processes behind itself. I also once had a problem which turned out to be hard to fix because of totally inadequate error logging (hint to developpers: programmers don't need logs. Logs are used by admins when things go wrong. They need to be useful to someone who doesn't know Erlang, nor what's happening at line 264 of file foobar.c).\n\nThis time, ejabberd's processes start up, but nothing happens. I mean, //nothing//. No ports open, not a single line in any of the logs.\n\nSo after too long of tinkering and googling, I replaced the server in about 20 minutes with a good ol' plain C server. I am a bit disappointed.\n\nSo if you see some subscription requests and things coming from me, that's why.\n\n
Just released a new version of [[sslh|http://www.rutschle.net/tech/sslh.shtml]]. It's beautiful and shiny, can connect to OpenVPN, is more RFC-compliant, and can run with select() i.e. without forking, which is supposed to be better for performance (especially under Cygwin).
I am doomed to work on old machines, which never have strcasecmp or strncasecmp. Each time I re-implement them, as I never remember where I last put them in. No more:\n\n{{{\n/* YR 19APR 2007 -- use at own risk */\nint strncasecmp(const char *s1, const char *s2, size_t n)\n{\n int c1, c2;\n while (n--) {\n c1 = toupper(*s1++);\n c2 = toupper(*s2++);\n\n if ((!c1 || !c2) || (c1 != c2))\n return c1 - c2;\n }\n return 0;\n}\n\n/* YR 19APR 2007 -- use at own risk */\nint strcasecmp(const char *s1, const char *s2)\n{\n int c1, c2;\n while (1) {\n c1 = toupper(*s1++);\n c2 = toupper(*s2++);\n\n if ((!c1 || !c2) || (c1 != c2))\n return c1 - c2;\n }\n}\n\n}}}
Bookmarks:\n\n[[How to burn a video DVD]]