<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Connection Endpoint</title>
	<atom:link href="http://connection-endpoint.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://connection-endpoint.de</link>
	<description></description>
	<lastBuildDate>Sun, 19 Feb 2012 12:45:25 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.2</generator>
		<item>
		<title>Highly available Samba on Ubuntu 8.04</title>
		<link>http://connection-endpoint.de/2009/10/03/highly-available-samba-on-ubuntu-8-04/</link>
		<comments>http://connection-endpoint.de/2009/10/03/highly-available-samba-on-ubuntu-8-04/#comments</comments>
		<pubDate>Sat, 03 Oct 2009 18:28:42 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/?p=149</guid>
		<description><![CDATA[This is something I worked on over the last few days. I was confronted with a particular network infrastructure, where a central Samba fileserver stores all important business data. Of course there is a working backup strategy, however &#8211; that server being a single point of failure &#8211; the situation wasn&#8217;t quite optimal. Usual failure [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://www.flickr.com/photos/vonkinder/318622997/"><img src="http://connection-endpoint.de/wordpress/wp-content/uploads/2009/09/318622997_407407d29c_m.jpg" alt="Wired by vonKinder" title="Wired by vonKinder" width="150" height="100" class="alignright size-full wp-image-151" align="right" /></a><br />
This is something I worked on over the last few days. I was confronted with a particular network infrastructure, where a central Samba fileserver stores all important business data. Of course there is a working backup strategy, however &#8211; that server being a single point of failure &#8211; the situation wasn&#8217;t quite optimal. Usual failure recovery times where as long as 2 days over which the critical data was only partly available. Thus the idea was born to move Samba onto a <a href="http://en.wikipedia.org/wiki/High_availability">high availability</a> setup. It&#8217;s implemented as a two-node cluster using Ubuntu 8.04 Server Edition, <a href="http://www.drbd.org/">DRBD</a> and <a href="http://www.linux-ha.org/">Hearbeat</a>.</p>
<p>In this article I will guide you through all the necessary steps to implement such sytem.<br />
<span id="more-149"></span></p>
<h1>Introduction</h1>
<p>I&#8217;ve already mentioned that the two important pieces of software for this project are DRBD and heartbeat. DRBD (Distributed Replicated Block Device) is comparable to RAID 1 in that it replicates write operations on a block device to another block device, thereby introducing redundancy. In contrast to a RAID array however, DRBD works over a TCP/IP network so your drives don&#8217;t have to be attached to the same machine.<br />
But that&#8217;s only for the storage part. There&#8217;s not much use in having a highly available storage device when all running services are down in case of a failure. This is where heartbeat comes into play.<br />
Heartbeat is a high-availability solution that detects server outages and can automatically restart the affected services on another node of the cluster. In fact heartbeat has out of the box support for DRBD devices, so using the two together is a popular choice. Heartbeat uses a so called heartbeat-network to send small special messages (&#8220;hearbeats&#8221;) to the other cluster nodes which basically is interpreted as &#8220;I&#8217;m still up and running, so there&#8217;s no need for you to take over any of my services&#8221;.</p>
<p>For this project we need two physical seperate computers with two NICs each and one free partition that should be about the same size on each of the nodes. Throughout the article I will use the following conventions:</p>
<ul>
<li><strong>master-server</strong> &#8211; (host)name of the master node, that is the server that should normally run our samba and DRBD services</li>
<li><strong>slave-server</strong> &#8211; (host)name of the slave node that takes over if the other one goes down</li>
<li><strong>eth0</strong> &#8211; NIC connected to the normal intranet</li>
<li><strong>eth1</strong> &#8211; connection to the heartbeat network</li>
<li><strong>10.0.0.1</strong> &#8211; fixed IP of the master-node in the company intranet (eth0)</li>
<li><strong>10.0.0.2</strong> &#8211; same for the slave-node</li>
<li><strong>10.0.0.5</strong> &#8211; this is a highly available IP that can switch between the nodes; usual clients (such as SMB clients) should only use this IP to contact the services</li>
<li><strong>10.0.1.1</strong> &#8211; master-servers IP in the heartbeat network</li>
<li><strong>10.0.1.1</strong> &#8211; same for slave-server</li>
</ul>
<p>Of course you&#8217;ll have to adapt these values in your specific environment.</p>
<h1>Basic setup</h1>
<p>The following steps are nearly identical for both nodes; there&#8217;s only one tiny difference in the network interface configuration.<br />
First of all let&#8217;s install the two packages we use as a base &#8211; DRBD and Heartbeat.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">$ apt-get install heartbeat drbd8-utils</pre></div></div>

<p>We don&#8217;t have to install the DRBD driver as it is already part of the standard Ubuntu 8.04 Server installation. Now we have to check that both nodes have their heartbeat network interfaces configured correctly. As stated earlier, on my setup I use eth1 for the heartbeat interfaces.</p>
<p>As we want a static ip address automatically assigned to the interface on each startup, we have to add the following lines to <strong>/etc/network/interfaces</strong></p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">auto eth1
iface eth1 inet static
  address 10.1.1.1
  netmask 255.255.255.0</pre></div></div>

<p>If there already was a section for eth1, you&#8217;ll have to replace that. Note that 10.1.1.1 is the ip address for the master node. Change that value to 10.1.1.2 on the slave. The next step is to add the nodes in <strong>/etc/hosts</strong> so they can be properly resolved.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">10.1.1.1    master-server.domain.tld  master-server
10.1.1.2    slave-server.domain.tld  slave-server</pre></div></div>

<h1>DRBD</h1>
<h2>Both nodes</h2>
<p><strong>/etc/drbd.conf</strong> is where all DRBD configuration is done. It&#8217;s important to keep this file identical on both nodes, in our example we will use the following content:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">resource r0 {
  # protocol to use; C is the the safest variant
  protocol C;
&nbsp;
  startup {
    # timeout (in seconds) for the connection on startup
    wfc-timeout       120;
    # timeout (in seconds) for the connection on startup
    # after detection of data inconsistencies (&quot;degraded mode&quot;)
    degr-wfc-timeout  120;
  }
&nbsp;
  syncer {
    # maximum bandwidth to use for this resource
    rate 100M;
  }
&nbsp;
  on master-server {
    ### options for master-server ###
    # name of the allocated blockdevice
    device     /dev/drbd0;
    # underlying blockdevice
    disk       /dev/sdc1;
    # address and port to use for the synchronisation
    # here we use the heartbeat network
    address    10.1.1.1:7788;
    # where to store DRBD metadata; here it's on the underlying device itself
    meta-disk  internal;                 
  }
&nbsp;
  on slave-server {
    ### options for slave-server ###
    device     /dev/drbd0;
    disk       /dev/sdc1;
    address    10.1.1.2:7788;
    meta-disk  internal;
  }
}</pre></div></div>

<p>Replace <strong>master-server</strong> and <strong>slave-server</strong> with the appropriate hostnames of your setup.<br />
Now we&#8217;ll load the kernel module and add DRBD to the default runlevels:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">modprobe drbd
echo 'drbd' &gt;&gt; /etc/modules
update-rc.d drbd defaults</pre></div></div>

<p>Setting up a new DRBD resource requires explicit ceation of it, so let&#8217;s do that now.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">/etc/init.d/drbd restart
drbdadm create-md r0
drbdadm up r0</pre></div></div>

<p>Ignore errors and warnigs, as we will check the correct operation with</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">cat /proc/drbd</pre></div></div>

<p>If everything is up and running, that command should print out something like this:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">version: 8.0.11 (api:86/proto:86)
GIT-hash: b3fe2bdfd3b9f7c2f923186883eb9e2a0d3a5b1b build by phil@mescal, 2008-02-12 11:56:43
 0: cs:Connected st:Secondary/Secondary ds:Inconsistent/Inconsistent C r---
    ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0
        resync: used:0/31 hits:0 misses:0 starving:0 dirty:0 changed:0
        act_log: used:0/127 hits:0 misses:0 starving:0 dirty:0 changed:0</pre></div></div>

<h2>Master node</h2>
<p>Initially DRBD doesn&#8217;t know which of the nodes should be primary, that&#8217;s why they are marked as &#8220;Inconsistent&#8221;. We have to force one of the nodes to be primary &#8211; in our case that will be master-server.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">drbdadm -- -o primary r0</pre></div></div>

<p>The synchronization should then start immediately, you can check its progress with <strong>cat /proc/drbd</strong>. After that we are now ready to format the new DRBD block device:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">mkfs.ext3 /dev/drbd0</pre></div></div>

<p>Mounting functions ust like with any other device, do a <strong>mount /dev/drbd0 /data</strong> if you want to test the setup, but <strong>do not</strong> add an entry into <strong>/etc/fstab</strong>, because heartbeat will mount the device later on.</p>
<h1>Heartbeat</h1>
<h2>Both nodes</h2>
<p>First of all put the following in /etc/ha.d/authkeys (this file <strong>must</strong> be chmod 600):</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">auth 1
1 crc</pre></div></div>

<p>In /etc/ha.d/haresources we will list all the resources that we want to be highly available (amongst others those are the DRBD device and the Samba service).</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">master-server 10.0.0.10/24/eth0 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext3 samba</pre></div></div>

<p>This line says, that master-server is the preferred node for all of the listed resources</p>
<ul>
<li>the IP address 10.0.0.10 with netask /24 on interface eth0 (that interface has to be brought up by other means, typically by listing it in /etc/network/interfaces)</li>
<li>the DRBD device r0</li>
<li>a filesystem-mount; namely /dev/dbd0 will be mounted to /data</li>
<li>the Samba service</li>
</ul>
<p>All ressources on one line will be started one after another as it&#8217;s assumed that each one depends on the ressources listed before it. When the master node fails, the slave will take over all of those ressources and if we choose to do an automatic failback, master-server will then again take over when it&#8217;s recovered later on.</p>
<h2>Master node</h2>
<p>Into <strong>/etc/ha.d/ha.cf</strong> put the following content:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">auto_failback   on
ucast           eth1 10.1.1.2
node            master-server slave-server
keepalive       2
deadtime        8</pre></div></div>

<ul>
<li>auto_failback &#8211; whether the master node will become master after it becomes available again</li>
<li>ucast &#8211; on which interface and ip to reach the partner node</li>
<li>node &#8211; simply lists all nodes of the cluster</li>
<li>keepalive &#8211; how often to send a heartbeat signal (every 2 seconds in this case)</li>
<li>deadtime &#8211; time after which the other node will be assumed to be dead</li>
</ul>
<h2>Slave node</h2>
<p><strong>/etc/ha.d/ha.cf</strong> is quite similar we only have to change the ucast address.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">auto_failback   on
ucast           eth1 10.1.1.1
node            master-server slave-server
keepalive       2
deadtime        8</pre></div></div>

<h1>Samba</h1>
<p><em>The following steps apply to both nodes.</em><br />
To make Samba highly available, we have to recall, that heartbeat should be in charge of starting / stopping the service. Therefor we have to remove Samba from the normal, runlevel-based, state management. Let&#8217;s do that first:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">$ update-rc.d -f mysql remove</pre></div></div>

<p>Now we have to put heartbeat in charge of controlling Samba. Open up <strong>/etc/ha.d/haresources</strong> again and <strong>replace</strong> the line we put there in the DRBD part with the following one:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">master-server 10.0.0.10/24/eth0 drbddisk::r0 Filesystem::/dev/drbd0::/data::ext3 samba</pre></div></div>

<p>See that little &#8220;samba&#8221; at the end? That tells heartbeat to take care of Samba in case of a resource takeover. You could actually add other things like mysql there, too. Heartbeat just takes any command and invokes <strong>/etc/init.d/ANY_COMMAND start|stop</strong>.<br />
Now we have to make sure that both nodes use the same netbios name so that shares stay available after a resource takeover. As a bonus I like to restrict Sambda to only listen on the highly available ip address. Here is what we have to add to <strong>/etc/samba/smb.conf</strong> in the [global] section:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">[global]
# ...
  netbios name = hv-samba
  interfaces = 10.0.0.10/24
  bind interfaces only = true
# ...</pre></div></div>

<p>The final step is just an easy example for a Samba share that uses the DRBD device, which is mounted at <strong>/data</strong>. Add the following lines to <strong>/etc/samba/smb.conf</strong>:</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">[myshare]
  path = /data
  guest ok = yes
  read only = no
  browsable = yes</pre></div></div>

<h1>A few notes</h1>
<p>It&#8217;s certainly useful to be notified somehow if a resource takeover takes place. I will demonstate here how that can be achieved via email.</p>
<h2>Email notification</h2>
<p>To get an email notification if master-server fails (and slave-server takes over the resources), we will use the simple smtp client &#8220;msmtp&#8221; which provides a sendmail interface. The version provided in the standard hardy repositories has a bug when used with TLS certificates, thus I installed it from the backport repository.<br />
We&#8217;ll also need mailx, a non-interactive command line mailclient.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">$ wget http://de.archive.ubuntu.com/ubuntu/pool/universe/m/msmtp/msmtp_1.4.16-1~hardy2_i386.deb
$ wget http://de.archive.ubuntu.com/ubuntu/pool/universe/m/msmtp/msmtp-mta_1.4.16-1~hardy2_all.deb
$ dpkg -i msmtp_1.4.16-1~hardy2_i386.deb msmtp-mta_1.4.16-1~hardy2_all.deb
$ apt-get -f update
$ apt-get install mailx</pre></div></div>

<p>Now we need to edit <strong>/etc/msmtprc</strong>. You&#8217;ll have to replace all example values with some real smtp account credentials.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">defaults
tls on
tls_certcheck off
tls_min_dh_prime_bits 512
&nbsp;
account myaccount
host smtp.myprovider.tld
from myaddress@myprovider.tld
auth on
user SMTP_USER
password SMTP_PASSWORD
&nbsp;
account default : myaccount</pre></div></div>

<p>See the <a href="http://msmtp.sourceforge.net/doc/msmtp.html">msmtp manpage</a> for more details.</p>
<p>At last, append the following line to <strong>/etc/ha.d/haresources</strong>. If you don&#8217;t want to be emailed on a takeover by master-server, do this step only on slave-server.</p>

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;">master-server MailTo::someadmin@domain.tld::Subject</pre></div></div>

]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2009/10/03/highly-available-samba-on-ubuntu-8-04/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Fedora LiveCD without CD Drive</title>
		<link>http://connection-endpoint.de/2009/02/12/fedora-livecd-without-cd-drive/</link>
		<comments>http://connection-endpoint.de/2009/02/12/fedora-livecd-without-cd-drive/#comments</comments>
		<pubDate>Thu, 12 Feb 2009 07:10:57 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/?p=84</guid>
		<description><![CDATA[Yesterday I wanted to give the new Fedora 11 alpha a spin. Unfortunately it seems that Virtualbox doesn&#8217;t like Fedora &#8211; the system would always run unusably slow. I started looking for a way to run the LiveCD without actually using a CD. Ubuntu has some good documentation on that, but I could not find [...]]]></description>
			<content:encoded><![CDATA[<p><img src="http://connection-endpoint.de/wordpress/wp-content/uploads/2009/02/logo_usageguidelines_logomark.png" alt="fedora_logo" title="fedora_logo" width="126" height="127" class="alignright size-full" align="right"/><br />
Yesterday I wanted to give the new Fedora 11 alpha a spin. Unfortunately it seems that Virtualbox doesn&#8217;t like Fedora &#8211; the system would always run unusably slow.<br />
I started looking for a way to run the LiveCD without actually using a CD. Ubuntu has some <a href="https://help.ubuntu.com/community/Installation#Installation%20without%20a%20CD">good documentation</a> on that, but I could not find anything similar for Fedora. So I had to figure it out myself and after a little tinkering I present to you the simple instructions on how to boot Fedora LiveCD&#8217;s from hard disk.</p>
<ol>
<li><a href="http://fedoraproject.org/en/get-fedora">Download</a> the LiveCD</li>
<li>Mount the CD Image and copy its contents to an unused partition (this *should* work with a in-use partition actually&#8230; but don&#8217;t blame me for lost data) like so:

<div class="wp_syntax"><div class="code"><pre class="bash" style="font-family:monospace;">$ <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>fedora-cd
$ <span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #660033;">-o</span> loop F11-Alpha-i686-Live.iso <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>fedora-cd  <span style="color: #666666; font-style: italic;"># as root</span>
$ <span style="color: #c20cb9; font-weight: bold;">mkdir</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>installer
$ <span style="color: #c20cb9; font-weight: bold;">mount</span> <span style="color: #000000; font-weight: bold;">/</span>dev<span style="color: #000000; font-weight: bold;">/</span>sda4 <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>installer  <span style="color: #666666; font-style: italic;"># as root</span>
$ <span style="color: #c20cb9; font-weight: bold;">cp</span> <span style="color: #660033;">-R</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>fedora-cd<span style="color: #000000; font-weight: bold;">/*</span> <span style="color: #000000; font-weight: bold;">/</span>tmp<span style="color: #000000; font-weight: bold;">/</span>installer</pre></div></div>

</li>
<li>Now you have to edit your boot loader configuration. For grub this will typically be done in a file called /boot/grub/menu.lst or something like that. Add the following lines:

<div class="wp_syntax"><div class="code"><pre class="none" style="font-family:monospace;"># adjust these settings for the device you're actually using
title Fedora 11 Alpha LiveCD
root (hd0,3)
kernel /isolinux/vmlinuz0 root=/dev/sda4 rootfstype=auto ro liveimg quiet rhgb
initrd /isolinux/initrd0.img</pre></div></div>

</li>
</ol>
<p>Now you can boot into the LiveCD from the according Grub menu entry.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2009/02/12/fedora-livecd-without-cd-drive/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>On the Theme Hospital project</title>
		<link>http://connection-endpoint.de/2008/05/13/on-the-theme-hospital-project/</link>
		<comments>http://connection-endpoint.de/2008/05/13/on-the-theme-hospital-project/#comments</comments>
		<pubDate>Tue, 13 May 2008 18:59:07 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[theme hospital]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/?p=83</guid>
		<description><![CDATA[There&#8217;s a new comment on one of the theme hospital posts. Just wondering. Is this project still going on? Hospital could do with an open source (enhanced) version. I know some people are busy on it at http://www.rounddonut.co.uk/ but this project is going very very slow. F Now here is my answer: Unfortunaltely I haven&#8217;t [...]]]></description>
			<content:encoded><![CDATA[<p>There&#8217;s a new comment on one of the theme hospital posts.</p>
<blockquote><p>Just wondering. Is this project still going on?<br />
Hospital could do with an open source (enhanced) version.</p>
<p>I know some people are busy on it at http://www.rounddonut.co.uk/ but this project is going very very slow.</p>
<p>F</p></blockquote>
<p>Now here is my answer:</p>
<p>Unfortunaltely I haven&#8217;t had much time for this lately. But indeed, there was some progress just a week ago &#8211; I made a few additions and cleanup-work in the wiki and also worked a bit on the viewer-program.<br />
When there was some good progress about a year ago, I initially expected other interested people would build upon my findigs. This has not been the case yet.<br />
Well&#8230;. I think there will be more stuff going on, but it may take some time &#8211; at least for the reverse engineering, as I kinda ditched the open-source-clone thing for now.</p>
<p>The latest THViewer brings improvements in file-handling and a completely Java based RNC decompressor.<br />
If you&#8217;re interested in the sourcecode, you can use <a href="http://bazaar-vcs.org/">bazaar</a> to branch/pull from my published branch:<br />
<code>bzr branch http://connection-endpoint.de/bazaar/THViewer</code></p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2008/05/13/on-the-theme-hospital-project/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>Seam Carving</title>
		<link>http://connection-endpoint.de/2007/11/25/seam-carving/</link>
		<comments>http://connection-endpoint.de/2007/11/25/seam-carving/#comments</comments>
		<pubDate>Sun, 25 Nov 2007 14:01:10 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/?p=60</guid>
		<description><![CDATA[Intro and Overview If you have already seen the video on content aware image resizing at seamcarving.com then you probably know what seam carving is. If not, I recommend you to do so. Seam carving is a method to resize an image that takes the images content into account &#8211; and can therefore produce really [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline.thumbnail.jpg' alt='sc_skyline.jpg' align="left" hspace="8" /><strong>Intro and Overview</strong></p>
<p>If you have already seen the video on content aware image resizing at <a href="http://www.seamcarving.com/">seamcarving.com</a> then you probably know what seam carving is. If not, I recommend you to do so.</p>
<p>Seam carving is a method to resize an image that takes the images content into account &#8211; and can therefore produce really great results. This is my attempt to provide the reader with an easy to understand explanation of how seam carving works.<br />
<span id="more-60"></span><br />
A few notes before we start. The images I used for this were released under the terms of CC-BY. They are:</p>
<ul>
<li><a href="http://flickr.com/photos/rene-germany/1593942617/">Skyline Boston</a> by ReneS</li>
<li><a href="http://flickr.com/photos/ilcama/951675493/">BOLOGNA GRAFFITI</a> by il CAMA</li>
<li><a href="http://flickr.com/photos/fotos_dos_ornelas/257887467/">P7122395</a> by :::Rui Ornelas:::</li>
</ul>
<p>The Sourcecode that I wrote is <a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/seamtar.bz2' title='seamtar.bz2'>available for download</a>. You may use it for anything you like, but be warned that this is highly unoptimized and quickly thrown together code. To compile and run you will also need the <a href="http://openil.sourceforge.net/">DevIL library</a>.<br />
Also note that I will mostly write about horizontal resizing and that this is also the only thing my code can do. However there is no real difference between horizontal and vertical resizing, besides some variable-swapping here and there.</p>
<p><strong>Basic algorithm</strong></p>
<p>The algorithm itself is actually really easy to understand. The paper is easy to read and there is only one or two things I had to figure out by myself.<br />
Here is an outline of the seam carving algorithm and its idea:</p>
<blockquote><p><strong>Step 1:</strong> calculate the energy for each pixel of the image<br />
<strong>Step 2:</strong> build a map of the minimum cumulative energies<br />
<strong>Step 3:</strong> do a backtrace on this data to get the path (&#8220;seam&#8221;) with the lowest energy<br />
<strong>Step 4:</strong> delete the pixels which belong to the seam</p></blockquote>
<p>A seam is an 8-connected path of pixels, where a vertical seam runs from top to bottom, containing exactly one pixel in each row. 8-connected means that for each pixel we only consider its 8 adjacent neighbors.</p>
<p><strong>Calculating the energy</strong></p>
<p>When we want to remove a seam with the lowest energy we need to decide how we calculate the energy of a single pixel. There are many ways to do that &#8211; the original paper lists a few. I chose to implement a gradient measure by using the so called <a href="http://en.wikipedia.org/wiki/Sobel_operator">Sobel operator</a>.<br />
Have a look at the following images to see what results the sobel operator yields:</p>
<table border="0">
<tbody>
<tr>
<td>Original</td>
<td>Sobel Operator</td>
</tr>
<tr>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert.jpg' title='sc_desert.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert.thumbnail.jpg' alt='sc_desert.jpg' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_e.png' title='sc_desert_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_e.thumbnail.png' alt='sc_desert_e.png' /></a>
</td>
</tr>
<tr>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti.jpg' title='sc_grafiti.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti.thumbnail.jpg' alt='sc_grafiti.jpg' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_e.png' title='sc_grafiti_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_e.thumbnail.png' alt='sc_grafiti_e.png' /></a>
</td>
</tr>
</tbody>
</table>
<p>This is also commonly referred to as &#8220;edge detection&#8221;. Here is an image that illustrates the gradient calculation: </p>
<p><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sobel.png' alt='sobel.png' /></p>
<p>To calculate the y-gradient of a pixel, you would add up the values of its neighbors, scaled following the sobel matrix. Lets call the result <strong>Gy</strong>.<br />
Now we usually want to be able to work with RGB images. To do this, I just evaluated the gradient for each color-channel (R, G, B) independently &#8211; say <strong>GyR</strong>, <strong>GyG</strong> and <strong>GyB</strong> &#8211; and took the average for <strong>Gy</strong>. Thus <strong>Gy = (GyR + GyG + GyB) / 3</strong>.<br />
Then I did the analogous part for the horizontal gradient <strong>Gx</strong> and finally stored the (x, y)-gradient magnitude at this pixels position in the energy map. The images you see above are directly rendered from that energy map.<br />
Note that my code sets the energy for border pixels (that is pixels which are at the very top / bottom / left / right) always to maximum energy.</p>
<p><strong>Cumulative Energy Map</strong></p>
<p>The next step with our seam carving is to prepare a map of the cumulative energies on that we can do the backtracing later on. This will be the <a href="http://en.wikipedia.org/wiki/Dynamic_programming">dynamic programming</a> part and it can be easily summarized by the following formula:<br />
<strong>M(x, y) = energy(x, y) + min( M(x-1, y-1), M(x, y-1), M(x+1, y-1) )</strong><br />
To compute the cumulative minimum energy <strong>M(x, y)</strong> for a pixel (x, y), add its energy to the minimum cumulative energy of one of its predecessors (remember the &#8220;8-connected&#8221; thing?).<br />
I again rendered the cumulative energy map:</p>
<table border="0">
<tbody>
<tr>
<td>Original</td>
<td>Energy</td>
<td>Min. Cumul. Energy</td>
</tr>
<tr>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline.jpg' title='sc_skyline.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline.thumbnail.jpg' alt='sc_skyline.jpg' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_e.png' title='sc_skyline_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_e.thumbnail.png' alt='sc_skyline_e.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_c.png' title='sc_skyline_c.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_c.thumbnail.png' alt='sc_skyline_c.png' /></a>
</td>
</tr>
</tbody>
</table>
<p><strong>Backtracing</strong></p>
<p>This is the part where we need to use the cumulative enrgy map (CE/M) to find the vertical seam with the lowest energy. Backtracing is a common method for doing such kind of things, so let me give you a brief explanation of how it works.<br />
We start by searching the pixel with the lowest CE in the very last row. After adding that pixel to the seam, we look at its 3 neighbors to the top and agian choose the one with the lowest CE. Have a look at the following image:</p>
<p><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/backtracing.png' alt='backtracing.png' /></p>
<p>The algorithm starts at the bottom row and finds that <strong>11</strong> is the minimal CE. We add that pixel to our seam and look at the two adjacent pixels above. <strong>8</strong> is the minimal CE, so this is the next pixel to be added to the seam. Again in the next step we consider the thre pixels with CE values <strong>7</strong>, <strong>2</strong> and <strong>6</strong> respectively. Can you tell how this goes on?<br />
Now let&#8217;s think about this for a few seconds. In each step we choose the pixel with the minimal CE, therefore when the algorithm arrives at the top of the image, we know the seam with the overall minimal CE. Remove all these pixels and you&#8217;ll have seem carving!<br />
Here is a real example with the seam rendered as a red line and a zoomed version:</p>
<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_s.png' title='sc_grafiti_s.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_s.thumbnail.png' alt='sc_grafiti_s.png' /></a>  <a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_sz.png' title='sc_grafiti_sz.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_sz.thumbnail.png' alt='sc_grafiti_sz.png' /></a></p>
<p><strong>Results</strong></p>
<p>Seam carving results depend almost entirely on the chosen energy function. I used a gradient based method because I thought that it was easy to implement and produces quite good results. Of course this will not work as well on some images as it does on others. Quality of the outcome can also be improved by providing the user with tools to manually add energy to parts of the image (therefore &#8220;protecting&#8221; those parts) or remove energy (force the removal of parts).<br />
Now for the results. I have used my program to resize three different images and these are the results.</p>
<table border="0">
<tbody>
<tr>
<td>
Original
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline.jpg' title='sc_skyline.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline.thumbnail.jpg' alt='sc_skyline.jpg' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti.jpg' title='sc_grafiti.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti.thumbnail.jpg' alt='sc_grafiti.jpg' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert.jpg' title='sc_desert.jpg'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert.thumbnail.jpg' alt='sc_desert.jpg' /></a>
</td>
</tr>
<tr>
<td>
Energy
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_e.png' title='sc_skyline_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_e.thumbnail.png' alt='sc_skyline_e.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_e.png' title='sc_grafiti_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_e.thumbnail.png' alt='sc_grafiti_e.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_e.png' title='sc_desert_e.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_e.thumbnail.png' alt='sc_desert_e.png' /></a>
</td>
</tr>
<tr>
<td>
CEM
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_c.png' title='sc_skyline_c.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_c.thumbnail.png' alt='sc_skyline_c.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_c.png' title='sc_grafiti_c.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_c.thumbnail.png' alt='sc_grafiti_c.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_c.png' title='sc_desert_c.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_c.thumbnail.png' alt='sc_desert_c.png' /></a>
</td>
<td>
</td>
</tr>
<tr>
<td>
First Seam
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_s.png' title='sc_skyline_s.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_s.thumbnail.png' alt='sc_skyline_s.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_s.png' title='sc_grafiti_s.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_s.thumbnail.png' alt='sc_grafiti_s.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_s.png' title='sc_desert_s.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_s.thumbnail.png' alt='sc_desert_s.png' /></a>
</td>
</tr>
<tr>
<td>
Result
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_small.png' title='sc_skyline_small.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_skyline_small.thumbnail.png' alt='sc_skyline_small.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_o1.png' title='sc_grafiti_o1.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_grafiti_o1.thumbnail.png' alt='sc_grafiti_o1.png' /></a>
</td>
<td>
<a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_o.png' title='sc_desert_o.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/sc_desert_o.thumbnail.png' alt='sc_desert_o.png' /></a>
</td>
</tr>
</tbody>
</table>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/11/25/seam-carving/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Mensaessen auf Knopfdruck</title>
		<link>http://connection-endpoint.de/2007/11/08/mensaessen-auf-knopfdruck/</link>
		<comments>http://connection-endpoint.de/2007/11/08/mensaessen-auf-knopfdruck/#comments</comments>
		<pubDate>Thu, 08 Nov 2007 09:31:09 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=58</guid>
		<description><![CDATA[Mein aktuelles kleines Miniprojekt (ich wollte mal was mit Ruby und GTK+ machen) ist fertig geworden. Ein Programm was den tagesaktuellen Mensaplan anzeigt, und auch das tagesweise Vor- und Zurückblättern erlaubt. Kleiner Screenshot: Sehr einfaches Script, vor allem dank Glade und Hpricot.]]></description>
			<content:encoded><![CDATA[<p>Mein aktuelles kleines <a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/mensa.zip' title='mensa.zip'>Miniprojekt</a> (ich wollte mal was mit <a href="http://www.ruby-lang.org/">Ruby</a> und <a href="http://www.gtk.org/">GTK+</a> machen) ist fertig geworden. Ein Programm was den tagesaktuellen Mensaplan anzeigt, und auch das tagesweise Vor- und Zurückblättern erlaubt.</p>
<p>Kleiner Screenshot:</p>
<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/mensa.png' title='mensa.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/mensa.thumbnail.png' alt='mensa.png' /></a></p>
<p>Sehr einfaches Script, vor allem dank <a href="http://glade.gnome.org/">Glade</a> und <a href="http://code.whytheluckystiff.net/hpricot/">Hpricot</a>.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/11/08/mensaessen-auf-knopfdruck/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Litter, Shadows, Heads and Sound</title>
		<link>http://connection-endpoint.de/2007/07/30/litter-shadows-heads-and-sound/</link>
		<comments>http://connection-endpoint.de/2007/07/30/litter-shadows-heads-and-sound/#comments</comments>
		<pubDate>Mon, 30 Jul 2007 19:42:15 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[theme hospital]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=54</guid>
		<description><![CDATA[I&#8217;d say this looks quite Theme Hospital&#8217;ish doesn&#8217;t it? The few things that were done since the last post: figured out how shadows and litter is represented in a savegame I worked out how the animation layers are stored; this is why the people have heads and different clothes on the new screenshot soundfiles; yeah [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/savegame2.gif' title='savegame2.gif'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/savegame2.thumbnail.gif' alt='savegame2.gif' align="right" hspace="8" /></a>I&#8217;d say this looks quite Theme Hospital&#8217;ish doesn&#8217;t it?</p>
<p>The few things that were done since the last post:</p>
<ul>
<li>figured out how shadows and litter is represented in a savegame</li>
<li>I worked out how the animation layers are stored; this is why the people have heads and different clothes on the new screenshot</li>
<li>soundfiles; yeah right! I messed with the sound files format and I now know how this works&#8230; well at least to a large extent</li>
</ul>
<p>And as always I also updated the wiki and implemented the new stuff in my TH Viewer. Get the latest version <a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/thviewer2.7z' title='thviewer2.7z'>here</a>.</p>
<p><strong>Outlook</strong></p>
<p>With the last bits waiting to be uncovered comes the time to think about the next steps.</p>
<p><strong>Finish the savegame format.</strong><br />
The next coupe of days/weeks are still mainly for finishing up the reverse engineering and getting the wiki in the right shape. Savegames are crucial in getting a feeling for &#8220;how Theme Hospital does stuff&#8221; without having to go through many painful debugging sessions. So that is something I&#8217;d like to get done.</p>
<p><strong>Finish other reverse engineering</strong><br />
Not too much left and not really that importent &#8211; unless of course we want a clone that is fully compatible with the original game.</p>
<p><strong>Toolchain evaluation</strong><br />
I will probably stick with java for a programming language, however I&#8217;m still not quite sure what graphics/media libraries to use. SDL may be a good choice but I also consider choosing a <a href="http://www.lwjgl.org/">LWJGL</a> based engine.</p>
<p><strong>Spread the word</strong><br />
I already received an email from Ted Tycoon recently, who expressed his interest in the project. I would also like to see what other people have to say and if there are more players and developers interested.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/07/30/litter-shadows-heads-and-sound/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Savegame rendering</title>
		<link>http://connection-endpoint.de/2007/07/25/savegame-rendering/</link>
		<comments>http://connection-endpoint.de/2007/07/25/savegame-rendering/#comments</comments>
		<pubDate>Wed, 25 Jul 2007 09:01:56 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[theme hospital]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=53</guid>
		<description><![CDATA[The last days I did some work on the savegame format. It&#8217;s far from complete, but I thought it would be nice to share some progress. Click on the image to the right. As you can see there are still some things to do &#8211; but I guess that it&#8217;s all not that complicated. Note [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/savegame.gif' title='savegame.gif'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/savegame.thumbnail.gif' alt='savegame.gif' align="right" hspace="8" /></a>The last days I did some work on the savegame format. It&#8217;s far from complete, but I thought it would be nice to share some progress.<br />
Click on the image to the right.<br />
As you can see there are still some things to do &#8211; but I guess that it&#8217;s all not that complicated. Note that this is not a playable game &#8211; it is just a rendered image, using the information from a savegame.<br />
I also updated the wiki with the new information.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/07/25/savegame-rendering/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Looks like Theme Hospital</title>
		<link>http://connection-endpoint.de/2007/06/23/looks-like-theme-hospital/</link>
		<comments>http://connection-endpoint.de/2007/06/23/looks-like-theme-hospital/#comments</comments>
		<pubDate>Sat, 23 Jun 2007 16:00:36 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[theme hospital]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=49</guid>
		<description><![CDATA[I have made some good progress on the reverse engineering of theme hospital&#8217;s data formats since the last time I wrote about it. My &#8220;Theme Hospital Viewer&#8221; is now able to render animations and maps. Still, there are some unknown pieces to the whole specification. But my guess would be that we are now at [...]]]></description>
			<content:encoded><![CDATA[<p><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/an.gif' alt='an.gif' align="right" hspace="8" />I have made some good progress on the reverse engineering of theme hospital&#8217;s data formats since the last time I wrote about it. My &#8220;Theme Hospital Viewer&#8221; is now able to render animations and maps.</p>
<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/map.png' title='map.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/map.thumbnail.png' alt='map.png' align="left" hspace="8" /></a>Still, there are some unknown pieces to the whole specification. But my guess would be that we are now at about 75% done and nearly all files classified by their format. By now it should be already possible to begin a theme hospital clone &#8211; if not even complete it.</p>
<p>So without further ado, I present to you:</p>
<p>- <a href="http://connection-endpoint.de/wiki/doku.php?id=format_specification">the format specification</a><br />
- <a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/thviewer.7z' title='thviewer.7z'>THViewer (132 kB, 7zip)</a></p>
<p>The Sourcecode of THViewer is included in the archive. I&#8217;ve also included a Win32 Binary and the sourcecode of dernc. Please read the readme.<br />
A word of warning: the source code of THViewer is quite a hack and the whole thing is more like a proof of concept / test-tool. It is by no means &#8220;user friendly&#8221;.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/06/23/looks-like-theme-hospital/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>About Bullfrog&#8217;s Theme Hospital</title>
		<link>http://connection-endpoint.de/2007/04/28/about-bullfrogs-theme-hospital/</link>
		<comments>http://connection-endpoint.de/2007/04/28/about-bullfrogs-theme-hospital/#comments</comments>
		<pubDate>Sat, 28 Apr 2007 14:21:23 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[theme hospital]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=47</guid>
		<description><![CDATA[click me more to come]]></description>
			<content:encoded><![CDATA[<p><a href="http://connection-endpoint.de/sc.htm">click me</a><br />
more to come</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/04/28/about-bullfrogs-theme-hospital/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Was ich so gemacht habe</title>
		<link>http://connection-endpoint.de/2007/04/03/was-ich-so-gemacht-habe/</link>
		<comments>http://connection-endpoint.de/2007/04/03/was-ich-so-gemacht-habe/#comments</comments>
		<pubDate>Tue, 03 Apr 2007 09:33:55 +0000</pubDate>
		<dc:creator>Alex</dc:creator>
				<category><![CDATA[Uncategorized]]></category>

		<guid isPermaLink="false">http://connection-endpoint.de/wordpress/?p=45</guid>
		<description><![CDATA[Die letzten Wochen habe ich mich hautpsächlich mit dem Programmieren einer etwas aufwändigeren Java Applikation beschäftigt. Zunächst sollte es nur darum gehen, eine Exceltabelle mit vorgegebenem Format ein ein anderes vorgegebenes Format zu konvertieren. Mit der Zeit stellte sich jedoch heraus, dass hier gewisse Faktoren eine Rolle spielen, die mir das Ganze nicht so einfach [...]]]></description>
			<content:encoded><![CDATA[<p><a href='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/oct.png' title='oct.png'><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/oct.thumbnail.png' alt='oct.png' align="right" hspace="8" /></a>Die letzten Wochen habe ich mich hautpsächlich mit dem Programmieren einer etwas aufwändigeren Java Applikation beschäftigt. Zunächst sollte es nur darum gehen, eine Exceltabelle mit vorgegebenem Format ein ein anderes vorgegebenes Format zu konvertieren.<br />
Mit der Zeit stellte sich jedoch heraus, dass hier gewisse Faktoren eine Rolle spielen, die mir das Ganze nicht so einfach machen würden.</p>
<p><strong>Kleiner Überblick</strong></p>
<p>Gegeben war eine Beispielexceltabelle, die dem Format der anderen verwendeten Exceltabellen entsprach. Desweiteren hatte ich ein etwa zwanzigseitiges Dokument, in dem das Zielformat spezifiziert war.<br />
Das Problem mit Exceltabellen: Prinzipiell sind sie nicht strukturiert. Es gibt für die Zeilen und Spalten kein festgelegtes Format, und ein Benutzer kann Daten in eine Zelle schreiben, die &#8211; bezogen auf das Zieldateiformat &#8211; nicht viel Sinn machen. Aufgrund der Tatsache, dass es keine eindeutige Abbildung von Quell- auf Zieldaten gibt, musste eine grafische Benutzeroberfläche her. Der Anwender soll die Möglichekeit bekommen, die konvertierten Daten nachträglich nocheinmal zu bearbeiten und, wo nötig, zu korrigieren.<br />
<span id="more-45"></span><br />
<strong>Kleine Helferlein</strong></p>
<p>Zum Einlesen der aus den Excelfiles erzeugten csv-Daten, diente mir der Excel-csv-Parser von <a href="http://ostermiller.org/utils/CSV.html">http://ostermiller.org/utils/CSV.html</a>.<br />
Entwickelt habe ich das ganze unter Ubuntu Linux, der Einsatzbereich würde jedoch eine Win2K Umgebung sein. Hier kann Java natürlich seine cross-platform Stärke ausspielen; die <a href="http://www.jgoodies.com/freeware/looks/">JGoodies Look &#038; Feel&#8217;s</a> sorgen für ein plattformunabhägiges, ansprechendes Auftreten.<br />
Beim Bauen der Oberfläche hat mit das <a href="http://www.eclipse.org/vep/WebContent/main.php">Visual Editor Project</a> von Eclipse sehr gute Dienste geleistet.</p>
<p><strong>Wichtige Kleinigkeiten</strong></p>
<p>Während des Projektes sind ein paar Sachen aufgetaucht, deren Lösung zunächst schwierig schien. Dabei waren dies keine größeren Probleme, allerdings doch Unbequemlichkeiten für den Nutzer der GUI.</p>
<p>JComboBox ist zu eng</p>
<p>Auch eine JComboBox wird, wie alle anderen GUI-Elemente, nur so breit gezeichnet wie die Fenstergröße und der LayoutManager zulässt. An sich kein Problem &#8211; wäre es nicht so, dass auch das Comboboxpopup in nur eben dieser Breite gezeichnet wird. </p>
<p><img src='http://connection-endpoint.de/wordpress/wp-content/uploads/2008/03/combobox.png' alt='combobox.png' /></p>
<p>Im ersten Bild ist schnell ersichtllich: So lässt sich nicht arbeiten. Dieses Problem ist schon lange bekannt. So gibt es auf <a href="http://bugs.sun.com/">bugs.sun.com</a>, Reports die auf Ende 1998 datieren. Umso verwunderlicher, dass es bis heute noch keine Standardmöglichkeit gibt das gewünschte Verhalten zu erzeugen.<br />
Allerdings finden sich dort auch <a href="http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4618607">mehrere Workarounds</a>.</p>
<p>Scrollbarposition soll fest bleiben</p>
<p>Sobald sich die Cursorposition innerhalb einer JTextArea ändert, wird automatisch der zu sehende Ausschnitt innerhalb einer JScrollPane verschoben. Meistens ist dies sinnvoll und erwünscht.</p>
<p>Kurzer Exkurs zur oben erwähnten Import-Funktion. Eine bestimmte Zeile pro Probe, sollte aus der csv-Datei in das Protokoll übernommen werden. Der jeweilige Text sieht für jede Probe ziemlich gleich aus &#8211; beim Durchblättern der Proben ist es jedoch wichtig, dass ein ganz bestimmter Teil des Protokolls direkt lesbar ist.</p>
<p>Nun wird beim Durchblättern der Beprobungen, immer der Text im Protokollfeld (man klicke oben auf den kleinen Screenshot) neu gesetzt. Damit wurde zunächst der Textausschnitt immer bis ans Ende gescrollt. Es ist zwar relativ einfach möglich, einfach den Cursor im Textfeld neu zu setzten (z.B. ganz an den Anfang). Die gewünschte Funktionalität war jedoch, dass der Scrollbalken immer an der gleichen Position bleibt.</p>
<p>Folgender Codeschnipsel garantiert dies:</p>

<div class="wp_syntax"><div class="code"><pre class="java" style="font-family:monospace;">prevRect <span style="color: #339933;">=</span> textArea.<span style="color: #006633;">getVisibleRect</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
textArea.<span style="color: #006633;">setText</span><span style="color: #009900;">&#40;</span> someStringHere <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
&nbsp;
<span style="color: #003399;">SwingUtilities</span>.<span style="color: #006633;">invokeLater</span><span style="color: #009900;">&#40;</span> <span style="color: #000000; font-weight: bold;">new</span> <span style="color: #003399;">Runnable</span><span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
  <span style="color: #000000; font-weight: bold;">public</span> <span style="color: #000066; font-weight: bold;">void</span> run<span style="color: #009900;">&#40;</span><span style="color: #009900;">&#41;</span> <span style="color: #009900;">&#123;</span>
    textArea.<span style="color: #006633;">scrollRectToVisible</span><span style="color: #009900;">&#40;</span> prevRect <span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span>
  <span style="color: #009900;">&#125;</span>
<span style="color: #009900;">&#125;</span><span style="color: #009900;">&#41;</span><span style="color: #339933;">;</span></pre></div></div>

<p>Der wichtige Teil ist hier das invokeLater. Normalerweise ist es so, dass die TextArea ihr Model mit dem neuen Text updatet, und dann irgendein Event feuert. Dieses Event führt dann bei der Parent-Scrollpane zum verschieben des Bildausschnittes.<br />
Nun ist es so, dass die AWT-Eventbehandlung in einem extra Thread abläuft. Wenn man also direkt nach dem Setzen des Textes zum gewünschten Bereich scrollt, ist es sehr wahrscheinlich dass das Swinginterne Scrollevent erst danach behandelt wird. Schließlich erfolgt das in diesem separaten Thread.<br />
Die Sachen die nun in invokeLater stehen, werden innerhalb des AWT-Eventthreads ausgeführt &#8211; und zwar erst nach allen anderen Swinginternen Events.<br />
Diese Geschichte geht sogar soweit, dass es heute wohl Best Practice ist, direkt am Anfang der main-Methode, alles Weitere in den Eventthread zu legen.</p>
]]></content:encoded>
			<wfw:commentRss>http://connection-endpoint.de/2007/04/03/was-ich-so-gemacht-habe/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

