<?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>64k</title>
	<atom:link href="http://www.burningdragon.de/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.burningdragon.de</link>
	<description>Software development and more ...</description>
	<lastBuildDate>Fri, 03 Sep 2010 11:39:26 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=abc</generator>
		<item>
		<title>Changing the default behavior of built-in Cocoa controls</title>
		<link>http://www.burningdragon.de/2010/06/changing-the-default-behavior-of-built-in-cocoa-controls/</link>
		<comments>http://www.burningdragon.de/2010/06/changing-the-default-behavior-of-built-in-cocoa-controls/#comments</comments>
		<pubDate>Sun, 13 Jun 2010 11:34:47 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[Archive]]></category>
		<category><![CDATA[delegate]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[NSCell]]></category>
		<category><![CDATA[NSControl]]></category>
		<category><![CDATA[NSSearchField]]></category>
		<category><![CDATA[objc]]></category>
		<category><![CDATA[Objective-C]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[search field]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=251</guid>
		<description><![CDATA[Apple has many task specific controls built into Cocoa. They are all well designed and have most of the functionality a user and a developer expect. One of this controls is the NSSearchField. This control has a special design which allows the user to recognize the provided functionality with ease. It is so well-known that [...]]]></description>
			<content:encoded><![CDATA[<p>Apple has many task specific controls built into Cocoa. They are all well designed and have most of the functionality a user and a developer expect. One of this controls is the <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSearchField_Class/Reference/Reference.html" target="_blank">NSSearchField</a>. This control has a special design which allows the user to recognize the provided functionality with ease. It is so well-known that Apple uses the design even on there website. It has support for menus (e.g. for recent search items), auto completion, a cancel button, and so one. Although this is mostly feature complete, there are sometimes cases where you like to extend it. In this post, I will show how to add another visual hint to this control when a search term isn't found. The aim is to change the background of the underlying text edit to become light red to visual mark the failed search.</p>
<h2>Understanding how Cocoa works</h2>
<p>The NSSearchField class inherits from an <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSControl_Class/Reference/Reference.html" target="_blank">NSControl</a>. NSControls are responsible for the interaction with the user. This implies displaying the content in a <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSView_Class/Reference/NSView.html" target="_blank">NSView</a>, reacting to user input like mouse or keyboard events and sending actions to other objects in the case the status of the control has changed. Usually a control delegate the first two tasks to a <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSCell_Class/Reference/NSCell.html" target="_blank">NSCell</a>. The main reasons for this are to persist on good performance even if there are many cells of the same type (like in the case of a table) and to be able to exchange the behavior of the control easily (like in the case of a combobox which also allow typing in a text field). With this information in mind we know that we need to overwrite the drawing routine of the cell (<a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSSearchFieldCell_Class/Reference/Reference.html" target="_blank">NSSearchFieldCell</a>) to achieve our goal. The implementation is straight forward and shown in the following:</p>
<pre class="brush: objc;">
@interface MySearchFieldCell: NSSearchFieldCell
{
  NSColor *m_pBGColor;
}
- (void)setBackgroundColor:(NSColor*)pBGColor;
@end

@implementation MySearchFieldCell
-(id)init
{
  if (self = [super init])
    m_pBGColor = Nil;
  return self;
}
- (void)setBackgroundColor:(NSColor*)pBGColor
{
  if (m_pBGColor != pBGColor)
  {
    [m_pBGColor release];
    m_pBGColor = [pBGColor retain];
  }
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
  if (m_pBGColor != Nil)
  {
    [m_pBGColor setFill];
    NSRect frame = cellFrame;
    double radius = MIN(NSWidth(frame), NSHeight(frame)) / 2.0;
    [[NSBezierPath bezierPathWithRoundedRect:frame
          xRadius:radius yRadius:radius] fill];
  }
  [super drawInteriorWithFrame:cellFrame inView:controlView];
}
@end
</pre>
<p>The user can set a custom background color by using setBackgroundColor. Also it is possible to reset the background color by passing Nil to this method. The method drawInteriorWithFrame draws a rounded rectangle on the background and forwards the call to the super class afterward.</p>
<h2>Replacing the cell class of a control</h2>
<p>The next step is tell the control to use our own cell class and not the default one. Although there is a <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSControl_Class/Reference/Reference.html#//apple_ref/occ/instm/NSControl/setCell:" target="_blank">setCell</a> method defined in NSControl it is not as easy as one might think. Creating an instance of MySearchFieldCell and passing it to setCell after the NSSearchField is created will not have the expected effect. The reason for this comes from the fact that the cell is initialized when the control is created. This includes setting all properties and targets for the actions. If one replaces the cell afterward these setting will be get lost. Later on, I will show a method how to keep this configuration, but for now we will start with an easier approach.</p>
<p>When the control creates a cell object it asks a static method for the class name to use. This method is called <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSControl_Class/Reference/Reference.html#//apple_ref/occ/clm/NSControl/cellClass" target="_blank">cellClass</a>. If we overriding this method with our own one, we are able to return MySearchFieldCell. The following code demonstrates this:</p>
<pre class="brush: objc;">
@interface MySearchField: NSSearchField
{}
@end

@implementation MySearchField
+ (Class)cellClass
{
  return [MySearchFieldCell class];
}
@end
</pre>
<p>Now, if you use MySearchField instead of NSSearchField when creating search fields, you are done. Unfortunately this isn't always possible. First you may not be able to inherit from NSSearchField for whatever reason and second this will not work when you are use the Interface Builder (<em>IB</em>) from Xcode. There you can't easily use your own version of NSSearchField, but you have to stick with the original one. Before we proceed the obligatory screenshot:</p>
<p><a href="http://www.burningdragon.de/wordpress/wp-content/uploads/MySearchField.png"><img class="aligncenter size-full wp-image-1071" title="MySearchField" src="http://www.burningdragon.de/wordpress/wp-content/uploads/MySearchField.png" alt="" width="180" height="21" /></a></p>
<h2>The power of Archives</h2>
<p>What we need is a method of setting our own cell class even when the control is already instantiated. In Cocoa it is possible to Archive and Serialize any object which implements the <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Protocols/NSCoding_Protocol/Reference/Reference.html" target="_blank">NSCoding</a> protocol. Archiving means that the whole class hierarchy, with all properties and connections, is saved into a stream. Xcode makes heavy use of this in the nib file format where all the project data of the IB is written in. This alone doesn't help us much, but additional to the archiving and unarchiving work, it is possible to replace classes in the decoding step. The relevant classes are <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedArchiver_Class/Reference/Reference.html" target="_blank">NSKeyedArchiver</a> and <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/Reference/Reference.html" target="_blank">NSKeyedUnarchiver</a>. NSKeyedUnarchiver has a method <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/Foundation/Classes/NSKeyedUnarchiver_Class/Reference/Reference.html#//apple_ref/occ/clm/NSKeyedUnarchiver/setClass:forClassName:" target="_blank">setClass:forClassName</a> which allow this inline replacement and the following code shows how to use it:</p>
<pre class="brush: objc;">
NSSearchField *pSearch = [[NSSearchField alloc] init];
/* Replace the cell class used for the NSSearchField */
[NSKeyedArchiver setClassName:@&quot;MySearchFieldCell&quot;
      forClass:[NSSearchFieldCell class]];
[pSearch setCell:[NSKeyedUnarchiver
      unarchiveObjectWithData: [NSKeyedArchiver
        archivedDataWithRootObject:[pSearch cell]]]];
/* Get the original behavior back */
[NSKeyedArchiver setClassName:@&quot;NSSearchFieldCell&quot;
      forClass:[NSSearchFieldCell class]];
</pre>
<p>Basically this creates an archive of the current NSSearchFieldCell of the NSSearchField, which is instantly unarchived, but with the difference that the NSSearchFieldCell class is replaced by MySearchFieldCell. Because the archiving preserve all settings the new created class will have the same settings like the old one. The last call to NSKeyedArchiver will restore the default behavior.</p>
<h2>Conclusion</h2>
<p>This post should have removed some of the mysteries of the control and cell relationship in Cocoa. Additional to a simple derivation approach, a much more advanced way for setting the cell of a control was shown. This allows the replacement of any class hierarchy without loosing any runtime settings. If you need such replacements much more often or working with the IB, you should have a look at <a href="http://www.mikeash.com/pyblog/custom-nscells-done-right.html" target="_blank">Mike's</a> post which shows a more generic way of the archive/unarchive trick.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/06/changing-the-default-behavior-of-built-in-cocoa-controls/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Installing Linux on a USB hard disk for the MacBook Pro</title>
		<link>http://www.burningdragon.de/2010/04/installing-linux-on-a-usb-hard-disk-for-the-macbook-pro/</link>
		<comments>http://www.burningdragon.de/2010/04/installing-linux-on-a-usb-hard-disk-for-the-macbook-pro/#comments</comments>
		<pubDate>Fri, 09 Apr 2010 02:29:11 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Root]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[boot]]></category>
		<category><![CDATA[Boot Camp]]></category>
		<category><![CDATA[EFI]]></category>
		<category><![CDATA[FireWire]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[hard disk]]></category>
		<category><![CDATA[installation]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[MacBook Pro]]></category>
		<category><![CDATA[removable media]]></category>
		<category><![CDATA[Ubuntu]]></category>
		<category><![CDATA[USB]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=885</guid>
		<description><![CDATA[One of the features of Mac OS X I love, is the possibility to install Mac OS X on any attached removable media, like a FireWire or USB hard disk. This makes it really easy for me to test VirtualBox on the several versions of Mac OS X we support (formerly Tiger, now Leopard and [...]]]></description>
			<content:encoded><![CDATA[<p>One of the features of Mac OS X I love, is the possibility to install Mac OS X on any attached removable media, like a FireWire or USB hard disk. This makes it really easy for me to test VirtualBox on the several versions of Mac OS X we support (formerly Tiger, now Leopard and Snow Leopard). The advantage of this setup is that I don't waste disk space for operation systems I usually don't use very often. Currently I have a 150GB hard disk in my MacBook Pro which is really not that much if you deal in the virtualization business. There are several test VM's of any kind of guest operation systems and of course the ISO's to install them. The second main OS, I do much of my work, is Linux. For this I have a standard PC with Gentoo on it, which have all that I need. Unfortunately this doesn't really help when I on travel. As I soon be away for some time, I decided I need, at least for testing, the same flexibility mentioned above for a Linux installation. And here the problems start to arise. Of course Apple didn't really support installing other OS's than Mac OS X on Apple hardware. Yes, there is Boot Camp, but this is mainly for Windows, is very inflexible and doesn't really help if you try to install something on another place than the integrated hard disk. There are projects like <a href="http://refit.sourceforge.net/" target="_blank">rEFIt</a>, which even makes Boot Camp superfluous, but this project has really bad USB boot support. In the following I will explain how it is even possible to install Ubuntu 9.10 on a USB hard disk.</p>
<p>The hardware used, as already said, is a MacBook Pro 3,1 and a Western Digital My Passport Essential 500GB USB hard disk. Other combination may work, but I don't guarantee this, as always. Also you should be warned that anything I describe here could destroy your existing installation and I'm not responsible for that. Doing some kind of backup might be a good idea. Time Machine is easy to use <img src='http://www.burningdragon.de/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
<p>Before we start, as usual, the credits for some sites I get my information from. This is mainly the <a href="http://www.produnis.de/blog/?p=678" target="_blank">Produnis blog</a>, <a href="http://blog.christophersmart.com/2009/07/23/linux-on-an-apple-xserve-efi-only-machine/" target="_blank">the Blog of Chris</a>, the <a href="https://wiki.ubuntu.com/MactelSupportTeam/CommunityHelpPages" target="_blank">Ubuntu wiki</a> and of course the guys around the <a href="http://grub.enbug.org/TestingOnMacbook" target="_blank">Grub2</a> development.</p>
<h2>Creating the EFI boot loader</h2>
<p>Apple doesn't use the legacy BIOS to boot their machines, they use the <a href="http://en.wikipedia.org/wiki/Extensible_Firmware_Interface" target="_blank"><em>Extensible Firmware Interface</em></a> (EFI). This new way of booting operation systems is very flexible, as the name suggest, but has several drawbacks, like most of the standard operation system doesn't speaks it language. Although Linux can be configured to use EFI directly we will emulate a legacy BIOS in the following. For this we need a connector which makes EFI and Linux happy and let them both work smoothly together. This connector is <a href="http://www.gnu.org/software/grub/" target="_blank">Grub2</a>, which is in development for several years now. It's the successor of Grub and is the standard in many popular Linux distributions these days. We have to build a version our self, for which an existing Linux installation is really helpful. I used my 64-bit Gentoo installation. First you have to find out if the EFI installation on your target Apple machine is 64 or 32-bit. You can do this by executing:</p>
<pre class="brush: bash;">
ioreg -l -p IODeviceTree | grep firmware-abi
</pre>
<p>This will return EFI64 or EFI32 respectively. In my case I need the 64-bit version, which is a little bit surprising when I consider that my MacBook Pro isn't able to boot a 64-bit Snow Leopard. Anyway, grab the <a href="ftp://alpha.gnu.org/gnu/grub/grub-1.98.tar.gz">latest version</a> of Grub2 and unpack it on the Linux machine. Please note that you need a gcc with multilib support if you are targeting an architecture which isn't the same as the host one. Use the following to configure Grub2 and to build it. Of course you have to adjust the target architecture if it is a different one.</p>
<pre class="brush: bash;">
./configure --with-platform=efi --target=x86_64 --disable-werror
make
</pre>
<p>When this is finished you create the EFI package by executing<a name="mkimage"></a></p>
<pre class="brush: bash;">
./grub-mkimage -d . -o bootx86.efi *.mod
</pre>
<p>Here I included all modules which are available. If size matter for you, you could of course make a selective choice on the modules included. I didn't test this myself, so you have to find out yourself which one are important.</p>
<h2>Whipping the USB hard disk into shape</h2>
<p>Next we have to prepare the USB hard disk for the new installation. In the following I assume your USB hard disk doesn't contain any valid data and could be reformatted without data lose. Make a backup of your data first if this isn't the case on your side. Apple uses the <a href="http://en.wikipedia.org/wiki/GUID_Partition_Table" target="_blank">GUID Partition Table</a> scheme to organize their partitions on a hard disk. This specification is part of EFI and remove many limitations of the <em><a href="http://en.wikipedia.org/wiki/Master_Boot_Record" target="_blank">Master boot record</a></em> (MBR) scheme, which is widely used in the PC world. That is e.g. the disk size limitation of 2TB or the maximum of 4 primary partitions. You reformat your disk, using the Disk Utility application of Mac OS X. Make sure all existing partitions on the disk are unmounted. When necessary, change the partition scheme from MBR to GUID in the Options dialog of the Partitions window. Select the partitions count you want to use. You need at least 3 partitions to make Linux works fine. My partition scheme looks like in the following: <a href="http://www.burningdragon.de/wordpress/wp-content/uploads/Disk-Utility.png"><img class="aligncenter size-full wp-image-972" title="GUID Partition Table scheme" src="http://www.burningdragon.de/wordpress/wp-content/uploads/Disk-Utility.png" alt="" width="188" height="390" /></a>As you can see I have 5 partitions configured. The first one is an additional Snow Leopard installation for testing. I also added a Data partition at the end for making the data transfer between the different operation systems as easy as possibly. LINUXBOOT is a small partition which will contain the EFI boot loader (size it 50MB or something like that). Linux Swap, obviously, will become the swap partition of the Linux installation. DISK1S5 is the Linux root partition itself. The Data partition has to be formated as Mac OS Extended. Don't use the Journaled version of HFS+, cause this makes trouble on the Linux side. The other partitions have to be formatted as MS-DOS (FAT).</p>
<p>After applying the changes we can add the EFI boot loader to the LINUXBOOT partition. The Apple EFI implementation is searching for a file with the efi extensions on all bootable hard disks. Mount LINUXBOOT and create a <strong>efi/boot</strong> directory on the root path. Copy the <a href="#mkimage">bootx86.efi</a> file into the boot/ directory. As bootx86.efi is a Grub2 boot loader we need a valid Grub2 configuration file. The following <strong>grub.cfg</strong> shows the configuration for a Ubuntu 9.10 i386 installation. For the 64-bit version or any other version of Ubuntu the settings might be slightly different.</p>
<pre class="brush: bash;">
menuviewer=&amp;quot;text&amp;quot;
timeout=10
default=0
set F1=ctrl-x
menuentry &amp;quot;ubuntu-9.10-desktop-i386&amp;quot;
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro quiet splash noefi video=efifb
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry &amp;quot;ubuntu-9.10-desktop-i386 single&amp;quot;
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro noefi video=efifb single
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry &amp;quot;ubuntu-9.10-desktop-i386 text&amp;quot;
{
 fakebios
 search --set -f /boot/vmlinuz-2.6.31-14-generic
 linux /boot/vmlinuz-2.6.31-14-generic root=UUID=4e140981-4ab3-41a2-a2fb-26b1287beb87 ro noefi vga=normal
 initrd /boot/initrd.img-2.6.31-14-generic
}
menuentry &amp;quot;Mac OS X&amp;quot;
{
 search --set -f /usr/standalone/i386/boot.efi
 chainloader /usr/standalone/i386/boot.efi
}
menuentry &amp;quot;CD&amp;quot;
{
 appleloader CD
}
menuentry &amp;quot;mbr&amp;quot;
{
 appleloader HD
}
menuentry &amp;quot;reboot&amp;quot;
{
 reboot
}
</pre>
<p>You have to change the root UUID to the one the Ubuntu installer will assign to your hard disk after installation. Just check the fstab file when the installation has finished. The first entry boots Linux with a splash image enabled. The second one is for the single user mode in the case something went wrong. Please note the <strong>video=efifb</strong> option, which enables the graphical mode in the boot phase.</p>
<h2>Installing Ubuntu</h2>
<p>Most of the installation process is straight forward and doesn't need any special attention. Download the version of your choice from one of the mirrors, burn it on CD and start the installation. You can select the CD as boot medium by pressing <strong>Alt</strong> when your Mac starts. When the installer ask for the partition scheme, you have to switch to "manual choice". Select the DISK1S5 (your what it is in your case) as the root / partition and change the filesystem type to ext3. Also remember the path to the system partition, cause you will need it later again. Select the swap partition and change its type to swap. Proceed with the rest of the installation until the last dialog. There select "advanced settings" and change the boot loader target from hd0 to <strong>/dev/sdXX</strong>, where you replace XX to the path you used previously in the partition tool.</p>
<p>If all went right you should be able to select the LINUXBOOT partition by pressing ALT when your Mac starts. After that Grub2 should shows up, you will be able to boot into your freshly installed Ubuntu.</p>
<h2>Conclusion</h2>
<p>In this post I showed how to easily add the possibility to boot Linux on your MacBook Pro. With the external USB hard disk solution, no internal valuable space is wasted. Of course the speed isn't the same as if the OS would be installed on the internal drive, but for testing software on different operation systems this is satisfactory. To increase the speed a little bit more, an external FireWire hard disk could be used.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/04/installing-linux-on-a-usb-hard-disk-for-the-macbook-pro/feed/</wfw:commentRss>
		<slash:comments>2</slash:comments>
		</item>
		<item>
		<title>Why an ending slash on a URL matters (or not)</title>
		<link>http://www.burningdragon.de/2010/03/why-an-ending-slash-on-a-url-matters-or-not/</link>
		<comments>http://www.burningdragon.de/2010/03/why-an-ending-slash-on-a-url-matters-or-not/#comments</comments>
		<pubDate>Fri, 05 Mar 2010 22:18:22 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[search engine optimization]]></category>
		<category><![CDATA[SEO]]></category>
		<category><![CDATA[web crawler]]></category>
		<category><![CDATA[web standards]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=748</guid>
		<description><![CDATA[Recently I read a report from Google about the status of their own Web sites in terms of Search Engine Optimization (SEO). Uhh, Google, the search engine giant, is looking how the own sites are behaving when a Web crawler is stumble over them! To be honest, it's fully clear to me that in such a [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I read a <a href="http://www.google.com/webmasters/docs/google-seo-report-card.pdf">report</a> from Google about the status of their own Web sites in terms of <em>Search Engine Optimization</em> (SEO). Uhh, Google, the search engine giant, is looking how the own sites are behaving when a Web crawler is stumble over them! To be honest, it's fully clear to me that in such a big company, like Google, not all is perfect in the sense of cooperative appearance. There are different projects, different teams, with different strengths and weaknesses, different priorities and of course different managers. To summaries the report: In some areas Google does a good job, but  in most it doesn't.</p>
<h2>How to optimize</h2>
<p>Although SEO even lead to a business case for some companies, I believe it's not so hard to do and in my humble opinion the most important points, a Web site owner should take care of, are the following 6:</p>
<ol>
<li>Usage of Web standards like XHTML 1.0 Transitional and making sure the Web site conforms to them.</li>
<li>Usage of the &lt;title&gt; tag.</li>
<li>Usage of meta tags like description and keywords.</li>
<li>Usage of the header tags &lt;h1&gt;, &lt;h2&gt;, and so one.</li>
<li>Adding canonical URL information to every site of the Web site, if a specific site is reachable from more than one URL.</li>
<li>Writing good content.</li>
</ol>
<p>Although 6. is quite obviously, it's the most important point and often people forget about it and wonder why there is no traffic on there Web site at all.</p>
<p>1.-5. are technical aspects and if a Web site owner is using e.g. WordPress the Web site should be in good shape, already. Of course this depends a little bit on the used theme and the plug-ins the user has installed. For item 1. I always propose to make a bug report if a theme or a plug-in doesn't confirm to them, as I have done for the theme used in this blog. Conformity could be easily tested with the <a href="http://validator.w3.org/check?uri=http%3A%2F%2Fwww.burningdragon.de&amp;charset=%28detect+automatically%29&amp;doctype=Inline&amp;group=0" target="_blank">W3C Valitator</a>.</p>
<p>Why one should use HTML tags like the title, the meta and the heading tag is also easy to understand. A Web crawler isn't a human, so he can't distinguish between structural information because e.g. the font size is different. Helping him by semantic marking some of the text with the available tags of HTML is therefor a good idea. For the same reason using HTML tables to layout a page is a bad idea. Although this was standard in Netscape 4.0 times it isn't necessary anymore these days.</p>
<h2>Slash or no slash</h2>
<p>Item 5. is about giving the Web crawler a clear idea about the structure of your Web site in a whole. Comparing <strong>burningdragon.de/test</strong> and <strong>burningdragon.de/test/</strong> as a human doesn't seem to be very different. From a technical point of view, it is. Considering that the Web itself is grown up in a UNIX environment, the former points to a filename and the later to a directory. This means for a Web crawler two different sites are targeted. The easiest way to fix this, is to decide about the nomenclature globally used. Either use the one form or the other. WordPress uses the "ending with a slash" variant (most of the time). By the way, this is also important for <strong>burningdragon.de/test/index.html</strong> and other variants<strong>. </strong>Another way is to tell the Web crawler the <a href="http://googlewebmastercentral.blogspot.com/2009/02/specify-your-canonical.html" target="_blank">canonical address</a> even if the site is served by another URL. This could be done by adding the <strong>link rel</strong> tag <strong>canonical</strong> to the header of the page. On my homepage this looks as follow:</p>
<pre class="brush: xml;">
&lt;link rel=&quot;canonical&quot; href=&quot;http://www.burningdragon.de/&quot; /&gt;
</pre>
<p>As you see, even on the top-level domain a slash is added. WordPress does this automatically for you since version <a href="http://markjaquith.wordpress.com/2007/09/25/wordpress-23-canonical-urls/" target="_blank">2.3</a>. On older versions plug-ins for this task are available. The canonical tag is a good way to make clear which address is the base URL of a specific page. On the other side I see some potential for improvements. I have found two places in my blog where the base address isn't targeted right. The first one is the tag for the site index relationship. It's noted as follow, on my blog:</p>
<pre class="brush: xml;">
&lt;link rel='index' title='64k' href='http://www.burningdragon.de' /&gt;
</pre>
<p>The second one is the link of the logo presented on top of every page on the blog. It use the following link:</p>
<pre class="brush: xml;">
&lt;a name=&quot;top&quot; title=&quot;64k&quot; href=&quot;http://www.burningdragon.de&quot;&gt;64k&lt;/a&gt;
</pre>
<p>As you see the ending slash is missing, both times. It is not really a problem, cause the page itself use the canonical tag. The second mistake is clearly a failure of the theme. It's not fully clear to me if the first wrong target is a failure of the theme or WordPress itself. It also happens with the default WordPress theme (version checked is 2.9.2).</p>
<h2>Conclusion</h2>
<p>Creating a Web site which is easily understandable by a Web crawler isn't any magic. Of course you could make a pure science out of it. There are tons of <a href="http://wordpress.org/extend/plugins/search.php?q=seo&amp;sort=" target="_blank">plug-ins</a> for WordPress available. On the other side considering some simple rules will help a lot. Reading <a href="http://googlewebmastercentral.blogspot.com/" target="_blank">Google's hints</a> or using <a href="https://www.google.com/accounts/ServiceLogin?service=sitemaps&amp;passive=true&amp;nui=1&amp;continue=https%3A%2F%2Fwww.google.com%2Fwebmasters%2Ftools%2Fhome%3Fhl%3Den&amp;followup=https%3A%2F%2Fwww.google.com%2Fwebmasters%2Ftools%2Fhome%3Fhl%3Den&amp;hl=en" target="_blank">Google webmaster tools</a> might help, too. Even for Web crawlers from other companies.</p>
<p>On a last note, here is a nice article about how to <a href="http://ma.tt/2009/08/kill-your-community/" target="_blank">effectively keep users out</a> of your blog <img src='http://www.burningdragon.de/wordpress/wp-includes/images/smilies/icon_wink.gif' alt=';)' class='wp-smiley' /> .</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/03/why-an-ending-slash-on-a-url-matters-or-not/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FRITZ!Box tuning part 3: Using the VoIP phone line from everywhere</title>
		<link>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-3-using-the-voip-phone-from-everywhere/</link>
		<comments>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-3-using-the-voip-phone-from-everywhere/#comments</comments>
		<pubDate>Sat, 06 Feb 2010 12:24:27 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Root]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[FritzBox]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[phone calls]]></category>
		<category><![CDATA[remote access]]></category>
		<category><![CDATA[softphone]]></category>
		<category><![CDATA[VoIP]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=667</guid>
		<description><![CDATA[The contract with my Internet service provider includes a VoIP connection. Together with the FRITZ!Box 7270 all phone calls are done over the Internet, an additional conventional phone connection isn't necessary anymore. One of the benefits of this is that you can connect to your registrar from everywhere in the world. But that's theory, cause [...]]]></description>
			<content:encoded><![CDATA[<p>The contract with my Internet service provider includes a VoIP connection. Together with the FRITZ!Box 7270 all phone calls are done over the Internet, an additional conventional phone connection isn't necessary anymore. One of the benefits of this is that you can connect to your registrar from everywhere in the world. But that's theory, cause e.g. my provider doesn't allow a connection if you are not in the network of the provider itself. Of course there are free services like <a href="http://www.sipgate.de" target="_blank">sipgate</a> or even Skype. There you could make free calls within the services itself, but as soon as you like to call a real phone number you have to pay. They are cheap, no question, but my contract includes a flat rate within Germany. That's even cheaper. So what I like to do is to use my VoIP phone connection even when I'm not at home. In the following third part of the FRITZ!Box tuning <a href="/?s=FRITZ!Box+tuning">series</a>, I will explain how to achieve this. As already said in the first two post, where you at least should read the <a href="http://www.burningdragon.de/2010/01/fritzbox-tuning-part-1-enable-remote-access-over-ssh/">first</a> one, I'm not responsible for anything happens to your FRITZ!Box after you have tried what is described here.</p>
<h2>Adding a softphone to the FRITZ!Box</h2>
<p>The FRITZ!Box fully supports softphones in its basic configuration. Adding new softphones is done in the web frontend in the extended configuration section. There is a wizard for this, where you have to answer some question about your new device. Select phone as device, LAN/WLAN (IP-Phone) for the connection type, choose a name and a password. You get a new internal phone number which usually starts at 620 for the first created device. The FRITZ!Box try's than to connect to the new device. You can skip this for now. After that you have to select which official phone number the new device should use. This is important cause this will be displayed as the caller id when you make a call. Now you could choose if the new softphone should react on all incoming calls, regardless of the phone number called, or only on a specific one.</p>
<h2>Configuring the client software</h2>
<p>I will explain the client setup with the help of a free VoIP software called <a href="http://code.google.com/p/telephone/" target="_blank">Telephone</a>. It's only available for Mac OS X, but there are many other VoIP clients out there which also works for other operation systems. After downloading and installing it you have to create a new account. Select a descriptive name for the account. For the domain use <em>fritz.box</em>, as username you have to use the internal number the FRITZ!Box selected above. Lets use 620 for now. The password is the one you chose previously. After the account is created, I had to select <em>Substitute "00" for "+"</em> in the advanced settings, cause the phone numbers in my address book are all saved with the international phone prefix of Germany which is +49. Assuming you are working in your home network right now, you should be able to connect with Telephone to your FRITZ!Box. Some simple tests like making an outgoing and incoming call with an additional mobile phone should verify a working setup. Some nice features like the Mac OS X Address Book integration, which also transfers incoming caller id's to real names if they are found in the address book, making Telephone a really useful application. For further phone call management functionality on Mac OS X, I can advice you to take a look at the also free software <a href="http://nexem.info/nexem-dev/" target="_blank">Frizzix</a>.</p>
<h2>Allowing calls from everywhere</h2>
<p>All the previously isn't any magic, cause it uses build in support of the FRITZ!Box. But this article is about allowing connections to the VoIP part of the FRITZ!Box from everywhere. To make this happen we have to edit an internal configuration file of the FRITZ!Box. This time we aren't change the ar7.cfg file, but a file called <strong>/var/flush/voip.cfg</strong>. As the name suggest there is most of the VoIP configuration included. Use nvi to edit it and search for a section called <em>extensions</em>. There should be a newly created one which have a value <em>extension_number</em> with 620. Change the value <em>reg_from_outside</em> from <em>no</em> to <em>yes</em>. This section should then look like the following:</p>
<pre class="brush: bash; highlight: [7];">
extensions {
    enabled = yes;
    username = &quot;$$$$SSFSDFSOPKSFDOPK;LWE§REWSDFMKFSLDF3232SDFSDFSDF&quot;;
    authname = &quot;&quot;;
    passwd = &quot;$$$$DFS342ASDFSDFDSFDS§344WLKKHMSJHAJHASDAHQASLKADJSA&quot;;
    extension_number = 620;
    reg_from_outside = yes;
    tx_packetsize_in_ms = 0;
}
</pre>
<p>Save the file and reboot your FRITZ!Box by typing <strong>reboot</strong>. Next we have to tell Telephone to use a proxy when connecting to the FRITZ!Box. Go to the advanced settings and add your DynDNS name, in this example it would be <em>xtestx.dyndns.org</em>, to the proxy field. That's all. Now you should be able to make calls from every network you are currently logged in.</p>
<h2>Conclusion</h2>
<p>This simple change to the internal configuration of the FRITZ!Box allows you to use your VoIP account from everywhere over the world. As nice this feature is, I like to add some words of caution at the end. First you need a good download and especially a good upload connection speed in your home setup, cause all phone calls are routed over the FRITZ!Box. Secondly I didn't know if VoIP transfers are encrypted in any way, so be aware that there is the possibility someone monitor your calls. And as last note you should understand that you opened a port on your FRITZ!Box for everyone, which in the case your password is stolen, could be abused. In the worst case someone use your account to SPAM other people or call expensive service numbers.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-3-using-the-voip-phone-from-everywhere/feed/</wfw:commentRss>
		<slash:comments>1</slash:comments>
		</item>
		<item>
		<title>FRITZ!Box tuning part 2: Access your home network with OpenVPN</title>
		<link>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-2-access-your-home-network-with-openvpn/</link>
		<comments>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-2-access-your-home-network-with-openvpn/#comments</comments>
		<pubDate>Tue, 02 Feb 2010 18:38:47 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Root]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[FritzBox]]></category>
		<category><![CDATA[Gentoo]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[OpenVPN]]></category>
		<category><![CDATA[PKI]]></category>
		<category><![CDATA[remote access]]></category>
		<category><![CDATA[VPN]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=379</guid>
		<description><![CDATA[AVM has built a VPN server into the FRITZ!Box, why should I use some other software for this job, you may ask. The reason is quite simple: the build in one is a piece of closed source software written by AVM and there is only one official client which could be used to connect to [...]]]></description>
			<content:encoded><![CDATA[<p>AVM has built a VPN server into the FRITZ!Box, why should I use some other software for this job, you may ask. The reason is quite simple: the build in one is a piece of closed source software written by AVM and there is only one official client which could be used to connect to it, the FRITZ!VPN software. This client software is only available for the Windows operation system family and so by no means anything useful to me. I'm pretty sure they are using some official protocol like <a href="http://en.wikipedia.org/wiki/IPsec" target="_blank">IPSec</a>, so it might be possible to connect to the FRITZ!Box with other clients as well, but that's something I didn't want to try. <a href="http://openvpn.net" target="_blank">OpenVPN</a> on the other side is a rock solid open source software which could be used from many popular OS's these days. Even graphical clients, like <a href="http://code.google.com/p/tunnelblick/" target="_blank">TunnelBlick</a> for Mac OS X, are available. So here comes the second article of the FRITZ!Box tuning <a href="/?s=FRITZ!Box+tuning">series</a>, which will explain how to convert your FRITZ!Box into a OpenVPN server, where any number of clients can concurrently be connected. I highly recommend to read the <a href="http://www.burningdragon.de/2010/01/fritzbox-tuning-part-1-enable-remote-access-over-ssh/">first part</a> of this series, because this post is build on top of the stuff done there. This count especially for the filesystem layout on the usbstick and the way additional software is started. Also in the following it will be helpful to have ssh access to the FRITZ!Box all the time. As already written in the first part, there is no guarantee that the information presented here will work on your side or that I'm responsible for anything happen to your FRITZ!Box. In preparation of the following you need access to a second OpenVPN installation which will be used to create all necessary certificates and keys and which could be used to test the installation afterward. I'm using a Gentoo Linux host where you could install OpenVPN simply by executing <strong>emerge openvpn</strong>. Make sure you have the <strong>examples</strong> USE flag set to get all the helper scripts which make the life much more easier.</p>
<h2>The agony of choice</h2>
<p>OpenVPN could be configured in many different ways. So first of all we have to decide which features of OpenVPN we will use. In its simplest variant OpenVPN could be used with one preshared static key. The advantage of this setup type is the easy configuration. The disadvantage is that only one client could be connected at the time. That is not what we want, so we will configure our setup to be using a <a href="http://en.wikipedia.org/wiki/Public_key_infrastructure" target="_blank">Public Key Infrastructure</a> (PKI). This allows more than one client to be connected at the time and it is possible to mark single keys invalid without affecting other client keys. The second question which has to be answered is, if we want use routing or bridging in our setup. Again, routing is simpler to set up and also a little bit faster than bridging. Bridging on the other side allows the tunneling of non IP protocols such as IPX, tunnel all the IP broadcast and make it possible to use the same subnet on the client side as on the server-side. Especially the last point is a nice feature as with routing all hosts on the server-side needs a routing table entry to find the connected clients. But my main reason for preferring bridging over routing is the broadcast feature of the first one. In my home network works a NAS station as a file server. This includes of course simple filesystem sharing with AFP and NFS, but also serves this box audio data with the <a href="http://en.wikipedia.org/wiki/Digital_Audio_Access_Protocol" target="_blank">Digital Audio Access Protocol</a> (DAAP). DAAP is used by Apple in iTunes to share music with other clients in the network and that is what my NAS station does. This protocol, as well AFP, using broadcast messages (ZeroConf) to find some potential clients. So now it should be clear why I want bridging, it allows me to hear music or to simply connect to my file station without any interaction.</p>
<h2>Building up a PKI</h2>
<p>To create all necessary certificates and keys we are using the <em>easy-rsa</em> scripts from OpenVPN. They are located under <em>/usr/share/openvpn/easy-rsa</em>. First we change the <em>vars</em> file. On the bottom of the file are personal information defined which should be changed to fit to your environment. The entries looking as follow on my side (with a pseudo email address).</p>
<pre class="brush: bash;">
export KEY_COUNTRY=&quot;DE&quot;ap
export KEY_PROVINCE=&quot;Sachsen&quot;
export KEY_CITY=&quot;Dresden&quot;
export KEY_ORG=&quot;64k&quot;
export KEY_EMAIL=&quot;you@yourdomain.org&quot;
</pre>
<p>You could also increase the <strong>KEY_SIZE</strong> from 1024 to 2048 within that file. This should make your keys unbreakable for the next few <span style="text-decoration: line-through;">decades</span> years. Now we are ready to create the master-key and the master certificate of the Certificate Authority (CA) by executing:</p>
<pre class="brush: bash;">
source vars
./clean-all
./build-ca
</pre>
<p>Please be aware that this will delete all previously created keys. Answering all questions with the default values should be sufficient. Next the key for the server has to be created.</p>
<pre class="brush: bash;">
./build-key-server server
</pre>
<p>You can again accept all default values. A challenge password is not necessary, but you have to sign the certificate. Now its time for our first client key and certificate. You could the following repeat again and again, for every new client you want allow to access the OpenVPN server.</p>
<pre class="brush: bash;">
./build-key client
</pre>
<p>Again, don't forget to sign the key. If you ever have to mark a client certificate invalid you could do it with the following command:</p>
<pre class="brush: bash;">
./revoke-full client
</pre>
<p>This will create or update a Certificate Revocation List (CRL)<em> </em> file which will be later used by the server to verify the certificate integrity of a connecting client. For now we create an empty one with</p>
<pre class="brush: bash;">
KEY_CN=&quot;&quot; KEY_OU=&quot;&quot; KEY_NAME=&quot;&quot; $OPENSSL ca -gencrl -out keys/crl.pem -config $KEY_CONFIG
</pre>
<p>The last step in this key building marathon is to create a <a href="http://en.wikipedia.org/wiki/Diffie%E2%80%93Hellman_key_exchange" target="_blank">Diffie-Hellman</a> key. This key will be used to initiate the secure channel between the two parties. Its created by:</p>
<pre class="brush: bash;">
./build-dh
</pre>
<h2>Creating the server and client configuration</h2>
<p>We start with the configuration of the server:</p>
<pre class="brush: bash; highlight: [2,8];">
# set the path to the tap device
dev tap
dev-node /var/tmp/tap0
mssfix
tun-mtu 1500

# TCP or UDP server?
proto udp
port 1194

# CA and key files
ca /var/media/ftp/FLASH-DISK-01/addons/openvpn/keys/ca.crt
cert /var/media/ftp/FLASH-DISK-01/addons/openvpn/keys/server.crt
key /var/media/ftp/FLASH-DISK-01/addons/openvpn/keys/server.key
crl-verify /keys/crl.pem # this is opened after the chroot

# Diffie hellman parameters
dh /var/media/ftp/FLASH-DISK-01/addons/openvpn/keys/dh1024.pem

# bridge setup
server-bridge 192.168.220.1 255.255.255.0 192.168.220.50 192.168.220.99
mode server
tls-server
push &quot;dhcp-option DNS 192.168.220.1&quot;

ifconfig-pool-persist ipp.txt
client-to-client

# compression?
comp-lzo

# The maximum number of concurrently connected clients we want to
# allow.
max-clients 20

# It's a good idea to reduce the OpenVPN daemon's privileges after
# initialization.
user nobody
group nobody

# Put openvpn in a jail.
chroot /var/media/ftp/FLASH-DISK-01/addons/openvpn

# The persist options will try to avoid accessing certain resources on
# restart that may no longer be accessible because of the privilege
# downgrade.
persist-key
persist-tun

# where to log
log-append /var/media/ftp/FLASH-DISK-01/addons/openvpn/log/openvpn.log

# verbose level for debugging
;verb 4

# make sure the connection is kept alive
keepalive 10 120
</pre>
<p>For bridged mode it is essential that OpenVPN uses a TAP device and not the TUN device mode (see <a href="http://en.wikipedia.org/wiki/TUN/TAP" target="_blank">here</a> for the reason). We use UDP as the transport protocol and enable compression. Also we want that OpenVPN drops its privileges after the initialization and chroot into a jail to make it a little bit more secure. As the subnet for clients 192.168.220.0/24 is used. That is the same as my internal network uses. OpenVPN is allowed to use addresses ranging from 192.168.220.50 to 192.168.220.99. You have to make sure that the FRITZ!Box (or any other DHCP server in your network) doesn't serve addresses from that range. Of course you could change some of the settings to your needs, but then you have to make sure they match the configuration of the client.</p>
<p>Next we create the client configuration, which looks as follow:</p>
<pre class="brush: bash; highlight: [6];">
# Specify that we are a client and that we will be pulling certain
# config file directives from the server.
client

# The hostname/IP and port of the server.
remote xtestx.dyndns.org 1194

proto udp
dev tap

pull

mssfix
tun-mtu 1500

# SSL/TLS parms.
tls-client
ca keys/ca.crt
cert keys/client.crt
key keys/client.key

ns-cert-type server

# Keep trying indefinitely to resolve the host name of the OpenVPN
# server. Very useful on machines which are not permanently connected
# to the Internet such as laptops.
resolv-retry infinite

# Don't enable this; It must be disabled for iTunes to find the iTunes
# server and for AFP broadcast in general.
#nobind

# Downgrade privileges after initialization (non-Windows only)
user nobody
group nobody

# Try to preserve some state across restarts.
persist-key
persist-tun

# Enable compression on the VPN link.
comp-lzo

# debug level
;verb 4

mute-replay-warnings
mute 20
</pre>
<p>You have to change the <em>remote</em> hostname to your needs. You may also add the full path to the certificates and keys depending on your client OpenVPN installation.</p>
<p>Next we pack all files up for the server and the client respectively. The server needs the following one:</p>
<pre class="brush: bash;">
server.conf
keys/ca.crt
keys/crl.pem
keys/dh1024.pem
keys/server.crt
keys/server.key
</pre>
<p>The client needs this one:<a name="client_pack"></a></p>
<pre class="brush: bash;">
client.conf
keys/ca.crt
keys/client.crt
keys/client.key
keys/server.crt
</pre>
<h2>Customizing the FRITZ!Box</h2>
<p>Connect to your FRITZ!Box and copy all the server files to the usbstick. I created a directory <em>openvpn</em> under the <em>/var/media/ftp/FLASH-DISK-01/addons</em> path. Next we need the OpenVPN binary for the FRITZ!Box. You can get it <a href="http://www.cswpro.de/_files/openvpn_kernel_2_6.zip">here</a>. Unpack the file and copy the openvpn binary to <em>/var/media/ftp/FLASH-DISK-01/addons/bin</em> on the FRITZ!Box. Make sure the file mode has the executable bit set for the user. All files are now on the right places, so we can adjust our start script. Add the following code to the <em>startup.sh</em> file.</p>
<pre class="brush: bash;">
# Add a nobody user
echo 'nobody:x:65534:65534:nobody:/:/bin/false' &gt;&gt; /var/tmp/passwd

# Add some groups
echo 'root:x:0:' &gt; /var/tmp/group
echo 'nobody:x:65534:' &gt;&gt; /var/tmp/group

# Create a tap device for openvpn
mknod /var/tmp/tap0 c 10 200

# Start openvpn
${BASE}/openvpn/bin/openvpn --config ${BASE}/openvpn/server.conf --daemon
</pre>
<p>As you see, we add a new <em>nobody</em> user to the Linux system. Then the device node for the TAP device is create and at the end the OpenVPN server is started. As we using the bridged setup, we have to add the new device to a bridge. Fortunately we haven't to create one, cause the FRITZ!Box itself is working in bridged mode. You can confirm this by executing:</p>
<pre class="brush: bash;">
brctl show lan
</pre>
<p>To let the system automatically add our TAP device to the <em>lan</em> bridge, we change the internal FRITZ!Box configuration. Edit the <strong>/var/flush/ar7.cfg</strong> file with nvi and search for the string <em>brinterfaces</em>. There should be one section with the name <em>lan</em>. Simply add the new <em>tap0</em> interface to the interfaces value. The section should then look like this:</p>
<pre class="brush: bash; highlight: [7];">
    brinterfaces {
        name = &quot;lan&quot;;
        dhcp = no;
        ipaddr = 192.168.220.1;
        netmask = 255.255.255.0;
        dstipaddr = 0.0.0.0;
        interfaces = &quot;eth0&quot;, &quot;ath0&quot;, &quot;tap0&quot;, &quot;wdsup1&quot;, &quot;wdsdw1&quot;,
                     &quot;wdsdw2&quot;, &quot;wdsdw3&quot;, &quot;wdsdw4&quot;;
        dhcpenabled = yes;
        dhcpstart = 192.168.220.100;
        dhcpend = 192.168.220.200;
    }
</pre>
<p>Now, as soon the tap0 interface is created it will be added to the bridge. The last important point in the server setup is to change the internal firewall to allow connections to port 1194 from the outside. Search for <em>forwardrules</em> in the ar7.cfg file and add this new rule:</p>
<pre class="brush: bash; highlight: [3];">
forwardrules =
               &quot;tcp 0.0.0.0:7777 0.0.0.0:22 0 # SSH-Server&quot;,
               &quot;udp 0.0.0.0:1194 0.0.0.0:1194 0 # VPN-Server&quot;;
</pre>
<p>Thats all for the server. A reboot of the FRITZ!Box should start the new OpenVPN server. If you have trouble you should manually start the OpenVPN server and increase the debugging level, as shown in the above configuration with the keyword <em>verb</em>.</p>
<h2>Setting up the client</h2>
<p>On the client side we need the files we packed <a href="#client_pack">above</a>. On Gentoo the OpenVPN configuration is located at <em>/etc/openvpn.</em> Copy the configuration, the certificates and the key file to that place. The OpenVPN start script of Gentoo looks for the configuration file, based on the start script name. So we have to create a link like this:</p>
<pre class="brush: bash;">
cd /etc/openvpn
ln -s client.conf openvpn.conf
</pre>
<p>By the way, this lets you configure more than one OpenVPN connection at the time. Just create a link in <em>/etc/init.d</em> with the new configuration name and link it to the openvpn start script.</p>
<p>To make a first attempt to start the OpenVPN connection type</p>
<pre class="brush: bash;">
/etc/init.d/openvpn start
</pre>
<p>If  all goes well you should have a new device <em>tap0</em> when you  execute <strong>ifconfig</strong>. Also there should be a route set,  which point to the tap0  device when the 192.168.220.0/24 subnet is the  target. Of course now you should be able to connect to any host in your  home network by the IP. I didn't experiment enough with the pushing of  the name server from the OpenVPN server, instead I just added the  FRITZ!Box as an additionally name server to my <em>/etc/resolv.conf</em>. So here is room for further experiments.</p>
<p>To let the OpenVPN client start at boot time add it to the default  runlevel by executing:</p>
<pre class="brush: bash;">
rc-update add openvpn default
</pre>
<p>Also note that with the above configuration the client always try to  reconnect to the server, even if the FRITZ!Box is rebooted, which is a nice feature.</p>
<h2>Conclusion</h2>
<p>This setup allows you to connect to your home network in a very secure way without loosing any functionality. You are able to browse network shares on the local network or using services like DAAP without any further interaction.  The public key infrastructure make this setup a candidate for small business installations. If an employee leave the company his certificate is simply revoked without affecting the access of other employees.</p>
<div id="_mcePaste" style="position: absolute; left: -10000px; top: 1754px; width: 1px; height: 1px; overflow: hidden;"><a href="http://www.cswpro.de/Howto/FritzBox_OpenVPN.aspx" target="_blank">http://wwww.cswpro.de</a></div>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/02/fritzbox-tuning-part-2-access-your-home-network-with-openvpn/feed/</wfw:commentRss>
		<slash:comments>5</slash:comments>
		</item>
		<item>
		<title>A simple WordPress plugin</title>
		<link>http://www.burningdragon.de/2010/01/a-simple-wordpress-plugin/</link>
		<comments>http://www.burningdragon.de/2010/01/a-simple-wordpress-plugin/#comments</comments>
		<pubDate>Fri, 29 Jan 2010 23:03:30 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Web]]></category>
		<category><![CDATA[Blog]]></category>
		<category><![CDATA[phlogger]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[plugin]]></category>
		<category><![CDATA[programming]]></category>
		<category><![CDATA[statistic]]></category>
		<category><![CDATA[WordPress]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=449</guid>
		<description><![CDATA[As you may noticed I use WordPress for my blog. This is an unbelievable great piece of software. It has uncountable possibilities for enhancements and as soon as you begin to explore these, you start adding some of them to your own blog. One of the plugins I added was WPtouch. This plugin wraps your [...]]]></description>
			<content:encoded><![CDATA[<p>As you may noticed I use <a href="http://wordpress.org" target="_blank">WordPress</a> for my blog. This is an unbelievable great piece of software. It has uncountable possibilities for enhancements and as soon as you begin to explore these, you start adding some of them to your own blog. One of the plugins I added was <a href="http://www.bravenewcode.com/products/wptouch/" target="_blank">WPtouch</a>. This plugin wraps your blog into a theme for mobile devices if they are detected. This works for the iPhone, the Android platform or even Palms webOS. The theme is styled in a way it makes the content more readable on such (screen) limited devices and moves the menus to some extra place.</p>
<h2>Why writing a plugin if there are so many</h2>
<p>On our web server we are using <a href="http://pphlogger.phpee.com/" target="_blank">Power PHLogger</a> for a simple user statistic tracking. Unfortunately this software isn't maintained anymore, but it does it job very well. To use it you have to embed some JavaScript code and a blind image to every website you want to track. My first try was to add this code to the theme I use. This worked ok, but I soon realized that this has to be done on every update of the theme. Additionally this doesn't work with plugins like WPtouch, as there the whole theme is replaced. I searched for a plugin which takes this job, but I didn't find one. So what, I'm a programmer, time for writing it myself.</p>
<h2>Creating the necessary bits of code</h2>
<p>Plugins in WordPress are located at the <strong>wp-content/plugins</strong> directory below the WordPress installation path. You have to choose a name, I used phlogger, and create a directory with that name. The plugin itself is written in PHP and named like the directory with the php extension. As the title says, it's a simple plugin with one public method only, as shown in the following code.</p>
<pre class="brush: php;">
php
/*
Plugin Name: phlogger
Plugin URI:
Description: Adds the power phlogger code to the footer.
Version: 0.1
Author: Christian Pötzsch
Author URI: http://www.burningdragon.de
*/

add_filter('wp_footer', 'phlogger_footer');

function phlogger_footer()
{
 $l = '&lt;script type=&quot;text/&lt;span class=&quot;&gt;&lt;!--mce:0--&gt;&lt;/script&gt;'.&quot;\n&quot;.'&lt;noscript&gt;mce:1&lt;/noscript&gt;'.&quot;\n&quot;;

 echo $l;
}
?&gt;
</pre>
<p>The method just outputs the code for the phlogger tracking. WordPress executes this method because of the <strong>add_filter</strong> call. <a href="http://codex.wordpress.org/Plugin_API/Action_Reference/wp_footer" target="_blank"><em>wp_footer</em></a> is the filter keyword for content which should be added to the footer of a webpage, just before the &lt;/body&gt; tag. The comment on the top of the file isn't only there for cosmetic reasons. It's parsed by WordPress and shown in the Plugin admin page of your blog settings. So it have to be there.</p>
<p>Of course I could have been adding methods for setting the phlogger link or the user name, but for my case this wasn't necessary. For more information on writing WordPress plugins have a look at the good <a href="http://codex.wordpress.org/Writing_a_Plugin" target="_blank">documentation</a>.</p>
<h2>Conclusion</h2>
<p>Starting to write WordPress plugins is easy. It makes even sense for so simple tasks like this, because it offers the possibility to inject code (and functionality) without changing WordPress or the theme itself.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/01/a-simple-wordpress-plugin/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>FRITZ!Box tuning part 1: Enable remote access over ssh</title>
		<link>http://www.burningdragon.de/2010/01/fritzbox-tuning-part-1-enable-remote-access-over-ssh/</link>
		<comments>http://www.burningdragon.de/2010/01/fritzbox-tuning-part-1-enable-remote-access-over-ssh/#comments</comments>
		<pubDate>Sat, 23 Jan 2010 10:44:17 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[IT]]></category>
		<category><![CDATA[Root]]></category>
		<category><![CDATA[administration]]></category>
		<category><![CDATA[communication]]></category>
		<category><![CDATA[FritzBox]]></category>
		<category><![CDATA[Linux]]></category>
		<category><![CDATA[remote access]]></category>
		<category><![CDATA[ssh]]></category>
		<category><![CDATA[telnet]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/?p=257</guid>
		<description><![CDATA[Recently I changed my Internet service provider to Kabel Deutschland which offers some really good bandwidth for a reasonable price. You get 32 MBit in the download direction and 2 Mbit in the upload direction. Additionally to this you can order a FRITZ!Box 7270 which allows you to use VoIP for the phone part. As [...]]]></description>
			<content:encoded><![CDATA[<p>Recently I changed my Internet service provider to Kabel Deutschland which offers some really good bandwidth for a reasonable price. You get 32 MBit in the download direction and 2 Mbit in the upload direction. Additionally to this you can order a FRITZ!Box 7270 which allows you to use VoIP for the phone part. As I always try to maximize the usage of new hardware I started to explore what is possible with this combination. In this post I will explain how you get access to your FRITZ!Box using ssh. Following this post, some articles about how you can turn the FRITZ!Box into a OpenVPN server and how you can use the VoIP access point remotely from any computer having a VoIP software installed, will be done. As I said the hardware used is a FRITZ!Box Fon WLAN 7270 with the firmware 54/74.04.80 from 2009/12/15 which is an official one from AVM. Other firmware versions may work also, but I haven't tested that. The following topics are all for advanced user. So if you aren't in touch with Linux or start asking what the hell is vi and how get I out of it, stop reading now. All the information in this and the following posts are based on several websites I found in the Internet. Mainly this are some forum entries at <a href="http://www.ip-phone-forum.de" target="_blank">http://www.ip-phone-forum.de</a>, the series about the FRITZ!Box at <a href="http://www.tecchannel.de/server/extra/432803/tuning_hacks_fritzbox_fritz_box_erweiterungen_ftp_telnet/" target="_blank">http://www.tecchannel.de</a>, the posts on <a href="http://www.teamarbyte.de/ssh-fritzbox.html" target="_blank">http://www.teamarbyte.de</a>, the blog at <a href="http://www.realriot.de/category/hardware/fritzbox/" target="_blank">http://www.realriot.de</a> and this article at <a href="http://www.cswpro.de/Howto/FritzBox_OpenVPN.aspx" target="_blank">http://www.cswpro.de</a>. So thanks to all the people for sharing this kind of information. Before we start some words of caution: It's easily possible to render the FRITZ!Box unusable. So there is no warranty of any kind if you do some of the things mentioned in this blog. Also I'm not responsible for anything happen to your FRITZ!Box or the Internet connection. After all making a backup of your current configuration might be a good idea.</p>
<h2>Preparing the FRITZ!Box</h2>
<p>First of all you should register an account at <a href="http://www.dyndns.com" target="_blank">http://www.dyndns.com</a> or any other service for dynamic IP resolution. You can then add this information to the "DynamicDNS" tab of the Internet settings in the FRITZ!Box web frontend. This will allow you to connect to your FRITZ!Box without knowing the IP after a reconnect. Lets use us <em>xtestx.dyndns.org</em> in the following examples. Next you need telnet access to the FRITZ!Box to make the initial configuration for the ssh server. Enabling telnet is as simple as calling <strong><tt>#96*7*</tt></strong> with a local connected phone. To disable the telnet daemon later you call <strong><tt>#96*8*</tt></strong>. Now you need a usbstick where all the software will be installed on and which have to be connected to the FRITZ!Box all the time. In principle the size doesn't matter, around 5 MBytes free space should be enough. Time to connect to the FRITZ!Box for the first time. A simple <strong>telnet fritz.box</strong> should do it.</p>
<h2>Installation and configuration of the ssh server</h2>
<p>For the ssh server software <a href="http://matt.ucc.asn.au/dropbear/dropbear.html" target="_blank">dropbear</a> is used. You can get a prepared version for the FRITZ!Box from the spblinux server.</p>
<pre class="brush: bash;">
cd /var/tmp
wget http://www.spblinux.de/fbox.new/cfg_dropbear
chmod u+x cfg_dropbear
</pre>
<p>After downloading, the server has to be installed on the usbstick by executing</p>
<pre class="brush: bash;">
./cfg_dropbear usb_install
</pre>
<p>In my case the software is installed into<em> /var/media/ftp/FLASH-DISK-01/addons</em>. Now we will create a host key which will be reused even after a reboot of the FRITZ!Box.</p>
<pre class="brush: bash;">
cd /var/media/ftp/FLASH-DISK-01/addons
dropbear/bin/dropbearkey -t rsa -f dropbear/etc/sshd_rsa_host_key
</pre>
<p>The FRITZ!Box has initial no root password entry. We have to create one and save the password hash for later usage.</p>
<pre class="brush: bash;">
passwd
cat /etc/passwd
</pre>
<p>You have to note the part between <em>root:</em> and the next <em>colon</em>.</p>
<h2>Putting all together</h2>
<p>The initial starting point for all modifications on the FRITZ!Box is a file called <strong>/var/flash/debug.cfg</strong>. Its executed on every boot after all the other services are started. We will use it only to start a script which is located on the usbstick. This makes sure that even after a firmware upgrade our changes are not lost. The content looks like the following:</p>
<pre class="brush: bash;">
# execute the start script which is on the usb stick
/var/media/ftp/FLASH-DISK-01/addons/startup.sh
</pre>
<p>Please note that you have to use the <strong>nvi</strong> to edit files on the flash device from the FRITZ!Box, cause all files there are marked as non regular. The <em>startup.sh</em> will do all the work necessary for preparing and starting the ssh server. The content is:</p>
<pre class="brush: bash;">
#!/bin/sh
# whats the base usb directory
BASE=/var/media/ftp/FLASH-DISK-01/addons

# change to a temporary directory
cd /var/tmp

# install and start dropbear with our host key
${BASE}/cfg_dropbear usb_install
/bin/dropbear -E -r ${BASE}/dropbear/etc/sshd_rsa_host_key

# set passwords
echo 'root:XXXXXX:0:0:root:/var/tmp/:/bin/sh' &gt; /var/tmp/passwd
echo 'ftpuser:any:1000:0:ftp user:/var/media/ftp:/bin/sh' &gt;&gt; /var/tmp/passwd

# add fritz box itself in resolv.conf to resolv dhcp attached machines in your network
echo &quot;nameserver 192.168.220.1&quot; &gt;&gt; /var/tmp/resolv.conf
</pre>
<p>You have to replace XXXXXX by the password hash you created above. In my case the network is in the 192.168.220.0/24 subnet and the FRITZ!Box has the IP 192.168.220.1. You have to adjust the name server entry to your environment. After a reboot which could be initiated with <strong>reboot</strong> you should be able to access your FRITZ!Box over ssh.</p>
<p>To allow connections from the outside of your home you need to change the forward rules of the internal FRITZ!Box firewall. Unfortunately you can't add this rule using the web frontend cause it isn't allowed to add rules which targeting the FRITZ!Box itself. Most of the settings for the FRITZ!Box configuration are located in a file called <strong>/var/flash/ar7.cfg</strong>. Use nvi to edit it and search for the string <strong>forwardrules</strong>. If this string is missing you could temporary create a rule in the web frontend, which will you later remove again. You have to change the line so that it looks like this:</p>
<pre class="brush: bash;">
forwardrules =
               &quot;tcp 0.0.0.0:7777 0.0.0.0:22 0 # SSH-Server&quot;;
</pre>
<p>Here the connection port is 7777, but of course could you use any valid port number. You could also add more rules by separating them with a comma. To make the configuration change happen the execution of <strong>ar7cfgchanged</strong> is sufficient.</p>
<h2>Conclusion</h2>
<p>With this setup its possible to connect to the FRITZ!Box with the very secure ssh protocol from inside of your home environment and from the outside. This makes it easily possible to change parameters without manually starting the telnet daemon which is in addition very insecure. Don't forget to remove any temporary rules from the ar7.cfg file and to disable the telnet daemon with the procedure explained above. Stay tuned for the <a href="http://www.burningdragon.de/2010/02/fritzbox-tuning-part-2-access-your-home-network-with-openvpn/">next post</a> about going one step further and making the FRITZ!Box an OpenVPN connection point for your internal network.</p>
<div id="_mcePaste" style="overflow: hidden; position: absolute; left: -10000px; top: 0px; width: 1px; height: 1px;">
<pre>54/74.04.80
</pre>
</div>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2010/01/fritzbox-tuning-part-1-enable-remote-access-over-ssh/feed/</wfw:commentRss>
		<slash:comments>12</slash:comments>
		</item>
		<item>
		<title>Integrating native Cocoa controls into Qt</title>
		<link>http://www.burningdragon.de/2009/12/integrating-native-cocoa-controls-into-qt/</link>
		<comments>http://www.burningdragon.de/2009/12/integrating-native-cocoa-controls-into-qt/#comments</comments>
		<pubDate>Wed, 30 Dec 2009 13:52:01 +0000</pubDate>
		<dc:creator>cp</dc:creator>
				<category><![CDATA[Cocoa]]></category>
		<category><![CDATA[IT]]></category>
		<category><![CDATA[Qt]]></category>
		<category><![CDATA[C++]]></category>
		<category><![CDATA[gcc]]></category>
		<category><![CDATA[help button]]></category>
		<category><![CDATA[Mac OS X]]></category>
		<category><![CDATA[Objective-C++]]></category>
		<category><![CDATA[programming]]></category>

		<guid isPermaLink="false">http://www.burningdragon.de/wordpress/?p=15</guid>
		<description><![CDATA[Making applications looking and feeling as native as possible on every supported platform is one of my main responsibilities within the VirtualBox development. Most of the work therefor is done by the Qt framework which we are using for our GUI. Qt does a nice job for Windows and most of the currently popular X11 [...]]]></description>
			<content:encoded><![CDATA[<p>Making applications looking and feeling as native as possible on every supported platform is one of my main responsibilities within the VirtualBox development. Most of the work therefor is done by the Qt framework which we are using for our GUI. Qt does a nice job for Windows and most of the currently popular X11 window toolkits used under Unix and Linux. They are behaving and looking similar in many ways which make it easy to develop for both architectures. Unfortunately this doesn't count in any case for Mac OS X, which often uses very different approaches or uses very specialized controls to reach a specific aim. One of this controls is the Mac OS X help button who every Mac user is familiar with. If an Mac OS X application doesn't use this help button, it breaks the design rules and the application, lets say, smells a little bit "under designed". The following little example shows how to integrate a <a href="http://developer.apple.com/mac/library/documentation/Cocoa/Reference/ApplicationKit/Classes/NSButton_Class/Reference/Reference.html" target="_blank">NSButton</a> seamlessly into your Qt application.</p>
<h2>Qt make it easy</h2>
<p>Nokia added the <a href="http://doc.trolltech.com/latest/qmaccocoaviewcontainer.html" target="_blank">QMacCocoaViewContainer</a> class with Qt 4.5. This class make it easy to integrate any NSView or deviate of the NSView class into the QWidget hierarchy of an application. The best integration is archived if one deviate from QMacCocoaViewContainer. To use Cocoa code and C++ classes at once the Objective-C++ compiler is necessary. The gcc uses the Objective-C++ compiler automatically if the source file ends with mm. We start with the C++ interface which looks like the following:</p>
<pre class="brush: objc; highlight: [1,12]; pad-line-numbers: 2; wrap-lines: false;">
ADD_COCOA_NATIVE_REF(NSButton);
class CocoaHelpButton: public QMacCocoaViewContainer
{
    Q_OBJECT
public:
    CocoaHelpButton(QWidget *pParent = 0);
    QSize sizeHint() const;
    void onClicked();
signals:
    void clicked();
private:
    NativeNSButtonRef m_pButton;
};
</pre>
<p>For any Qt programmer this class definition is easy to understand. The only unusual is the ADD_COCOA_NATIVE_REF macro call and the NativeNSButtonRef type itself. One could say NativeNSButtonRef should be NSButton* and you are done, but it's not that easy. The reason for this is that the include file will be included first in the Objective-C++ source code file, where the NSButton* definition wouldn't be a problem, but secondly in every C++ source file which will use the CocoaHelpButton, where on the other side any Cocoa code is forbidden. The ADD_COCOA_NATIVE_REF macro avoid this problem by expanding NativeNSButtonRef to NSButton* if Objective-C++ code is compiled and to void* if C++ code is compiled. The macro itself looks like this:</p>
<pre class="brush: cpp; wrap-lines: false;">
#ifdef __OBJC__
# define ADD_COCOA_NATIVE_REF(CocoaClass) \
    @class CocoaClass; \
    typedef CocoaClass *Native##CocoaClass##Ref
#else /* __OBJC__ */
# define ADD_COCOA_NATIVE_REF(CocoaClass) typedef void *Native##CocoaClass##Ref
#endif /* __OBJC__ */
</pre>
<p>The advantage of using such a macro is that one can use all methods of the NSButton in the Cocoa part of the source code without any casting.</p>
<h2>A little bit of Cocoa</h2>
<p>The initialization of the CocoaHelpButton class is straight forward as seen in the next code part:</p>
<pre class="brush: objc; highlight: [14,15,16]; wrap-lines: false;">
CocoaHelpButton::CocoaHelpButton(QWidget *pParent /* = 0 */)
  :QMacCocoaViewContainer(0, pParent)
{
    m_pButton = [[NSButton alloc] init];
    [m_pButton setTitle: @&quot;&quot;];
    [m_pButton setBezelStyle: NSHelpButtonBezelStyle];
    [m_pButton setBordered: YES];
    [m_pButton setAlignment: NSCenterTextAlignment];
    [m_pButton sizeToFit];
    NSRect frame = [m_pButton frame];
    frame.size.width += 12; /* Margin */
    [m_pButton setFrame:frame];
    /* We need a target for the click selector */
    NSButtonTarget *bt = [[NSButtonTarget alloc] initWithObject: this];
    [m_pButton setTarget: bt];
    [m_pButton setAction: @selector(clicked:)];
    /* Make sure all is properly resized */
    resize(frame.size.width, frame.size.height);
    setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed);
}

QSize CocoaHelpButton::sizeHint() const
{
    NSRect frame = [m_pButton frame];
    return QSize(frame.size.width, frame.size.height);
}

void CocoaHelpButton::onClicked()
{
    emit clicked(false);
}
</pre>
<p>This set up the NSButton object and make sure that everything has the right size. As shown there, to make a standard button a help button the bezel style has been set to NSHelpButtonBezelStyle. To get the click notification the wrapper class NSButtonTarget is necessary.  As highlighted in the code above the target action is set to the selector "clicked".  The NSButtonTarget class looks as follow:</p>
<pre class="brush: objc; wrap-lines: false;">
@interface NSButtonTarget: NSObject
{
    CocoaHelpButton *m_pTarget;
}
-(id)initWithObject:(CocoaHelpButton*)object;
-(IBAction)clicked:(id)sender;
@end
@implementation NSButtonTarget
-(id)initWithObject:(CocoaHelpButton*)object
{
    self = [super init];
    m_pTarget = object;
    return self;
}
-(IBAction)clicked:(id)sender;
{
    m_pTarget-&gt;onClicked();
}
@end
</pre>
<p>If you put all this together and add the CocoaHelpButton class to your project you will get some output like this:</p>
<p style="text-align: left;"><a href="http://www.burningdragon.de/wordpress/wp-content/uploads/help1.png"><img class="size-full wp-image-220  aligncenter" title="help" src="http://www.burningdragon.de/wordpress/wp-content/uploads/help1.png" alt="" width="38" height="37" /></a>More integration could be reached by adding wrapper methods for e.g. setting the tooltip, but this is left out as an exercise for the reader.</p>
<h2>Conclusion</h2>
<p>For more complex controls like a NSSearchField more interaction with Cocoa will be necessary. On the other hand this little excursion to the Cocoa world should make it easy for everyone to add shiny new Mac OS X controls to the own Qt application.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.burningdragon.de/2009/12/integrating-native-cocoa-controls-into-qt/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
