BigSmoke

Smokes your problems, coughs fresh air.

Page 39 of 52

Removing unwanted grey values in scanning white papers

When doing automated scanning, like I do to for properly organizing paper administration, the resulting images can get quite large because the background has near-white information that is still very complex to save. Imagemagick has nice solution for that; -white-threshold x%. It also has -black-threshold, should it be necessary.

reCAPTCHA fun

If you’ve never heard of reCAPTCHA before, reCAPTCHA is a free CAPTCHA service that helps to digitize books, newspapers and old time radio shows. I’m using reCAPTCHA on this and other blog to protect myself from automated spam comments. I’m also using it on some of my MediaWiki sites to protect myself from wiki spam.

The great thing about reCAPTCHA is that it solves two problems at once. First, the OCR problem: it uses user time that would otherwise have been wasted solving meaningless capchas to aid the digitization process of public texts, to fill in the gaps where OCR fails. By doing so it solves the automated spam problem by challenging website visitors to proof that they’re human. We can be pretty confident that someone is human if they’re able to recognize characters that the best OCR software cannot.

Anyway, enough about the serious stuff. I’m blogging about this now because Wiebe sent me a few links to funny reCAPTCHA combinations. Here’s a nice example (from the I Am Not A Robot weblog):

Johnson Chorus

Johnson Chorus

www.stichting-ecosafe.org

Stichting EcoSafe is a Dutch foundation for the safe-keeping of the funds that are necessary for the maintenance of hardwood plantations. In July of 2006, together with Johan Ockels, I created a website for the Foundation. Johan was responsible for the organization of the whole process. This went very smooth and the website ended up being an emblem of simplicity and clarity. That’s why I wanted to blog a bit about it now, even though there are a few things that I’d probably end up doing different if I were to start from scratch. [There’s actually a disturbing number of things for which this is true, I’m coming to notice.]

File structure

Like with most websites, I started with creating an SVN repo so that I wouldn’t have to be afraid of ever losing anything.

The file structure was pretty standard:

  • a css dir for stylesheets;
  • img for images;
  • inc for shared PHP and mod_include stuff and for AJAX partials;
  • jot for to-do’s and other notes;
  • and js for JavaScript files and libraries.

Possible file structure improvements

If I were to redesign this file structure, I’d collapse css, img and js into one directory called layout, because these are typically things that require the same robots.txt and caching policy. Also, it is meaningless to organize things by file extension. If you want to sort something by file extension, use ls -X (or ls --sort=extension if you’re on GNU).

Server-side includes

The site would be so simple that I felt that any type of CMS or content transformation would be completely unnecessary. Instead, I decided to rely on Apache’s mod_include and just use a few partials for repeating page elements such as the left sidebar containing the logo and the menu.

Also, because I didn’t need to transform the HTML files, I decided I could use good ol’ HTML 4 instead of XHTML 1 (which I’d have to send to the browser with the wrong mime-type anyway).

This is the HTML for contact.nl.shtml:

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/loose.dtd">
 
<html lang="en">
  <head>
    <title>Contact EcoSafe</title>
 
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
 
    <link rel="stylesheet" type="text/css" href="/css/style.css"></link>
  </head>
 
  <body>
    <!--#include virtual="/inc/left-side.en.html"-->
 
    <!--#include virtual="/inc/alt-lang.phtml"-->
 
    <div id="content">
      <h1>Contact</h1>
 
      <p>Your email to EcoSafe kan be sent to the following address:
      <a href="mailto:service@stichting-ecosafe.org">service@stichting-ecosafe.org</a>.
      Or, alternatively, you can fax us at +31 50 - 309 66 58.</p>
 
      <h2>About this website</h2>
 
      <p>For comments and/or suggestions concerning this website,
      you can direct an email message at:
      <a href="mailto:webmaster@stichting-ecosafe.org">webmaster@stichting-ecosafe.org</a>.</p>
    </div>
  </body>
</html>
Alternative language selection

Alternative language selection

I use <!--#include virtual--> to include the repeating parts. <!--#include virtual--> has several advantages over <!--#include file--> in that it allows for content-negotiation, execution of dynamic content etc., but here the only place were it holds an advantage is in the inclusion of /inc/alt-lang.phtml. alt-lang.phtml is a messy PHP script that figures out which language variants of a page are available and displays a selection of alternative language versions (variants with a language different from the current).

SSI and caching

Without the XBitHack directive set to full, all content handled by mod_include is sent without a Last-Modified header. However, I don’t want to use XBitHack at all, because I don’t want just any executable file to be handled by mod_include; that just too much of a … hack.

If I were to do something similar now, I’d use some kind of (sed) substitution to pre-process the includes locally so that more of what I end up uploading is simple static content. The dynamic part of the included PHP script, I would simply replace with JavaScript.

Visual design

As you can see in the HTML example, there’s hardly anything layout oriented in the HTML source. This is good, and means that I have to touch only the CSS for most minor and major lay-out modifications. (It is a pipe-dream to think that you only need to change the CSS to make the same HTML page look however you want as long as that HTML is rich enough in meaning, but for a site with pages of such simple structure, it’s a dream that comes pretty close to reality.)

I’m not much of a designer, but I think design is overrated anyway. Actually, I think that most website suffer from too much design.

The EcoSafe logo

The EcoSafe logo

To start the design, I got a logo made by Huite Zijlstra. Because the logo was pretty big and didn’t look good scaled down, I decided to put it at the left of the content area instead of at the top. This would still leave enough room for the menu (which actually takes less space horizontally than the logo).

Colors

For the color scheme, I just picked a few colors from the logo. As always, the base of the scheme would be black text on a white background for maximum readability. The print version hardly uses any colors.

@media screen {
body            {:;  }
*               {:;             }
a:link          {: #585;              }
h1              {: #880;              }
h2              {: #888;              }
strong          {: #a62;              }
#menu li a      {: #660;              }
}

Underlines

I wanted an underline below the level 1 and 2 headings. Because I didn’t like the effect of text-decoration:underline (too thick for <h2>s, too dark for <h1>s and different from browser to browser) and because border-bottom was set too far from the text, I made two simple PNG images that I could repeat-x along the bottom edge.

@media screen {
h1 {:('/img/h1-border-bottom.png'); }
h2 {:('/img/hx-border-bottom.png'); }
}

The menu is very simple. The markup is part of inc/left-side.en.html for the English version and inc/left-side.nl.html for the Dutch version:

cat inc/left-side.en.html
<div id="left" lang="en">
  <a class="logo" href="/index.en"><img class="logo" alt="[Logo]" src="/img/logo.jpg"></img></a>
 
  <ul id="menu" class="menu">
    <li><a href="/index.en" rel="start">Start page</a></li>
    <li><a href="/plantations.en">For plantations</a></li>
    <li><a href="/investors.en">For investors</a></li>
    <li><a href="/history.en">History</a></li>
    <!--<li><a href="/goals">Goals</a></li>-->
    <li><a href="/methods.en">How it works</a></li>
    <li><a href="/cost-structure.en">Cost structure</a></li>
    <li><a href="/cost-calculator.en">Cost calculator</a></li>
    <!--<li><a href="/clients.en">Clients</a></li>-->
    <li><a href="/contact.en">Contact</a></li>
  </ul>
</div>
 
<script type="text/javascript" src="/js/menu.js"></script>
The EcoSafe menu (in English)

The EcoSafe menu (in English)

As is customary, I started by removing all the default list styles and made the anchors behave as block-level elements. I used the big O from the logo for bullets in the list (using background-image instead of list-style-image because the latter gives unpredictable cross-browser results and doesn’t make the bullet clickable).

#menu {
 : 2em;
 : 2em;
 :;
 : 0;
}
 
#menu li {
 : 0;
}
 
#menu li a {
 :;
 :('/img/o-21x16.png');
 :;
 :;
 : 30px;
 :;
 :;
 :;
 : #660;
}
 
#menu li a:hover,
#menu li.active a {
 :('/img/oSafe-21x16.png');
}
 
#menu a:hover {
 : #787800;
}

JavaScript menu item activation

To add the active class to the currently active list item (<li>), I used a client-side solution using JavaScript. After all, it’s proper use of JavaScript to enhance your user interface with it (as long as, as many would say, it isn’t required for the UI to function (as it is in the Cost Calculator)).

// menu.js
 
var menu = document.getElementById('menu');
var anchors = menu.getElementsByTagName('a');
var locationHref = window.location.pathname.toString();
  
for (i = anchors.length - 1; i >= 0; i--) {
  a = anchors[i];
  aHref = a.href;
    
  // Does this menu item link to the current page?
  // We find out by looking if the window location contains the URL in the anchor
  // or the other way arround. The reason to look at both is content-negotiation.
  // It's also true if the location is just '/' and we're looking at the anchor of
  // the 'start' page.
  if ( (locationHref === '/' && a.rel === 'start') ||
       (locationHref !== '/' && ( locationHref.indexOf(aHref) !== -1 ||
                                  aHref.indexOf(locationHref) !== -1 ) ) ) {
    a.parentNode.className = 'active';
    break;
  }
}

I actually just fixed a long-standing bug that was caused by me not being able to fully rely on HTTP language negotiation for the selection of the appropriate language variant, which made me change all links from being language-neutral to including the language in the link target (e.g.: http:///history became http:///history.en and http:///history.nl), the problem with this being that, instead of being able to link to link to http:/// (http://www.stichting-ecosafe.org/), I had to link to http:///index.en or http:///index.nl, making it more difficult to detect the active anchor if we’re requesting the home page through http:/// instead of on of its language-specific URLs.

The JavaScript rested on the assumption that by reverse iterating through all the anchors in the menu and thus processing the link to http:/// as last, I’d know that I had struck the home page and wouldn’t need to worry that any of the links contain a slash. (I don’t know if I intended it to work this way, but it sure seems to me now that the only way this could ever have worked was as an apparent side-effect of the looping order; the SVN logs seem to agree.)

I could have solved this by redirecting all requests for http:/// to the appropriate variant. Maybe I should have (to avoid duplicate content). Instead I chose to add a rel="start" attribute to the links to the home page, as can be deduced from the JavaScript above. (To resolve the duplicate content issue, I could also add a canonical link to the header of the two language variants.)

Anyway, all this brings me to the messy subject of content negotiation.

Content and language negotiation

The EcoSafe website would be bi-lingual (English and Dutch) from the onset. Initially, I wanted to use language negotiation to the extend of having completely language-neutral URLs. For example: http:///cost-calculator instead of http:///cost-calculator.en and http:///cost-calculator.nl. In the end, you can make this work properly in the browser with the help of a cookie, but it’s still a pipe-dream because nothing else will work if you do not also offer another navigational path to the different variants. Maybe, we’ll revisit this topic for a later experiment.

Content-type negotiation is almost effortless with Apache thanks to mod_negotiation. If, like me, you despise to have .html, .htm, .xhtml, .phtml, .pxhtml. .sxhtml, .php, .xml in your URL (I actually used all of these at some time or other), you only have to make sure that MultiViews is in your options.

I’ve configured SSI by means of the following instead of a “magic mime-type”:

AddType         text/html       .shtml
AddHandler      server-parsed   .shtml
AddCharset      UTF-8           .shtml
AddOutputFilter Includes        .shtml

For PHP I couldn’t do the same because my web host was still at Apache 1.3. Otherwise, the following should have worked equally well for PHP:

# This doesn't work with Apache 1.3
AddType        text/html       .phtml
AddHandler     php-script      .phtml
AddCharset     UTF-8           .phtml

Configuring language priority is easy with Apache:

Integrating PHP and SSI

The integration of PHP with all the weirdness that I had configured and created around SSI took some figuring out. Luckily, PHP offers a virtual() function that works roughly the same as mod_include's <!--#include virtual-->. Here’s an example:

<body>
  <?php virtual('/inc/left-side.en.html'); ?>
  <?php $uri = '/cost-calculator.en.phtml'; include('inc/alt-lang.phtml'); ?>

In retrospect, it’s pretty much bullshit to use it. I could have just as well require()d the partials (which I actually did for the alternate language selection), but I probably started out using virtual on a more generic URL without language and content-type selection in it.

406 handling

Because I deployed on Apache 1.3 and the ForceLanguagePriority directive was only introduced with Apache 2.0.30, I had to write an ugly hack to avoid visitors getting 406 errors. To that end, I added a 406 handler to my .htaccess file:

LanguagePriority en nl
ForceLanguagePriority Prefer Fallback # This doesn't work with 1.3
 
ErrorDocument 406 /error-406.php # Luckily, this does 

error-406.php is a PHP file that figures out the available variants based on $_SERVER['REQUEST_URI']. Then, it simply picks the first one (which works because, accidentally, that’s the one I’ve given priority using the LanguagePriority directive as well), outputs a 200 OK header instead of the 406, and virtual()s the file of the variant. The code looks somewhat like this:

<?php
chdir($_SERVER['DOCUMENT_ROOT']);
$filenames = glob(basename($_SERVER['REQUEST_URI']) . ".*");
 
$filename = $filenames[0];
 
apache_setenv('DOCUMENT_URI', "/$filename");
 
header('HTTP/1.1 200 OK');
virtual("$filename");
EcoSafe Cost Calculator

EcoSafe Cost Calculator

EcoSafe Cost Calculator results

EcoSafe Cost Calculator results

The Cost Calculator

The EcoSafe Cost Calculator is some of the least neatly contained and most procedurally oriented PHP code I’ve ever produced while knowing full well what I was doing. It does almost everything it does in global scope. Yet, it does it well.

The thing is designed as a dynamic web page rather than a web application. What I mean by this is that it’s simply two pages (one for English and one for Dutch) using PHP among a number of pages using SSI. In an application, it’s usual to have just one ‘view’ that is the same for all languages, but here I chose to put the different language versions in different language pages and then include everything reusable (and language-neutral) from within these files.

Most of the actual processing and calculating is done in inc/costs-functions.php. (The part about gotos is a joke. (Labeled blocks would have been quite sufficient. 😉 ))

<?php # costs-functions.php - Stuff that's includes by cost-calculator.{nl,en}.phtml
/**
 * Just remember that this code was never meant to be general purpose or anything.
 * So, relaxeeee and keep your OO-axe burried where it belongs.
 * Oh, if only PHP would support GOTO's ... Sigh ...
 */

The rest of the file is just a whole lot of processing of form data and turning it into something that can be easily traversed for display to the user. There are even the function calls without arguments doing all their work on globals. These are actually only added to make it clearer em a piece of code is doing. And—I must say—after a few years it’s still remarkably clear to me what each part of the code is doing. There’s no deep, confusing nesting structures or anything. There’s just a whole lot of very simple code.

Some simple AHAH increases form interactivity

Users of the calculator can add any number of plantings and locations. When the user decides to add a planting or a location, the onClick event triggers the execution of addExtraPlanting() or addExtraLocation(). Here’s how addExtraPlanting() looks:

function addExtraPlanting() {
  lang = document.documentElement.lang;
 
  new Ajax.Updater(
    'plantings', '/inc/planting.' + lang, {
      method: 'get',
      insertion: Insertion.Bottom
    }
  );
}

Ajax.Updater comes from the Prototype JavaScript framework.

Here’s what inc/planting.en.phtml looks like. The same file is also included in a loop to rebuild the form’s state after submitting.

<li>
  <input name="num_hectares[]" type="text" size="5" value="<?php echo $num_hectares ?>" />
 
  hectares have been planted in
 
  <select name="plant_years[]"><?php require('planting_options.php') ?></select>
 
  (<a title="Remove this planting" href="#" onclick="removePlanting(this); return false;">x</a>)
</li>

I think that I’ve gone into small enough detail by now to get to the conclusion. Also showing the contents of planting_options.php would be pushing it. Ah, well…

<?php
 
if ( !isset($this_year) ) $this_year = intval(date('Y'));
if ( !isset($plant_year) ) $plant_year = $this_year;
 
for ($i = $this_year; $i >= $this_year - 20; $i--)
  echo "<option" . ($i == $plant_year ? " selected='1'" : "") . ">$i</option>\n";

(Yesterday, I couldn’t resist the temptation of turning this into a simple file to require() instead of the function definition it was. I think it’s funny to refactor something to remove encapsulation.)

Conclusion

As is usual when looking at old code, I see many things that I’d do (even just a little) different today, but I saw a surprising number of solutions that I actually still like now that I see them back after three years. Removing some of the remaining warts probably won’t do much good besides the masturbatory satisfaction it could give me. (It’s likely that the website won’t live much longer, making such extra attention very undeserved.) But, nevertheless, I’ve enjoyed blogging about it now to recoup the whole experience and to at least look at what I’d do different now and what I learned in the meantime.

Some links

XKB compose sequences

I just ended a post about inserting special characters in VIM with the remark that I should find out how to insert special punctuation marks using just XKB, so I set out to find out how to add these to the list of existing compose options for XKB. Turns out that I should have simply taken another look at the configuration file for Compose mode (/usr/X11R6/share/X11/locale/en_US.UTF-8/Compose on my system).

Now I learned how to easily type a bunch of characters that I find myself using so often that I know their Unicode numbers by heart. This going to save my a ton of time and annoyance, and there’s no longer any need to remember the VIM digraphs either, although these were equally easy to remember.

Char.XMLHTMLXKB compose
&#8212;&mdash;Compose - - -
&#8211;&ndash;Compose - - .
&#8230;&hellip;Compose . .
&#8216;&lsquo;Compose < '
&#8217;&rsquo;Compose > '
&#8220;&ldquo;Compose < "
&#8221;&rdquo;Compose > "

VIM tips for editing prose

I was transcribing a draft for a manuscript. Using VIM, of course. But, I found my VIM skills to be lacking somewhat, enough to become sufficiently annoyed to investigate the holes.

Word wrapping

The first thing that I wanted to learn to remember was how to control word wrapping and, especially, how to rewrap text.

I had noticed already that on my current machine, VIM enables word wrapping by default for .txt files. I liked this, except I had forgotten long ago (or never properly remembered) how to rewrap lines. This can be done with gq. gq operates on the current selection or on the argument (a number of words/characters/sentences/paragraphs/etc).

Soon, I decided to turn my .txt into a simple TeX file (to be able to add annotations using TeX comments). This disabled the word wrapping, so I had to find the setting to control this. There's actually two settings:

  • wrapmargin defines how close the text may approach the right edge of the VIM window before it starts wrapping,
  • whereas textwidth tells VIM to start wrapping when a fixed number of characters is approached.

Because VIM doesn't do wrapping by default for .tex files, I added the following modeline to the bottom of my draft:

% vim: set textwidth=80 spelllang=nl:

Note that I find 80 characters way too small for most programming tasks, but very convenient as a width for reading prose from a screen. On occasion, I've even used width: 80ex; in the CSS of a website.

Sentences and paragraphs

A few movement commands that I've never used enough to remember well are {/} and (/). } and { are used to move a paragraph forward or backward, respectively;) and ( are used to move a whole sentence forward or backward. This is particularly useful while editing prose.

To quickly select a paragraph, for example, you can easily move to the beginning of the paragraph using {, press v to start a selection and go to the end of the paragraph with } (or type 2} to also select the next).

If you want to delete a sentence, go to the start of the sentence (using either ( or )) and type d). It’s as easy as that.

If deleting the sentence fucked up the formatting of your paragraph, reformat by going to the beginning of the paragraph and typing gq}.

Proper punctuation and other special characters

TeX offers a method to construct special characters using plain ASCII source files. In the past, in my inability to properly configure everything for UTF-8, I’ve often made use of this. In TeX, \'e will be turned into é, \"i into ï, etc. This can be convenient, but it’s much more convenient to have an environment that’s properly configured for UTF-8. To enter special characters on my US keyboard layout (standard in The Netherlands), I’ve added compose:ralt to my XKB options. Using this option I can press Right Alt followed by a punctuation character, followed by a character to combine it with.

Clearly, constructing special characters on the level of X holds many advantages over having to do this differently for each and every application. This way I can also type in ë in this HTML <textarea> instead of having to type &euml;. (In HTML, it’s actually better to use a numeric character reference, such as &#235; instead of &euml;, because that doesn’t require the loading of the DTD, but that’s another rant altogether.)

If you don’t have an accommodating XKB configuration, it’s still possible to enter the characters directly at the VIM level. In VIM, :help digraph (see also the on-line HTML version) tells you everything about it. In short, use Control+K followed by a punctuation character, followed by a character to compose special characters in a way similar to X.

What’s very nice about VIM’s default setup is that it allows you to also easily create proper opening and closing single and double quotes. In TeX these are traditionally done using combinations of back-ticks (`) and apostrophes ('). TeX’s default behavior can be problematic, a good reason to switch to Unicode.

char.VIM digraphTeX
Ctrl+K, ", 6``
Ctrl+K, ", 9''
Ctrl+K, ', 6`
Ctrl+K, ', 9'

Something else that becomes very easy with VIM’s digraphs is entering proper punctuation characters, such as em/en dashes. These are done by following Ctrl+K with a hyphen and a capital N or M. In TeX these could already be done by simply entering two or three hyphens, but if you prefer it that way, you’re probably better of with the UniCycle plugin for VIM, which I personally don’t dig. Anyway, you’re running out of excuses to let -- appear in your production documents.

char.VIM digraphTeX
Ctrl+K, -, N--
Ctrl+K, -, M---

I have to admit that I’ve waited an awful long time before finding this out. I’m ashamed to tell you that I’ve often gone to Alan Wood’s Unicode resources to look up a character and copy/paste it into an application. 😳 Now, at least I don’t have to further embarrass myself when I’m using VIM.

What remains is to configure XKB in such a way that I don’t need to use VIM digraphs for punctuation. Then I will no longer need to use character references for punctuation at times like these, when I’m typing HTML/XML outside of VIM (or, worse, using copy/paste from VIM into this <textarea>, which I just did :oops:). Let’s see if I can get XKB to compose these using the same combinations as VIM. That is where I’ll continue my quest next time.

PHP fgetcsv() behavior on empty lines

The PHP documentation for fgetcsv() states that A blank line in a CSV file will be returned as an array comprising a single null field, and will not be treated as an error. Here’s a quick demonstration of this behavior.

fgetcsv.php:

<?php
 
while ($fields = fgetcsv(STDIN, 0, ';'))
  print_r($fields);
 
exit(0);

Execute the script and feed it some CSV with empty lines:

php -q fgetcsv.php
"Veld 1";"Veld 2";"Veld 3";;"Veld 5"
 
"Field 1";;"Field 3";"Field 4";
;;;;
;"Campo 2";;;"Campo 5"

After pressing Ctrl+D, I’m presented with the following output:

Array
(
    [0] => Veld 1
    [1] => Veld 2
    [2] => Veld 3
    [3] => 
    [4] => Veld 5
)
Array
(
    [0] => 
)
Array
(
    [0] => Field 1
    [1] => 
    [2] => Field 3
    [3] => Field 4
    [4] => 
)
Array
(
    [0] => 
    [1] => 
    [2] => 
    [3] => 
    [4] => 
)
Array
(
    [0] => 
    [1] => Campo 2
    [2] => 
    [3] => 
    [4] => Campo 5
)
Array
(
    [0] => 
)

This behaviour on empty lines is a little bit annoying if you want to test if the line is empty():

$a = array(null);
print_r($a);
 
if ( empty($a) )
  echo '$a is empty';
else
  echo '$a is not empty';
 
echo "\n";

This code will print:

Array
(
    [0] => 
)
$a is not empty

Hence, the following function:

/**
 * This function tests if the given array (as returned by fgetcsv())
 * is the result of an empty line in the CSV file.
 *
 * It does not work for lines that contain only delimiters.
 * From the POV of this function, these are simply records with
 * many empty fields.
 */
function fgetcsv_empty_line($row_array) {
  return ( !isset($row_array[1]) and empty($row_array[0]) );
}

Now, if I change the call to empty() in my test to a call to fgetcsv_empty_line():

$a is empty

Expanded output in MySQL prompt

When you have tables with a large amounts of columns, it can be easy to show the columns vertically, as opposed to horizontally. In Postgresql, you can toggle this with \x. In MySQL it’s a little bit different.

In MySQL you can end your query with a \G instead of a ; and it outputs like this:

select * from permission \G
*************************** 1. row ***************************
 pid: 1
 rid: 1
perm: access content
 tid: 0
*************************** 2. row ***************************
 pid: 2
 rid: 2
perm: access comments, access content, post comments, post comments without approval
 tid: 0

Simple, but I thought I’d blog about it.

Change in law regarding cell phone contracts

Cell phone providers in the Netherlands always try to screw you as hard as they can. The way it was, they were able to automatically extend your contract for another year. The way they screwed you here, is because when you sign up for a new contract, you often get discount. I for instance, was able to get a service worth € 17,50 per month for € 12,50 (240 minutes), the entire year. But, when the contract period would end, my contract would be extended automatically and I would pay € 17,50 per month for a year. You had to remember to call KPN before the contract would end and manually extend the contract to receive another discount.

The change in law is this: they now extend the contract one day, every day after the contract period is over. So, you can easily switch provider after you’ve seen that you suddenly pay € 17,50 instead of € 12,50, or sign up for another subscription at the same provider, or whatever you want to do.

Unfortunately, I couldn’t get the same amount of minutes (240) for € 12,50 again, but this time for € 15,00. For € 12,50 I would have gotten 130 minutes, which is too low. But luckily the guy gave me my first month for free, because I was long-time customer (or so he said), so that saves € 15,00, in other words, 6 months the difference between the 130 and 240 minutes. Yet in other words, I pay € 13.75 per month. I think this is an OK enough deal.

I could go through the hassle to see what kind of discount I get if I switch providers, because providers often give new customers more discount than existing ones, but I also hate that kind of administrative work and the risk of problems when I switch, so I’m happy now.

Setting paper size in Mozilla products

Mozilla products, firefox and thunderbird, seem to have the strange behaviour of overriding the paper size set by the operating system; it scales the page to letter and then prints it to A4.

To fix that, you need to go into about config and set the print_paper_data parameter to 9.

APC CS-500 causes USB disruption

I’m having a EM interference problem with the APC CS-500 UPS on two different locations. Those two locations are near each other and there seems to be something wrong the power grid in that area. Both UPS’s momentarily switch over to battery several times a day. Some of these times, the apcupsd daemon sends a message saying that the communication with the UPS has been restored (and therefore it had been lost at some point).

Here is the syslog of one of those computers with everything but the power failure and EMI notices filtered out:

Aug  7 06:59:10 bitler apcupsd[22622]: Power failure.
Aug  7 06:59:18 bitler apcupsd[22622]: Power failure.
Aug  7 06:59:31 bitler apcupsd[22622]: Power failure.
Aug  7 06:59:35 bitler apcupsd[22622]: Power failure.
Aug  7 13:59:19 bitler apcupsd[22622]: Power failure.
Aug  7 13:59:38 bitler apcupsd[22622]: Power failure.
Aug  7 18:59:11 bitler apcupsd[22622]: Power failure.
Aug  7 18:59:25 bitler apcupsd[22622]: Power failure.
Aug  7 18:59:28 bitler apcupsd[22622]: Power failure.
Aug  7 21:29:12 bitler apcupsd[22622]: Power failure.
Aug  7 21:29:19 bitler apcupsd[22622]: Power failure.
Aug  7 21:29:23 bitler apcupsd[22622]: Power failure.
Aug  7 21:29:51 bitler apcupsd[22622]: Power failure.
Aug  7 21:30:05 bitler apcupsd[22622]: Power failure.
Aug  7 21:30:09 bitler apcupsd[22622]: Power failure.
Aug  7 21:30:12 bitler apcupsd[22622]: Power failure.
Aug  7 21:30:14 bitler apcupsd[22622]: Power failure.
Aug  7 21:35:21 bitler apcupsd[22622]: Power failure.
Aug  7 21:35:29 bitler apcupsd[22622]: Power failure.
Aug  7 21:35:32 bitler apcupsd[22622]: Power failure.
Aug  7 21:35:38 bitler apcupsd[22622]: Power failure.
Aug  7 22:39:11 bitler apcupsd[22622]: Power failure.
Aug  7 22:39:22 bitler apcupsd[22622]: Power failure.
Aug  7 22:39:31 bitler apcupsd[22622]: Power failure.
Aug  7 22:39:35 bitler apcupsd[22622]: Power failure.
Aug  7 22:39:36 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  7 22:59:10 bitler apcupsd[22622]: Power failure.
Aug  7 22:59:25 bitler apcupsd[22622]: Power failure.
Aug  7 22:59:28 bitler apcupsd[22622]: Power failure.
Aug  7 22:59:32 bitler apcupsd[22622]: Power failure.
Aug  7 22:59:37 bitler apcupsd[22622]: Power failure.
Aug  7 23:59:32 bitler apcupsd[22622]: Power failure.
Aug  8 05:51:10 bitler apcupsd[22622]: Power failure.
Aug  8 05:51:21 bitler apcupsd[22622]: Power failure.
Aug  8 05:51:31 bitler apcupsd[22622]: Power failure.
Aug  8 05:51:35 bitler apcupsd[22622]: Power failure.
Aug  8 06:59:24 bitler apcupsd[22622]: Power failure.
Aug  8 06:59:32 bitler apcupsd[22622]: Power failure.
Aug  8 06:59:36 bitler apcupsd[22622]: Power failure.
Aug  8 11:29:11 bitler apcupsd[22622]: Power failure.
Aug  8 11:29:28 bitler apcupsd[22622]: Power failure.
Aug  8 13:59:17 bitler apcupsd[22622]: Power failure.
Aug  8 13:59:22 bitler apcupsd[22622]: Power failure.
Aug  8 13:59:23 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 14:00:19 bitler apcupsd[22622]: Power failure.
Aug  8 18:59:37 bitler apcupsd[22622]: Power failure.
Aug  8 21:27:11 bitler apcupsd[22622]: Power failure.
Aug  8 21:27:16 bitler apcupsd[22622]: Power failure.
Aug  8 21:27:17 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 21:27:25 bitler apcupsd[22622]: Power failure.
Aug  8 21:27:39 bitler apcupsd[22622]: Power failure.
Aug  8 21:29:11 bitler apcupsd[22622]: Power failure.
Aug  8 21:29:13 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 21:29:22 bitler apcupsd[22622]: Power failure.
Aug  8 21:29:25 bitler apcupsd[22622]: Power failure.
Aug  8 21:29:27 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 21:29:37 bitler apcupsd[22622]: Power failure.
Aug  8 21:29:38 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 21:30:20 bitler apcupsd[22622]: Power failure.
Aug  8 21:30:22 bitler apcupsd[22622]: Power failure.
Aug  8 21:30:24 bitler apcupsd[22622]: Power failure.
Aug  8 21:30:28 bitler apcupsd[22622]: Power failure.
Aug  8 21:30:29 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  8 21:30:37 bitler apcupsd[22622]: Power failure.
Aug  8 22:39:11 bitler apcupsd[22622]: Power failure.
Aug  8 22:39:25 bitler apcupsd[22622]: Power failure.
Aug  8 22:39:28 bitler apcupsd[22622]: Power failure.
Aug  8 22:59:11 bitler apcupsd[22622]: Power failure.
Aug  8 22:59:18 bitler apcupsd[22622]: Power failure.
Aug  8 22:59:26 bitler apcupsd[22622]: Power failure.
Aug  8 22:59:28 bitler apcupsd[22622]: Power failure.
Aug  8 22:59:40 bitler apcupsd[22622]: Power failure.
Aug  8 23:59:11 bitler apcupsd[22622]: Power failure.
Aug  8 23:59:22 bitler apcupsd[22622]: Power failure.
Aug  8 23:59:24 bitler apcupsd[22622]: Power failure.
Aug  9 05:54:10 bitler apcupsd[22622]: Power failure.
Aug  9 05:54:21 bitler apcupsd[22622]: Power failure.
Aug  9 05:54:22 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  9 05:54:39 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:10 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:17 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:19 bitler kernel: hub 5-0:1.0: port 1 disabled by hub (EMI?), re-enabling...
Aug  9 06:59:27 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:28 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:32 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:36 bitler apcupsd[22622]: Power failure.
Aug  9 06:59:39 bitler apcupsd[22622]: Power failure.
Aug  9 12:59:22 bitler apcupsd[22622]: Power failure.
Aug  9 12:59:23 bitler apcupsd[22622]: Power failure.
Aug  9 12:59:27 bitler apcupsd[22622]: Power failure.
Aug  9 13:59:24 bitler apcupsd[22622]: Power failure.
Aug  9 13:59:28 bitler apcupsd[22622]: Power failure.
Aug  9 13:59:34 bitler apcupsd[22622]: Power failure.

As you can see, all the EMI notices correspond exactly with the UPS switching over to battery; all the EMI notices are 1 or 2 seconds after the power failure notice, without exception. And no, I didn’t just show the EMI notices that suit me; these are all of them.

APC suggested it might have something to do with the 3rd party software (because they don’t support Linux themselves), but that’s ridiculous of course. The software doesn’t have the ability to command the UPS to switch over to battery, so the order of events has to be that the UPS switches and that the USB hub is disrupted by that. This is exactly the order of events the logs show.

I think this problem is common in the CS type of UPS’s and perhaps in other models as well and that just because of the frequent switching it shows more often. I still have to find out whether it’s the proximity of the UPS to the computer or if the EMI is traveling over the USB cable. Putting the UPS about a meter below the machine didn’t help, anyway.

One very big problem with this situation is that I can’t reliably connect a USB hard disk to the system for backups. The filesystem and the data on it will not take kindly to connection interrupts.

« Older posts Newer posts »

© 2024 BigSmoke

Theme by Anders NorenUp ↑