Smokes your problems, coughs fresh air.

Category: Technology (Page 47 of 47)

Scaling bitmap graphics versus scaling vector graphics

Due to some organizational changes, past December, I had to remove the S.A. suffix from the Sicirec logo:

Sicirec logo with “S.A.” - scaled some time earlier
The original logo with the “S.A.” suffix intact.

After removing the S.A. suffix from the vector file in Illustrator’s vector format, I wanted to export the logo to a small PNG again. Annoyingly, though, the PNG—if I wanted Illustrator to respect the correct aspect ratio—could not be the same width as the original PNG if I gave it the same height; it would always be one pixel higher. If, however, I exported it as a huge PNG corresponding to the vector’s original dimensions and scaled it down in The GIMP, the dimensions turned out about the same.

It was then that I noticed that The GIMP’s scaling algorithm is actually very decent. From just looking at the two images below, you need a moment or two to notice that one is a little sharper than the other. Obviously, that’s the Illustrator version.

Sicirec logo without “S.A.” - scaled in The GIMP Sicirec logo without “S.A.” - scaled in Adobe Illustrator

In the end, though, neither version integrated easily with the complex layout which I had based around the logo image, so I simply opened the existing PNG image in The GIMP and erased the S.A. suffix.

Sicirec logo with the “S.A.” suffix removed in The GIMP
The original PNG after the GIMP treatment.

I still don’t understand why I couldn’t repeat the scaling result of the original image in Illustrator. But, I’ve probably wasted enough time on a rounding issue that isn’t even an issue…

Apache’s ForceType directive overrides AddCharset directives

Yesterday, after uploading a refreshed www.sicirec.org, some character encoding issues popped up because I had converted the website’s content from ISO-8859-1 (Latin 1) to UTF-8. (I wanted to be able to type and paste special characters from PuTTY into VIM without worrying about the particular encoding of each file.)

The Apache HTTPD at InitFour, our webhosting provider, is configured to send ISO-8859-1 by default, while the one on our test server is configured for UTF-8. This caused a little bit of a surprise when I uploaded the refreshed website and saw all characters outside the ASCII range mangled on the life website!

I quickly dug into my .htaccess file to add the AddCharset utf-8 .xhtml directive. To my surprise, this didn’t do squat. A lot of fiddling, reloading and researching later, I realized that the following section in my .htaccess file rendered the AddCharset directive irrelevant:

<Files *.xhtml>
ForceType text/html
</Files>

I had to change the ForceType directive to include the charset as a MIME parameter:

<Files *.xhtml>
ForceType 'text/html; charset=UTF-8'
</Files>

Now, it all seemed to work. (Except that it didn’t really because I do some ridiculously complex content negotiation stuff involving a 406 handler in PHP that virtuals the most appropriate variant when no match is found. This script didn’t send a useful Content-Type header. After first adding it to the script, I noticed that the AddDefaultCharset is actually allowed in .htaccess context—a discovery which luckily rendered the other hacks useless.)

Replacing the trunk of a Subversion repository with a feature branch

For the Sicirec website, I use Subversion to track all changes. When working on big changes which take more than a day to implement, I follow the Feature Branches branching pattern. This pattern means that the trunk remains relatively stable and usable for everyday updates while I can climb in a feature branch whenever I want to work on the big new feature(s).

Subversion’s merge tracking is non-existent. This means that, when I climb from branch to trunk and back again a lot, I have to manually keep track of all the changes in trunk/ that I merged into the branch. Every one such change, once merged, loses much of its meaningful history unless I painstakingly merge all the commit messages of the patch into the message of the commit that I do after the merge.

Today, after having maintained a branch for months to keep it somewhat in sync with an every-changing trunk, I’m at the point of having to merge the branch back into trunk. This is rather nightmarish because there are bound to be the many merge conflicts that I already suffered whenever merging changes from the trunk into the branch and then multiplied some.

To avoid torture, I decided I’d rather just replace the trunk with my feature branch. This is especially attractive because I then retain the history of the branch which is a little more useful to me than the history of the trunk.

I googled around a bit and could find one thread discussing a similar problem. The solution proposed there seemed to involve a few too many steps for my taste, so I did the following:

# From the working copy of my branch:
$ svn del file:///repos/trunk -m "Temporarily deleted trunk."
$ svn mv file:///repos/branches/my_branch file:///repos/trunk -m "Moved /branches/my_branch to /trunk"
$ svn switch file:///repos/trunk 

That worked perfectly fine. (Except that I still want automatic merge tracking, dammit!)

Nested hashes derail Rails’ url_for helpers

While working on the Sicirec PostgreSQL database front-end today, I had to pass a lot of nested parameters to a link_to helper in Rails. Software being what it is, this didn’t work.

There are a few patches awaiting acceptance. The most promising of these patches was part of an open Trac ticket. Because we use Rails as an svn external, applying the patch myself wouldn’t work when deploying unless I’d create a vendor branch for Rails in our own repository. Hoping that someone had forgotten to close the ticket, I first tried to upgrade to Rails 1.2.2, which was about time anyway because we were still in the 1.1 branch. The upgrade went fine but didn’t fix the problem.

Next, I tried to integrate the patch by redefining the methods changed by the patch in our lib/ directory. When this didn’t work, I decided to simply do some flattening of the hash myself for this one particular case.

A bit of googling around gave me many clues that the problem has cost a lot of people lots of time already.

Eventually, I settled with a derivate of some code by Peter Marklund to flatten my hashes:

class Hash
  # Flatten a hash into a flat form suitable for an URL.
  # Accepts as an optional parameter an array of names that pretend to be the ancestor key names.
  #
  # Example 1:
  #
  #   { 'animals' => {
  #       'fish' => { 'legs' => 0, 'sound' => 'Blub' }
  #       'cat' => { 'legs' => 4, 'sound' => 'Miaow' }
  #   }.flatten_for_url
  #
  #   # => { 'animals[fish][legs]'  => 0,
  #          'animals[fish][sound]' => 'Blub',
  #          'animals[cat][legs]'   => 4,
  #          'animals[cat][sound]'  => 'Miaow'
  #        }
  #
  # Example 2:
  #
  #   {'color' => 'blue'}.flatten_for_url( %w(world things) )  # => {'world[things][color]' => 'blue'}
  #
  def flatten_for_url(ancestor_names = [])
    flat_hash = Hash.new
 
    each do |key, value|
      names = Array.new(ancestor_names)
      names << key
 
      if value.is_a?(Hash)
        flat_hash.merge!(value.flatten_for_url(names))
      else
        flat_key = names.shift.to_s.dup
        names.each do |name|
          flat_key << "[#{name}]"
        end
        flat_key << "[]" if value.is_a?(Array)
        flat_hash[flat_key] = value
      end
    end
 
    flat_hash
  end
end

As you can see, I turned my code into a single method of the Hash class. It can be used simply in any url_for (based) call as in the following example:

url_for {
    :controller => 'post',
    :action => 'new',
    'author' => {'name' => 'Rowan', 'gender' => 'm'}
  }.flatten_for_url
  # => /post/new?author[name]=Rowan&author[gender]=m 

Now if only some Rails developer would commit the patch already.

Automatic resizing of an HTML <textarea> element

Today, while improving the Rails GUI for the Sicirec database, I was struck once again by how annoyingly small <textarea>s can be when having the user type lots of text.

I had already seen the ideal solution when commenting on Laurelin’s waarbenjij.nu weblog. Although their response box is much too narrow, the height of the box auto-adjusts to the amount of text typed. I decided to borrow their code and amend it slightly for our own use. Differences are:

  • My code works with Opera, but is untested in IE because we don’t feel the need to support IE for an internal application.
  • In our DB, notes will often be shortened, so my code also shrinks the textarea when the text shrinks. The function remembers the original number of rows set in the source and will never shrink past that number.
userAgentLowerCase = navigator.userAgent.toLowerCase();
 
function resizeTextarea(t) {
  if ( !t.initialRows ) t.initialRows = t.rows;
 
  a = t.value.split('\n');
  b=0;
  for (x=0; x < a.length; x++) {
    if (a[x].length >= t.cols) b+= Math.floor(a[x].length / t.cols);
  }
 
  b += a.length;
 
  if (userAgentLowerCase.indexOf('opera') != -1) b += 2;
 
  if (b > t.rows || b < t.rows)
    t.rows = (b < t.initialRows ? t.initialRows : b);
}

The function can easily be added to the onkeyup and onmouseup event handlers of a <textarea> element as in:

<textarea cols="60" rows="4"
          onkeyup="resizeTextarea(this)"
          onmouseup="resizeTextarea(this)"></textarea>

I didn’t add it inline as in the example, though. I used Ben Nolan’s Behaviour Javascript library to tie things together a little more cleanly.

Using an outgoing SSH tunnel from behind a NAT for incoming VNC

Laurelin is working as an Au Pair for a Greek family in—where else than Greece. Her hostess has arranged for an Internet connection through Vivodi Telecom to allow Laurelin to maintain some form of contact with her friends and family at home.

Once connected, Laurelin quickly installed the Azureus BitTorrent client to be able to download some things (only legal things licensed under a liberal license, of course). Correct usage of the BitTorrent protocol implies opening up a port or two for incoming connections. After all, BitTorrent is all about sharing.

So, she needed help configuring port forwarding on the ADSL modem / NAT router (a microcom AD 2636) in Greece. She asked for this help two days ago while Wiebe was looking at my screen, because we where doing an extreme programming session on a database schema using VNC and Skype. We interrupted our work hoping that we could easily solve her problem.

I had been looking at screenshots and manuals of her router and her modem’s administrative interface earlier when they couldn’t get the connection to work. After making sure that the problem was not a configuration or software problem and identifying that there was probably a problem between their modem and their telephone exchange, they later got their problem fixed. So, now I had to dig up the manual again. But, this time I could only find some screencaps which accompanied a useless tutorial in Greek. This exemplifies why I think it is useful to keep a blog.

So, Wiebe and I did our best to guide her through a GUI we couldn’t see and eventually she succeeded in defining a few forwards. However, they didn’t do their job. According to nmap they were still filtered. She then installed RealVNC server for us and added port 5900 to the list of forwarded ports. Wiebe tried to connect using the kvnc client, but no response. By that time, we had fooled around quite a bit and after mucking about a little more, we decided to postpone the rest and return to our database design. We decided for next time to let her use PuTTY to put a hole through the NAT router.

Today was the next time. She installed PuTTY. I gave her an account on the Debian server in our local LAN (I am behind a Windows terminal myself). Now she had to set up a tunnel and connect to that account:

Configuring a remote tunnel for VNC in PuTTY

At this point, I still couldn’t access the tunnel between her box and the Debian machine from my Windows terminal:

$ netstat -l -n|grep 5900
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 127.0.0.1:5900          0.0.0.0:*               LISTEN

Since PuTTY was configured to let remote ports accept connections from other hosts, the problem had to be in the OpenSSH configuration on the Debian box. And indeed it was. I had to set the following option:

GatewayPorts yes

After a restart of the OpenSSH daemon, she opened a tunnel which I could access from my own machine:

$ netstat -l -n|grep 5900
Proto Recv-Q Send-Q Local Address           Foreign Address         State
tcp        0      0 0.0.0.0:5900            0.0.0.0:*               LISTEN

I could now control her desktop through the RealVNC viewer. Next time, I’ll need to actually do something with this connection.

Using the standard HTML link colors

Occasionally, I have to foray into web design. From the look of this blog you can deduce that I’m not really into the design part of web design. First and foremostly this is because I suck at graphics and colors. But another reason is that I assume that people visit my blog to read some text and not to look at the fancy graphical borders and background of that text.

Recently I’ve gotten into the habit of simply using the default HTML link colors instead of trying to come up with a comprehensible color scheme for each design. This means that my links are blue, my visited links are purple and my active links are red as in the example CSS snippet below.

a:link {
 :;     /* #00f */
}
a:visited {
 :;   /* #800080 */
}
a:active {
 :;      /* #f00 */
}

Related links

Unique constraints and indexes in PostgreSQL

This afternoon, I had to add a unique index for some table in the Sicirec PostgreSQL database. I had already assumed that I needed to use CREATE UNIQUE INDEX to create my new unique index until I noticed, thanks to pgAdmin‘s clear GUI, that some tables clearly had unique constraints and unique indexes while one table lacked a unique constraint and only had an unique index defined.

This motivated me to take a closer look at PostgreSQL’s documentation on unique indexes:

Note: The preferred way to add a unique constraint to a table is ALTER TABLE ... ADD CONSTRAINT. The use of indexes to enforce unique constraints could be considered an implementation detail that should not be accessed directly. One should, however, be aware that there’s no need to manually create indexes on unique columns; doing so would just duplicate the automatically-created index.

Grepping for CREATE UNIQUE INDEX in our migration history quickly revealed that the index which lacked an accompanying constraint was indeed created by CREATE UNIQUE INDEX instead of by ALTER TABLE ... ADD CONSTRAINT. So, now I know that, indeed, I have to use ALTER TABLE ... ADD CONSTRAINT instead of CREATE UNIQUE INDEX to add unique constraints with accompanying indexes to existing tables.

Rowan Rodrik van der Molen

Beginning

Norg, on an April the 8th in 1982: It was around 18:45 when my mother’s physician arrived, leaving his dessert untouched at home, just in time to witness my birth. (I was my mother’s fourth already and she never took much time between anouncing a birth and giving birth.) Without much further ado, I was delivered into this world as a sacky, slow, little fellow. So slow, in fact, that it was wondered by some (not my mom) if I wasn’t suffering Down Sydrome or something similar.

Name

My father’s family name was van der Molen. This is what I inherited. To make me uniquely identifyable within our family, I was given a first name, Rowan. To also make things a little symmetrical, a middle name, Rodrik, was added some years later.

This is me, in 2004, copy-pasted between some rowan berries.

This is me, in 2004, copy-pasted between some rowan berries.

Geek Code

-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GCS/IT/LS/MC/SS/TW d-(+) s:++ a? C++$ UL+++$ P++$ L+++$ E--- W+++$ N++ o K-
w---$ O? M->+ V? PS+++ !PE Y+ PGP-(++) t 5 X R(-) !tv b++@ Dl D G !e- !h !r
y-(---)**
------END GEEK CODE BLOCK------

Hacker Key

I like to call myself a [Hacker glider button]

v2sw6+9$Phw5+7ln6pr7$Ock4+9ma2+9u8$LFw2+1$WTm5g/l7$Di2e0/2t2b7OHTen6+8g2HPaIs1SMr1p8  hackerkey.com

Wiebe Hedde Cazemier

If you’re into Open Source software, 3D modeling or Do It Yourself audio, you may already know Wiebe under his on-line alias, Halfgaar. Personally, I’ve known him since I was 10 and he was 9. These days he’s still a very good friend, and even a colleague.

His Ferrari F50, not your usual lawn decoration.

His Ferrari F50, not your usual lawn decoration.

Strongly straight-forward

As a very analytical, factual thinker, Wiebe is the kind of person who doesn’t run with the newest buzzwords. He simply says what he thinks and his thoughts usually follow from very sound and steady logic. As a programmer, this makes him invaluable. At times, as a human, this may make him hard to stomach if, as is usual, he is right and you are not. But, don’t worry: he will usually be kind enough to explain to you exactly—very exactly—why it is that you are wrong.

So, he may not be the type for marketing, but for anything that needs to be done robustly and thoroughly, he is irreplaceable.

Solid knowledge

  • System administration: As every Geek with family and friends, Wiebe has the obligatory knowledge of how to keep a network of Windows systems somewhat stable, but this knowledge is irrelevant compared to his experience and skill in Unix system administration. His favourite Linux distribution is Gentoo Linux and, as follows from his many posts to the Gentoo Forums, he is a Linux Guru indeed.

  • Backups: even to most system administrators, they’re just an afterthought, but he really knows his dar backups from your tar’s. And, he’s published about it too.

  • Audio-engineering requires an enormous level of insight in the complex dynamics of audio waves and electronics. To me, it’s mostly Chinese, but he has built his own amps, speakers and subwoofer. If he notices even the slightest artifact in the sound, he goes back to the drawing board and just redoes the circuits another time.

Learn more

Wiebe can be contacted at wiebe@halfgaar.net, unless if you’re a spammer, because he happens to be an expert-level SpamAssassin administrator.

Web presence

Newer posts »

© 2025 BigSmoke

Theme by Anders NorenUp ↑