Kwissle

My real-time quiz battle game Kwissle.com

Crosstips.org

My fun Crossword solver project. Crosstips.org & Krysstips.se

Kung Fu

Fujian White Crane Kung Fu

Photos

Photoalbum, both old and new.

Twitter

Follow me on Twitter

Contact me

My contact details and how to contact me.

 

KungFuPeople.com
Do you train Kung Fu?
Or know someone who does?
Then check out KungFuPeople.com


Mobile version of this page Mobile version of this page

RSS

Hot topics

by Anderson Pierre Cardoso: Thanks =]. I'm definitely going to use it. Great post, thanks again!...

Integrate BrowserID in a Tornado web app

by : Pretty cool app! BTW I'm working now on my own first web app: http://www.fi...

My first iPhone web app - Crosstips iPhone interfa

by Jonathan: I had a similar issue with setAttribute not working on IE. I put it in a t...

setAttribute('style', ...) workaround for IE

by terrence: The simpsons are from Ohio. Check the Halloween special #5 or #6. The one w...

Ask Yahoo "What state do the Simpsons live in?"

by terrence: The simpsons are from Ohio. In the Halloween episode where the giant ads c...

Ask Yahoo "What state do the Simpsons live in?"

by Ashraf at Akbar: Hi Thanks for help...

Lost my mobile phone

by selevistar: verey good...

fcgi vs. gunicorn vs. uWSGI

by scott: the simpsons live in florida because in the simpson hit and run buy marges ...

Ask Yahoo "What state do the Simpsons live in?"

Old entries


July, 2011
A blog comment spam solution: Retalition!
A taste of the Django on inside Mozilla, Sheriffs Duty
Comparing Google Closure with UglifyJS
Slides about Kwissle from yesterdays London Python Dojo

June, 2011
Chinese tea sampler pack now on sale
Optimization story involving something silly I call "dict+"
Launching Kwissle.com
Google teething problems still with duplicated content
Test static resources in Django tests

2011
2010
2009
2008
2007
2006
2005
2004
2003

 

You're viewing blogs from Web development only. RSS?

View all different categories

13th of October

Web developmentJavaScript

Going real simple on HTML5 audio

DoneCal users are to 80+% Chrome and Firefox users. Both Firefox and Chrome support the HTML <audio> element without any weird plugins and they both support the Ogg Vorbis (.ogg) file format. change log here

So, I used use the rather enterprisey plugin called SoundManager2 which attempts to abstract away all hacks into one single API. It uses a mix of browser sniffing, HTML5 and Flash. Although very promising, it is quite cumbersome. It doesn't work flawlessly despite their hard efforts. Unfortunately, using it also means a 30kb (optimized) Javascript file and a 3kb .swf file (if needed). So, instead of worrying about my very few Internet Explorer users I decided to go really dumb and simple on this.

The solution basically looks like this:

 // somewhere.js
 var SOUND_URLS = {
   foo: 'path/to/foo.ogg',
   egg: 'path/to/egg.ogg'
 };

 // play-sounds.js

 /* Call to create and partially download the audo element.
  * You can all this as much as you like. */

 function preload_sound(key) {
  var id = 'sound-' + key;
  if (!document.getElementById(id)) {
    if (!SOUND_URLS[key]) {
      throw "Sound for '" + key + "' not defined";
    } else if (SOUND_URLS[key].search(/\.ogg/i) == -1) {
      throw "Sound for '" + key + "' must be .ogg URL";
    }
    var a = document.createElement('audio');
    a.setAttribute('id', id);
    a.setAttribute('src', SOUND_URLS[key]);
    document.body.appendChild(a);
  }
  return id;
 }

 function play_sound(key) {
   document.getElementById(preload_sound(key)).play();
 }

 // elsewhere.js
 $.lightbox.open({
    onComplete: function() {
       preload_sound('foo');
    }
 });
 $('#lightbox button').click(function() {
    play_sound('foo');
 });

Basically, only Firefox, Chrome and Opera support .ogg but it's a good and open source encoding so I don't mind being a bit of an asshole about it. This little script could be slightly extended with some browser sniffing to work with Safari people but right now it doesn't feel like it's worth the effort.

This make me happy and I feel lean and light. A good feeling!

8th of October

Web development

New feature on Too Cool For Me: Everyone I follow

New feature on Too Cool For Me: Everyone I follow I've added a new feature to Too Cool For Me that lists all the users that you follow and splits them up into "Follows me" and "Too cool for me".

To try it you have to authenticate with Twitter (READ ONLY mode) then go to toocoolfor.me/everyone

This means you can use Too Cool For Me without having to use the Bookmarklet.

4th of April

Web development

Google's new Page Speed Online hard to beat

I like the new Google Page Speed Online for it's simplicity. However, I threw it the URL of my Crosstips site http://crosstips.org and it only gave me a 80 out of 100 even though there were no high priority suggestions.

Google's new Page Speed Online hard to beat

Seems hard to beat. Surely, to win over the remaining 20 points I don't have to tick all the medium and low priority suggestions.

15th of February

Web developmentPython

How I profile my Nginx + proxy pass server

Like so many others you probably have an Nginx server sitting in front of your application server (Django, Zope, Rails). The Nginx server serves static files right off the filesystem and when it doesn't do that it proxy passes the request on to the backend. You might be using proxy_pass, uwsgi or fastcgi_pass or at least something very similar. Most likely you have an Nginx site configure something like this:

 server {
    access_log /var/log/nginx/mysite.access.log;
    location ^~ /static/ {
        root /var/lib/webapp;
        access_log off;
    }
    location / {
        proxy_pass http://localhost:8000;
    }
 }

What I do is that I add an access log directive that times every request. This makes it possible to know how long every non-trivial request takes for the backend to complete:

 server {
    log_format timed_combined '$remote_addr - $remote_user [$time_local]  ' 
                              '"$request" $status $body_bytes_sent '
                              '"$http_referer" "$http_user_agent" $request_time';
    access_log /var/log/nginx/timed.mysite.access.log timed_combined;

    location ^~ /css/ {
        root /var/lib/webapp/static;
        access_log off;
    }
    location / {
        proxy_pass http://localhost:8000;
    }
 }


> Read the whole text (259 more words)

13th of November

Web development

How to book a ticket on the Royal Academy of Music's website

I've finally managed to book my ticket to see Zappa. It's the Royal Academy of Music Manson Ensemble who play about 10 Frank Zappa classics. It's here in London on Baker Street.

The Royal Academy of Music website sucks. Its ticket booking part is completely broken. Fortunately I found a way to "hack" it so that I could get a ticket. And it only cost me £1 extra.

On that note, why isn't the box office open on weekends? And why is no one answering any of their phones on a Saturday?


> Read the whole text (351 more words)

10th of September

Web development

wkhtmltopdf and font size shrinkage

wkhtmltopdf is by far the best tool available to make PDFs. Yes. I have tried ReportLab and PISA. ReportLab might be more powerful but what you gain in fine-grained control you lose in hours and hours of productivity.

Anyway, I've learned something about font-size shrinkage and using wkhtmltopdf. Basically, if use percentage to change a font size (Arial in this case) you get a PDF where the letters are unevenly spaced between. It took me a while to figure out what the hell was going on until I changed the font-size from 90% to exactly 11px.

font-size: 90% ('font-size:90%'; the spots of red are my highlights of the ugly spacings)

font-size: 11px ('font-size:11px'; not perfect but much better)

So, at first I thought this was the first time wkhtmltopdf has disappointed me but I guess I'll just have to remember not to use percentages and continue to favor wkhtmltopdf as my choice of weapon in the PDF production world.

15th of June

Web development

TfL Traffic cameras on a Google map

TfL Traffic cameras on a Google map Yesterday I found out that Transport for London lifted all restrictions for commercial use of its data that it has made available for developers.

In lack of better imagination I decided to attack the Live Traffic Cameras data and whipped up this little app: tflcameras.peterbe.com

It basically shows a map of London and then shows all the spots where traffic cameras are installed so that you can click on them. The data is updated every 3 hours I think but I haven't checked that claim yet. Use this if you're a London commuter and want to check the traffic before you hit the road.

Oh, and this app uses the geo location stuff so that I know where to zoom in first. But if you're not based in London it zooms in over Trafalgar square by default.

23rd of April

Web developmentPython

OpenID, Attribute Exchange, SReg, python-openid and Google

OpenID logo I've learned a couple of things this week on deploying my first site to use a user friendly OpenID.

My first revelation was when I realized that Google and Yahoo! have solved the usability stumbling block that you can use them as providers without having to know a personally unique URL. For example, for Yahoo! it's just http://yahoo.com which means that you don't need to offer a cryptic URL form and you can just show it as a logo image.

The second thing is that Google's hybrid OpenID + OAuth isn't as complicated as it sounds. It's basically a light extension to the OpenID "protocol" whereby you say, "while you're at it, also give me a OAuth token please so that I can connect back into Google's services later". What's important to understand though is that if you use this you need to know the "scope". scope is a URL to a service. Google Docs is a service for example and you need to search the web to figure out what the scope URL is for that service.

The third revelation was when I understood the difference between Simple Registration Extension (SREG) and Attribute Exchange (AX). Basically, AX is a newer more modern alternative and SREG was the first one. AX is better but some OpenID providers don't yet support it. Google for example, only supports AX. Key to be able to support not just Google's OpenID but any OpenID is that you can request both AX and SREG and whichever one works will be returned.

The fourth thing that helped a lot to understand was the Google's OpenID has a bug in its implementation of Attribute Exchange. Actually, perhaps it's a deliberate design choice they've made but in my opinion a bad one. Unless you say you require email, firstname, lastname, country etc. it won't return it. If you use the if_available directive you won't get it. Another bug/bad design choice is that Google seems to not forward the country attribute. It can happily do first- and last name but not country even if the documentation claims so.

The fifth thing is that python-openid is a lot easier to work with than you think. You don't need to do any crazy network checks or callbacks. For initiating the challenge all you're effectively doing is creating a long URL. If you don't like the API methods python openid offers, just add your own with:

 redirect_url += '&openid.ax.mode=fetch_request' # etc.

After so many years since OpenID arrived, I'm only now excited about it. It's tonnes easier to implement than OAuth and now it's actually really pleasant to use as an end user.

19th of April

Web development

UPPER vs. ILIKE

I have a Zope web app that uses hand coded SQL (PostgreSQL) statements. Similar to the old PHP. My only excuse for not using an ORM was that this project started in 2005 and at the time SQLAlchemy seemed like a nerdy mess with more undocumented quirks than it was worth losing hair over.

Anyway, several statements use ILIKE to get around the problem of making things case insensitive. Something like the Django ORM uses UPPER to get around it. So I wonder how much the ILIKE statement slows down compared to UPPER and the indexed equal operator. Obviously, neither ILIKE or UPPER can use an index.

Long story short, here are the numbers for selecting on about 10,000 index records:

 # ONE
 EXPLAIN ANALYZE SELECT ... FROM ... WHERE name = 'Abbaye';
 Average: 0.14 milliseconds

 # TWO
 EXPLAIN ANALYZE SELECT ... FROM ... WHERE  UPPER(name::text) = UPPER('Abbaye');
 Average: 18.89 milliseconds

 # THREE
 EXPLAIN ANALYZE SELECT ... FROM ... WHERE  name ILIKE 'Abbaye';
 Average: 24.63 milliseconds

UPPER vs. ILIKE

First of all, the conclusion is to use UPPER instead of ILIKE if you don't need to do regular expressions. Secondly, if at all possible try to use the equal operator first and foremost and only reside on the case insensitive one if you really need to.

Lastly, in PostgreSQL is there a quick and easy to use drop in alternative to make an equality operatorish thing for varchars that are case insensitive?

5th of March

Web development

Importance of public URLs and how enterprisecarsales.com gets it wrong

Importance of public URLs and how enterprisecarsales.com f's it up A friend of mine found a nice car she on www.enterprisecarsales.com so she copied the current URL from the address bar and emailed that to me. The URL was: http://www.enterprisecarsales.com/carsales/vehicleDetails.do?carIndex=1&vin=1GCHC24U36E112452 which by the look of it (notice the /vehicleDetails.do part of the URL) takes you to a page that says "Sorry, we are unable to complete your page request since the page you are trying to access no longer is available." How stupid is that? Come on, web developers made those kind of mistakes in 2001. Not 2010.

This means that people can't talk to each other about found matches on the site and this is something people want to do. Especially if you're going to spend $thousands on a car.

Come on Enterprise web team: install Django or something and give users what they want not your excuses.

17th of February

Peterbe.com Bookmark

Looking for icons?

http://www.iconfinder.net/free_icons 

Check out these all free icons

16th of January

Web developmentDjango

Bookmarklet to replace the current domain with localhost:8000

If you, like me, have various projects that do things like OAuth on Twitter or Google or you have a development site that goes to PayPal. So you're doing some Django development on http://localhost:8000/foo and click, for example, to do an OAuth on Twitter with an app you have there. Then Twitter will redirect you back to the live site with which you've set it up. But you're doing local development so you want to go back to http://localhost:8080/... instead.

Add this bookmarklet: to localhost:8000 to your browser Bookmarks toolbar and it does exactly that.

Here's its code in more verbose form:

 (function() { 
    a = function(){
      location.href = window.location.href.replace(/http:\/\/[^\/]+\//,
             'http://localhost:8000/')
    };
    if (/Firefox/.test(navigator.userAgent)) { 
      setTimeout(a,0)
    } else {
       a()
    }
  })()

25th of October

Web development

iPhone push notifications for Twitter with Prowl

iPhone push notifications for Twitter with Prowl Bruno Renié has written a nifty app:iPhone push notifications for Twitter with Prowl

With the power of Prowl it pushes a notification to your iPhone when someone mentions you on Twitter. You first need to install the Prowl app on your iPhone and then go to their website to get your notification key. Then, go to Bruno's site, sign in with your Twitter account (OAuth, so no password give-away) and badabing! you get instant notifications on your phone, for free, when someone mentions you.

If you're one of those people who use Twitter instead of instant messaging and have lots of mentions this might be excessive for you but if not it can be very useful if you are like me who is very slow to spot that someone has replied or mentioned your name.

Great work Bruno!

8th of October

Web development

A user-friendly TinyMCE config

A user-friendly TinyMCE config When you enable TinyMCE you can either choose theme="simple" or theme="advanced". If you go for the simple you get one lovely little bar of buttons but it's missing the link button which is more important than most other buttons altogether. When you enable "advanced" you get three rows of buttons that makes you dizzy. I mean, should really be editing advanced tables in a WYSIWYG editor or mathematical equations?

Here's a config that I think works great. It's all in one row and it's got the bare minimum in terms of additional plugins (no extra downloads required). It's in Python but translates quite easily into Javascript:

 TINYMCE_DEFAULT_CONFIG = {
    'plugins': "fullscreen,paste,autoresize",
    'theme': "advanced",
    'theme_advanced_buttons1' : "bold,italic,strikethrough,bullist,numlist,"\
                                "separator,undo,redo,separator,link,unlink,image"\
                                ",separator,cleanup,code,removeformat,charmap,"\
                                "fullscreen,paste",
    'theme_advanced_buttons2' : "",
    'theme_advanced_buttons3' : "",
 }

20th of August

Peterbe.com Bookmark

The Secret to SEO Search Engine Optimization

http://ajax.sys-con.com/node/1072453 

"SEO is not about creating a website sausage overstuffed with key words and phrases. It’s all about creating relevant and compelling content that transforms you into a thought leader who can become a trusted provider That is ultimately how you convert visitors into buyers"

 

Older entries Order entries