Author Archives: Keeyai

Django Deployment – create superuser fails with locale error

I was playing with my django configuration on my ubuntu server when I ran into this problem creating a superuser:

Traceback (most recent call last):
  File "manage.py", line 18, in 
    execute_manager(settings)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/__init__.py", line 438, in execute_manager
    utility.execute()
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/__init__.py", line 361, in execute
    self.fetch_command(subcommand).run_from_argv(self.argv)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 191, in run_from_argv
    self.execute(*args, **options.__dict__)
  File "/usr/local/lib/python2.6/dist-packages/django/core/management/base.py", line 222, in execute
    output = self.handle(*args, **options)
  File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/management/commands/createsuperuser.py", line 63, in handle
    default_username = get_default_username()
  File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/management/__init__.py", line 105, in get_default_username
    default_username = get_system_username()
  File "/usr/local/lib/python2.6/dist-packages/django/contrib/auth/management/__init__.py", line 85, in get_system_username
    return getpass.getuser().decode(locale.getdefaultlocale()[1])

The issue comes from no default locale being set on the server.

There are a couple bug reports in for this already, with some minor argument among the developers on fixing it or just making users set up their locale properly.

I tried setting my locale correctly, but I basically stumble around linux using google as a seeing eye dog, so after a couple minutes of searching and trying locale commands I still couldn’t get it to work. This was the only time I have had this problem, so I decided to just fix it manually with a little hack. Use the locale setting that fits your implementation.

All I did was edit manage.py and stick this at the top

import os
os.environ.setdefault('LANG','en_US')

This makes the python locale.getdefaultlocale() call return en_US, which stops django from being a crybaby and lets you get on with your day.

Disclaimer – I have no idea if this causes any negative side effects. I can’t see it doing so and I’m using this myself, but if you magically light your box on fire and bring forth the apocalypse because of this, I’m not taking any blame. Use at your own risk.

Adding custom parsers to Mootools’ HtmlTable.Sort

Mootools’ HtmlTable and HtmlTable.sort are fantastic. Pretty much every table I put on a page uses them (and HtmlTable.zebra). They work great and come with a handful of useful parsers to make sorting extremely easy to implement and maintain.

For most sites the built in parsers are plenty, but recently I ran into the need for some custom column sorting. The parser docs make sense in hindsight but I didn’t really understand what I was supposed to do until I dug into the code (which, as usual, is well written and easy to understand). They are designed quite well, actually – you can add parsers to the HtmlTable prototype with their built in defineParsers function and each parser is simply an object with three properties – a regex to match what you’re looking for (if not it skips it), a convert function that is passed the td content and expects back an easily sortable output, and a flag for if your convert return is a number or not.

In my particular case, I was using some icons as table cell content to save space, but I still wanted them to be sortable and in a particular order. Here are two of the parsers I ended up adding. first_child_class tries to get the first child of the td using getFirst then returns the class name. This works perfectly for the times I was inserting divs and controlling their images via css. Notice I’m really just checking a property – this can be easily adapted to any kind of custom sorting by property. Additionally, in some columns I had direct image tags. The img_src parser only matches image tags and simply returns their src tag. This isn’t nearly as flexible as the property parser, but it worked for what I needed.

HtmlTable.defineParsers({
    first_child_class: {
        match: /.*/,
        convert: function(){
        	first = this.getFirst();
        	if(first)
        	        return first.getProperty('class');
		else
			return '';
	},
        number: false
    },
 
    img_src: {
        match: /<img|^\s.$/,
        convert: function(){
        	img = this.getElement('img');
        	if(img)
			return img.src;
		else
			return '';
	},
        number: false
    }
});

Simple and easy. Now go write your own super parsers.

A boatload of crazy

Today, January 18, 2012, has become a protest day against the US government bills called SOPA and PIPA. Major sites like google, wikipedia, reddit, wordpress, tumblr, and mozilla, along with literally thousands of others, are raising awareness by ‘going dark’ in various degrees. Other sites aren’t ‘going dark’, but are spreading the word by highlighting their views on the proposed legislation on their front pages. Overall, it has been extremely successful – discussion is rampant across the internet among the less technical crowd, which was exactly the goal.

Generally, the tech community feels that the SOPA/PIPA proposals are a problem because they give too much power to interest groups with no accountability like the MPAA, and because they propose the heavy handed and poorly thought out ‘solution’ of DNS blocking that will do essentially nothing to the illegal pirate sites that are supposed to be the target, yet will incur huge costs for sites operating legitimately on the internet.

I personally would add that any suggestion to take away freedoms and give policing power to private interest groups is a really really bad idea.

As publicity ramped up yesterday, the MPAA released this statement.

Only days after the White House and chief sponsors of the legislation responded to the major concern expressed by opponents and then called for all parties to work cooperatively together, some technology business interests are resorting to stunts that punish their users or turn them into their corporate pawns, rather than coming to the table to find solutions to a problem that all now seem to agree is very real and damaging.It is an irresponsible response and a disservice to people who rely on them for information and use their services. It is also an abuse of power given the freedoms these companies enjoy in the marketplace today.

It’s a dangerous and troubling development when the platforms that serve as gateways to information intentionally skew the facts to incite their users in order to further their corporate interests.

A so-called “blackout” is yet another gimmick, albeit a dangerous one, designed to punish elected and administration officials who are working diligently to protect American jobs from foreign criminals. It is our hope that the White House and the Congress will call on those who intend to stage this “blackout” to stop the hyperbole and PR stunts and engage in meaningful efforts to combat piracy.

As terrified as I am that these people have jobs, let alone astronomical budgets and countless politicians in their pockets, I can’t help but feel amazed at the sheer amount of blatent crazy they crammed into these three short paragraphs. Let’s start at the top!

White House…responded to the major concerns expressed by opponents and then called for all parties to work cooperatively together…

They might be talking about this, but they would be crazy to imply that is on their side. I encourage you to read the White House stance, but from where I’m sitting it basically says everything the protesters have been saying: piracy sucks and needs to be fought actively but not at the expense of internet freedom and not in a way that punishes legitimate businesses.

…some technology business interests are resorting to stunts that punish their users or turn them into their corporate pawns, rather than coming to the table to find solutions to a problem…

So much crazy in one little sentence fragment! First of all, gathering like minded people together to contact their representatives about how they feel about upcoming legislation is EXACTLY THE RIGHT THING TO DO. Exactly. Derisively calling this a stunt is sheer stupidity, but it does a good job of highlighting the MPAA’s views toward the system. Secondly – punishing their users? Seriously? Even if these sites are ‘punishing their users’, which they most certainly are NOT, does the MPAA actually have a problem with that? Are they not allowed to select the content on their sites? Wouldn’t the MPAA, who would benefit immensely from this legislation passing, want these sites to lose support? Lastly, these companies are the entire reason a discussion is even happening. Implying they are in some way unwilling to provide feedback and propose better solutions is crazy on a new level, even for these guys. The doublethink that is going on over there must be palpable.

It is also an abuse of power given the freedoms these companies enjoy in the marketplace today.

This is absolutely crazy. Every single website should always have the right/power/freedom to not only select their content but to decide if they are going to show that content, ‘go dark’, push their political agendas, or shutdown altogether. The MPAA, on the other hand, has a long list of what I would call actual ‘abuses of power’. Maybe they don’t know what this phrase means?

It’s a dangerous and troubling development when the platforms that serve as gateways to information intentionally skew the facts to incite their users in order to further their corporate interests.

Here, let me fix that.

It’s a dangerous and troubling development when the platforms that serve as gateways to information intentionally skew the facts [CITATION NEEDED] to incite their users in order to further their corporate interests [CITATION NEEDED].

There, that’s better.

[the blackouts are] designed to punish elected and administration officials who are working diligently to protect American jobs from foreign criminals

WHAT? Are we still having the same discussion here? I’m not sure what is more crazy: the MPAA is saying that getting citizens to contact their representatives is a punishment, or implying that these sites (many of which create high paying American jobs) asking not to be destroyed by crazy legislation means they are somehow against American jobs.

It is our hope that the White House and the Congress will call on those who intend to stage this “blackout” to stop the hyperbole and PR stunts and engage in meaningful efforts to combat piracy.

Hyperbole is another one of those words they should be careful of. For those of you playing at home, hyperbole is an english word meaning “Exaggerated statements or claims not meant to be taken literally”. In this case, the MPAA is saying one or more of the following:

  1. “these companies are exaggerating their claims that censoring the internet is bad and that we should not be putting legislative power into the hands of interest groups”
  2. “these companies don’t actually intend for anyone to take literally their claims that censoring the internet is bad and that we should not be putting legislative power into the hands of interest groups”
  3. “all these guys are liars and jerk heads!”

Maybe I can clear this up for them with some examples. Encouraging people to make their voices heard is not hyperbole or exaggeration. Better ways to describe this might be ‘taking part in your government’ or ‘discouraging corruption using the voices of the people’. On the other hand, here are some articles detailing how the MPAA has exaggerated and falsified their numbers about losses to piracy. Summary – the MPAA claims every single person to watch a pirated clip, episode, or film would have purchased the entire DVD at full price (which is absolutely crazy). On top of that, one of their examples is that when they sell a $10 DVD, $7 of those dollars go to the manufacturer and $2 goes to the shipper, for a total of $19 of loss! Somehow they are claiming that the $10 you spend on a DVD becomes $19 of payout. I’m honestly shocked any of their accountants are still employed.

tl;dr – the MPAA is a crazy, lying, hypocritical group of power-hungry psychopaths who either don’t understand representative government or would rather this country be less concerned with its citizens’ freedom and more concerned the MPAA’s profits.

Double page numbers in XHTML2PDF/Pisa

I’ve been working on a django project recently that generates PDFs from html using the XHTML2PDF library (formerly Pisa). I have html successfully in a pdf in just a couple lines, so overall it’s fantastic, but there are some quirks to get around. I ran into one of these quirks today while trying to put page numbers in my footer template – when it rendered, every page was showing its page number twice (11, 22, 33). My code looked fine; no extra tags, everything was properly formatted, etc, but I could not stop it from happening. Here is my page/footer style and my extremely simple footer markup.

@page {
	size: {% if pagesize %}{{pagesize}}{% else %}letter{% endif %};
	margin: 1cm;
	@frame footer {
		-pdf-frame-content: footerContent;
		bottom: 1cm;
		margin-left: 1cm;
		margin-right: 1cm;
		margin-top: 0cm;
		height: 1.4cm;
	}
}

...

<div id="footerContent">Page <pdf:pagenumber /></div>

Finally I got smart and found this answer on the mailing list. Essentially its a bug in the xhtml2pdf parser – without a new line after the tag it freaks out and decides you meant it twice. Interesting bug, but not interesting enough for me to go look at their parser code to figure it out. :)

Anyway, this simple change fixed the problem and hopefully you won’t waste any time banging your head on the desk with page 11, 22, etc.

<div id='footerContent'>
 Page <pdf:pagenumber />
</div>

MochaUI Custom Tiling

Our flagship product over at the dayjob is a webapp built on Mootools and MochaUI. Mootools makes everything work and Mocha gives us a dashboard with widgets and windows and all that fancy stuff.

To start with I was simply using the Tiling script that comes with mocha out of the box. It grabs all the windows, counts them up, and distributes them evenly across the screen (you can see it at their demo – open a bunch of windows and hit View->Tile Windows). This worked wonderfully for me (23″ monitors) and the VP (30″ monitor), but some of the testers with smaller computer screens (13″ craptop) were complaining that their windows weren’t ‘good’. When the dashboard was that small, opening more than a couple widgets and tiling them resulted in things overlapping or offscreen and all the windows too small to be useful.

The suggestions started rolling in about having a fixed layout instead of a dynamic one based on the number of windows you have open, but nobody agreed on the ‘proper’ numbers. Some with really small screens suggested 2 wide and only 1 tall. The majority were in the 2×2 – 2×3 range. Mr. 30″ screen was comfortable with windows up to 3×3. Clearly we needed a better solution.

Introducing the tile layout selector. New accounts get started with 2×1 and a simple walkthrough so even the tiniest screens should survive the instructions. After that, everyone has this on their toolbar.

Tile Layout Selector and Auto-Tile Option

Now you can choose which layout works best for you. I’m sure 30″ monitor VP has his set on 3×3, most are on 2×3, and the craptop guy has 2×1. Everybody is happy, everybody can read their widgets, and all the lay people think it’s a really clever feature. Additionally, you can see the ‘Auto-Tile Widgets’ checkbox in the image. That’s another feature you should consider adding. Personally, I detest it re-tiling my windows all the time, but the non-technical people seem to love it. Keep it as an option and nobody should be upset.

Now implementing this isn’t terribly hard, but it isn’t trivial either. One of the new problems you have to solve is where to put additional windows that go beyond the user selected layout. For example, if the user picks 2×2, that creates 4 ‘slots’ on the dashboard. Where does the fifth tile go? The default Mocha script makes the right decisions for rows and columns based on the total number of tiles but, since we are giving it the layout, it will just start running additional windows off screen.

Step one in my solution is to break the dashboard into the ‘slots’ mentioned above and simply loop through them placing windows. In the above example, the fifth window in the 2×2 layout would loop back around and get placed in the top left slot again. This keeps things from being placed off screen, but just overlapping the other windows isn’t very useful.

Step 2 combines step 1 and cascading. When the windows loop back around, I want them to cascade inside their ‘slots’ so we can still see all the title bars and everything stays nice and tidy. First we calculate the maximum number of overlaps we will have in any ‘slot’. Then we take that number and use it to scale some additional padding we are going to use when calculating the new tiled window size. This will keep a long stack of cascaded windows from overflowing their tile slot and looking bad. Then we place the tiles as normal but every time we loop back to the top we increase the top and left offsets a bit so they automatically get cascaded.

The result is a nice looking fixed-layout tiling that can handle a large number of additional windows beyond the specified layout without losing window visibility or aesthetic value.



Here is the code so you can implement this yourself. The placement and sizing code is almost the same as the default mocha script and the rest is fairly well commented so you should be able to see what is going on. You may notice I also added firing resize events to each window when it gets tiled. We save the user’s window locations and sizes every time they get moved, so this lets the system save their windows when they get tiled as well. Depending on how your dashboard looks, you’ll probably want to tweak the padding numbers – especially loopoffsetx and loopoffsety. These are what get added every time the script loops to make the windows ‘cascade’ down from the previous window. Play with them until you’re happy.

Note: You’ll need some way to get the layout you want — the code below looks for a dom element with ID ‘dashboard-tilelayout’ and gets its value (the dropdown pictured above). Change to suit your own needs.

This is my entire arrangeTile function (with some non-relevant stuff stripped out). It comes from the original function by Greg Houston and Harry Roberts (thanks guys!) which is included in the Mocha distribution.

arrangeTile: function(){
 
// some offsets for dashboard and dock items
var viewportTopOffset = 180;
var viewportLeftOffset = 40;
var x = 10;
var y = 130;
 
// get the desired layout from the tilelayout dropdown on the dashboard
var tilelayout = $('dashboard-tilelayout').value;
var cols = parseInt( tilelayout.substring(0,1));
var rows = parseInt( tilelayout.substring(2,3));
 
// get all the window instances
var instances =  MUI.Windows.instances;
 
// count the windows that are not minimized, not maximized, and additionally have isWidget = true
var windowsNum = 0;
instances.each(function(instance){
	if (!instance.isMinimized && !instance.isMaximized){
		windowsNum++;
	}
});
 
// calculate how much extra to space widgets based on total slots vs total widgets visible
var slots = cols * rows;
var overlaps = Math.floor( windowsNum / slots);
 
// increment the 'slot' padding based on overlaps
var widthpadding = 5;
var heightpadding = 5;
for(var i=0; i<overlaps; i++)
{
	widthpadding += 20;
	heightpadding += 20;
}
 
// figure out where the tile slots go
var coordinates = document.getCoordinates();
var col_width = ((coordinates.width - viewportLeftOffset) / cols);
var col_height = ((coordinates.height - viewportTopOffset) / rows);
 
var row = 0;
var col = 0;
 
// play with these until you're happy
var loopoffsetx = 15; // how far to offset the next widget that hits the same tile 'slot'
var loopoffsety = 25; // vertical offset
var offsetx = 0; // start at zero -- this gets increased every loop to make the cascade look
var offsety = 0; // start at zero -- this gets increased every loop to make the cascade look
 
instances.each(function(instance){
	if (!instance.isMinimized && !instance.isMaximized && instance.options.draggable){
 
		var content = instance.contentWrapperEl;
		var content_coords = content.getCoordinates();
		var window_coords = instance.windowEl.getCoordinates();
 
		// Calculate the amount of padding around the content window
		var padding_top = content_coords.top - window_coords.top;
		var padding_bottom = window_coords.height - content_coords.height - padding_top;
		var padding_left = content_coords.left - window_coords.left;
		var padding_right = window_coords.width - content_coords.width - padding_left;
 
		// This resizes the windows
		if (instance.options.shape != 'gauge' && instance.options.resizable == true){
			var width = (col_width - widthpadding - padding_left - padding_right);
			var height = (col_height - heightpadding - padding_top - padding_bottom);
 
			if (width > instance.options.resizeLimit.x[0] && width < instance.options.resizeLimit.x[1]){
				content.setStyle('width', width);
			}
			if (height > instance.options.resizeLimit.y[0] && height < instance.options.resizeLimit.y[1]){
				content.setStyle('height', height);
			}
 
		}
 
		// place the window, including the offsets for cascading
		var left = (x + (col * col_width)) + offsetx;
		var top = (y + (row * col_height)) + offsety;
 
		instance.drawWindow();
 
		MUI.focusWindow(instance.windowEl);
 
		if (MUI.options.advancedEffects == false){
			instance.windowEl.setStyles({
				'top': top,
				'left': left
			});
			// fire resized event
			instance.fireEvent('resize', instance.windowEl);
		}
		else {
			var tileMorph = new Fx.Morph(instance.windowEl, {
				'duration': 550,
				'onComplete': function(){
					// fire resized event
					instance.fireEvent('resize', instance.windowEl);
				}
			});
			tileMorph.start({
				'top': top,
				'left': left
			});
		}				
 
		// if at the right side of the screen
		if (++col === cols) {
			// reset and move down one row
			col = 0;
 
			// if at the bottom of the screen
			if(++row === rows)
			{
				// reset to top and increase the offsets
				row = 0;
				offsetx += loopoffsetx;
				offsety += loopoffsety;
			} // end if(++row === rows)
		} // end if (++col === cols)
 
	} // end if this is a window we want to tile -- !minimized, !maximized,  isDraggable
}.bind(this));
} // end function arrangeTile