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

Chronolapse 1.0.8 Test Release

Chronolapse has a new test release that needs your help. Most importantly, this is the linux/mac code (no webcams yet, sorry). Please download and leave your feedback.

http://code.google.com/p/chronolapse

Chronolapse 1.0.4

Chronolapse has hit version 1.0.4!

The last version was built without the console window, but when frozen into an executable this was causing the mencoder process to freeze indefinitely. This addresses the issue, fixes the update checking code, and makes the mencoder feedback not hang the GUI while it runs.

Just in time for LD!

http://code.google.com/p/chronolapse/