simon-dreher.dehttps://blog.simon-dreher.de/2024-03-24T20:26:57+01:00DMARC and friends2024-03-24T20:26:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2024-03-24:/dmarc.html<p>With large providers such as Google and Yahoo looking more into DMARC, this article explains some background
and how to set up DKIM and DMARC with Postfix.</p><p>Beginning february Google and Yahoo start to require DMARC.
They ramp this up slowly: first only temporary errors, then gradually increasing rejection rate (see <a href="https://support.google.com/a/answer/81126?visit_id=638468863104975390-32836362&rd=1">Google documentation</a>).
Some requirements also only affect large senders with more than 5000 messages per day.
Still DMARC is actually a good idea and it doesn't hurt to implement it.</p>
<h2>What is DMARC?</h2>
<p>First some background on DMARC: actually DMARC builds upon two other security mechanisms that you may already know:</p>
<ul>
<li><strong>Sender Policy Framework (SPF)</strong>: is a simple DNS record that specifies which servers should be trusted to send mail for this domain.
For example for my domain it looks like this: <code>ff02.de. TXT "v=spf1 mx a:ananas.ff02.de ~all"</code> (it allows the ingoing mailserver, my second server and disallows all other).
The options are pretty well documented in http://www.open-spf.org/SPF_Record_Syntax/</li>
<li><strong>Domain Keys Identified Mail (DKIM)</strong>: in this case the mail server signs outgoing mails with a key.
The key is published in a DNS record.
DKIM has the advantage that it survives forwarding.</li>
</ul>
<p><strong>DMARC</strong> is then a policy that defines what should happen if a message fails one of the two security mechanisms above.
It has the nice feture that failing messages can be reported to a mail address of your choice.</p>
<p>There are also ARC headers that keep the authenticity chain for forwarded messages.
Did not yet look too much into it, but maybe there's a follow-up blog post coming about this.</p>
<h2>DKIM for Postfix</h2>
<p>Signing messages is handled by OpenDKIM.
For my configuration I followed the docs in <a href="https://wiki.archlinux.org/title/OpenDKIM">Arch wiki</a> and <a href="https://wiki.debian.org/opendkim">Debian</a>.</p>
<p>After installing the package with <code>yay -S opendkim</code>, I configured the config files:</p>
<div class="highlight"><pre><span></span><code><span class="c1"># /etc/opendkim/opendkim.conf</span>
<span class="c1"># Secure base cofiguration from https://wiki.archlinux.org/title/OpenDKIM#Security</span>
<span class="n">Selector</span><span class="w"> </span><span class="n">default</span>
<span class="n">Socket</span><span class="w"> </span><span class="n">local</span><span class="p">:</span><span class="o">/</span><span class="k">var</span><span class="o">/</span><span class="n">spool</span><span class="o">/</span><span class="n">postfix</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">opendkim</span><span class="o">.</span><span class="n">sock</span>
<span class="n">Syslog</span><span class="w"> </span><span class="n">Yes</span>
<span class="n">TemporaryDirectory</span><span class="w"> </span><span class="o">/</span><span class="n">run</span><span class="o">/</span><span class="n">opendkim</span>
<span class="n">UMask</span><span class="w"> </span><span class="mi">002</span>
<span class="n">UserID</span><span class="w"> </span><span class="n">opendkim</span>
<span class="c1"># To tolerate tools that fiddle with headers</span>
<span class="n">Canonicalization</span><span class="w"> </span><span class="n">relaxed</span><span class="o">/</span><span class="n">simple</span>
<span class="c1"># main domain</span>
<span class="n">Domain</span><span class="w"> </span><span class="n">ff02</span><span class="o">.</span><span class="n">de</span>
<span class="c1"># Config based on https://wiki.archlinux.org/title/OpenDKIM#Multiple_domains</span>
<span class="n">KeyTable</span><span class="w"> </span><span class="n">file</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">KeyTable</span>
<span class="n">SigningTable</span><span class="w"> </span><span class="n">refile</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">SigningTable</span>
<span class="n">ExternalIgnoreList</span><span class="w"> </span><span class="n">refile</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">TrustedHosts</span>
<span class="n">InternalHosts</span><span class="w"> </span><span class="n">refile</span><span class="p">:</span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">TrustedHosts</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code><span class="gh">#</span> /etc/opendkim/KeyTable
default._domainkey.ff02.de ff02.de:default:/etc/opendkim/keys/ff02.de/default.private
</code></pre></div>
<p>Contrary to what the Arch wiki says, you dont need multiple line if you use the same key.</p>
<div class="highlight"><pre><span></span><code><span class="err">#</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">opendkim</span><span class="o">/</span><span class="n">SigningTable</span>
<span class="o">*</span><span class="nv">@ff02</span><span class="p">.</span><span class="n">de</span><span class="w"> </span><span class="k">default</span><span class="p">.</span><span class="n">_domainkey</span><span class="p">.</span><span class="n">ff02</span><span class="p">.</span><span class="n">de</span>
<span class="o">*</span><span class="nv">@simon</span><span class="o">-</span><span class="n">dreher</span><span class="p">.</span><span class="n">de</span><span class="w"> </span><span class="k">default</span><span class="p">.</span><span class="n">_domainkey</span><span class="p">.</span><span class="n">ff02</span><span class="p">.</span><span class="n">de</span>
</code></pre></div>
<div class="highlight"><pre><span></span><code># /etc/opendkim/TrustedHosts
127.0.0.1
::1
localhost
37.187.17.172
babaco.ff02.de
</code></pre></div>
<div class="highlight"><pre><span></span><code>opendkim-genkey --restrict --selector default --domain ff02.de --directory /etc/opendkim/keys/ff02.de --bits=2048 --verbose
chown -R opendkim:mail /etc/opendkim
cat /etc/opendkim/keys/ff02.de/default.txt
</code></pre></div>
<p>Then set in <code>default._domainkey TXT</code> in every domain to the output from <code>default.txt</code> (remove the brackets and quotes).</p>
<p>You can test that the DKIM config is correct with <code>sudo -u opendkim opendkim-testkey -vv</code>.
Optionally you can also specify a domain with <code>-d simon-dreher.de</code>.</p>
<p>As I run Postfix with a chroot, the socket file needs to be under <code>/var/spool/postfix</code> and therefore needed to create and fix the owner of the file: <code>chown -R opendkim:postfix /run/opendkim/opendkim.sock</code></p>
<p>In my case I also needed to change the group, as Postfix didn't have he permissions to access the socket file:</p>
<div class="highlight"><pre><span></span><code><span class="err">#</span><span class="w"> </span><span class="o">/</span><span class="n">etc</span><span class="o">/</span><span class="n">systemd</span><span class="o">/</span><span class="k">system</span><span class="o">/</span><span class="n">opendkim</span><span class="p">.</span><span class="n">service</span><span class="p">.</span><span class="n">d</span><span class="o">/</span><span class="n">override</span><span class="p">.</span><span class="n">conf</span>
<span class="o">[</span><span class="n">Service</span><span class="o">]</span>
<span class="err">#</span><span class="w"> </span><span class="k">Use</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="k">group</span><span class="w"> </span><span class="ss">"postfix"</span><span class="p">,</span><span class="w"> </span><span class="n">so</span><span class="w"> </span><span class="n">the</span><span class="w"> </span><span class="n">socket</span><span class="w"> </span><span class="n">uses</span><span class="w"> </span><span class="n">that</span><span class="w"> </span><span class="k">group</span><span class="w"> </span><span class="ow">and</span><span class="w"> </span><span class="k">postfix</span><span class="w"> </span><span class="n">can</span><span class="w"> </span><span class="n">access</span><span class="w"> </span><span class="n">it</span>
<span class="k">Group</span><span class="o">=</span>
<span class="k">Group</span><span class="o">=</span><span class="k">postfix</span>
</code></pre></div>
<p>And then we can finally start OpenDKIM:</p>
<div class="highlight"><pre><span></span><code><span class="n">systemctl</span><span class="w"> </span><span class="n">daemon</span><span class="o">-</span><span class="n">reload</span>
<span class="n">systemctl</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="n">opendkim</span>
</code></pre></div>
<p>To make Postfix communicate with OpenDKIM, we add config like this to <code>main.cf</code>:</p>
<div class="highlight"><pre><span></span><code>non_smtpd_milters = unix:/run/opendkim/opendkim.sock
smtpd_milters = unix:/run/opendkim/opendkim.sock
<span class="gh">#</span> Also run bounce through milters, so bounces are signed by DKIM
internal_mail_filter_classes = bounce
</code></pre></div>
<p>and <code>systemctl restart postfix</code>.</p>
<h2>DMARC</h2>
<p>I used the <a href="https://dmarcian.com/dmarc-record-wizard/">DMARC wizard</a> to generate my DMARC record.
You could also do it manually if you want.</p>
<p>For the start I was conservative and used the most permissive policy (none = don't block anything): <code>v=DMARC1; p=none; rua=mailto:postmaster@simon-dreher.de;</code>
Then set this record into <code>_dmarc.simon-drher.de TXT</code>.</p>
<p>With multiple domains, you can use a reporting adress of the same domain (easier) or point all of them to the same address (then need whitelisting on the receiving domain).</p>
<h2>Test</h2>
<p>Finally we also want to validate that DKIM and DMARC now work.
The https://www.mail-tester.com that was linked in the Debian docs is really easy to use: generate a mail address, send a test mail to it and see the score.
the downside is, that you can only test 3 mails per day for free.
Pro tip: Write a bit more that "Test" into your mail, otherwise you get warnings because pyzor thinks that it looks like spam.</p>
<p>It will probably tell you that the <code>List-Unsubscribe</code> header is missing, but this is not relevant if you don't operate a mailing list.</p>
<p>You could also configure to validate DMARC on incoming mail with <a href="https://wiki.archlinux.org/title/OpenDMARC">OpenDMARC</a>, but for now saved this for another weekend project.</p>Kindle as information dashboard2024-01-01T22:07:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2024-01-01:/kindle-info-dashboard.html<p>How to build an info screen that you can hang into your home by upcycling an old Kindle.
All data gathering, image generation and showing the image are done in a single Go binary running on the Kindle itself.
Featuring a cute penguin that shows the weather.</p><p>Probably in every nerdy household, old hardware lies in drawers and gathers dust.
Since getting a Tolino ebook reader, this also happened to my old Kindle.
EInk displays are actually quite nice to display information without too much energy consumption and are easy to read even in bright light.
So why not recycle the Kindle and use it to display useful information in the hallway?</p>
<p>There are already some similar projects:</p>
<ul>
<li><a href="https://matthealy.com/kindle">Kindle as smart home device by Matt Healy</a>: using a server to render a website to a screenshot; download and display it using a shell script.
It doesn't display the website directly in Kindles browser, because you can't hide the address bar.</li>
<li><a href="https://davidhampgonsalves.com/life-dashboard/">Life dashboard by David Hamp-Gonsalves</a>: using a (lambda) service to render an image, simlarly download it using a shell script, but use an own binary to display it.
Has some additional logic on when to refresh, so it can be still used as normal ebook reader.
The first version used Rust, but in a complete rewrite he used Go.</li>
</ul>
<h2>Jailbreaking the Kindle</h2>
<p>The first step on my journey was to get some more access to the Kindle than just downloading ebooks and opening them.</p>
<p>Luckily there are several tutorials for jailbreaking.
As I had a Kindle 4, I could follow the <a href="https://wiki.mobileread.com/wiki/Kindle4NTHacking">instructions in mobileread wiki</a>, <a href="https://gist.github.com/estysdesu/c90478aac75b732820be6720254aeda7">a pretty nice gist</a> and a <a href="https://www.shatteredhaven.com/2012/11/1337365-ssh-on-kindle-4-usbnetwork-hack.html">blogpost on Kindle jailbreak</a>.
They all cover more or less the same steps, but it helped me to read multiple of them to make some things clearer to me.
For example I skipped to execute the installer of USBNetwork before editing etc files.
If you have another model, you will need to use a different jailbreak.</p>
<p>After this you can add your public ssh key and can ssh into your Kindle the same as every other linux machine.</p>
<h2>Proof of concept</h2>
<p>Before diving into technical implementation, I tried out available tools on the Kindle and what could be sensibly fit onto the screen.</p>
<p>The screen uses a resolution of 600x800px, so the first prototype was just some SVG of that size that I did with inkscape.
Then converted this to a PNG with the required color mode:</p>
<div class="highlight"><pre><span></span><code><span class="n">inkscape</span><span class="w"> </span><span class="n">display</span><span class="o">.</span><span class="n">svg</span><span class="w"> </span><span class="o">-</span><span class="n">o</span><span class="w"> </span><span class="n">display</span><span class="o">.</span><span class="n">png</span><span class="w"> </span><span class="o">--</span><span class="k">export</span><span class="o">-</span><span class="n">png</span><span class="o">-</span><span class="n">color</span><span class="o">-</span><span class="n">mode</span><span class="o">=</span><span class="n">Gray_8</span><span class="w"> </span><span class="o">--</span><span class="k">export</span><span class="o">-</span><span class="n">background</span><span class="o">=</span><span class="n">ffffffff</span>
</code></pre></div>
<p>To display this on the Kindle I <code>scp</code>ed it and drew it using <code>eips -g display.png</code>.
(The mobileread wiki also has <a href="https://wiki.mobileread.com/wiki/Eips">documentation on eips</a>)</p>
<p><a href="/images/kindle-poc.jpg"><img alt="Proof of concept with some ideas" src="/images/kindle-poc.tb.jpg"></a></p>
<h2>Running Go on Kindle</h2>
<p>The biggest technical challenge was to get a Go binary running on the Kindle.</p>
<p>The other similar projects (metnioned in introduction) used a server component to generate the image and then only download and display the image on the Kindle.
I didn't want to maintain another service and additionally I want to keep me the option to also fetch data from the local network.</p>
<p>Cross-compiling for the Kindle was pretty easy: <code>env GOOS=linux GOARCH=arm GOARM=5 go build</code>.
However I then ran into the problem that the binary always panicked with <code>runtime: epollwait on fd 3 failed with 38</code>.
I first thought, this would be related to my network calls, but it even happened with code that just contained sleeps.
Apparently Gos garbage collector or something was the issue, as <a href="https://go-review.googlesource.com/c/go/+/346789">Go requires a Linux kernel >= 2.6.32 since Go 1.18</a>.
You already guessed it: the Kindle uses a kernel version of 2.6.31.
So close ...</p>
<p>The solution is simply to use Go 1.17.
It doesn't suffice to just set the toolchain in go.mod to 1.17, also the go build needs to be of that version.
I used docker/podman to do this:</p>
<div class="highlight"><pre><span></span><code>podman<span class="w"> </span>run<span class="w"> </span>--rm<span class="w"> </span>-v<span class="w"> </span>"<span class="cp">${</span><span class="n">PWD</span><span class="cp">}</span>":/app<span class="w"> </span>-it<span class="w"> </span>docker.io/golang:1.17.13<span class="w"> </span>bash<span class="w"> </span>-c<span class="w"> </span>"cd<span class="w"> </span>/app<span class="w"> </span><span class="err">&&</span><span class="w"> </span>env<span class="w"> </span>GOOS=linux<span class="w"> </span>GOARCH=arm<span class="w"> </span>GOARM=5<span class="w"> </span>go<span class="w"> </span>build"
</code></pre></div>
<p>As Go has an <code>image</code> module in the standard module, I just used that to write a PNG and display it with <code>eips</code>.</p>
<p>Tadaa: we can run a single binary and it paints to the display.
Now what should we show there?</p>
<h2>Modules</h2>
<p>Did separate "modules" that you can theoretically extend and combine as you like.</p>
<h3>Weather</h3>
<p>The very first idea was to display the current weather and weather forecast.
It turns out that the german "Deutsche Wetterdienst" has a public API under https://dwd.api.bund.dev.
The documentation could be better, but with comparing to what is shown in the app, you can determine the units (mostly tenth of normal units, e.g. 0.1°C or 0.1mm).</p>
<p>Most difficulties I had with finding the station ID.
In the end using the <a href="https://www.dwd.de/DE/leistungen/met_verfahren_mosmix/mosmix_stationskatalog.cfg;jsessionid=2212691D61141D9D49556AD72329C265.live21071?view=nasPublication&nn=16102">mosmix list</a> and trying to find the nearest city was working best for me.
The API then returns current values or forecasts (and maxints for past values), depending on the type of the station.
I think the stations from the mosmix list all return forecasts, but not sure.
The app also shows values like wind over time, which is not returned in this API.</p>
<p>Apart from showing the numbers, I also had fun to visualize the weather using a penguin.
Depending on rain, sun and temperature he wears a scarf, sunglasses, carries an umbrella etc.
Implementation wasn't actually that complicated: in a SVG I drew the penguin and its accessoires in multiple layers.
Every layer is then exported to one PNG each and simply printed over each other if e.g. it is cold.</p>
<p>The diagram will probably be extended to also have sunrise and sunset as well as wind.</p>
<h3>Tram departures</h3>
<p>The trams in Karlsruhe are operated by KVV and luckily they do have a public API.
In fact they don't have one API: they have several.
The <a href="https://verkehrsforum-karlsruhe.de/threads/was-ist-mit-der-kvv-live-api-passiert.280/page-2">most comfortable KVV API was shut down</a>, but in the thread another API under https://projekte.kvv-efa.de is mentioned.
To find the station ID you can use</p>
<div class="highlight"><pre><span></span><code><span class="nx">https</span><span class="p">:</span><span class="c1">//www.kvv.de/tunnelEfaDirect.php?action=XSLT_STOPFINDER_REQUEST&coordOutputFormat=WGS84[dd.ddddd]&name_sf=Karlsruhe%20Europaplatz&language=de&outputFormat=JSON&type_sf=stop</span>
</code></pre></div>
<p>(replacing <code>Karlsruhe%20Europaplatz</code> with your station name).
The same APIs are used by <a href="https://github.com/harbaum/kvv">github.com/harbaum/kvv</a>, which uses an Arduino to show departures on an epaper display.</p>
<h3>Word clock</h3>
<p>Also wanted to show the current time and to make it a bit more interesting, it describes the time like "just before quarter past eight".</p>
<h3>Further ideas</h3>
<p>There are a lot of further ideas:</p>
<ul>
<li>calendar events of different sources, e.g. personal calendar, trash collection, public events, birthdays</li>
<li>smart home, like having a floor plan with indoor temperatures and humidity sensors, the current power of photo voltaic ...</li>
<li>a QR code showing WIFI credentials, similar to what your smartphone can do</li>
<li>funny quote/image/pokemon of the day</li>
<li>todo list</li>
</ul>
<h2>Run</h2>
<p>To run the binary every minute, I currently simply use cron as described by <a href="https://matthealy.com/kindle">Matt Healy</a>.</p>
<div class="highlight"><pre><span></span><code>mntroot rw
cp display /mnt/us/display
nano /etc/crontab/root
<span class="gs">* *</span> * <span class="gs">* *</span> /mnt/us/display
/etc/init.d/cron restart
</code></pre></div>
<p>In the future, I would like to do that more sophisticated, e.g. to not poll the weather API every minute.</p>
<h2>Frame</h2>
<p>The info dashboard also should get a nice frame and of course a place where it can be seen.</p>
<p>Using a normal picture frame is tricky, as the screen is 9x12.2cm and fotos are normally 9x13cm.
So all normal foto frames and passepartouts are too high and at the same time a bit tight when using the USB jack.
Also with the Kindle border and buttons there is quite some gap between the screen and frame.
I think I'll try to print a passepartout with cutouts for the buttons.
But I first need to model it and have it printed by some colleague or so.
Will update this article when I've done that.</p>
<h2>Finish</h2>
<p>The code was published to <a href="https://github.com/Semoar/display">github.com/Semoar/display</a>.
Feel free to open issues there.
Or contact me as usual :)</p>
<p><a href="/images/kindle-finished.jpg"><img alt="The finished info dashboard" src="/images/kindle-finished.tb.jpg"></a>
<a href="/images/kindle-without-frame.jpg"><img alt="Kindle without frame" src="/images/kindle-without-frame.tb.jpg"></a></p>security.txt2022-04-10T12:28:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2022-04-10:/security-txt.html<p>How to ease the life of security researchers and improve your security with a simple text file.</p><p>Todays blog post is a simple thing, that a co-worker made me aware of. Do you have some service available on the internet? Would you like to know if there are security vulnerabilities in the service? And would like to ease the life of security researchers if they find such a vulnerability?</p>
<p>For exactly this use case, there is the convention of having a security.txt. Basically this is just a text file placed under <code>/.well-known/security.txt</code> which specifies some parameters on who and how to contact, in case someone found vulnerabilities.</p>
<h1>Creating the file</h1>
<p>The content of the file can be easily crafted manually (see RFC 9116) or you can use a generator, e.g. https://securitytxt.org</p>
<p>There are several options, but the minimal file can be as simple as:</p>
<div class="highlight"><pre><span></span><code><span class="n">Contact</span><span class="o">:</span><span class="w"> </span><span class="n">mailto</span><span class="o">:</span><span class="n">admin</span><span class="err">@</span><span class="n">example</span><span class="o">.</span><span class="na">com</span>
<span class="n">Expires</span><span class="o">:</span><span class="w"> </span><span class="mi">2023</span><span class="o">-</span><span class="mi">03</span><span class="o">-</span><span class="mi">31</span><span class="n">T00</span><span class="o">:</span><span class="mi">00</span><span class="o">:</span><span class="mf">00.000</span><span class="n">Z</span>
</code></pre></div>
<p>If you want to sign it with your GPG key, it is recommended to include the canonical URL. The signing itself you should do on your local machine with <code>gpg --clear-sign security.txt</code></p>
<h1>Publishing the file</h1>
<p>To make the security.txt available on all subdomains, I added this snippet to all my nginx server configurations:</p>
<div class="highlight"><pre><span></span><code>location = /.well-known/security.txt {
alias /srv/security.txt;
}
</code></pre></div>
<p>Additionally it is recommended to also make the security.txt available under <code>/security.txt</code>. For this I added some redirects:</p>
<div class="highlight"><pre><span></span><code><span class="nt">location</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="o">/</span><span class="nt">security</span><span class="p">.</span><span class="nc">txt</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="err">return</span><span class="w"> </span><span class="err">301</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="err">$</span><span class="n">host</span><span class="o">/.</span><span class="n">well-known</span><span class="o">/</span><span class="n">security</span><span class="o">.</span><span class="n">txt</span><span class="p">;</span>
<span class="p">}</span>
</code></pre></div>
<p>And tadaa, it is available under https://blog.simon-dreher.de/.well-known/security.txt</p>IPv6 Stateless Address Autoconfiguration (SLAAC) explained using penguins2020-08-01T16:29:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2020-08-01:/zine-slaac.html<p>IPv6 is cool. The coolest animal is of course the penguin. So why not combine those two and explain the SLAAC protocol with penguins?</p><p>Do you like writing documentation?
I am actually one of the strange people that like to write documentation, maybe because I also like to explain things in general.
The biggest problem I often have with documentation is, that it is either too vague or too dry, so nobody wants to read it.</p>
<p>There have been some attempts to make explanations more playful:</p>
<ul>
<li>For example for Kubernetes, there is the <a href="https://www.cncf.io/phippy/">"The Illustrated Children's Guide to Kubernetes"</a>.
It's beautifully illustrated, but really only barely scratching the surface of what Kubernetes is.</li>
<li>Another attempt is the <a href="https://people.redhat.com/duffy/selinux/selinux-coloring-book_A4-Stapled.pdf">SELinux coloring book</a>.
I personally like, that it tries to dive deeper into the features of SELinux, but the layout and the metaphor with changing protagonists is a bit confusing to me.</li>
<li>A somewhat different attempt are the <a href="https://wizardzines.com">zines by Julia Evans</a>.
They don't have a story line and I would more describe them as kind of sketch notes with more text.
She really manages to make great layouts, but what I most love about her zines is that they are sooo informative.</li>
</ul>
<p>Mostly inspired by Julia, I tried to do my own zine. At the time when I began, I was just hearing a lecture about IPv6. Althoug that protocol is over 20 years old, it took until the last recent years to slowly get traction.
One part of IPv6 is Stateless Link Address Autoconfiguraion (SLAAC): how to assign an unique IPv6 address to every computer without needing an (central) authority, which gives them out one by one and keeps track of all the IP addresses.
At first this sounds like a complicated problem, but SLAAC protocol itself is pretty simple and elegant and so I thought it would be a perfect candidate to make a zine about.</p>
<p>And since I like penguins (a lot!), I tried to explain it using penguins. In the end it became more of a childrens book instead of a zine, but I hope you like the result:</p>
<ul>
<li><a href="/downloads/slaac-with-penguins.pdf">PDF to read</a></li>
<li><a href="/downloads/slaac-with-penguins-printable.pdf">PDF to print</a></li>
</ul>
<p>I'm always happy about mentions of interseting zine and of course feedback via <a href="/pages/email.html">E-Mail</a>.</p>Password management on Linux2019-02-10T11:12:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2019-02-10:/password-management-linux.html<p>A simple solution to store your passwords securly in such a way that they
can be used in multiple programs and machines and also be shared with other people.</p><p>In my <a href="https://inovex.de">work</a> we often us <a href="https://www.passwordstore.org">pass</a> to store team intern shared secrets.
It's a pretty simple wrapper, which encrypts every password in a file (using gpg), can be combined with git and is just easy to use.
(By the way it's from Jason A. Donenfeld, who also is behind WireGuard, which is the hip new VPN.)</p>
<p>As always the <a href="https://wiki.archlinux.org/index.php/Pass">ArchWiki</a> has an awesome documentation on how to set pass up.
The most complicated part is, that you need an GPG key.
For key generation a shameless plug of my colleague's <a href="https://www.inovex.de/blog/openpgp-create-a-new-gnupg-key-1/">blog post on generating a new GnuPG key</a>.</p>
<p>The remaining setup is really simple:</p>
<div class="highlight"><pre><span></span><code>pacman -S pass
# replace with your key id
pass init B528DAC8C4CE9F1DD40FCEA498528C52F33E51D7
</code></pre></div>
<p>After that you can insert your passwords:</p>
<div class="highlight"><pre><span></span><code>#<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">just</span><span class="w"> </span><span class="nv">storing</span><span class="w"> </span><span class="nv">a</span><span class="w"> </span><span class="nv">password</span>
<span class="nv">pass</span><span class="w"> </span><span class="nv">insert</span><span class="w"> </span><span class="nv">example</span>.<span class="nv">com</span><span class="o">/</span><span class="nv">Username</span>
#<span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">multiline</span><span class="w"> </span><span class="nv">content</span>
<span class="nv">pass</span><span class="w"> </span><span class="nv">insert</span><span class="w"> </span><span class="o">-</span><span class="nv">m</span><span class="w"> </span><span class="nv">example</span>.<span class="nv">com</span><span class="o">/</span><span class="nv">Username</span>
</code></pre></div>
<p>I generally use the scheme where the folder is the URL of a website or a pretty clear category such as wifi and the file name is the username or e-mail address used to log in.
If your migrating from another password manager, maybe thats supported by <a href="https://github.com/roddhjav/pass-import">pass-import</a>.</p>
<p>Multiline content allows you to store more information on an account than just a password.
The password always has to be placed in the first line.
The other lines can be filled with whatever you like, e.g. answers to security questions (always use random "answers" and not the real answers, since it's pretty trivial to social engineer most security questions)
or with your username, if you didn't want to use the file name for that.
If you want to store the username in a multiline file, you should prefix the line with 'login:' 'user:' or 'username:', since some scripts (such as browserpass below) assume this formatting.</p>
<h2>Browser extension</h2>
<p>For Firefox and chromium-based web browsers you can use <a href="https://github.com/browserpass/browserpass">browserpass</a> (also works with vivaldi).</p>
<p>On Arch Linux just install it from AUR with</p>
<div class="highlight"><pre><span></span><code>yay -S browserpass
</code></pre></div>
<p>Usage is simple: On the site where you want to log in, you click on the lock icon.
Then you search for the password file, enter your PGP key passphrase and the extension fills in the login form.
The username is extracted from the file name or the content of the pass file, if there is a line starting with 'login:', 'user:' or 'username:'.</p>
<h2>Pass addons</h2>
<p>I ony learned about this addons when researching for this blog article, but they are really cool:</p>
<ul>
<li><a href="https://github.com/tadfisher/pass-otp">pass-otp</a> supports storing and generating of TOTP tokens within pass.
Of course you need to make sure you don't break the second factor principle with this.
E.g. you must not store password and TOTP secret on the same device, only being protected by one single master password.</li>
<li><a href="https://github.com/roddhjav/pass-audit">pass-audit</a> checks password quality using zxcvbn (a more advanced algorithm for guessing password strength) and haveibeenpwnd (a web service with a list of leaked passwords).</li>
<li><a href="https://github.com/roddhjav/pass-update">pass-update</a> simplifies the process of updateing passwords by printing it and then generating and storing a new one when you are ready.</li>
</ul>
<h1>Bonus</h1>
<h2>Encrypted text file</h2>
<p>The first iteration of password management I used (for many years..) was to simply store passwords and other login details in a text file,
which was encrypted using gpg. vim can be configured to decrypt on opening and encrypt on writing with this snippet:</p>
<div class="highlight"><pre><span></span><code><span class="err">"</span> <span class="n">Settings</span> <span class="n">to</span> <span class="n">edit</span> <span class="n">gpg</span> <span class="n">files</span> <span class="n">with</span> <span class="n">vim</span> <span class="n">without</span> <span class="n">leaving</span> <span class="n">decrypted</span> <span class="n">data</span> <span class="n">on</span> <span class="n">the</span> <span class="n">hdd</span>
<span class="err">"</span> <span class="n">Don</span><span class="err">'</span><span class="n">t</span> <span class="n">save</span> <span class="n">backups</span> <span class="n">of</span> <span class="o">*</span><span class="p">.</span><span class="n">gpg</span> <span class="n">files</span>
<span class="n">set</span> <span class="n">backupskip</span><span class="o">+=*</span><span class="p">.</span><span class="n">gpg</span>
<span class="err">"</span> <span class="n">To</span> <span class="n">avoid</span> <span class="n">that</span> <span class="n">parts</span> <span class="n">of</span> <span class="n">the</span> <span class="n">file</span> <span class="n">is</span> <span class="n">saved</span> <span class="n">to</span> <span class="p">.</span><span class="n">viminfo</span> <span class="n">when</span> <span class="n">yanking</span> <span class="n">or</span>
<span class="err">"</span> <span class="n">deleting</span><span class="p">,</span> <span class="n">empty</span> <span class="n">the</span> <span class="s">'viminfo'</span> <span class="n">option</span><span class="p">.</span>
<span class="n">set</span> <span class="n">viminfo</span><span class="o">=</span>
<span class="n">augroup</span> <span class="n">encrypted</span>
<span class="n">au</span><span class="err">!</span>
<span class="err">"</span> <span class="n">Disable</span> <span class="n">swap</span> <span class="n">files</span><span class="p">,</span> <span class="n">and</span> <span class="n">set</span> <span class="n">binary</span> <span class="n">file</span> <span class="n">format</span> <span class="n">before</span> <span class="n">reading</span> <span class="n">the</span> <span class="n">file</span>
<span class="n">autocmd</span> <span class="n">BufReadPre</span><span class="p">,</span><span class="n">FileReadPre</span> <span class="o">*</span><span class="p">.</span><span class="n">gpg</span>
<span class="err">\</span> <span class="n">setlocal</span> <span class="n">noswapfile</span> <span class="n">bin</span>
<span class="err">"</span> <span class="n">Decrypt</span> <span class="n">the</span> <span class="n">contents</span> <span class="n">after</span> <span class="n">reading</span> <span class="n">the</span> <span class="n">file</span><span class="p">,</span> <span class="n">reset</span> <span class="n">binary</span> <span class="n">file</span> <span class="n">format</span>
<span class="err">"</span> <span class="n">and</span> <span class="n">run</span> <span class="n">any</span> <span class="n">BufReadPost</span> <span class="n">autocmds</span> <span class="n">matching</span> <span class="n">the</span> <span class="n">file</span> <span class="n">name</span> <span class="n">without</span> <span class="n">the</span> <span class="p">.</span><span class="n">gpg</span>
<span class="err">"</span> <span class="n">extension</span>
<span class="n">autocmd</span> <span class="n">BufReadPost</span><span class="p">,</span><span class="n">FileReadPost</span> <span class="o">*</span><span class="p">.</span><span class="n">gpg</span>
<span class="err">\</span> <span class="n">execute</span> <span class="s">"'[,']!gpg --decrypt 2> /dev/null"</span> <span class="p">|</span>
<span class="err">\</span> <span class="n">setlocal</span> <span class="n">nobin</span> <span class="p">|</span>
<span class="err">\</span> <span class="n">execute</span> <span class="s">"doautocmd BufReadPost "</span> <span class="p">.</span> <span class="n">expand</span><span class="p">(</span><span class="s">"%:r"</span><span class="p">)</span>
<span class="err">"</span> <span class="n">Set</span> <span class="n">binary</span> <span class="n">file</span> <span class="n">format</span> <span class="n">and</span> <span class="n">encrypt</span> <span class="n">the</span> <span class="n">contents</span> <span class="n">before</span> <span class="n">writing</span> <span class="n">the</span> <span class="n">file</span>
<span class="n">autocmd</span> <span class="n">BufWritePre</span><span class="p">,</span><span class="n">FileWritePre</span> <span class="o">*</span><span class="p">.</span><span class="n">gpg</span>
<span class="err">\</span> <span class="n">setlocal</span> <span class="n">bin</span> <span class="p">|</span>
<span class="err">\</span> <span class="s">'[,'</span><span class="p">]</span><span class="err">!</span><span class="n">gpg</span> <span class="o">--</span><span class="n">symmetric</span>
<span class="err">"</span> <span class="n">After</span> <span class="n">writing</span> <span class="n">the</span> <span class="n">file</span><span class="p">,</span> <span class="n">do</span> <span class="n">an</span> <span class="p">:</span><span class="n">undo</span> <span class="n">to</span> <span class="n">revert</span> <span class="n">the</span> <span class="n">encryption</span> <span class="n">in</span> <span class="n">the</span>
<span class="err">"</span> <span class="n">buffer</span><span class="p">,</span> <span class="n">and</span> <span class="n">reset</span> <span class="n">binary</span> <span class="n">file</span> <span class="n">format</span>
<span class="n">autocmd</span> <span class="n">BufWritePost</span><span class="p">,</span><span class="n">FileWritePost</span> <span class="o">*</span><span class="p">.</span><span class="n">gpg</span>
<span class="err">\</span> <span class="n">silent</span> <span class="n">u</span> <span class="p">|</span>
<span class="err">\</span> <span class="n">setlocal</span> <span class="n">nobin</span>
<span class="n">augroup</span> <span class="kr">END</span>
</code></pre></div>
<p>You can even automate it more with the following snippet (if you save in the format password url/username/whatever-identifier):</p>
<div class="highlight"><pre><span></span><code>#<span class="w"> </span><span class="nv">Print</span><span class="w"> </span><span class="nv">the</span><span class="w"> </span><span class="nv">password</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nv">given</span><span class="w"> </span><span class="nv">service</span>
<span class="nv">function</span><span class="w"> </span><span class="nv">pw</span><span class="ss">()</span><span class="w"> </span>{
<span class="w"> </span><span class="nv">gpg</span><span class="w"> </span><span class="o">-</span><span class="nv">d</span><span class="w"> </span><span class="nv">password</span><span class="o">-</span><span class="nv">file</span>.<span class="nv">gpg</span><span class="w"> </span><span class="mi">2</span><span class="o">&>/</span><span class="nv">dev</span><span class="o">/</span><span class="nv">null</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">grep</span><span class="w"> </span><span class="mh">$1</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">awk</span><span class="w"> </span><span class="s1">'{printf "%s",$1}'</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="nv">xclip</span><span class="w"> </span><span class="o">-</span><span class="nv">selection</span><span class="w"> </span><span class="nv">clipboard</span>
}
</code></pre></div>
<h2>XKCD pass</h2>
<p>No blog post on passwords would be complete without a reference to https://www.xkcd.com/936/.
Unfortunately pass doesn't have support for it (yet? maybe time for a merge request for pwgen...).
But of course you can use your favorite password generation tool to feed passwords into pass.</p>
<h2>Further reads</h2>
<p>Nice blog series on pass and crypto on Linux in general: https://sanctum.geek.nz/arabesque/gnu-linux-crypto-passwords/</p>Cryptographically securing git operations2017-08-28T16:52:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2017-08-28:/git-crypto.html<p>Overview of several lesser known cryptographic features of git and their advantages.</p><p>git is not only totally awesome at storing your source code, it also has many features (just look at <code>git help -a</code>).
Today I want to show you some of them, which use cryptographic signing for various things.</p>
<h1>Signing commits</h1>
<p>The first feature is signed commits, which aren't really common today, but get used increasingly.
They can be easily used, without changing the workflow and provide authentication that this commit has been authored by the signer.</p>
<p>Important to note here is the difference between (cryptographically) signing a commit and signing off a commit.
Signing off is done using the command line switch <code>-s</code> (lower-case s) and justs add a line containing the committer at the end of the commit message.
It is typically used for legal reasons (see git documentation for more details).</p>
<p>For cryptographically signing a commit you have to use the command line switch <code>-S</code> (upper-case s) and either specify the key to use or you have beforehand configured your key in the git config.</p>
<h3>Config</h3>
<p>The <a href="https://git-scm.com/book/en/v2/Git-Tools-Signing-Your-Work">official documentation</a> has a nice introduction on how to use signed commits.
Basically you only have to find the ID of your key and add it to the config (can also be locally configured or passed on the command line):</p>
<div class="highlight"><pre><span></span><code>gpg<span class="w"> </span>--list-secret-keys
git<span class="w"> </span>config<span class="w"> </span>--global<span class="w"> </span>user.signingkey<span class="w"> </span><span class="cp">${</span><span class="n">KEY_ID</span><span class="cp">}</span>
</code></pre></div>
<p>You can verify a specific commit with <code>git verify-commit</code>.
To show for each commit if it is signed you can view the log with this:</p>
<div class="highlight"><pre><span></span><code><span class="nv">git</span><span class="w"> </span><span class="nv">log</span><span class="w"> </span><span class="o">--</span><span class="k">show</span><span class="o">-</span><span class="nv">signature</span>
</code></pre></div>
<p>or include <code>%G?</code> into your custom pretty log format.</p>
<h3>Benefits</h3>
<p>By signing commits you can cryptographically securely prove that a commit has been authored or at least approved by you.
The regular author of a commit can freely be chosen, so anyone could forge it.
Mike Gerwitz spun an amusing <a href="https://mikegerwitz.com/papers/git-horror-story.html">git horror story</a> out of this scenario and shows how signed commits, together with a security policy, can prevent this.</p>
<p>Another plus side is, that if you <a href="https://help.github.com/articles/signing-commits-using-gpg/">add your gpg public key</a> in your github profile it shows a verified badge on your signed commits.</p>
<p>In principle signing the last commit is enough to implicitly sign all the previous commits, since the commits form kind of a <a href="https://en.wikipedia.org/wiki/Merkle_tree">merkle tree</a> (also see the later section on SHA-1).</p>
<p>Signing is not restricted to commits, you can also sign tags or merges (with <code>--verify-signatures</code> on merge you can even verify that the commit to be merged is correctly signed).
Since version 2.2.0 you can even sign your pushes!</p>
<h1>Signed push</h1>
<p>The signing of whole pushes seems to be a much less commonly used feature.
Nearly all the search results I could find were different versions of the git man page.</p>
<p>The protocol between server (where it's pushed to) and client (the pusher) works roughly as follows (according to the original <a href="https://github.com/git/git/commit/a85b377d0419a9dfaca8af2320cc33b051cbed04">commit introducing push signing</a>):</p>
<ol>
<li>The server generates a text file containing the commiter, the old and new refs, a timestamp etc. and a nonce
(computed as HMAC(path, timestamp, secret seed)).</li>
<li>The client then has to sign this file (using GPG) and sends the resulting certificate.</li>
<li>The server (by default) does nothing with this signatue, but it can be used in receive-hooks.
For this several GIT_PUSH_CERT* variables are set and can be used in pre- and post-receive-hook.</li>
</ol>
<p>Such an certificate could look as follows:</p>
<div class="highlight"><pre><span></span><code><span class="n">certificate</span> <span class="n">version</span> <span class="mf">0.1</span>
<span class="n">pusher</span> <span class="n">B528DAC8C4CE9F1DD40FCEA498528C52F33E51D7</span> <span class="mi">1503779574</span> <span class="o">+</span><span class="mi">0200</span>
<span class="n">pushee</span> <span class="o">/</span><span class="n">home</span><span class="o">/</span><span class="n">simon</span><span class="o">/</span><span class="n">test</span><span class="o">-</span><span class="n">gitbare</span>
<span class="n">nonce</span> <span class="mi">1503779574</span><span class="o">-</span><span class="mi">6</span><span class="n">bc9f1573f6b509aa93b</span>
<span class="mi">64</span><span class="n">a8f3381bebb5d66c8380ea7a0afb879cca0c30</span> <span class="n">ab229000201ca35016fdd619d55f7153d3ac9fab</span> <span class="n">refs</span><span class="o">/</span><span class="n">heads</span><span class="o">/</span><span class="n">master</span>
<span class="o">-----</span><span class="kr">BEGIN</span> <span class="n">PGP</span> <span class="n">SIGNATURE</span><span class="o">-----</span>
<span class="n">iQEzBAABCAAdFiEEtSjayMTOnx3UD86kmFKMUvM</span><span class="o">+</span><span class="n">UdcFAlmh2vYACgkQmFKMUvM</span><span class="o">+</span>
<span class="n">UddONAf</span><span class="o">/</span><span class="n">dVsPei9QZ9JpZb6T4yRKMSMlZyjL</span><span class="o">/</span><span class="n">xNr7GwAMrvXmUQFGNtuM8ihTk</span><span class="o">/</span><span class="n">I</span>
<span class="n">zextMCeZ3Wpkzns1j1HG</span><span class="o">+/</span><span class="mi">3</span><span class="n">zZjH8ULFIg31XOO9ek8J0Onl2BH0QwdyGndBW3gUt</span>
<span class="n">axFH97848S1eBYlUPcEl8u2O30rvLCWvEBJ5TsT9LFI3Ujzh</span><span class="o">+</span><span class="mi">6</span><span class="n">kp69wBhdzv</span><span class="o">/</span><span class="n">Zb9</span>
<span class="n">aJX2Sf05l5n4nkEOuhyU4jVAXpK6Xg44cdaZdKYgrD</span><span class="o">/</span><span class="n">ayTnsC</span><span class="o">/</span><span class="mi">6</span><span class="n">CIw605zsP8YAR</span>
<span class="n">ZSdC</span><span class="o">+</span><span class="n">Beth</span><span class="o">/</span><span class="n">cgR1N5e63a6gswnN4wSWiamvaE</span><span class="o">+</span><span class="n">D9BjNEEFK98tzbe1pYj2AY11mR9</span>
<span class="mi">7</span><span class="n">Nf3F6WeuQlsXh6xjwYq09KNedrAxg</span><span class="o">==</span>
<span class="o">=</span><span class="n">nrlt</span>
<span class="o">-----</span><span class="kr">END</span> <span class="n">PGP</span> <span class="n">SIGNATURE</span><span class="o">-----</span>
</code></pre></div>
<p>For this whole exchange to work the server has to offer signed pushes, and for this the <code>certNonceSeed</code> has to be configured on the server:</p>
<div class="highlight"><pre><span></span><code>git config receive.certNonceSeed whateverRandomValue
</code></pre></div>
<p>And then you can push with</p>
<div class="highlight"><pre><span></span><code>git push --signed origin master
</code></pre></div>
<p>What happens with the signed push is totally up to the server.
The receive-hooks could either be used to only accept pushes of specific authors or accept all pushes, but store them into an audit trail.</p>
<p><code>git cat-file blob ${GIT_PUSH_CERT}</code> in a receive-hook yields the certificate with accompanying signature.
Storing them somewhere you could create a chain of certificates, where for each ref update the signer is cryptographically authenticated.
Further tools for creating or auditing such a chain I don't know of, so if you're interested you have to invent something by yourself.</p>
<h3>Inspect the certificate</h3>
<p>A problem I had with the certificate was that I couldn't directly get gpg to verify this combined format.
I had to either split it by hand and verify or use the following commands:</p>
<div class="highlight"><pre><span></span><code><span class="n">csplit</span> <span class="n">certificate</span> <span class="s">'/^-----BEGIN PGP SIGNATURE-----$/'</span> <span class="s">'{*}'</span> <span class="o">--</span><span class="n">prefix</span><span class="o">=</span><span class="s">'signature'</span>
<span class="n">gpg</span> <span class="o">--</span><span class="n">verify</span> <span class="n">signature01</span> <span class="n">signature00</span>
</code></pre></div>
<h3>Benefits</h3>
<p>If you use only signed commits but unsigned pushes, this allows an attacker to reset the head back to an old commit, unless you prevent it server side with settings which disallow force pushes etc.</p>
<p>Even if you do prevent this you can't be sure, to which branch name the signer assigned the commit to.
So an attacker could move the current state of a development branch to master.
For this scenario it's neccessary that he needs some kind of write access, but should actually not be allowed to write to some special branches (such as master).</p>
<p>In summary you can realize a kind of access control system with signed pushes.
Normally git relies for the access control on ssh or classical file attributes.
The committer and author of a git commit are easy to forge and therefore can't be used for (secure) access control.
With cryptographical signing the identity of the pusher is authenticated and the receive-hook can safely decide based on this information.</p>
<p>For now different write access to different branches is solved by separate repos and pull request (e.g. as done on github).
With some signed push based access control it could be even more fine grained (you are only limited to what can be done in a git hook).</p>
<p>This push certificates don't allow to make sure that the repo is on the most recent state in case of a malicious server.
Such a server could just ignore new pushes and serve an old state.</p>
<h1>Security implications of SHA-1</h1>
<p>Since SHA-1 is the hash function used in git and lately there have been several attacks on SHA-1 there remains the question if this has implications on the security of the functions shown above.</p>
<p>As Linus Torvalds himself <a href="https://plus.google.com/+LinusTorvalds/posts/7tp2gYWQugL">explained</a>, originally git didn't rely on the cryptographic collision resistance of SHA-1.
In the signing functions above the signed data is based on SHA-1 hashes.
So if you could find a collision for a commit hash you could get someone to sign one commit content and then change it to the other content, without invalidating the signature.</p>
<p>For now (as Linus rightly mentions) the SHA-1 attacks aren't practical for forging commits.
For one the method described in <a href="https://shattered.it">SHAttered</a> can be detected (which git does)
and secondly it relies on a large block of not displayed binary data (unused jpeg image) in a pdf file.
If your file format isn't that forgiving, it is much more difficult to create colliding documents which don't look like garbage.
Git has few places where something like this could be hidden and the developers implemented protection against the mentioned attack.</p>
<p>So for now it isn't practically exploitable, but moving to a better hash function would be beneficial and is already in development.</p>
<h1>Conclusion</h1>
<p>Signing your commits is backwards compatible and proves the authorship of a commit, so I see nearly no reasons not to use it,
at least for tags and commits of a release it's very beneficial.</p>
<p>For signing pushes I haven't found much practical applications, but there are cases where it's extremely useful.
For example I'm currently building a kind of configuration management system and for this it's not enough to secure that some commit is signed by me, otherwise the config of a machine could be reset to an old state.
With signed pushes however I can ensure that the newest commit is used as long as my server isn't malicous (in which case I'm lost anyways).</p>IoT-LED-Leuchte2017-03-06T20:31:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2017-03-06:/iot-leuchte-de.html<p>Nachdem das Internet-of-Things der neue Hype ist und selbst Hacker
es für ihre DDoS-Attacken entdeckt haben, ist es Zeit auch
etwas aus meinem Haushalt ins Internet zu hängen. Darum hier also eine
Anleitung zum Bau einer Leuchte mit RGB-LEDs und dem ESP8266, die über das lokale Netzwerk
mit MQTT gesteuert werden kann.</p><h1>Hardware</h1>
<p>Material:</p>
<ul>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=nodemcu">NodeMCU</a>
Es geht eigentlich jedes der Boards, ich habe hierfür einen der länglichen
NodeMCU genommen, nicht den D1 mini, den man noch löten muss.</li>
<li><a href="https://de.aliexpress.com/wholesale?SearchText=ws2812+ring">WS2812/NeoPixel Ring</a>
In meinem Fall ein Ring mit 12 LEDs, lässt sich aber ganz einfach an Ringe
anderer Größe anpassen. Bei den LEDs gibt es auch Varianten mit dem
Nachfolger WS2812b, der noch eine weiße Komponente in den LEDs integriert
hat. Diese gibt es in verschiedenen Farbtemperaturen, wie z.B. in <a href="https://de.aliexpress.com/item/1-8-12-16-24-32-40-48-60-93-241-Bits-LEDs-SK6812-WS2812-5050/32782028721.html">warmweiß</a>.</li>
<li>Stromversorgung mit 5V, z.B. <a href="https://www.amazon.de/dp/B01K4XWWE4">ein Hohlstecker-Netzteil</a>
mit dazu passender <a href="https://www.amazon.de/dp/B00CI6ISMG">Einbaubuchse</a>.
Man kann auch direkt die MicroUSB-Buchse auf dem NodeMCU-Board verwenden,
allerdings fiel die Buchse bei einem meiner Boards nach ein paar Mal einfach
ab.</li>
<li>Optional: Eine Steckverbindung zwischen LEDs und ESP8266. Ich habe einfach
herumliegende dreipolige Lüfterstecker verwendet.</li>
</ul>
<p>Hardwareseitig ist wenig zu tun, es muss nur der LED-Ring mit dem ESP8266
verbunden werden und irgendwie mit Strom versorgt werden.</p>
<p>Ich habe dazu einen alten, dreipoligen Lüfteranschluss an die LEDs gelötet (Rot
an 5V, Schwarz an GND und weiß an DI (Data In)). Zum Testen habe ich es dann
mit dem Steckbrett verbunden an 5V, GND und D4. Später habe ich noch eine
passende Buchse an ESP8266 und Stromversorgung angelötet, um später einfacher
den LED-Ring austauschen zu können.</p>
<p>Die Stromversorgung kann man einfach über das USB-Kabel oder ein USB-Netzteil
lösen. Da mir beim Testen allerding bereits einmal die MicroUSB-Buchse abbrach,
habe ich für die endgültige Lösung eine Buchse für einen Hohlstecker angelötet.</p>
<h1>Software</h1>
<p>Softwareseitig benötigt man auf dem ESP8266 auch nicht besonders viel. Ich
nutzte die NodeMCU-Firmware. Diese stellt einen Lua-Interpreter und verschiedene
nützliche Bibliotheken zur Verfügung, hier zum Beispiel eine für MQTT und WS2812.
Die Firmware kann man entweder selbst bauen oder auf https://nodemcu-build.com
die modules auswählen (hier MQTT und WS2812) und später erhält man eine
E-Mail, wo man die Firmware herunterladen kann.</p>
<p>Die Firmware wird dann mit <a href="https://github.com/espressif/esptool">esptool</a> auf
den ESP8266 geflasht:</p>
<div class="highlight"><pre><span></span><code><span class="o">$</span><span class="n">package_manager_install</span><span class="w"> </span><span class="n">esptool</span>
<span class="n">sudo</span><span class="w"> </span><span class="n">esptool</span><span class="w"> </span><span class="o">--</span><span class="n">port</span><span class="w"> </span><span class="o">/</span><span class="n">dev</span><span class="o">/</span><span class="n">ttyUSB0</span><span class="w"> </span><span class="n">write_flash</span><span class="w"> </span><span class="mh">0x00000</span><span class="w"> </span><span class="n">firmware</span><span class="o">.</span><span class="n">bin</span>
</code></pre></div>
<p>Dabei natürlich die richtige USB-Schnittstelle auswählen. Am besten nur den
einen zu beschreibenden Mikrocontroller an den Rechner anschließen.</p>
<p>Anschließend müssen noch die Lua-Dateien darauf geladen werden. Dies kann zum
Beispiel mit <a href="https://esp8266.ru/esplorer/">esplorer</a> erledigt werden (benötigt
Java und die Rechte, mit einer seriellen Schnittstelle zu interagieren). Für
diese Software gibt es viele Tutorials im Internet, darum hier nur in
Kurzfassung:</p>
<ul>
<li>Lua-Dateien aus dem <a href="https://github.com/Semoar/esp8266">github-Repo</a> herunterladen</li>
<li>config.lua anpassen</li>
<li>ESP8266 mit USB verbinden, esplorer verbinden, ESP8266 resetten</li>
<li>Alle Lua-Dateien mit upload auf den ESP8266 laden</li>
<li>ESP8266 resetten</li>
</ul>
<p>Nun sollte zuerst eine LED leuchten, die zweite leuchtet nach ein paar Sekunden
auf, wenn der ESP8266 eine IP-Adresse erhalten hat. Die dritte und vierte
leuchten auf, wenn erfolgreich mit dem MQTT-Server verbunden wurde bzw. wenn
erfolgreich subscribed wurde.</p>
<h2>Infrastruktur</h2>
<p>Die Lampe wird über das MQTT-Protokoll gesteuert, bei dem die Kommunikation zwischen
verschiedenen Knoten über einen zentralen Broker läuft. Genau diesen müssen
wir noch aufsetzen. Dazu kann man auf einem Raspberry Pi oder, wie ich, auf
einem Heimserver einen Server wie <a href="https://mosquitto.org">mosquitto</a> installieren.
Bereits in der Standardkonfiguration funktioniert unsere Lampe, da ich auf
besondere Sicherheitsmaßnahmen verzichtet habe. Ansonsten könnte man noch
Benutzer mit Passwörtern anlegen, Zertifikate konfigurieren oder mit einem
anderen MQTT-Server verbinden, der anderswo steht und beispielsweise die
Lampe aus dem Internet erreichbar macht.</p>
<p>Wenn der MQTT-Server läuft, kann man ihn mit den bei mosquitto mitgelieferten
Kommandozeilenwerkzeugen testen. In einem Terminal abonniert man das Thema <code>/foo</code></p>
<div class="highlight"><pre><span></span><code>mosquitto_sub -h $MQTT_SERVER_IP -t /foo
</code></pre></div>
<p>und in einem anderen sendet man eine Nachricht an dieses Thema:</p>
<div class="highlight"><pre><span></span><code>mosquitto_pub -h $MQTT_SERVER_IP -t /foo -m "bar"
</code></pre></div>
<p>Dann sollte im ersten Terminal die Nachricht <code>bar</code> erscheinen.</p>
<p>Wenn der ESP8266 läuft, kann man die Farbe im Terminal mit folgendem Befehl
ändern:</p>
<div class="highlight"><pre><span></span><code>mosquitto_pub -h $MQTT_SERVER_IP -t /shoji-lamp/light -m "#303010"
</code></pre></div>
<p>Dabei ist die Nachricht eine Farbe, hexadezimal kodiert. Die Farbe per
Kommandozeile zu ändern ist jetzt natürlich nicht besonders komfortabel (ja,
außer für die Linux-Kommandozeilen-Nerds ;)
Dafür gibt es verschiedene Apps für das Smartphonebetriebsystem der Wahl.
Ich habe <a href="https://play.google.com/store/apps/details?id=net.routix.mqttdash">MQTT Dash</a>
ausprobiert, darin konfiguriert man den Server, das Topic und hat dann einen
Farbwähler, mit dem man die Lampe setzen kann.</p>
<h2>Bemerkungen</h2>
<p>In anderen Projekten gibt es noch die Funktion, dass der ESP8266 ein eigenes
WLAN aufmacht, wenn er keine gültige Konfiguration hat. Dann kann man sich mit
diesem WLAN verbinden und auf einer Webseite die Kofiguration bearbeiten.
Damit ist die Einrichtung deutlich einfacher, aber für meine Zwecke reichte mir
der bisherige Stand aus. Wenn so etwas eingebaut werden soll kann man die
vorgefertigte Bibliothek <a href="http://nodemcu.readthedocs.io/en/master/en/modules/enduser-setup/">enduser-setup</a>
benutzen.</p>Lilypond2016-05-28T22:35:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2016-05-28:/lilypond-de.html<p>Mit dem Programm lilypond können Noten in Textform eingegeben werden und daraus ein
optisch ansprechender Notensatz und midi-Dateien erstellt werden. Außerdem
können mehrere Lieder in ein Dokument kombiniert werden.</p><p>Letztens hatte ich den Fall, dass ich ein paar Noten
zusammenschreiben wollte, um bei den Liedern nicht zwischen den Strophen die
Bücher wechseln zu müssen. Ich hatte schon gehört, dass man mit lilypond
Notenblätter erstellen kann und der Ansatz, eine Textdatei zu erstellen und
daraus die Notenblätter zu erstellen, ähnlich wie bei LaTeX, gefällt mir. Da
lilypond auch midi-Dateien erstellen kann, die man mit einem Mediaplayer
abspielen kann, wäre zumindest für mich ein Ersatz für professionelle
Notensatzprogramme wie finale oder Sibelius vorhanden, wenn ich Noten eingeben,
probehören und dann als PDF ausgeben könnte. Zumindest den Notensatz von finale
schlägt lilypond schonmal um Längen...</p>
<h2>Eingabe</h2>
<p>Noten werden so eingegeben, dass zuerst der Notenname (klein geschrieben) und
dahinter die Länge der Note eingegeben wird, zum Beispiel <span
class="key">g4</span> wäre ein Viertel g. Dabei wird immer die Tonhöhe gewählt,
die am nächsten zum vorherigen Ton ist. Möchte man also größere Sprünge machen
muss man mit <span class="key">,</span> oder <span class="key">'</span> eine
Oktave nach unten oder oben verschieben, z.B. mit <span class="key">a,2</span>.
Für deutsche Benutzer ist noch wichtig zu wissen, dass ein h mit dem Buchstaben
<span class="key">b</span> eingegeben wird und der Ton b mit <span
class="key">bes</span>. Ein -es und -is funktioniert auch bei allen anderen
Tönen. Einen Bindebogen erstellt man mit Klammern.</p>
<div class="highlight"><pre><span></span><code>g4 a4( b4 c4)
</code></pre></div>
<p>Obiges Beispiel erstellt einen Bogen vom a bis zum c. Ein Haltebogen wird
erstellt, indem an die zu haltende Note ein <span class="key">~</span> angehängt wird. Auch auf der
lilypond-Webseite gibt es hierzu eine
<a href="http://lilypond.org/website/text-input.de.html">Einführung</a>.</p>
<p>Mit diesen Grundkenntissen lassen sich einfache Noten eingeben, alle weiteren
Funktionen finden sich in der
<a href="http://lilypond.org/doc/v2.18/Documentation/notation/index">lilypond-Hilfe</a>.
Meine größte Schwierigkeit am Anfang war herauszufinden, welchen Text ich wo
platzieren sollte. Darum hier eine Vorlage, die sich für mich bewährt hat:</p>
<div class="highlight"><pre><span></span><code><span class="o">\</span><span class="n">header</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="nb">title</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"Titel"</span>
<span class="w"> </span><span class="nb">subtitle</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"Untertitel"</span>
<span class="w"> </span><span class="n">composer</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="s">"Komponist"</span>
<span class="w"> </span><span class="c">% Hinweis auf lilypond auf der letzten Seite entfernen</span>
<span class="w"> </span><span class="n">tagline</span><span class="w"> </span><span class="p">=</span><span class="w"> </span>##<span class="n">f</span>
<span class="p">}</span>
<span class="o">\</span><span class="n">paper</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="n">indent</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">0</span><span class="o">\</span><span class="n">cm</span>
<span class="w"> </span><span class="n">ragged</span><span class="o">-</span><span class="n">right</span><span class="w"> </span><span class="p">=</span><span class="w"> </span>##<span class="n">f</span>
<span class="p">}</span>
<span class="c">% Einstellungen, die für alle Stimmen gelten</span>
<span class="k">global</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c">% Tonart</span>
<span class="w"> </span><span class="o">\</span><span class="n">key</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="o">\</span><span class="n">major</span>
<span class="w"> </span><span class="c">% Takt</span>
<span class="w"> </span><span class="o">\</span><span class="nb">time</span><span class="w"> </span><span class="mi">4</span><span class="o">/</span><span class="mi">4</span>
<span class="w"> </span><span class="o">\</span><span class="n">tempo</span><span class="w"> </span><span class="mi">4</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="mi">110</span>
<span class="p">}</span>
<span class="c">% Stimmen:</span>
<span class="n">TrompeteA</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">\</span><span class="n">relative</span><span class="w"> </span><span class="n">c</span><span class="o">''</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">\</span><span class="nb">set</span><span class="w"> </span><span class="n">Staff</span><span class="p">.</span><span class="n">midiInstrument</span><span class="w"> </span><span class="p">=</span><span class="w"> </span>#<span class="s">"acoustic grand"</span>
<span class="w"> </span><span class="c">% Noten:</span>
<span class="p">}</span>
<span class="n">Tuba</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="o">\</span><span class="n">relative</span><span class="w"> </span><span class="n">c</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">\</span><span class="nb">set</span><span class="w"> </span><span class="n">Staff</span><span class="p">.</span><span class="n">midiInstrument</span><span class="w"> </span><span class="p">=</span><span class="w"> </span>#<span class="s">"acoustic grand"</span>
<span class="w"> </span><span class="o">\</span><span class="n">clef</span><span class="w"> </span><span class="n">bass</span>
<span class="w"> </span><span class="c">% Noten:</span>
<span class="p">}</span>
<span class="c">% Ausgabe</span>
<span class="o">\</span><span class="n">score</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="o">\</span><span class="n">new</span><span class="w"> </span><span class="n">StaffGroup</span><span class="w"> </span><span class="o"><<</span>
<span class="w"> </span><span class="o">\</span><span class="n">new</span><span class="w"> </span><span class="n">Staff</span><span class="w"> </span><span class="o"><<</span>
<span class="w"> </span><span class="o">\</span><span class="n">new</span><span class="w"> </span><span class="n">Voice</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">\</span><span class="n">voiceOne</span><span class="w"> </span><span class="o">\</span><span class="k">global</span><span class="w"> </span><span class="o">\</span><span class="n">TrompeteA</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">\</span><span class="n">new</span><span class="w"> </span><span class="n">Voice</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="o">\</span><span class="n">voiceTwo</span><span class="w"> </span><span class="o">\</span><span class="k">global</span><span class="w"> </span><span class="o">\</span><span class="n">TrompeteA</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="o">>></span>
<span class="w"> </span><span class="o">\</span><span class="n">new</span><span class="w"> </span><span class="n">Staff</span><span class="w"> </span><span class="o"><<</span>
<span class="w"> </span><span class="o">\</span><span class="k">global</span><span class="w"> </span><span class="o">\</span><span class="n">Tuba</span>
<span class="w"> </span><span class="o">>></span>
<span class="w"> </span><span class="o">>></span>
<span class="w"> </span><span class="o">\</span><span class="n">midi</span><span class="p">{}</span>
<span class="w"> </span><span class="o">\</span><span class="nb">layout</span><span class="p">{}</span>
<span class="p">}</span>
</code></pre></div>
<p>Mit dieser Vorlage kann man zuerst einstellen, wie das Stück heißt, Takt, Tempo
usw. Für jede Stimme wird so etwas wie für TrompeteA und Tuba angelegt. Dabei
muss "TrompeteA" natürlich in etwas anderes geändert werden, wobei nur Klein-
und Großbuchstaben verwendet werden dürfen. Damit wird eine Variable
angelegt, die man später mit \TrompeteA oder
\welchenStimmennamenSieAuchImmerNehmen verwendet wird. Eine Verwendung ist das
selbe, wie wenn alles hinter dem Gleichheitszeichen kopiert und für \TrompeteA
einsetzt wird.</p>
<p>Zum Inhalt der Variablen: \relative zeigt dabei an, wie hoch der erste Ton sein
soll, mit \clef legt man den Notenschlüssel fest. Danach kommen die
eigentlichen Noten der Stimme. Wenn ich ein Stück abschreibe setze ich immer
<span class="key">|</span> zwischen die Noten um Taktgrenzen zu markieren und
fange auch eine neue Zeile an, wenn in der Vorlage eine neue Zeile beginnt. Das
sind aber nur kosmetische Hilfen, um besser vergleichen zu können und hat
keinen funktionalen Grund.</p>
<p>In dem score-Bereich werden dann die Stimmen zu Notensystemen (Staff)
zusammengefügt und diese wiederum zu Gruppen. Mit \voiceOne werden alle Hälse
der Stimme nach oben ausgerichtet, mit \voiceTwo nach unten. So passen zwei
Stimmen in ein System, wie man es zum Beispiel von mehrstimmigen Klaviernoten
oder von Posaunenchorsätzen kennt [<a href="http://lilypond.org/doc/v2.18/Documentation/notation/multiple-voices">1</a>].</p>
<p>Mit dem midi wird angegeben, dass eine midi-Datei ausgegeben werden soll, um
die Komposition probehören zu könne. Dafür kann auch in den Stimmen ein
Instrument angeben werden, in der Zeile mit midiInstrument. Eine Liste der
Instrumente gibt es
<a href="http://lilypond.org/doc/v2.19/Documentation/notation/midi-instruments.en.html">hier</a>.
Durch die Angabe von midi muss mit \layout auch explizit angeben werden, dass
ein pdf dazugeneriert werden soll, ansonsten erhalten wir nur die midi-Datei.</p>
<p>Wiederholungen sind dabei schwierig, denn sie werden für die midi-Datei
standardmäßig nicht verdoppelt, sondern nur einmal gespielt. Dafür muss, wie in
<a href="http://lilypond.org/doc/v2.18/Documentation/notation/repeats-in-midi">der Dokumentation</a>
\unfoldRepeats festgelegt werden, dass Wiederholungen ausgeschrieben werden.</p>
<h2>midi</h2>
<p>Um diese midi-Datei abspielen zu können müssen unter Linux zusätzliche Pakete
installiert werden, ein Synthesizer und eine Soundfont. Dafür habe ich
fluisynth mit der dazugehörigen Soundfont und einem Plugin für VLC installiert,
damit es dort abgespielt werden kann.</p>
<div class="highlight"><pre><span></span><code>yaourt fluidsynth soundfont-fluid vlc-plugin-fluidsynth
echo "soundfont /usr/share/soundfonts/FluidR3_GM2-2.sf2" >> /etc/timidity++/timidity.cfg
</code></pre></div>
<p>Das Plugin wird dann nach
<a href="https://wiki.archlinux.org/index.php/MIDI#VLC">dieser Anleitung</a> in VLC
eingebunden.</p>
<h2>Ausgabe</h2>
<div class="highlight"><pre><span></span><code>lilypond $dateiname.ly
</code></pre></div>
<p>Generiert eine midi-Datei und ein PDF. Die midi-Datei kann man probehören und
so lange an der lilypond-Datei herumbasteln, bis es einem gefällt. Die
Wiedergabe klingt oft nicht besonders realistisch, aber um abschätzen zu
können, wie ein Stück klingt, reicht es aus.</p>
<p>Wenn man aus der midi-Datei noch eine realistischer klingende Audiodatei
erhalten möchte muss man dafür eine Digital Audio Workstation (DAW), wie
Rosegarden oder Ardour, verwenden. Damit fehlt mir aber die Erfahrung,
vielleicht greife ich das Thema einmal in einem späteren Artikel auf.</p>
<h2>Mehrere Stücke zusammenbringen</h2>
<p>Um entweder mehrere Musikstücke auf ein Blatt zu drucken oder aus mehreren
Liedern ein Buch zu erstellen gibt es zwei Wege:</p>
<ol>
<li>lilypond \book: Um das Score-Elemt in der Lilypond-Datei wird eine
book-Umgebung gepackt [<a href="http://lilypond.org/doc/v2.18/Documentation/notation/file-structure">Doc</a>]. Dabei können andere lilypond-Dateien mit
include eingebunden werden. Nachteile dabei sind, dass nur ein Titel
(nämlich der des letzten Stückes) gesetzt wird und Variablen wie das oben
verwendete global zu Fehlern führen. Dies ist also dafür gedacht, für ein
großes Werk (Oper o.ä.) mehrere Teilstücke zu kombinieren.</li>
<li>Alternativ können lilypond-book und LaTeX verwendet werden. Eigentlich ist
es dazu gedacht, in LaTeX-Dokumenten Notenbeispiele einbinden zu können.</li>
</ol>
<p>Grundsätzlich muss nur ein LaTeX-Dokument angelegt werden und darin</p>
<div class="highlight"><pre><span></span><code>\<span class="nv">begin</span>{<span class="nv">lilypond</span>}
\<span class="k">include</span><span class="w"> </span><span class="s2">"/dateipfad.ly"</span>
\<span class="k">end</span>{<span class="nv">lilypond</span>}
</code></pre></div>
<p>eingebaut werden. Mit diesem Code wird zwischen Notensystemen noch kein Platz
gelassen, darum muss im LaTeX-Dokument noch ein Makro definiert werden, das den
<a href="https://en.wikibooks.org/wiki/LaTeX/Lengths">Abstand</a> zwischen den Systemen
festlegt:</p>
<div class="highlight"><pre><span></span><code><span class="o">\</span><span class="n">newcommand</span><span class="p">{</span><span class="o">\</span><span class="n">betweenLilyPondSystem</span><span class="p">}[</span><span class="mi">1</span><span class="p">]{</span>
<span class="w"> </span><span class="o">\</span><span class="n">linebreak</span>
<span class="w"> </span><span class="c">% Abstand 0.7 bis 2cm, Standard 1cm</span>
<span class="w"> </span><span class="o">\</span><span class="n">vspace</span><span class="p">{</span><span class="w"> </span>1<span class="n">cm</span><span class="w"> </span><span class="nb">plus</span><span class="w"> </span>1<span class="n">cm</span><span class="w"> </span><span class="n">minus</span><span class="w"> </span><span class="mi">0</span><span class="p">.</span>3<span class="n">cm</span><span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c">% Alternativ allen verfügbaren Platz auf die Zwischenräume aufteilen</span>
<span class="w"> </span><span class="c">%\vspace{ \stretch{1} }</span>
<span class="p">}</span>
</code></pre></div>
<p>Dann zu LaTeX transformieren mit</p>
<div class="highlight"><pre><span></span><code>lilypond-book --output=out-dir --pdf Vorspiele.lytex
</code></pre></div>
<p>und im Ordner out-dir das LaTeX-Dokument kompilieren (ich verwende gerne
latexrun).</p>
<h2>Rechtliches</h2>
<p>Noch ein bisschen was zur rechtlichen Seite (wozu hatte ich Jura im
Ergänzungsfach...): Eine Eigenkomposition ist natürlich unproblematisch, doch
oft genug möchte man vielleicht ein vorhandenes Musikstück anpassen, zum
Beispiel um es zu vereinfachen oder an die Besetzung anzupassen. Dabei kommt
das Urheberrecht ins Spiel, das in §23 UrhG genau den Bereich der Bearbeitung
regelt. Damit ist nach Satz 2 zwar das Anfertigen einer Bearbeitung erlaubt,
nach Satz 1 muss jedoch für eine Veröffentlichung und Verwertung die
Genehmigung des Urhebers eingholt werden. Als Veröffentlichung zählt dabei auch
eine Aufführung in der Öffentlichkeit. Rechtlich gesehen ist eine Aufführung
öffentlich, sobald zumindest ein Gast keine persönliche Bindung zum Gastgeber
hat. Also ist eine Aufführung praktisch immer öffentlich, wenn man es nicht
gerade nur einem Freund vorspielt.</p>
<p>Zudem ist zu Beachten, dass nicht nur ein Komponist Urheberrechte an einem
Musikstück hat. So haben bei einer Tonaufnahme die Musiker oder bei einem
Notensatz der Setzer ein Leistungsschutzrecht. Es bietet sich darum an,
Portale für freie Musik zu verwenden. Auf <a href="https://imslp.org">https://imslp.org</a> und
<a href="https://musopen.org">https://musopen.org</a> gibt es jeweils Noten (und zum Teil auch Aufnahmen), bei
denen die Lizenzsituation dabei steht und die als Grundlage für eigene Bearbeitungen
dienen können.</p>Neue KIT Prüfungsordnung2015-10-05T15:17:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2015-10-05:/kit-spo-de.html<p>In meinem Studiengang gibt es eine neue Studienordnung. Weil keiner Lust
hat, beide Ordnungen zu vergleichen habe ich hier eine Auflistung der Unterschiede
zusammengestellt.</p><p>Seit diesem Semester (Wintersemester 2015/16) gibt es eine <a href="http://www.informatik.kit.edu/formulare.php">neue Prüfungsordnung</a>
am <a href="https://kit.edu">KIT</a> für die Masterstudenten in Informatik. Wer wie ich schon letztes Jahr mit
dem Master angefangen hat kann sich
entscheiden, ob man nach der alten Prüfungsordnung weiterstudieren möchte oder
zur neuen wechseln möchte. Leider gibt es die Ordungen nur im PDF-Format und nicht
ein schönes Diff, was sich denn geändert hat. Darum hier eine kurze Zusammenfassung
der Änderungen. Achtung: Es kann sein, dass ich etwas übersehen habe, wer Korrekturen
hat bitte auf jeden Fall bei mir melden!</p>
<h1>Wichtige Änderungen</h1>
<p>Die meiner Meinung nach wichtigsten Änderungen:</p>
<ul>
<li>Die Bedingungen werden flexibler. Bisher musste man eine genau Anzahl an ECTS
in bestimmten Bereichen absolvieren, in Zukunft muss man nur in einem bestimmten
Bereich liegen, wie in der folgenden Tabelle dargestellt:</li>
</ul>
<table>
<thead>
<tr>
<th>Bereich</th>
<th>SPO 2008</th>
<th>SPO 2015</th>
</tr>
</thead>
<tbody>
<tr>
<td>Vertiefungsfach</td>
<td>>15</td>
<td>15 - 52</td>
</tr>
<tr>
<td>Wahlbereich</td>
<td>Rest</td>
<td>12 - 49</td>
</tr>
<tr>
<td>Ergänzungsfach</td>
<td>15 - 18</td>
<td>9 - 18</td>
</tr>
<tr>
<td>Überfachliche (Schlüssel-)Qualifikationen</td>
<td>6</td>
<td>2 - 6</td>
</tr>
</tbody>
</table>
<ul>
<li><em>Praktika / Seminare</em> werden in der SPO 2015 nicht mehr erwähnt, laut Modulhandbuch
gilt jedoch weiterhin, dass maximal 18 ECTS aus Seminaren und Praktika stammen
dürfen, dafür fallen allerdings die anderen Randbedingungen weg.</li>
<li><em>Gesamtprüfung je Vertiefungsfach:</em> Im Modulhandbuch wird von einer Gesamtprüfung
mit 10 - 15 ECTS je Vertiefungsfach gesprochen, in der Studienordung steht jedoch
nichts dazu und auch das Modulhandbuch verweist auf Bestimmungen, die
"demnächst veröffentlicht" werden.</li>
<li><em>Stammmodule:</em> Laut Modulhandbuch müssen nach der neuen Prüfungsordnung vier, anstatt
wie bisher drei, Stammmodule geprüft werden. Dafür werden im Modulhandbuch auch
drei neue Stammmodule aufgezählt: Algorithmen II, Robotik I und Mensch-Maschine
Interaktion. Diese tauchen aber nur in der Übersicht auf, werden jedoch nicht
genauer beschrieben.</li>
</ul>
<h1>Weitere Änderungen</h1>
<p>Weitere Änderungen in der neuen Ordung, geordnet nach Paragraphen:</p>
<ul>
<li>Allgemein: Das generische Femininum der alten Ordnung wurde durch die neutrale Bezeichnung
"Studierende" ersetzt. Dadurch wird leider jeder automatische Diff des Textes
vollkommen sinnlos...</li>
<li>§1 und §2: Einleitung ist gleich geblieben</li>
<li>§3: Regelstudienzeit weniger genau definiert; Vorlesungssprache deutsch wird
nicht mehr erwähnt.</li>
<li>§4: Erfolgskontrollen anderer Art sind nicht mehr exemplarisch aufgezählt;
Aufteilung in Prüfungleistungen und Studienleistungen (lehrveranstaltungsbegleitend);
Änderungen für Lehrende (min. 70% zu benoten); Neue modulübergreifende Prüfungsleistung</li>
<li>§5: Onlineanmeldung zu Prüfungen wird Pflicht; Klausel, dass der Prüfende auswählen
kann, beispielsweise um weiter fortgeschrittene Studierende zu bevorzugen.</li>
<li>§6: Prüfender muss nicht mehr 6 Wochen vor Prügung festgelegt sein; §6 Abs. 4 SPO2008
wurde in §13 SPO2015 verschoben; Maximale schriftliche Prüfungsdauer nun 300 Minuten,
mündlich: maximal 60 Minuten und eine Gruppenprüfung wird möglich.
Kein Beisitzer mehr bei Spezialfällen (§6 Abs. 12 Satz 2 SPO2008).</li>
<li>§6a Erfolgskontrollen im Antwort-Wahl-Verfahren und §6b Computergestützte Erfolgskontrollen werden ermöglicht</li>
<li>§7 Note 4,7 wurde gestrichen; Absatz 8 zum Bestehen von Modulprüfungen geändert
(mein bisheriges Verständnis entspricht der neuen Formulierung); Absätze 10, 11,
sowie 13, 14 (ECTS-Noten) wurden gestrichen.</li>
<li>§8 Fehlversuche von Prüfungen an anderen Hochschulen sind nicht mehr anzurechnen;
Prüfungen anderer Art generell nur einmal wiederholbar (vorher im Modulhandbuch geregelt);
Studienleistungen können mehrfach wiederholt werden; Zur Wiederholung der
Prüfung hat man maximal 4 Semester Zeit; Härtefallantrag (Antrag auf Zweitwiederholung)
geämdert.</li>
<li>§9 in §8 SPO2008 enthalten (ab jetzt unterscheiden sich die Paragraphennummern
der alten und neuen Prüfungsordnung).</li>
<li>§10 Amtsärztliches Attest kann bei Prüfungsrücktritt wegen Krankheit nicht
mehr verlangt werden, nur normales ärztliches Attest;
Sonderfälle bei bereits unmnöglich zu bestehender Prüfung gestrichen.</li>
<li>§11 Überprüfung der Beschuldigung wegen Täuschung/Ordnungsverstoß nicht mehr
möglich; §9 Abs. 4 Satz 2 SPO2008 gestrichen.</li>
<li>§12 Familienpflichten hinzugekommen.</li>
<li>§13 Studierende mit Behinderung oder chronischer Erkrankung: Stärkere
Berücksichtigung der Belange.</li>
<li>§14 Masterarbeit: Präsentation wird Pflicht, Vorschlag zur Formulierung der
Erklärung der selbständigen Arbeit; Student muss Ausgabe der Arbeit auch festhalten;
jetzt nur noch ein Monat Rückgaberecht; bei Differenzen zur Benotung ist ein
Gutachten möglich.</li>
<li>§15 Mehr (30 LP) Zusatzleistungen möglich (Modulhandbuch widerspricht hier).</li>
<li>§16 Prüfungsausschuss: Mehrere kleine Änderungen.</li>
<li>§17 Beisitzer werden nun vom Prüfer benannt; Masterarbeit kann auch extern geprüft werden.</li>
<li>§18 Anerkennung: Studierende haben Anerkennung im ersten Semester vornehmen zu
lassen; unbenotetete Leistungen müssen jetzt mit bestanden eingetragen werden;
Anrechnung von Kenntniserwerb außerhalb des Hochschulsystems möglich.</li>
<li>§19 Minindestens 3 Stammmodule werden nicht mehr erwähnt (im Modulhandbuch allerdings
sogar vier benötigte); Projektgruppen gestrichen; Bedingungen zu Seminaren /
Praktika fehlen.</li>
<li>§§ 20 und 22 - 24 bleiben gleich</li>
<li>§21 Länger (3 Monate) Zeit für die Uni zur Ausstellung des Masterzeugnisses;
Sonderfälle bei differenzierter Bewertung.</li>
<li>§25 Regelungen zum Inkrafttreten</li>
</ul>
<h1>Offene Fragen</h1>
<p>Was diese Gesamtprüfungen sind wird hoffentlich bald geklärt. Ob die im Modulhandbuch
formulierten Bedingungen für Praktika / Seminare und Stammmodule wirklich gelten
oder ob diese möglicherweise noch ein
Überbleibsel oder Irrtum sind wird sich hoffentlich auch noch klären, ebenso wie
auch irgendwann einmal das endgültige Modulhandbuch erscheinen wird, das mehr als
nur die Stammmodule enthält...</p>
<p>Sollte ich neue Informationen erhalten wird dieser Artikel natürlich aktualisiert,
ebenso, wenn jemand näheres weiß und mich per <a href="https://blog.simon-dreher.de/pages/email.html">E-Mail</a> darauf hinweist.</p>Securing your server2015-06-10T23:42:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2015-06-10:/securing-server.html<p>After researching for the university I post my findings on the internet, too.
I will show some tools you should definitely have on your server and some
which are nice to have to improve the security of your server.</p><p>This article is the result of some synergy effects: I had a lecture in university,
where a fellow student and I had to hold a talk about 'Logging, Forensics & Honeypots'.
For this we researched and tested many tools and now that I already learned about
them, I thought to share it with everyone on the internet. </p>
<h1>Basics</h1>
<p>First of all there are the usual basics you always should check:</p>
<ul>
<li>change the password of root</li>
<li>ssh with key-identification only and no direct root login</li>
<li>firewall</li>
<li>if you don't want to fulltime watch for updates: use unattended updates</li>
<li>shut down unneeded services</li>
</ul>
<h1>Logs</h1>
<p>In articles on how to harden linux you can often read that you should read the logs.
But to be honest: How often do you take the time to read all the thousands of log
messages that pile up every day? Right, you never do. Therefore you should use
some kind of log aggregator. Thats a little program that reads your logfiles, throws
the unimportant messages out and summarizes the rest. For this I personally use
<a href="http://sourceforge.net/projects/logwatch/">logwatch</a>, an often used alternative
is <a href="http://logcheck.org/">logcheck</a>. For logwatch there is an excellent german
description on <a href="http://wiki.ubuntuusers.de/Logwatch">ubuntuusers</a> or an english
version by <a href="https://www.digitalocean.com/community/tutorials/how-to-install-and-use-logwatch-log-analyzer-and-reporter-on-a-vps">DigitalOcean</a>.
Usually you configure it to send you an email with the summary every day and then
you just have to look that through every day, which is just a minute of work.
logcheck works a bit differently: it doesn't summarize your logs but sends you
the log lines which look unexpected or suspicious.</p>
<p>Additionally I find it useful to get an information as soon as someone logs in
via ssh. Most simply you can use a little script in the bashrc or similar to
send an email on every login, as shown <a href="http://www.linux-magazin.de/Ausgaben/2010/07/Tuerspion">here (german)</a>
by Charly Kühnast.</p>
<p>Also to this category belongs <a href="http://www.fail2ban.org">fail2ban</a>. It looks into log
files and bans users with too much authentication failures. It delivers filter for
nearly every popular software out of the box and is pretty easy to configure. There
are many tutorials available on the internet.</p>
<h1>IDS/IPS</h1>
<p>The biggest part in our talk was the use of Intrusion Detection Systems (IDS) and Intrusion
Prevention Systems (IPS). In general they try to supervise the system or the network
and try to detect attecks (IDS) or even react to them in order to mitigate them (IPS).
The problem with them is that most are very complex to configure or they spam
you with false positives. We tried a few of them, but for my use case (one up to
maybe five machines) it is too much of a hassle. </p>
<p>If you have a whole network to protect, <a href="https://www.snort.org/">snort</a> looks like
the tool you want, but I personally have no experience with it, since I have just some
servers in different places and no network.</p>
<p>An example for a more simple hostbased IDS is <a href="http://www.tripwire.org">tripwire</a>: It monitors the integrity
of your files. For this you configure which files it should watch, it generates
hashes of them, stores them cryptographically secure (for which you generate a password that
you shouldn't forget...) and then it checks with every run if the hashes changed.
It's pretty simple to use: just install, uncomment some directories, start the
initial run and add a cronjob that informs you regularly. Only downside is, it doesn't
know how logrotate works, so you can't let it check /var/log.</p>
<p>For bigger scenarios you might want to look at <a href="http://www.ossec.net">OSSEC</a>, it also
features rootkit detection and advanced monitoring. Additionally you can integrate
it with splunk, but for my use case it would have been overkill.</p>
<h1>Honeypots</h1>
<p>Honeypots are a very interesting and funny thing. Basically they simulate a vulnerable
host and protocol everything an attacker tries to do. If you like to see, what script
kiddies try to do to your server you can for example run <a href="https://github.com/desaster/kippo">kippo</a>, a very simple
honeypot implemented in Python, or it's improved fork <a href="https://github.com/micheloosterhof/cowrie">cowrie</a>.
I only used kippo, but based on my attackers the added sftp support of cowrie
would have been very useful ;-)</p>
<p><strong>But be warned:</strong> I wouldn't trust the honeypot to be 100% secure, so don't use
it on your production machine or at least separate it in a virtual machine.</p>
<h1>Final words</h1>
<p>As always, but in this case especially, feedback is very much appreciated! Surely
I missed some great tool and I'm always eagerly to know more of them, so just send
me an <a href="https://blog.simon-dreher.de/pages/email.html">email</a>.</p>
<p>And last but not least: If you have, don't forget to secure the weakest link: your users ;-)</p>Automatically backup fotos on Sailfish2014-10-09T00:56:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2014-10-09:/jolla-foto-backup.html<p>Tutorial on automatically uploading fotos to a server when they're made
on the Jolla using systemd and rsync. Can also be applied to other kind of files.</p><p>As previously <a href="/seafile.html">described</a> I use seafile to keep my devices in sync.
Unfortunately there is only a client for Android which packs the Webinterface into
an app but doesn't offer automatic syncing so that I couldn't easily integrate my Jolla-device.
Anyway I didn't want to sync all my
images to my phone, but I thought it would be pretty nice if at least all my
photos from the phone would be uploaded and backed up right after they are made.</p>
<p>So after searching for some app that would do what I want, I realized that my
Jolla phone is like a normal linux distribution and I can use all the normal
linux tools.</p>
<p>The classic tool for syncing is rsync and it perfectly fits for this job
where you just have to sync in one direction.</p>
<h2>Preparing the Client</h2>
<p>First of all you need some way to get access to your server from your phone. We use
a ssh login with a key to do this. Therefor you have to generate a ssh key on your phone.</p>
<div class="highlight"><pre><span></span><code>ssh-keygen
</code></pre></div>
<p>Choose a filename and choose no passphrase. For comfortable use you have to add
the host and the identity file to your ssh-config in '~/.ssh/config'.</p>
<div class="highlight"><pre><span></span><code>Host ananas
HostName ananas.simon-dreher.de
User $username
IdentityFile ~/.ssh/ananas
</code></pre></div>
<p>Of course you have to adjust the values to your needs.
Now comes the main part of the work, we have to set a script up, that monitors a
directory for us and executes a script if any file changes or gets added. Normally
inotify would be used, but since our Sailfish OS is so bleeding edge we can already
use systemd. </p>
<p>The setup is based on the tutorial on <a href="https://wiki.archlinux.org/index.php/rsync#Automated_backup_with_systemd_and_inotify">rsync in the arch wiki</a>.
BTW: vim is already installed, but available under 'vi' or you can use TinyEdit if
you prefer a GUI.</p>
<p>Create a file '~/.config/systemd/user/backup.path' with following content:</p>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">Checks if paths changed or contain new images.</span>
<span class="k">[Path]</span>
<span class="na">PathChanged</span><span class="o">=</span><span class="s">%h/Pictures/Camera</span>
<span class="k">[Install]</span>
<span class="na">WantedBy</span><span class="o">=</span><span class="s">default.target</span>
</code></pre></div>
<p>Next you create the file '~/.config/systemd/user/backup.service' which contains</p>
<div class="highlight"><pre><span></span><code><span class="k">[Unit]</span>
<span class="na">Description</span><span class="o">=</span><span class="s">Backs up files</span>
<span class="k">[Service]</span>
<span class="na">ExecStart</span><span class="o">=</span><span class="s">/home/nemo/backup.sh</span>
</code></pre></div>
<p>Here comes a difference to the arch wiki, where rsync is called directly, whereas
here we use a custom script where we can do additional computations. This script
we have to create next:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="c1"># Check if we're on wlan</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="k">$(</span>ifconfig<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-o<span class="w"> </span>wlan0<span class="k">)</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"WLAN used"</span>
<span class="w"> </span><span class="c1"># Start backup using rsync</span>
<span class="w"> </span>/usr/bin/rsync<span class="w"> </span>Pictures/Camera/<span class="w"> </span>-CErltm<span class="w"> </span>ananas:/mnt/Bilder/Jolla
<span class="k">else</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"No WLAN"</span>
<span class="k">fi</span>
<span class="nb">exit</span>
</code></pre></div></td></tr></table></div>
<p>This text is saved into '/home/nemo/backup.sh'. It still misses some functionality
that starts a sync when you come back to a WLAN and you made photos without WLAN
connection. Until now you have to run the script manually or take another photo.
If you instead like to automatically sync the photos when the WLAN comes back you
can use the following source:</p>
<div class="highlight"><table class="highlighttable"><tr><td class="linenos"><div class="linenodiv"><pre><span class="normal"> 1</span>
<span class="normal"> 2</span>
<span class="normal"> 3</span>
<span class="normal"> 4</span>
<span class="normal"> 5</span>
<span class="normal"> 6</span>
<span class="normal"> 7</span>
<span class="normal"> 8</span>
<span class="normal"> 9</span>
<span class="normal">10</span>
<span class="normal">11</span>
<span class="normal">12</span>
<span class="normal">13</span>
<span class="normal">14</span>
<span class="normal">15</span>
<span class="normal">16</span>
<span class="normal">17</span>
<span class="normal">18</span>
<span class="normal">19</span>
<span class="normal">20</span>
<span class="normal">21</span>
<span class="normal">22</span>
<span class="normal">23</span>
<span class="normal">24</span>
<span class="normal">25</span></pre></div></td><td class="code"><div><pre><span></span><code><span class="ch">#!/bin/sh</span>
<span class="c1"># Check if we're on wlan</span>
<span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="k">$(</span>ifconfig<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-o<span class="w"> </span>wlan0<span class="k">)</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"WLAN used"</span>
<span class="w"> </span><span class="c1"># Start backup using rsync</span>
<span class="w"> </span>/usr/bin/rsync<span class="w"> </span>Pictures/Camera/<span class="w"> </span>-CErltm<span class="w"> </span>ananas:/mnt/Bilder/Jolla
<span class="k">else</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"No WLAN"</span>
<span class="w"> </span>mkdir<span class="w"> </span>/tmp/backup.lock
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="nv">$?</span><span class="w"> </span>-ne<span class="w"> </span><span class="m">0</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">then</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Another script is already waiting for WLAN to sync."</span>
<span class="w"> </span><span class="nb">exit</span><span class="w"> </span><span class="m">0</span>
<span class="w"> </span><span class="k">else</span>
<span class="w"> </span><span class="c1"># Wait for WLAN to come back</span>
<span class="w"> </span><span class="k">until</span><span class="w"> </span><span class="o">[</span><span class="w"> </span><span class="k">$(</span>ifconfig<span class="w"> </span><span class="p">|</span><span class="w"> </span>grep<span class="w"> </span>-o<span class="w"> </span>wlan0<span class="k">)</span><span class="w"> </span><span class="o">]</span><span class="p">;</span><span class="w"> </span><span class="k">do</span>
<span class="w"> </span><span class="nb">echo</span><span class="w"> </span><span class="s2">"Still no WLAN"</span>
<span class="w"> </span>sleep<span class="w"> </span><span class="m">60</span>
<span class="w"> </span><span class="k">done</span>
<span class="w"> </span>/usr/bin/rsync<span class="w"> </span>Pictures/Camera/<span class="w"> </span>-CErltm<span class="w"> </span>ananas:/mnt/Bilder/Jolla
<span class="w"> </span>rm<span class="w"> </span>-rf<span class="w"> </span>/tmp/backup.lock
<span class="w"> </span><span class="k">fi</span>
<span class="k">fi</span>
<span class="nb">exit</span>
</code></pre></div></td></tr></table></div>
<p>Since I found no way to trigger the script when WLAN comes back I had to fall back
to polling. You can change the interval, how long the script sleeps.</p>
<h2>Preparing the server</h2>
<p>For the SSH connection the server has to know the public key and therefor you
have to somehow get '~/.ssh/ananas.pub' or how you called the SSH keyfile in
part one onto your server. There you have to append it to '~/.ssh/authorized_keys'.</p>
<div class="highlight"><pre><span></span><code>cat ananas.pub >> .ssh/authorized_keys
</code></pre></div>
<p>I recommend that you secure this ssh access since the key file lies on a mobile
device and is not protected by a passphrase.</p>
<p>You can add two v to the options of the rsync command in the shell script. Then it's
more verbose and shows you which command is executed on the server. </p>
<div class="highlight"><pre><span></span><code>rsync --server -vvlmtErCe.iLs . /mnt/Bilder/Jolla
</code></pre></div>
<p>This command can now pasted into the authorized_keys file before the appended key, on
the same line:</p>
<div class="highlight"><pre><span></span><code>command="rsync --server -lmtErCe.iLs . /mnt/Bilder/Jolla",no-agent-forwarding,no-port-forwarding,no-pty,no-user-rc,no-X11-forwarding ssh-rsa AA...
</code></pre></div>
<p>Now this is the only command that can be executed with this SSH key. Note that
if you remove the vv from the script you also have to remove them from the
authorized_keys file.</p>
<h2>Finishing</h2>
<p>Now run the script manually once to test and add fingerprint to known hosts.
If everything worked we can now enable our systemd files:</p>
<div class="highlight"><pre><span></span><code>systemctl --user start backup.path
systemctl --user enable backup.path
</code></pre></div>
<p>Now we can take a photo and magically it syncs to your server and all your other devices. Tadaa.</p>100 Tage Jolla2014-09-29T10:47:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2014-09-29:/jolla-de.html<p>Bericht über mein neues Jolla-Phone und Sailfish OS.</p><p>Mein altes Smartphone kam so langsam in die Jahre und nach kurzer Abwägung zwischen
<a href="http://www.google.de/nexus/5/">Nexus 5</a>, <a href="http://oneplus.net/de">OnePlus One</a> und
<a href="https://jolla.com/">Jolla</a> entschied ich mich für letzteres und will hier meinen
ersten Eindruck sowie die Erfahrungen nach 100 Tagen wiedergeben.</p>
<h1>Hardware</h1>
<p>Das Jolla-Phone liegt vom Preis her ungefähr bei einem Nexus 5, hat jedoch weniger
eingebauten Speicher, eine schlechtere Auflösung sowie weniger Rechenleistung.
Dafür hat das Jolla einen SD-Karten-Platz und einen wechselbaren Akku. Vor allem
der SD-Speicher ist für mich ein wichtiges Feature, ich verstehe nicht, warum das
Verwenden einer Speicherkarte für Android-Nutzer zu <a href="https://plus.google.com/+MatiasDuarte/posts/JAAMUzx1PFX">verwirrend</a> sein sollte. Das eigentliche
Alleinstellungsmerkmal des Jolla ist jedoch die "Other Half", die wechselbare Akkuabdeckung,
die mit dem Telefon kommunizieren kann. Bis jetzt gibt es noch kaum marktreife
"Andere Hälften", es sind aber schon mehrere in Entwicklung, zum Beispiel eine
ausziehbare Tastatur.</p>
<h1>Software</h1>
<p>Eine weitere Besonderheit ist das Betriebsystem: <a href="https://sailfishos.org/">Sailfish OS</a>. Es ist eine Linuxdistribution,
die sehr große Ähnlichkeit mit einer normalen Distribution für den Desktop hat
und oft auf die neuesten Programme setzt.
Nebenbei hat man damit natürlich die Hoffnung, dass man damit ein NSA-freies Telefon
hat.</p>
<h2>Erstes Einschalten</h2>
<p>Nach dem ersten Einschalten kommen wie auch bei Android-Telefonen einige Einstellungen
und eine Einführung. Auf der eigentlichen Oberfläche angekommen folgt erst einmal
Ernüchterung: es gibt genau 9 vorinstallierte Applikationen. Nach kurzem Nachdenken
macht es allerdings durchaus Sinn, das Telefon nicht vollzustopfen und ist eine
willkommene Abwechslung zu den üblichen Samsung-Android-Telefonen mit drölfzig
schrottigen Apps. Ein Blick in den Jolla-Store zeigt, dass zumindest die grundlegenden
Anwendungen alle vorhanden sind und einfach nach Bedarf nachinstalliert werden
können. Die Bedienung erfolgt mit Gesten, die man mit Hilfe der Einführung
recht schnell lernt und danach nicht mehr missen möchte. Im Gegensatz zu meinem
Android-Telefon, und auch den meisten anderen, die ich kenne, treten keine Ruckler
auf, obwohl die Rechenleistung nicht unbedingt üppig ist.</p>
<h2>Kalender</h2>
<p>Mein Radicale Server ließ sich ganz leicht einbinden. Etwas ungewohnt ist, dass
Konten nicht in der jeweiligen App eingerichtet werden, sondern in den ganz normalen
Einstellungen. Darum geht man einfach in die Einstellungen und kann dort
ein neues Konto hinzufügen und zwar ein CalDAV-Konto. Dort "General CalDAV" auswählen
und dort Benutzername und Passwort eingeben. Als Serveradresse den Namen des Servers
inklusive Protokoll eingeben und als Serverpfad die Ordner. Beispielsweise also
"http://calendar.example.net" als Servername und $Name/$Kalender/ als Pfad. Nach einer
kurzen Wartezeit kommen die Termine dann auch in der Kalender-App an.</p>
<p>Für Kontalte gibt es bisher leider noch keine Möglichkeit, sie über CardDAV zu
synchronisieren, sondern nur über Microsoft Exchange.</p>
<h2>E-Mail</h2>
<p>Auch E-Mail-Accounts lassen sich genauso einfach einrichten, einfach unter den Einstellungen
hinzufügen, die üblichen Angaben wie bei einem normalen Desktop-Client machen und
schon können die Mails mit der Mail-App abgerufen werden.</p>
<p>Bei mir zeigte die App merkwürdigerweise mehrere schon gelöschte Mails an, die schon
vor dem ersten Sync gelöscht worden waren. Wenn man in Thunderbird den entsprechenden
Ordner komprimiert oder Thunderbird neu startet verschwinden die gelöschten Mails auch
im Jolla-Client. Anscheinend ignoriert Jolla das Gelöscht-Flag.</p>
<h2>WhatsApp</h2>
<p>Wie viele, die sich das Jolla-Phone gekauft haben, gehöre auch ich zu den Privatsphäre-
Paranoikern. Deshalb war mir WhatsApp bisher immer suspekt (abgesehen von dem absolut
grottigen Interface). Für Sailfish gibt es dagegen einen alternativen Client: <a href="https://www.openrepos.net/content/coderus/mitakuuluu">Mitäkuuluu</a>.
Dieser hat den großen Vorteil, dass es nicht einfach alle Kontakte zu WhatsApp hochlädt,
sondern man kann auswählen, welche gesynct werden. Da Mitäkuuluu leider (noch) nicht
im normalen Jolla-Store zu finden ist muss man dafür die Installation von Fremdsoftware
erlauben und den OpenRepo-Paketmanager installieren. Darin findet man dann die
Mitäkuuluu-App und andere, wie zum Beispiel gpodder. Die Einrichtung von mitäkuuluu
funktioniert ähnlich wie beim normalen WhatsApp: Nummer, Name und Passwort eingeben,
auf Verifikations-SMS warten und Kontakte hinzufügen.</p>
<p><strong>Hinweis:</strong> Inzwischen wurden mehrere Mitäkuuluu-Nutzer gebannt und deshalb die App aus
OpenRepos herausgenommen. Der normale Client funktioniert über die Android-Runtime jedoch auch
und konnte zumindest bei mir zunächst nicht auf die Kontakte zugreifen, sondern erst nach einem
Neustart.</p>
<h2>Jabber</h2>
<p>Für die Kontakte, welche nicht bei WhatsApp sind braucht man natürlich auch noch eine
Kommunikationsmöglichkeit. Bei mir haben diese alle einen Jabber-Account, so dass
auf dem Telefon natürlich nach Möglichkeit auch ein Jabber-Account eingerichtet
werden sollte. Wie sich herausstellte war dies allerdings deutlich schwieriger als
die vorherigen Apps. In den Einstellungen kann man ganz einfach ein XMPP-Konto
hinzufügen. Damit hört der einfache Teil aber auch schon auf: keine Ahnung, ob ich
online bin, keine Ahnung wo das Konto verwendet werden kann. Eigentlich sollte
sich das Telefon mit dem Jabber-Server verbinden, die Kontakte herunterladen und
in die eigenen Kontakte einfügen. Mit der Nachrichten-App sollte man dann Jabber-
Nachrichten versenden und empfangen können. Nach einiger Suche fand ich auch, wo
man den Status des Kontos ansehen kann: Im Notification-Bereich findet man im
Pull-Down-Menü den Status und kann ihn auch ändern. Bei mir werden allerdings nicht
einmal Konten angezeigt, bei denen der Status geändert werden kann. Auch einige
Threads auf <a href="https://together.jolla.com">together.jolla.com</a> halfen nicht weiter (sonst übrigens eine großartige
Informationsquelle). Ein Neustart half auch nichts, löschen und wieder hinzufügen
auch nicht. Ein Blick in meine Serverlogs zeigte, dass dieser eine Verbindung angenommen
hatte, das Jolla versuchte allerdings nach wenigen Sekunden eine neue Verbindung,
also wird wohl irgendetwas nicht geklappt haben. Zum Glück gibt es auf dem Jolla
eine Konsole (taucht auf, sobald man den Entwickler-Modus aktiviert). Damit
sagte telepathy/gabble mir dann mal, dass es mit dem TLS nicht zufrieden ist.
Bis jetzt konnte ich leider noch nicht herausfinden, wie das Problem zu lösen ist.</p>
<h2>Podcasts</h2>
<p>Für Podcasts kann man bei openrepos.net <a href="https://www.openrepos.net/content/thp/gpodder">gpodder</a> herunterladen und damit Podcasts
abonnieren. Zuerst war ich von der App enttäuscht, denn der Funktionsumfang sieht
sehr klein aus. Nach etwas ausprobieren stellt man dann fest, dass sämtliche Funktionen
in den Pull-Down-Menüs versteckt sind. So lässt sich zum Beispiel damit nach neuen
Episoden suchen (leider nur manuell). Die neuen Episoden kann man dann mit Hilfe von
"Filter Episodes" anzeigen lassen und dort manuell herunterladen. Im dortigen
Pull-Down-Menü kann man dann wiederum den Filter ändern und beispielsweise alle
noch ungehörten, heruntergeladenen Podcasts anzeigen. Was leider trotzdem fehlt
ist die Möglichkeit, OPML-Dateien zu importieren oder sich die Liste aus seinem
gpodder.net-Account zu holen. Immerhin werden Shownotes und Kapitelmarken unterstützt.
gpodder ist damit zwar benutzbar, es wäre aber schön, wenn die Bedienung noch
intuitiver gestaltet würde.</p>
<h2>Weitere Apps</h2>
<p>Man kann aber bisher auch gut den kompletten Jolla-Store durchschauen und alle
Apps installieren, die interessant aussehen. Es hat auch Vorteile, wenn es wenige
Apps gibt ;-)</p>
<h2>Aussehen</h2>
<p>Ein nettes Gimmick sind die Ambiente. Damit kann man ein beliebiges Bild als
Hintergrundbild festlegen und davon werden passende Farben für die UI-Elemente
abgeleitet.</p>
<h2>Android-Apps</h2>
<p>Gerade jetzt, wo es noch nicht Hunderttausende von Apps für Sailfish gibt, ist es
praktisch, dass man auch Android-Unterstützung nachinstallieren kann. Leider fallen
diese Apps natürlich auf, da sie sich nicht in das Look&Feel einfügen, es sind
nicht alle Apps im Store verfügbar und auch die verfügbaren funktionieren nicht
reibungslos, sondern stürzen manchmal ab, wenn sie mit dem Betriebsystem interagieren.</p>
<p>Sehr praktisch ist es allerdings, K-9 Mail zu installieren, falls man dringend
Push-Mail bzw. IMAP-Idle benötigt, solange der native Client das nicht kann.
Man muss dann eben damit leben, die unschöne Android-Oberfläche zu benutzen.
Sinnvoll ist auch der VLC Videoplayer, denn der eingebaute spielt nicht alles ab,
beim Video schauen sieht man die Android-Oberflache sowieso nicht und der VLC
nutzt sogar Gesten zur Steuerung, so dass man sich fast schon wieder wie bei Sailfish
fühlt.</p>
<h2>LPM</h2>
<p>LPM steht für Low Power Mode und steht für etwas, das sich vor allem die Jolla-Nutzer,
die vom N9 umgestiegen sind, gewünscht haben. Dort werden nämlich immer die Uhrzeit
und grundlegende Informationen angezeigt, ohne dass man den Bildschirm extra anschalten
muss. Beim Jolla geht das aufgrund der Bildschirmtechnik zwar nicht genau so, doch
kann man mit <a href="http://www.jollausers.com/2014/07/video-tutorial-want-lpm-on-jolla-heres-a-tutorial/">dieser Anleitung</a></p>
<div class="highlight"><pre><span></span><code><span class="n">devel</span><span class="o">-</span><span class="n">su</span>
<span class="o"><</span><span class="n">Passwort</span><span class="o">></span>
<span class="n">pkcon</span><span class="w"> </span><span class="n">update</span>
<span class="n">pkcon</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">mce</span><span class="o">-</span><span class="n">tools</span>
<span class="n">mcetool</span><span class="w"> </span><span class="o">--</span><span class="n">set</span><span class="o">-</span><span class="n">low</span><span class="o">-</span><span class="n">power</span><span class="o">-</span><span class="n">mode</span><span class="o">=</span><span class="n">enabled</span>
</code></pre></div>
<p>den Näherungssensor dazu verwenden, dass immer wenn das Display nicht mehr abgedeckt ist
für 10 Sekunden die Uhrzeit usw. angezeigt.</p>
<h1>Nach 100 Tagen</h1>
<p>Einziges Problem, das bei mir bis jetzt aufgetaucht ist, ist eine endlose Neustartschleife,
die manchmal auftritt, wenn man längere Zeit kein Netz hatte und dann wieder eine
Mobilfunkdatenverbindung bekommt. Dieser Fall tritt allerdings selten auf und lässt
sich durch unterbrechen der Stromversorgung wieder beheben.</p>
<h1>Fazit</h1>
<p>Das Jolla-Phone ist gut benutzbar, wenn es auch natürlich noch nicht perfekt
ist und an einigen Stellen noch verbessert werden kann. Die Gestensteuerung ist
großartig und schon nach kurzer Zeit so in mein Blut übergegangen, dass ich kein
normales Android-Telefon bedienen kann ohne irgendwelche Wischgesten zu versuchen.
Die Software wird sich mit der Zeit wahrscheinlich noch verbessern und im Gegensatz
zu Android bekommt man sogar Updates! Was mich bisher mehr stört sind fehlende
Hardware wie NFC oder dass es bis jetzt leider noch keine Tastatur dafür gibt.
Aber man kann hoffen dass sich daran ja noch etwas ändert...</p>Color Management on Linux2014-03-15T22:35:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2014-03-15:/color-management.html<p>Some instructions on using some color management on linux, especially covering
display calibration with argyllcms and scanner calibration from the command
line, all on linux with xfce.</p><p>As someone who occasionally does some amateur drawing on the computer I often am
upset about the quality of the colours of my display. Presets from the factory are
nearly always total rubbish and the worst is: You don't believe it until you have
two monitors side-by-side displaying the same colour completely different.
Additionally my scanner also measures wrong colours, which I only noticed after having
calibrated my display. So I decided to calibrate both devices.</p>
<h2>Display</h2>
<p>I think this will be the most interesting part for most of you. Think about how
much time you are spending in front of this thing every day. Shouldn't it then show
you exactly the color it should?</p>
<p>The first thing you need in this part is some kind of calibration measurement hardware,
in german called Kolorimeter. An interesting open source project is <a href="http://www.hughski.com/index.html">ColorHUG</a>,
nevertheless I decided to use a more common device, the <a href="https://www.amazon.de/dp/B006TF3746">Spyder4Express</a>.
If you have some experience with the ColorHUG please let me know, I would be very interested. </p>
<p>First of all you should turn off dynamic contrast in your monitor and wait approximately
half an hour until your display has warmed up. Since most displays are way too bright
you can also reduce the brightness to an amount you like. Keep in mind that you
will lose a bit of brightness by calibrating.</p>
<p>Now that the hardware side is ready we can come to the interesting part: the software.
I used the following workflow on an arch linux derivate with xfce desktop (<a href="http://manjaro.org/">Manjaro</a>).</p>
<p>Next I installed the necessary software: <a href="http://www.argyllcms.com/">argyllcms</a>
and <a href="http://dispcalgui.hoech.net/">dispcalGUI</a>, which is a GUI for argyll.</p>
<p>The process of calibration itself is pretty easy and self explanatory. Just start dispcalGUI,
select the display you want to calibrate on the left, the default settings should
be okay and click on "calibrate & profile".
A little window appears where you can click the middle button to center it on your display.
Now you have to position your colorimeter above this window. For this it has a little
movable balance weight which you can place behind the monitor and then adjust the height of
your colorimeter. After this step another window appears, where you have to use the
settings of your monitor to adjust the white level and then finally "Continue on to calibration".
In the middle of the screen is then shown a square that changes it color.
This takes some time, you can get a coffee or some other <a href="https://github.com/the-teacher/cocktails_for_programmers/blob/master/cocktails_for_programers.md">drink</a>.</p>
<p>When this step ran through you can find the finished icc-profile in ~/.local/share/dispcalGUI/storage/<profilename>/.
According to the dispcalGUI documentation it should automatically configure the loading
of the profile at startup, but since it also says there should be an according option
and I couldn't find it in my version I decided to go safe and configure it manually,
it's really no rocket science and I can once again just recommend the excellent
<a href="https://wiki.archlinux.org/index.php/xfce#Loading_a_profile">arch wiki article on xfce and colour management</a>.</p>
<h2>Scanner</h2>
<p>For the calibration of the scanner you first need a so called target. There are
some by experienced photo companies. Just search for "IT8 target", but these are
all pretty expensive. Alternatively I can recommend you the site of <a href="http://www.targets.coloraid.de/">IT8-Targets by Wolf Faust</a>.
Don't be scared by the ancient looking page, I just sent a letter with the money and
very soon I got a letter back, containing my target and a CD containing the reference file.</p>
<p>When you got your target, you first have to clean the glass of your scanner a bit and then
simply insert the image. Then you have to scan the target using exactly the software
and the presets you will use later and save it as "scanner.tif".</p>
<p>Next you have to somehow get the reference file. Either you insert the cd and copy it
from there or you download the corresponding file from <a href="http://www.targets.coloraid.de/">the website</a> and
extract it.</p>
<p>Then use the command line:</p>
<div class="highlight"><pre><span></span><code>scanin -v Dokumente/scanner.tif /usr/share/argyllcms/ref/it8.cht R130730/R130730.txt
</code></pre></div>
<p>If scanin says something about an incompatible tif file it may help to open it in
gimp and save it again as tif-file.</p>
<p>The last step resulted in a ti3-file, which we can now use to make the icc-profile.
For this you can use dispcalGUI: Open it and go to <em>Options > Create profile from measurement data</em>.
There you have to select the scanner.ti3 file and then can save the finished icc-profile
to a place of your choice.</p>
<p>Now you can use your scanner software with the same settings as above to scan
an image and can then use a photo manipulation software like the gimp to add the
icc-profile to correct the colors. In gimp you can make this by going to <em>Image >
Mode > Assign Color Profile</em>. There you have to select the icc profile and gimp
embeds it into the image. If you want to change the colors you can then use
<em>Image > Mode > Convert to Color Profile</em>. There you select e.g. "sRGB" and gimp
converts the colors.</p>Seafile2014-02-16T21:38:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2014-02-16:/seafile.html<p>Description of my setup of seafile instances and some little hints.</p><p>Ever since I had my home NAS I tried to setup a solution to sync my files. First I
tried <a href="http://owncloud.org/">owncloud</a> which back then had none really working sync
client. The next candidate was <a href="http://www.bittorrent.com/intl/de/sync">BitTorrent Sync</a>.
It had the big advantage of automatically finding local clients for faster transfer
but it is closed source and that was not good for my paranoia...</p>
<p>So I settled for an open source solution, that has proofed for decades: <a href="http://www.cis.upenn.edu/~bcpierce/unison/">unison</a>.
It worked really good but I had to sync it manually or to use a cron job but not
with autosync when a file changes. </p>
<p>So I searched for another solution and found <a href="https://github.com/jewel/clearskies">clearskies</a>,
which is an open source clone of BitTorrent Sync, but it was a very young project,
about 1 month old, and was merely a work in progress. It still looks very promising
and maybe I'll give it a try again later.</p>
<p>Other solutions like <a href="http://sparkleshare.org/">SparkleShare</a> or plain <a href="http://git-scm.com/">git</a>
had problems with large binary files because everything is basically just in a
git repository.</p>
<p>Finally I came to <a href="https://github.com/haiwen/seafile">seafile</a>. It uses git for the metadata and changelog and keeps
the data outside of the git. I first was a bit sceptic because the software is
from China. This is pretty irrational: american software is trusted, chinese
is associated with spyware. Since the NSA it is actual a plus, and furthermore
because it's open, others and I could read the code. Additionally it has built-in
client side encryption, so I can store only encrypted data on my untrusted server
at the hosting company.</p>
<h2>Setup Server</h2>
<ol>
<li>
<p>First install dependencies and add the user to run seafile under.</p>
<div class="highlight"><pre><span></span><code><span class="n">sudo</span><span class="w"> </span><span class="n">aptitude</span><span class="w"> </span><span class="n">install</span><span class="w"> </span><span class="n">python2</span><span class="o">.</span><span class="mi">7</span><span class="w"> </span><span class="n">python</span><span class="o">-</span><span class="n">setuptools</span><span class="w"> </span><span class="n">python</span><span class="o">-</span><span class="n">simplejson</span><span class="w"> </span><span class="n">python</span><span class="o">-</span><span class="n">imaging</span><span class="w"> </span><span class="n">sqlite3</span>
<span class="n">sudo</span><span class="w"> </span><span class="n">adduser</span><span class="w"> </span><span class="n">seafile</span>
<span class="n">sudo</span><span class="w"> </span><span class="n">su</span><span class="w"> </span><span class="n">seafile</span>
</code></pre></div>
</li>
<li>
<p>Next we run the following commands under the user seafile.</p>
<div class="highlight"><pre><span></span><code><span class="n">cd</span>
<span class="n">wget</span><span class="w"> </span><span class="n">https</span><span class="p">:</span><span class="o">//</span><span class="n">bitbucket</span><span class="o">.</span><span class="n">org</span><span class="o">/</span><span class="n">haiwen</span><span class="o">/</span><span class="n">seafile</span><span class="o">/</span><span class="n">downloads</span><span class="o">/</span><span class="n">seafile</span><span class="o">-</span><span class="n">server_2</span><span class="o">.</span><span class="mf">1.4</span><span class="n">_x86</span><span class="o">-</span><span class="mf">64.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span>
<span class="n">tar</span><span class="w"> </span><span class="o">-</span><span class="n">xvf</span><span class="w"> </span><span class="n">seafile</span><span class="o">-</span><span class="n">server_2</span><span class="o">.</span><span class="mf">0.2</span><span class="n">_x86</span><span class="o">-</span><span class="mf">64.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span>
<span class="n">rm</span><span class="w"> </span><span class="n">seafile</span><span class="o">-</span><span class="n">server_2</span><span class="o">.</span><span class="mf">0.2</span><span class="n">_x86</span><span class="o">-</span><span class="mf">64.</span><span class="n">tar</span><span class="o">.</span><span class="n">gz</span>
<span class="n">cd</span><span class="w"> </span><span class="n">seafile</span><span class="o">-</span><span class="n">server</span><span class="o">-</span><span class="mf">2.0</span><span class="o">.</span><span class="mi">2</span><span class="o">/</span>
<span class="o">./</span><span class="n">setup</span><span class="o">-</span><span class="n">seafile</span><span class="o">.</span><span class="n">sh</span>
<span class="o">./</span><span class="n">seafile</span><span class="o">.</span><span class="n">sh</span><span class="w"> </span><span class="n">start</span>
<span class="o">./</span><span class="n">seahub</span><span class="o">.</span><span class="n">sh</span><span class="w"> </span><span class="n">start</span><span class="w"> </span><span class="mi">8000</span>
<span class="o"><</span><span class="n">Ctrl</span><span class="o">-</span><span class="n">D</span><span class="o">></span>
</code></pre></div>
<p>Of course you have to adjust the version number if it differs from the one
used in this example. If you're paranoid you can also compile it from the
sources.</p>
</li>
<li>
<p>Set your firewall to let through port 12001 (or whatever ccnet listens to).</p>
<div class="highlight"><pre><span></span><code>sudo ufw allow 12001/tcp
</code></pre></div>
</li>
<li>
<p>Make your port 8000 reachable from the outside by either opening the port
in your firewall oder setting up a reverse proxy like nginx for a nice URL.
With nginx you can also terminate SSL there and let seafile handle just HTTP.
If you may want to download files via the web interface you have to open port
8082, too.</p>
</li>
<li>For updates I recommend following the <a href="https://github.com/haiwen/seafile/wiki/Upgrading-Seafile-Server">documentation in the official wiki</a>.</li>
</ol>
<h2>Setup Client</h2>
<ol>
<li>Install seafile. You can either download the client from http://seafile.com/en/download/
or using your favourite package manager. It is contained in most distributions repositories.</li>
<li>Start it and start to enter your account information. In the server field
you enter https://servername:8000 or your appropriate url if you proxy it, E-Mail and
Password are the same as you set in the setup process of the server.</li>
<li>Now add libraries, as you like. Most of it is really self explanatory and easy
to set up. The only thing I stumbled apon is the setting of the path.
If you are creating a library you select the whole path to the folder you want
to sync, e.g. /home/user/Documents. If the library already exists you have to omit the
last part, e.g. only /home/user/.</li>
</ol>
<h2>Setup Mirror</h2>
<p>This machine mirrors all the data unencrypted. Can be used to have a replication
of the data on a machine you absolutely trust.</p>
<ol>
<li>
<p>Also first get dependencies and seafile package manually or via package manager.</p>
<div class="highlight"><pre><span></span><code><span class="nx">sudo</span><span class="w"> </span><span class="nx">apt</span><span class="o">-</span><span class="nx">get</span><span class="w"> </span><span class="nx">install</span><span class="w"> </span><span class="nx">python</span><span class="o">-</span><span class="nx">argparse</span><span class="w"> </span><span class="nx">python</span><span class="o">-</span><span class="nx">simplejson</span>
<span class="nx">wget</span><span class="w"> </span><span class="nx">http</span><span class="p">:</span><span class="c1">//seafile.googlecode.com/files/seafile-cli_2.0.6_x86-64.tar.gz</span>
<span class="nx">tar</span><span class="w"> </span><span class="nx">xzf</span><span class="w"> </span><span class="nx">seafile</span><span class="o">-</span><span class="nx">cli_2</span><span class="m m-Double">.0.6</span><span class="nx">_x86</span><span class="o">-</span><span class="mi">64</span><span class="p">.</span><span class="nx">tar</span><span class="p">.</span><span class="nx">gz</span>
<span class="nx">mkdir</span><span class="w"> </span><span class="o">-</span><span class="nx">p</span><span class="w"> </span><span class="o">/</span><span class="nx">etc</span><span class="o">/</span><span class="nx">seafile</span><span class="o">/</span>
<span class="nx">cd</span><span class="w"> </span><span class="nx">seafile</span><span class="o">-</span><span class="nx">cli</span><span class="o">-</span><span class="m m-Double">2.0.6</span><span class="o">/</span>
<span class="p">(</span><span class="nx">sudo</span><span class="p">)</span><span class="w"> </span><span class="p">.</span><span class="o">/</span><span class="nx">seaf</span><span class="o">-</span><span class="nx">cli</span><span class="w"> </span><span class="nx">init</span><span class="w"> </span><span class="o">-</span><span class="nx">d</span><span class="w"> </span><span class="o">~/</span><span class="p">.</span><span class="nx">seafile</span>
</code></pre></div>
</li>
<li>
<p>Now it's time to add all the libaries you want to sync</p>
<div class="highlight"><pre><span></span><code>seaf-cli sync -l <lib-id> -s <server> -d <local-dir> -u <username>
</code></pre></div>
<p>Explanation: You can find the lib-id by going to the overview in the
webinterface and taking the last part of the links to the libraries.
For example something like aabbccdd-eeff-1234-5678-abcdef1234.
The server is the same adress as you set in the GUI-client.
The username should be self explanatory, whereas the local-dir is a bit tricky:
In contrast to the gui client you have to omit the name of the library at the
end of the path.
The client then asks you for the password of your user and the password
of the library.</p>
</li>
<li>
<p>To check the status of the sync you can use</p>
<div class="highlight"><pre><span></span><code>seaf-cli status
</code></pre></div>
</li>
</ol>
<h2>Using it</h2>
<p>Now your setup is ready and syncs everything you throw into the directories.
And when I say everything, I mean everything including swap file from your editor,
temporary files and so on. Therefor I recommend you add a seafile-ignore.txt. If
you're familiar to git you'll recognize the format: You insert a regex per line and
everything that matches at least one line is ignored. Please note that if the file is
already synced and then ignored it doesn't get deleted.</p>
<p>Out of the box seafile doesn't support a global seafile-ignore but you can just
insert a file called ignore.txt into the Seafile directory (e.g. ~/Seafile) and
can then symlink to it using <code>ln -s</code>. The downside is that all other clients just
get the content of the ignore files and don't know of the link and if you change
the content of a seafile-ignore.txt on an other client the link disappears.</p>
<p>Good exlusion rules can be copied from <a href="https://github.com/github/gitignore">gitignore examples</a>.
A basic ignorefile could look like this:</p>
<div class="highlight"><pre><span></span><code><span class="gh">#</span> Editors
*.swp
<span class="gs">*.un~</span>
<span class="gs"># pdfLaTex</span>
<span class="gs">*</span>.aux
<span class="gs">*.nav</span>
<span class="gs">*</span>.out
<span class="gs">*.snm</span>
<span class="gs">*</span>.toc
<span class="gs">*.tmp</span>
<span class="gs">*</span>~
*.lock
</code></pre></div>
<p>For my part I have restricted the whole syncing to only work inside my tinc (
<a href="http://florianjacob.de/tinc-vpn-with-ipv6-and-iproute2.html">these</a> two <a href="https://execfoo.de/blog/setup-vpn-using-tinc.html">tutorials</a>)
network and made only one folder publicly available on my mirroring server as
attempt to increase the security.</p>Quadrokopter2014-01-20T02:08:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2014-01-20:/quadrokopter-de.html<p>Sehr ausführliche Anleitung für den Bau eines Quadrokopters und nützliche
Tipps, welche Fehler man vermeiden sollte.</p><h2>Einleitung</h2>
<p>Eigentlich wollte ich schon seit ich das erste Mal einen Quadrokopter sah auch einen
besitzen. Natürlich macht es immer mehr Spass, sich sein Spielzeug selbst zu bauen.
Mein Wissen über Modellbau und dergleichen war allerdings so gering, dass ich nicht
über ein wenig Planung und Träumerei hinaus kam. Im August letzten Jahres kaufte ich
mir dann allerdings das Magazin <a href="http://www.heise.de/hardware-hacks/">c't Hardware Hacks</a>.
Darin wurde unter anderem beschrieben, wie man einen Quadrokopter bauen kann.
Es erinnerte mich wieder einmal daran, dass ich eigentlich schon einmal
einen bauen wollte und da sowieso die Semesterferien anstanden, entschloss ich mich,
ihn zu bauen. Meine Erfahrung mit Elektronik ist allerdings sehr beschränkt,
in der Schule hatten wir zwar schon gelötet, aber das war auch schon mindestens 6 Jahre
her. Trotz der Hilfe aus dem Artikel beging ich also viele Anfängerfehler und
hoffe, mit diesem Artikel den Aufbau eines Quadrokopters idiotensicher zu beschreiben.</p>
<h2>Benötigte Teile</h2>
<ul>
<li>1 <a href="http://flyduino.net/Quadrokopter-Rahmen-Set-20cm-arm">Quadrokopter Frame</a>
z.B. von Warthox. Am besten einen, der in der Centerplate schon eine Stromverteilung
eingebaut hat. Andernfalls braucht man noch eine gesonderte Platine wie das
<a href="http://flyduino.net/Flydubution-Stromverteiler-Board">Flydubution</a>.</li>
<li>4 bis 12 <a href="http://flyduino.net/Distanzbolzen-10mm-M3-Polyamid">Distanzbolzen (M3 x 10mm)</a>.
Am besten sind die aus Kunststoff geeignet, es genügen aber auch welche aus Metall.
Die Anzahl variiert, 4 werden auf jeden Fall zur Befestigung des Flugkontroll-Boards
benötigt. Hat man eine extra Stromverteilungsplatine kann man diese mit weiteren
vier Distanzbolzen befestigen. Für die Akkuhalterung kann man nochmals vier Distanzbolzen
benutzen, ich habe dafür <a href="http://www.reichelt.de/Distanzhuelsen-etc-/DKR-8MM/index.html?ARTICLE=44745">Distanzbolzen zum Einrasten</a>
benutzt, diese sind aber nicht für die Platinen geeignet, deren Löcher sind etwas zu klein.</li>
<li>4 Motorenregler (ESCs), z.B. <a href="http://flyduino.net/Flyduino-10A-ESC-SimonK-Firmware">10A Flyduino SimonK</a>,
je nach Wahl der Motoren auch gerne mit etwas mehr Ampere.</li>
<li>1 <a href="http://flyduino.net/Multikopter-FC-Multiwii">NanoWii-Board</a></li>
<li>1 <a href="http://flyduino.net/10cm-Servokabel-female-to-female-1-Stueck">3-auf-3-Pin Servokabel</a></li>
<li>1 <a href="http://flyduino.net/2-poliger-Stecker-veriegelbar-254mm-pitch">2-Pin Stecker</a>,
lässt sich auch mit dem Stecker der Disketten-LED eines alten PC-Gehäuses ersetzen.</li>
<li>1 <a href="http://flyduino.net/8-Stueck-10cm-1-Pin-Servokabel-female-to-female">1-auf-1-Pin Servokabel Set</a> (4 einzelne Kabel)</li>
<li>1 <a href="http://flyduino.net/Stiftleiste-36x1">Stiftleiste</a></li>
<li>1 <a href="http://flyduino.net/Stiftleiste-40x3-90-gewinkelt">gewinkelte Stiftleiste</a>,
diese sind sonst nur schwer zu bekommen.</li>
<li>1 <a href="http://flyduino.net/XT60-Stecker-und-Buchse">XT60 Stecker und Buchse</a></li>
<li>4 <a href="http://flyduino.net/Suppo-A2208-17-1100KV-Brushless-Outrunner">Motoren</a></li>
<li>4 Propeller 8"x4.5, jeweils 2 im Uhrzeigersinn und im Gegenuhrzeigersinn.
Am Anfang würde ich nicht gleich die <a href="http://flyduino.net/Multikopter-Propeller-CW-CCW_9">Carbon-Propeller</a>
nehmen, da diese schneller brechen. Am Anfang können ein paar Ersatzpropeller nicht
schaden, sinnvoll ist es auch, zwei verschiedene Farben zu wählen, damit kann man später
am Quadrokopter leichter vorne und hinten unterscheiden, z.B. <a href="http://flyduino.net/Multikopter-Propeller-CW-CCW_4">orange</a>/
<a href="http://flyduino.net/Multikopter-Propeller-CW-CCW_1">grün</a> und <a href="http://flyduino.net/Multikopter-Propeller-CW-CCW_2">schwarz</a>.</li>
<li><a href="http://flyduino.net/Schrumpfschlauchset-3mm-und-8mm-ca20cm-Laenge">Schrumpfschlauchsortiment</a></li>
<li>Kabelbinder</li>
<li>1 LiPo-Akku, 3S, 25C, mindestens 2200 mAh, z.B. von <a href="https://www.hobbyking.com/hobbyking/store/__35819__Turnigy_2200mAh_3S_25C_Lipo_Pack_EU_warehouse_.html">Turnigy</a>.</li>
<li>1 <a href="https://www.hobbyking.com/hobbyking/store/__31281__Turnigy_Accucel_6_50W_6A_Balancer_Charger_w_accessories_EU_warehouse_.html">Ladegerät</a>.</li>
<li>1 Netzteil, falls wie bei dem vorgeschlagenen Ladegerät noch kein Netzteil dabei ist.
Bitte beachten, dass das Netzteil zwischen 11 und 18 Volt liefern muss und
in diesem Bereich auch stärkere Ströme aushalten muss. Mein 500mA Netzteil
war zumindest nicht ausreichend, mit <a href="https://www.amazon.de/dp/B000NZO28I">diesem Schaltnetzteil</a>
geht es auf jeden Fall, 2,5 A dürften jedoch ausreichen.</li>
<li>Fernsteuerung mit Empfänger, viele Quadrokopter-Piloten schwören auf Funken von
Futaba oder Graupner. Wenn man vor hat mehrere Modelle zu bauen oder mehr als
8 Kanäle braucht machen diese auch Sinn, für mich war der Preis jedoch einfach zu
hoch und ich kann nur die <a href="https://www.hobbyking.com/hobbyking/store/__8992__Turnigy_9X_9Ch_Transmitter_w_Module_8ch_Receiver_Mode_2_v2_Firmware_.html">Turnigy 9X</a>
empfehlen.</li>
<li><a href="https://www.amazon.de/dp/B00295CU0M/">Schraubensicherung</a></li>
<li>Jeweils ca. 15cm rotes und schwarzes dickes Kabel, z.B. <a href="http://flyduino.net/10-Meter-Silikon-Kabe-Sets-AWG16-13mm-schwarz-und-rot-je-5-meter">davon</a></li>
<li>Kurze Schrauben (M3x5mm oder M3x4mm) mit Linsenkopf</li>
<li>Kunststoffplatte (oder Champignon-Kiste) für das Landegestell</li>
<li>1 kleine Kunststoffdose als Akkuhalterung, etwa in <a href="https://www.amazon.de/dp/B004FVA5TQ">dieser Art</a>,
gab es bei uns im örtlichen Supermarkt jedoch auch als billige China-Variante, die
es hier auch tut.</li>
</ul>
<h2>Werkzeug</h2>
<ul>
<li>Lötkolben/Löstation und Lötzinn</li>
<li>Schraubendreher, die Form hängt von den Schrauben des Rahmens und der Linsenkopfschrauben
ab</li>
<li>Seitenschneider</li>
<li>Abisolierzange</li>
<li>Feuerzeug</li>
<li>Spitzzange</li>
<li>Computer mit Mini-USB-Kabel. Achtung: Hier gibt es auch reine Stromkabel, die
keine Leitung für die Daten haben.</li>
</ul>
<h2>Zusammenbau</h2>
<p>Zuallererst den Arbeitsplatz vorbereiten, vor allem um den Tisch vor heißem Lötzinn
zu schützen.</p>
<ol>
<li>Als erstes löten wir den Akkuanschluss. Grundsätzlich verwenden wir für Minus (GND) immer
schwarze Kabel und für Plus (Vcc) immer rote. Von den beiden dickeren Kabeln schneiden
wir jeweils ein ungefähr 20cm langes Stück ab und isolieren die Enden ab. Dazu brauchen wir noch zwei Stücke
mit jeweils 3cm Schrumpfschlauch. Von dem 2-Pin Stecker isolieren wir die Enden
auf der gleichen Länge wie die dickeren Kabel ab und stecken jedes Ende
durch einen Schrumpfschlauch und stecken das gleichfarbige dicke Kabel dazu, so dass die
Enden 5cm überstehen. Nun löten wir dieses Ende an die XT60-Buchse. Dazu verdrillen
wir das Ende des dünnen und des dicken Kabels und <a href="https://wiki.raumzeitlabor.de/wiki/Löten_lernen#.C3.9Cbung_3:_Eine_Litze_verzinnen">verzinnen</a> es.
Bei der Buchse finden sich auf der Außenseite zwei Anschlüsse. Diese verbinden wir
nun mit Lötzinn, indem wir die Anschlüsse erwärmen und auf die Halbkreise Lötzinn
aufbringen. Nun löten wir auf der angeschrägten Seite die beiden schwarzen Kabel an,
am anderen Anschluss werden die beiden roten angelötet. Sitzen die Lötstellen fest werden die
Schrumpfschläuche darübergeschoben und geschrumpft, indem sie erhitzt werden, entweder
mit einem Heißluftfön, dem Lötkolben oder einem Feuerzeug. Zuletzt lötet man noch
die anderen Enden der dicken Kabel an die Stromverteilung, wieder rot an Plus
und schwarz an Minus.</li>
<li>Als nächstes löten wir die Stiftleisten auf das NanoWii-Board. Wenn man das Board
mit dem Pfeil in der Mitte nach oben legt kommt die gebogene Dreierleiste unten an
die drei Reihen von Löchern, rechts daneben kommen zwei Stifte für die Stromversorgung
und am linken Rand müssen zumindest die horizontale Dreierreihe und alle darüber
angeschlossen werden. Mehr zu Löten schadet auch nicht, dann muss man später nicht extra nachzulöten.
<img alt="Pinbelegung NanoWii" src="/images/nanowii.svg"></li>
<li>Nun bauen wir den Rahmen zusammen. Dazu nimmt man zuerst die Bodenplatte und
steckt vier Schrauben von unten durch die inneren vier Löcher. Arme darauf stecken,
darauf achten, dass am äußeren Ende der Ausleger die größeren Löcher nach unten zeigen, und
die Deckplatte darauf. Auf die vier Schrauben kommen nun die Distanzbolzen, darauf
das NanoWii-Board, das mit selbstsichernden Muttern befestigt wird. An den anderen
acht Löchern werden Schrauben von oben durchgesteckt. Die äußeren werden von unten mit
Muttern befestigt, an die mittleren kommen Distanzbolzen. Hat man ein extra
Stromverteilungsboard kommt das darauf und danach wieder Distanzbolzen.</li>
<li>Nun machen wir uns an die Motoren und die ESCs. Darum schließen wir die
3-Pin-Anschlüsse der ESCs an das NanoWii an um zu sehen, an welcher Stelle auf den Armen man sie
befestigen kann. Die ESCs vorne rechts und hinten links werden mit der Schrift nach
unten, die anderen beiden nach oben befestigt. Vorne ist dort, wo auf
dem NanoWii-Board der Pfeil hinzeigt, beziehungsweise dort wo die USB-Buchse
sitzt. Damit müssten sich nachher die Rotoren vorne rechts und hinten links gegen
den Uhrzeigersinn drehen, die anderen beiden im Uhrzeigersinn. Als nächstes werden
die Motoren auf die Arme geschraubt, dabei keine Senkkopfschrauben benutzen,
da diese sich in das Aluminium drücken. Die Kabel sollten dabei Richtung Mitte
zeigen, damit sie bei einem Absturz geschützt sind. Die Schrauben werden mit
Schraubensicherung gesichert. Als nächstes muss man die ESCs mit den Motoren
verbinden, dazu kürzt man die drei Anschlusskabel des ESCs und/oder der Motoren und
verzinnt sie. Dann steckt man ca. 2cm lange Stücke Schrumpfschlauch auf die Kabel und
verlötet die Enden der Kabel, dabei kommen die beiden mittleren zusammen und die äußeren
jeweils zu dem Kabel auf der jeweiligen Seite. Die Schrumpfschläuche noch nicht
schrumpfen.</li>
<li>Nun müssen wir die BECs trennen, da wir das NanoWii-Board gesondert mit Strom versorgen.
Dazu trennen wir an dem 3-Pin-Stecker jedes ESCs das mittlere, rote Kabel durch und
versiegeln das Ende mit etwas Schrumpfschlauch.</li>
<li>Die ESCs werden nun an die Stromverteilung angelötet, dazu einfach das rote Kabel
wieder an Plus und das Schwarze an Minus anlöten.</li>
<li>Als nächstes bauen wir eine Akkuhalterung. Dazu kann man entweder mit einem
Klettband den Akku unter der Centerplate befestigen oder man baut aus einer
Kunststoffdose einen Behälter. Dazu bohrt man einfach in den Boden der Dose
vier Löcher, die dem Abstand der Distanzbolzen auf der Quadrokopterunterseite entsprechen.
Mit vier Muttern und vier Unterlegscheiben kann man diesen Behälter dann festschrauben.
Mit vier Streifen eines festen, leicht federndem Material kann man sich auch noch
Landebeine bauen. Dazu habe ich eine Kunststoffgitterkiste genommen, in denen
normalerweise Champignons transportiert werden, in 3cm breite Streifen geschnitten
und mit jeweils einem Kabelbinder direkt vor dem Motor und am Übergang vom Arm zur
Centerplate angebracht. Da der Streifen ein gutes Stück länger war bildet sich dadurch
ein Bogen, der nach unten zeigt und auf dem man landen kann.</li>
<li>Den Empfänger der Fernsteuerung kann man irgendwo befestigen, danach geht es ans
Verkabeln:<ul>
<li>Vom Empfänger zum NanoWii wird mit dem 3-Pin-Kabel Channel 3 mit den drei
horizontalen Pins auf dem NanoWii auf der linken Seite verbunden. Dabei kommt
das braune Kabel an den Rand und das gelbe in Richtung Mitte. Am Empfänger
kommt das gelbe Kabel auf den Pin, der der beschrifteten Seite zugewandt ist.
Die anderen Kabel werden am Empfänger an den Pins am nächsten zur Schrift angebracht.
Sie werden auf dem Board so eingesteckt, dass von dem eben eingesteckten aufwärts
folgendes anliegt: Channel 1, 2, 4, 5.
<img alt="Pinbelegung Receiver" src="/images/receiver.svg"></li>
<li>Dann werden die ESCs angeschlossen. Diese kommen an die gewinkelten Dreierleisten,
mit dem gelben Kabel nach oben. Dabei werden von links nach rechts zuerst der
hintere rechte, dann der vordere rechte, hintere linke und der vordere linke
ESC angeschlossen.</li>
<li>Rechts daneben sind noch zwei Pins. Daran wird der 2-Pin-Stecker angeschlossen,
den wir an die XT60-Buchse angelötet haben. Rot kommt nach oben, schwarz an den Rand.</li>
</ul>
</li>
<li>Nun sollte man den Empfänger mit dem Sender koppeln. Dazu steckt man das Bindkabel
in die Reihe mit der Beschriftung BAT und versorgt das Board mit Strom indem man
es per USB an einen Rechner anschließt. Im Empfänger sollte nun eine LED blinken.
Nun hält man am Sender den Bind-Knopf gedrückt und schaltet währendessen den Sender
ein. Kommt hierbei ein "Switch Error" stellt man alle Schalter nach oben und hinten
und wiederholt das Binden. Danach sollte die LED im Empfänger dauerhaft leuchten.
Nun schaltet man den Empfänger aus und dann den Sender.</li>
<li>Nun ist der Quadrokopter fast fertig, wir machen uns nun an die Software. Dazu
verbinden wir den Quadrokopter per USB und laden die Arduino-Software herunter. Für Windows findet man sie unter
<a href="https://www.arduino.cc">www.arduino.cc</a>, für Arch findet man sie im AUR. Bei der Installation
hilft dort wie immer das <a href="https://wiki.archlinux.org/index.php/arduino">Arch Wiki</a>.
Unter Arch sollte man noch die <a href="https://wiki.archlinux.org/index.php/arduino#Configuration>`">Serielle Schnittstelle konfigurieren</a>
und die <a href="https://wiki.archlinux.org/index.php/arduino#Error_when_launching_Arduino_IDE_or_uploading_sketch">Zugriffsrechte einstellen</a>.
Unter allen Betriebssystemen muss man die MultiWii-2.2-Software herunterladen
von <a href="http://code.google.com/p/multiwii/">http://code.google.com/p/multiwii/</a> und entpacken. In der Arduino-Software öffnet
man dann die Datei MultiWii.ino. In der config.h werden einige Einstellungen gemacht,
dazu entfernt man die //, um die Zeilen <span class="key">#define QUADX</span> und <span class="key">#define NANOWII</span>
nicht mehr auszukommentieren. In der Arduino-Software wählt man dann unter
<span class="key">Tools</span> > <span class="key">Board</span> >
<span class="key">Arduino Leonardo</span> aus und klickt auf Überprüfen (Haken) und
Uploaden (Pfeil).</li>
<li>Nun bereiten wir den Sender vor. Dazu müssen wir zuerst einmal MultiWiiConf zum
Laufen bringen. Unter Linux muss man dazu erst einmal von einem freien seriellen
Anschluss auf den eigentlichen Anschluss linken mit <span class="key">sudo ln -s /dev/ttyACM0 /dev/ttyS8</span>
Danach startet man die MultiWiiConf-Software, die sich in dem entpackten Ordner
finden lässt. In der Software klickt man dann links auf die Schnittstelle
und danach auf <span class="key">START</span>. Mit einem Klick auf
<span class="key">CALIB_ACC</span> wird der Beschleunigungssensor
kalibriert. Danach kann man den Copter etwas herumbewegen und sollte im Diagramm
unten Veränderungen erkennen. Oben rechts sieht man eine Anzeige der Werte,
die der Empfänger gerade an NanoWii weitergibt. Zuerst müssen wir die Zuordnung
der Steuerknüppel zu den Kanälen einstellen. An der Fernsteuerung kommen wir Mit
<span class="key">MENU</span> (etwas länger) zu den Einstellung, nochmal <span class="key">MENU</span> bringt uns
in die Systemeinstellungen. 2x <span class="key">DN</span> und <span class="key">MENU</span>
lässt uns den Typ des Fliegers auswählen. Hier wählen wir <span class="key">ACRO</span> und
verlassen das Menü wieder mit <span class="key">MENU</span>. Zwei darunter können wir die Steuerknüppelbelegung
festlegen. Dort wählen wir Mode 2, damit der Gas-Knüppel links liegt, bestätigen mit <span class="key">MENU</span>,
verneinen „Throttle reverse“ mit <span class="key">EXIT</span> und verlassen das Menü mit 2x <span class="key">EXIT</span>.
Nicht irritieren lassen, dass im Display noch MODE 1 steht, das bezieht sich
nicht auf die gerade geänderte Zuordnung. Wir müssen nun den Sender so
einstellen, dass die Ausschläge möglichst genau von 1000 bis 2000 gehen und in
der Ruhestellung bei 1500 liegen. Dazu gehen wir in der Fernbedienung in das
Einstellungsmenü. Wir schalten also den Sender ein und drücken <span class="key">MENU</span> (etwas länger),
nach rechts mit <span class="key">+</span>, <span class="key">MENU</span>, 3x <span class="key">DN</span> auf
E.Point und wieder <span class="key">MENU</span>. Dort kann man mit
<span class="key">UP</span> und <span class="key">DN</span> die Zeile wechseln,
mit <span class="key">+</span> und <span class="key">-</span> die Werte verändern und mit
dem Steuerknüppel für die jeweilige Funktion kann man die Spalte wechseln.
Nun kann man den Steuerknüppel ganz in eine Richtung drücken, in der MultiWiiConf
den Wert ablesen und mit + und - verändern. Mit <span class="key">MENU</span> (kurz) verlässt man
das Menü wieder. Mit den kleinen Schalterchen neben den Steuerknüppeln kann man
die Trimmung verändern und damit den Mittelwert möglichst genau auf 1500 einstellen.</li>
<li>
<p>Wenn man nun den linken Knüppel nach rechts unten drückt sollte in MultiWiiConf
der Hintergrund von ARM grün werden. Mit dieser Knüppelstellung schaltet man
den Quadrokopter standardmäßig scharf und die Motoren laufen an, wenn er nicht am USB
hängt. Da bei mir das Scharfstellen nicht funktionierte und mir so auch zu kompliziert war
habe ich den Quelltext geändert. Dazu ging ich wie folgt vor:</p>
<ul>
<li>MultiWii.ino in der Arduino IDE öffnen</li>
<li>
<p>In <span class="key">MultiWii</span> suchen wir die Funktion <span class="key">go_arm()</span>
(bei mir bei Zeile 801) und ändern es folgendermaßen ab:</p>
<div class="highlight"><pre><span></span><code><span class="kt">void</span><span class="w"> </span><span class="nf">go_arm</span><span class="p">()</span><span class="w"> </span><span class="p">{</span>
<span class="w"> </span><span class="c1">//if(calibratingG == 0 && f.ACC_CALIBRATED </span>
<span class="w"> </span><span class="c1">//#if defined(FAILSAFE)</span>
<span class="w"> </span><span class="c1">// && failsafeCnt < 2</span>
<span class="w"> </span><span class="c1">//#endif</span>
<span class="w"> </span><span class="c1">// ) {</span>
<span class="w"> </span><span class="k">if</span><span class="p">(</span><span class="o">!</span><span class="n">f</span><span class="p">.</span><span class="n">ARMED</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="c1">// arm now!</span>
<span class="w"> </span><span class="n">f</span><span class="p">.</span><span class="n">ARMED</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span>
<span class="w"> </span><span class="n">headFreeModeHold</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">heading</span><span class="p">;</span>
<span class="w"> </span><span class="cp">#if defined(VBAT)</span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">vbat</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">conf</span><span class="p">.</span><span class="n">no_vbat</span><span class="p">)</span><span class="w"> </span><span class="n">vbatMin</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">vbat</span><span class="p">;</span>
<span class="w"> </span><span class="cp">#endif</span>
<span class="w"> </span><span class="cp">#ifdef LCD_TELEMETRY </span><span class="c1">// reset some values when arming</span>
<span class="w"> </span><span class="cp">#if BARO</span>
<span class="w"> </span><span class="n">BAROaltMax</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">BaroAlt</span><span class="p">;</span>
<span class="w"> </span><span class="cp">#endif</span>
<span class="w"> </span><span class="cp">#endif</span>
<span class="w"> </span><span class="cp">#ifdef LOG_PERMANENT</span>
<span class="w"> </span><span class="n">plog</span><span class="p">.</span><span class="n">arm</span><span class="o">++</span><span class="p">;</span><span class="w"> </span><span class="c1">// #arm events</span>
<span class="w"> </span><span class="n">plog</span><span class="p">.</span><span class="n">running</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">1</span><span class="p">;</span><span class="w"> </span><span class="c1">// toggle on arm & disarm to monitor for clean shutdown vs. powercut</span>
<span class="w"> </span><span class="c1">// write now.</span>
<span class="w"> </span><span class="n">writePLog</span><span class="p">();</span>
<span class="w"> </span><span class="cp">#endif</span>
<span class="w"> </span><span class="p">}</span>
<span class="w"> </span><span class="c1">//} else if(!f.ARMED) { </span>
<span class="w"> </span><span class="c1">// blinkLED(2,255,1);</span>
<span class="w"> </span><span class="c1">// alarmArray[8] = 1;</span>
<span class="w"> </span><span class="c1">//}</span>
<span class="p">}</span>
</code></pre></div>
</li>
<li>
<p>Dann gehen wir weiter in die Funktion <span class="key">loop()</span>. Diese ist recht
lang, darin suchen wir (ungefähr bei Zeile 926) <span class="key">if (rcData[THROTTLE] <= MINCHECK) {</span> und
ändern den nachfolgenden Block so ab:</p>
<div class="highlight"><pre><span></span><code><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">rcData</span><span class="o">[</span><span class="n">THROTTLE</span><span class="o">]</span><span class="w"> </span><span class="o"><=</span><span class="w"> </span><span class="n">MINCHECK</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">THROTTLE</span><span class="w"> </span><span class="k">at</span><span class="w"> </span><span class="n">minimum</span>
<span class="w"> </span><span class="n">errorGyroI</span><span class="o">[</span><span class="n">ROLL</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">errorGyroI</span><span class="o">[</span><span class="n">PITCH</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">errorGyroI</span><span class="o">[</span><span class="n">YAW</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="n">errorAngleI</span><span class="o">[</span><span class="n">ROLL</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span><span class="w"> </span><span class="n">errorAngleI</span><span class="o">[</span><span class="n">PITCH</span><span class="o">]</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="mi">0</span><span class="p">;</span>
<span class="w"> </span><span class="o">//</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">conf</span><span class="p">.</span><span class="n">activate</span><span class="o">[</span><span class="n">BOXARM</span><span class="o">]</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="mi">0</span><span class="p">)</span><span class="w"> </span><span class="err">{</span><span class="w"> </span><span class="o">//</span><span class="w"> </span><span class="n">Arming</span><span class="o">/</span><span class="n">Disarming</span><span class="w"> </span><span class="n">via</span><span class="w"> </span><span class="n">ARM</span><span class="w"> </span><span class="n">BOX</span>
<span class="w"> </span><span class="o">//</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">rcOptions</span><span class="o">[</span><span class="n">BOXARM</span><span class="o">]</span><span class="w"> </span><span class="p">)</span><span class="w"> </span>
<span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">rcData</span><span class="o">[</span><span class="n">AUX1</span><span class="o">]</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">MAXCHECK</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="n">go_arm</span><span class="p">();</span><span class="w"> </span>
<span class="w"> </span><span class="o">//</span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">rcData</span><span class="o">[</span><span class="n">AUX1</span><span class="o">]</span><span class="w"> </span><span class="o"><</span><span class="w"> </span><span class="n">MINCHECK</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">f</span><span class="p">.</span><span class="n">ARMED</span><span class="p">)</span><span class="w"> </span><span class="n">go_disarm</span><span class="p">();</span>
<span class="w"> </span><span class="o">//</span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="w"> </span><span class="n">rcOptions</span><span class="o">[</span><span class="n">BOXARM</span><span class="o">]</span><span class="w"> </span><span class="o">&&</span><span class="w"> </span><span class="n">f</span><span class="p">.</span><span class="n">OK_TO_ARM</span><span class="w"> </span><span class="p">)</span><span class="w"> </span><span class="n">go_arm</span><span class="p">();</span><span class="w"> </span><span class="k">else</span><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">f</span><span class="p">.</span><span class="n">ARMED</span><span class="p">)</span><span class="w"> </span><span class="n">go_disarm</span><span class="p">();</span>
<span class="w"> </span><span class="o">//</span><span class="err">}</span>
<span class="w"> </span><span class="err">}</span>
</code></pre></div>
</li>
<li>
<p>Mit <span class="key">AUX1</span> legen wir fest, dass wir mit Channel 5 die
Motoren ein- und ausschalten wollen.</p>
</li>
<li>Um dem Kanal nun noch einen Schalter zuzuweisen müssen wir noch die Fernsteuerung einstellen.
Dazu gehen wir wieder in die Settings, einmal <span class="key">UP</span> und
<span class="key">MENU</span> um den den Punkt AUX-CH auszuwählen. Dort kann man
nun mit <span class="key">UP</span> und <span class="key">DOWN</span> kann man
den Kanal wechseln, mit <span class="key">+</span> und <span class="key">-</span>
wechselt man den dazugehörigen Schalter, bei uns wählen wir Gear aus, das ist
der Schalterauf der Oberseite ganz rechts vorne.</li>
<li>Wenn man den 3-Wege-Schalter daneben auch noch verwenden möchte muss man den
Pin des Empfängers mit dem RX-Pin verbinden, in config.h RCAUX2PINRX0 auskommentieren
und die Fernsteuerung entsprechend <a href="http://www.rcgroups.com/forums/showpost.php?p=26114681&postcount=32">diesem Forenbeitrag</a> einstellen.</li>
<li>Zuletzt noch die Software wieder überprüfen und uploaden.</li>
</ul>
</li>
<li>
<p>Vor dem ersten Flug muss nun noch der LiPo-Akku aufgeladen werden. Mit dem Ladegerät
von Turnigy schließt man zuerst den Akku mit dem XT60-Anschluss an, dann den
kleinen weißen Balancestecker. Mit diesem kann das Ladegerät die Spannung der
einzelnen Zellen des Akkus auslesen und ausbalancieren. Zuletzt schließt man
das Netzteil an. Am Ladegerät muss man nun noch einiges einstellen. Zuerst kann
man das Program auswählen, indem man mit <span class="key">Type</span> durchwechselt.
Wir wählen "LiPo Batt" aus und bestätigen mit <span class="key">Start</span>. Mit
<span class="key">INC</span> wechselt man nun zu "LiPo Balance". Nun müssen
wir die Einstellungen für den Akku ändern. Dazu setzen wir den Ladestrom auf 2.0A
(wird berechnet, indem man die Akkugröße in Ah etwas abrundet, hier als 2200mAh = 2.2Ah => 2A)
und die Anzahl der Zellen auf den richtigen Wert. Zum Ändern benutzt man
<span class="key">INC</span> und <span class="key">DEC</span>, gewechselt wird mit
kurzem Druck auf <span class="key">Start</span>. Den Ladevorgang startet man mit
einem ca. 3 Sekunden langen Druck auf <span class="key">Start</span>. Auf der
nächsten Anzeige sieht man links die erkannte Anzahl der Zellen und rechts die eingegebene
Anzahl. Sind beide gleich kann man es mit <span class="key">Start</span> bestätigen und
der Ladevorgang beginnt.
Beim Laden sollte man beachten, dass LiPo-Akkus unter bestimmten Umständen explodieren,
deshalb sollte man den Akku am besten in einem feuerfesten Gefäß platzieren, zum
Beispiel in einem Keramiktopf mit Sand oder ähnlichem.</p>
</li>
<li>Vor dem Flug muss man auch noch einige rechtliche Aspekte beachten. Zuerst sollte
man eine Modellflugversicherung haben. Diese kann man entweder bei der <a href="http://www.deutsche-modellsport-organisation.de/Versicherungen.html">DMO</a>
oder beim <a href="http://dmfv.aero/mitgliedschaft/versicherung/versicherungen-fuer-modellflug-einzelmitglieder/">DMFV</a>
abschließen. Der DMFV empfiehlt sich vor allem, wenn man in einem Verein Mitglied
werden möchte.<br>
Außerdem muss man auf einer sogenannten ICAO-Karte nachschauen, an welcher Stelle
man überhaupt fliegen darf. Eine solche Karte findet man zum Beispiel bei der
deutschen Flugsicherung, nachdem man sich <a href="https://secais.dfs.de/pilotservice/user/user_register.jsp">registriert</a>
hat oder bei <a href="http://fl95.de/index.php">fl95.de</a> ohne Registrierung, wenn auch
etwas umständlich. Eine analoge Ausgabe auf totem Baum geht natürlich auch und
oft kann man bei einem Tower mit freundlichem Fragen auch sehr kostengünstig eine bekommen.
Die Karte zu lesen ist eigentlich recht einfach, wir brauchen nur die Zahl
unter dem "Bruchstrich". Diese gibt die Untergrenze des kontrollierten Flugraumes in Fuß
über Grund (AGL) oder über Meereshöhe an (FL x bedeutet x mal 100 Fuß). Damit
interessieren uns meistens nur Zonen, die bis zum Boden (GND) kontrolliert sind
sowie Flugverbotszonen (ED-R und ED-D). In Kontrollzonen darf man zwar fliegen, muss
aber vorher beim zuständigen Tower eine Genehmigung einholen. Bei weiteren Fragen
hilft auch die <a href="http://www.flightplanner.de/legenden/ICAOD.png">ausführliche Legende</a> weiter.
Zusätzlich dürfen wir nicht näher als 1,5km an Flugplätze heran fliegen und nicht
über bewohntem Gebiet fliegen. Außerdem braucht man natürlich noch die Erlaubnis
des Inhabers des Grundstückes von dem man starten will.</li>
<li>Endlich nähern wir zum ersten Flug, ein historischer Moment^^. Ein kleines Wort der
Warnung noch vorneweg: Quadrokopter sehen zwar harmlos aus, die Rotoren drehen sich
jedoch wirklich schnell und haben dadurch eine ganz schöne Wucht. Also bitte auf
Gegenstände und vor allem Personen in der Nähe achten. Ansonsten kann es vorkommen, dass
man beim Schreiben eines Blogposts an der Fernsteuerung den Gashebel verkehrt,
sich dann wundert, warum die Motoren nicht anlaufen und beim Testen auf dem
Schreibtisch dann feststellt, dass sie doch anlaufen, wenn man den Hebel nach oben
schiebt und vor Schreck dann Vollgas gibt. Ergebnis: Kratzer im Notebook, zwei
zerstörte Tasten und mehrere zerschredderte Rotor- und Papierblätter. Nicht dass
mir so etwas passiert wäre...</li>
<li>Damit können wir nun endlich die Propeller anbringen: Bei mir musste man die
Löcher der Propeller mit einem Bohrer etwas weiten, damit sie auf die Mitnehmer
passen. Dann stecken wir sie einfach auf die Wellen der Motoren und ziehen die
Kappen mit einem dünnen Bohrer oder ähnlichem fest, wie <a href="http://diydrones.com/forum/topics/propeller-install-notes">hier</a>
auch auf Englisch beschrieben. In unserem Fall ist nur die Anordnung etwas anders,
die Propeller gegen den Uhrzeigersinn kommen vorne rechts und hinten links auf
die Motoren. Sie sind meistens mit einem kleinen CCW gekennzeichnet.</li>
<li>Jetzt kommen wir endlich zum ersten Flug. Dazu gehen wir an einen freien Platz,
bestenfalls eine Wiese, und stellen den Quadrokopter in das Gras. Zuerst schalten
wir den Sender ein und stecken danach den Akku am Quadrokopter an. Der Quadrokopter testet dann
die Motoren und meldet mit 4 ansteigenden Piepsern, dass alles OK ist. Nun ziehen
wir den Gashebel (links) ganz nach unten und klappen den Schalter oben rechts nach
vorne. Damit sollten die Motoren anlaufen und mit langsamem Erhöhen des Schubes
kann man nun den Quadrokopter abheben lassen. Sollte er sich dabei zu einer Seite
neigen kann man die Lage mit dem rechten Stick korrigieren. Die Dosierung des
Schubes erfordert ein wenig Übung, ebenso sollte man mit horizontalen Bewegungen
vorsichtig sein, da der Kopter schnell reagiert. Bis der Kopter nicht mehr
unkontrolliert durch die Gegend fliegt, abstürzt oder gegen beliebige Gegenstände
kracht dauert es eine Weile, aber irgendwann kann man ruhig schweben und sich
präzise bewegen ... hoffentlich.</li>
</ol>
<p>Nach ein paar Erfahrungen, hier noch einige praktische Tipps:</p>
<ul>
<li>Nicht in Räumen einschalten, auch nicht um zu probieren, warum der Quadrokopter nicht anläuft.</li>
<li>Wenn schon, dann wenigstens die Propeller vorher entfernen.</li>
<li>Beim Fliegen eine möglichst große Wiese benutzen.</li>
<li>Darauf achten, dass keine großen Bäume in der Nähe sind. Lieber in ein paar niedrige
reinfliegen, auf die man zur Not hochklettern kann, anstatt in eine hohe Birke,
bei der man zwei Leitern braucht.</li>
<li>Äußerst nützlich ist es auch, wenn man Zugang zu einem Birnenhaken hat.</li>
</ul>
<h2>Bilder</h2>
<p><a href="/images/quadrokopter1.jpg"><img alt="Quadrokopter auf blauer Decke" src="/images/quadrokopter1.tb.jpg"></a>
<a href="/images/quadrokopter2.jpg"><img alt="Quadrokopter auf der Wiese" src="/images/quadrokopter2.tb.jpg"></a>
<a href="/images/quadrokopter3.jpg"><img alt="Quadrokopter im Flug" src="/images/quadrokopter3.tb.jpg"></a></p>alaCarte on Debian2013-12-12T22:00:00+01:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2013-12-12:/alacarte-debian.html<p>Instructions to run an instance of the OpenStreetMap rendering server alaCarte.</p><p>About a year ago we were in the third semester and had to attend a lecture called
PSE (Practical Software Engineering). There we got the task to write a renderer for
<a href="http://www.openstreetmap.org">OpenStreetMap</a>-Data. Because it has something to do
with maps or in german „Karten“, which also stands for menu cards, we gave it the
name „<a href="http://alacarte-maps.github.io/">alaCarte</a>“. After we finished the lecture
we open sourced the project and since then developed it a little bit further. For
demonstration purpose we had an instance hosted on a server by a member of the KIT.
This one disappeared somewhen in August or September and now I thought to try how
big maps I can host on my little home NAS.</p>
<h2>Hardware</h2>
<p>My Home-NAS contains just a little AMD E350 processor and 4 GiB of RAM. alaCarte
uses a lot of RAM, for importing you approximately need the size of the uncompressed
OSM-Data as free RAM. For whole Germany this would be around 32GB. For running the
server is much less RAM needed. Therefore it is acceptable to use a huge swap partition for
importing the data. I didn't want to reformat my disks so I just plugged in an USB-Stick,
partitioned it as swap and configured debian to use it. The federal state of Baden-Württemberg
worked like a charm, whole Germany was a bit too much: It always stopped at 46% although
it had enough free swap space. Probably it just slowed down very much because swap is
that much slower than RAM. For Christmas I'm going to make a gift to myself and will
upgrade the RAM and try again to import bigger data.</p>
<h2>Step-by-step</h2>
<ol>
<li>
<p>Install dependencies:</p>
<div class="highlight"><pre><span></span><code>sudo apt-get install libboost-all-dev cmake libcairomm-1.0-dev liblog4cpp5-dev
</code></pre></div>
</li>
<li>
<p>Clone the <a href="https://github.com/alacarte-maps/alacarte">source</a> of alaCarte</p>
<div class="highlight"><pre><span></span><code>git clone https://github.com/alacarte-maps/alacarte.git
</code></pre></div>
</li>
<li>
<p>Build alacarte</p>
<div class="highlight"><pre><span></span><code>cd alacarte
mkdir build
cd build
cmake .. -DCMAKE_BUILD_TYPE=Release
make -j <#CPU-Cores>
</code></pre></div>
</li>
<li>
<p>Download and unpack the OSM-XML extract of your choice. A good source for this
is the <a href="http://download.geofabrik.de/">geofabrik-Server</a></p>
<div class="highlight"><pre><span></span><code><span class="n">wget</span><span class="w"> </span><span class="o">-</span><span class="n">O</span><span class="w"> </span><span class="o">-</span><span class="w"> </span><span class="n">http</span><span class="p">:</span><span class="o">//</span><span class="n">download</span><span class="o">.</span><span class="n">geofabrik</span><span class="o">.</span><span class="n">de</span><span class="o">/</span><span class="n">europe</span><span class="o">/</span><span class="n">germany</span><span class="o">/</span><span class="n">baden</span><span class="o">-</span><span class="n">wuerttemberg</span><span class="o">-</span><span class="n">latest</span><span class="o">.</span><span class="n">osm</span><span class="o">.</span><span class="n">bz2</span><span class="w"> </span><span class="o">|</span><span class="w"> </span><span class="n">bzcat</span><span class="w"> </span><span class="o">></span><span class="w"> </span><span class="n">bawue</span><span class="o">.</span><span class="n">osm</span>
</code></pre></div>
</li>
<li>
<p>Because of the memory consumption I had to mount additional swap space. Using a
Flash Drive is not recommended for permanent uses but for importing it does
the job. For this you have to first format the USB-Stick to contain a swap partition.
Then it has to be added to /etc/fstab according to <a href="https://wiki.archlinux.org/index.php/swap#Swap_with_USB_device">this instruction</a>
and then mount it. You can of course also just create a temporary swap file.</p>
</li>
<li>
<p>Import data (can take some time)</p>
<div class="highlight"><pre><span></span><code>./alacarte-importer bawue.osm bawue.carte
</code></pre></div>
</li>
<li>
<p>Make a user for running the server</p>
<div class="highlight"><pre><span></span><code>sudo adduser alacarte
</code></pre></div>
</li>
<li>
<p>Change ownership of alacarte and data. I would recommend to move the alacarte-server
binary, the bawue.carte file, default tile and mapcss directory to a dedicated folder.
You can place it anywhere.</p>
<div class="highlight"><pre><span></span><code>mkdir ../server
mv alacarte-server ../server
mv bawue.carte ../server
cp -r ../data/* ../server
cd ..
sudo chown -R alacarte server
cd server
</code></pre></div>
</li>
<li>
<p>Run the server in the background, either use nohup:</p>
<div class="highlight"><pre><span></span><code>sudo su alacarte
nohup ./alacarte-server -g bawue.carte -s mapcss -z -1 &
</code></pre></div>
<p>Or use a terminal multiplexer like screen or tmux: </p>
<div class="highlight"><pre><span></span><code>tmux new -s alacarte
sudo su alacarte
(cd alacarte-dir)
./alacarte-server -g bawue.carte -s mapcss -z -1
<CTRL-B> d
</code></pre></div>
<p>With -z you can set the zoom level until which is prerendered, -1 means,
that nothing is prerendered.</p>
</li>
<li>
<p>Configurate your firewall to allow port 8080 or set your webserver to reverse
proxy to the alaCarte server.</p>
</li>
</ol>
<p>On my home NAS the server is running using this method, you can try our <a href="http://alacarte.simon-dreher.de/">Demo</a>.
Please keep in mind that this is behind a slow DSL connection and the data transmission
can be slow. If the rendering process would be slow, you would have to wait for
a block of 4x4 tiles (a meta-tile) to render, which then load all at once.</p>
<p>We also of course always welcome new contributors on <a href="https://github.com/alacarte-maps/alacarte">github</a>.</p>Mailserver2013-08-19T14:00:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2013-08-19:/mailserver.html<p class="first last">In this article I describe how to use ansible to easily set up a mailserver.</p>
<div class="section" id="introduction">
<h2>Introduction</h2>
<p>Since february I'm running a little server from my home network. I planned a while
to run a mail server on it, but since it's behind a dynamic ip, no other server
would accept outgoing mail from me. At the end of july the hoster <a class="reference external" href="http://ovh.net">ovh</a>
offered a very small but <a class="reference external" href="http://www.ovh.de/dedicated_server/isgenug.xml">cheap server</a>.
Additionally I wanted to get away from all the mailhosters helping the NSA to spy.
This server is not intended for servers with many users but is more for single
users or small user groups. Therefore plain config files are used instead of a
database.</p>
<p>When I was configuring the new server I decided to use scripts because of two reasons:
First because I automatically have kind of documentation on what I have done and second
because I very easily can set up new servers. Because I'm kind of a python fanboy
and I'm not really into puppet or chef I decided to use <a class="reference external" href="http://www.ansibleworks.com/">ansible</a>
for this.</p>
<p>For the configuration I read a lot of tutorials and did the best I can, if you
have improvements please just email me or make a pull request on github.</p>
</div>
<div class="section" id="code">
<h2>Code</h2>
<p>My code is of course kept in a git repository and you can find <a class="reference external" href="https://github.com/Semoar/ansible">here</a>.
A short description of the structure of ansible playbooks:</p>
<ul class="simple">
<li><strong>host.ini:</strong> Contains all servers with parameters and to which groups they belong.</li>
<li><strong>main.yml:</strong> Includes the other yaml files which define roles and such.</li>
<li><strong>secure:</strong> All files that have to stay private (keys, passwd file...)</li>
<li><strong>roles:</strong> Contains one directory per role. You can map hosts or groups to roles, so you
can reuse the roles. In this article we only concentrate on the mailserver directory.</li>
</ul>
<p>The mailserver directory contains tasks, here grouped by applications, templates and
vars. The templates use the vars to generate the config files for the server.
This part of the playbook is mainly based on the <a class="reference external" href="http://git.kafe-in.net/ansible-kafein/">ansible repo of kafe-in.net</a>.
<a class="reference external" href="http://www.kafe-in.net">Fabien Dupont</a> did a great job on this, I just added
some minor tweaks and some documentation to the config file.</p>
</div>
<div class="section" id="how-to-use">
<h2>How to use</h2>
<div class="section" id="preparation">
<h3>Preparation</h3>
<p>First of all you have to set the hostname of your server if you haven't done that already.
Don't use the 'hostname'-command, this only changes the hostname temporarily and
ansible doesn't use this temporary hostname. Just set it manually: Enter the hostname
without domain into <em>/etc/hosts</em> and in <em>/etc/hostnames</em> enter the line</p>
<pre class="code c literal-block">
<span class="mf">127.0.1.1</span><span class="w"> </span><span class="n">hostname</span><span class="p">.</span><span class="n">domain</span><span class="p">.</span><span class="n">tld</span><span class="w"> </span><span class="n">hostname</span>
</pre>
<p>and then restart or use <em>/etc/init.d/hostname.sh start</em> if youre on debian..
If your hoster supports it you should also set your reverse DNS entry to the same value.</p>
<p>Then you have to prepare the <em>host.ini</em>: Put every mailserver into the group 'mailservers'.
If you want to relay your mail instead of sending them directly, put the relaying
servers into the group 'secondarymx' and configure the according variables in
<em>roles/mailserver/vars/main.yml</em> if they are the same for all servers or in <em>host_vars/<hostname></em>
if they differ per host.</p>
<p>Next you have to edit <em>roles/mailserver/templates/etc_ssl_dovecot.cnf</em>. It is used to generate the
ssl certificate. Just read the comments in the file and you should pass easily.</p>
<p>Most important is to create the file <em>dovecot.passwd</em> in the folder <em>secure</em>:
The easiest way to do this is to use <a class="reference external" href="http://wiki2.dovecot.org/Tools/Doveadm/Pw">doveadm pw</a>.
For this you have to install dovecot (or dovecot-core on Debian) on your desktop machine.
For each account you have to insert one line looking like this:</p>
<pre class="code c literal-block">
<span class="nl">username</span><span class="p">:{</span><span class="n">scheme</span><span class="p">}</span><span class="n">password</span>
</pre>
<p>If you don't want to install dovecot on your desktop only to generate some password
hashes you can instead use a provisional <em>dovecot.passwd</em> where you use plain text
passwords. This makes it easier to debug and you can run ansible one time, use the
dovecot installation on the server to generate the password hashes, use them to
make the <em>dovecot.passwd</em> on your local machine and run ansible again.</p>
<p>You should also adjust the variable 'mx_aliases' in <em>roles/mailserver/vars/main.yml</em>.
It configures redirects from the first listed account to the second account. It is
very useful to map the root account to your personal main account because you can
not directly login as root via imap.</p>
<p>You should also go through the complete <em>roles/mailserver/vars/main.yml</em> and check if
you want to adjust something.</p>
<p>For ansible to work you must only install python onto the server.</p>
</div>
<div class="section" id="installation">
<h3>Installation</h3>
<p>After you have configured everything as you wanted it's now time to roll that thing out.</p>
<pre class="code c literal-block">
<span class="n">ansible</span><span class="o">-</span><span class="n">playbook</span><span class="w"> </span><span class="o">-</span><span class="n">i</span><span class="w"> </span><span class="n">hosts</span><span class="p">.</span><span class="n">ini</span><span class="w"> </span><span class="n">mailservers</span><span class="p">.</span><span class="n">yml</span><span class="w"> </span><span class="o">--</span><span class="n">user</span><span class="w"> </span><span class="o"><</span><span class="n">username</span><span class="o">></span><span class="w"> </span><span class="o">--</span><span class="n">ask</span><span class="o">-</span><span class="n">sudo</span><span class="o">-</span><span class="n">pass</span>
</pre>
</div>
<div class="section" id="tests">
<h3>Tests</h3>
<p>Finally you can use some tools to test if your server is working properly, for example
<a class="reference external" href="http://www.mailradar.com/openrelay/">this one</a> tests specifically , if your
server is an open relay. Another one is <a class="reference external" href="http://www.emailsecuritygrader.com/">this</a>,
which grades the overall security of your server.</p>
<p>Of course you can also use telnet or send some emails from, to and within your domain.</p>
<p>You can now also configure your DNS to contain a SPF record and the DKIM record if
you use it.</p>
</div>
</div>
<div class="section" id="problems">
<h2>Problems</h2>
<p>Here I have listed some problems I have run into. They are mostly a bit stupid but maybe
they are helpful for someone.</p>
<pre class="code c literal-block">
<span class="o"><</span><span class="n">date</span><span class="o">></span><span class="w"> </span><span class="n">babaco</span><span class="w"> </span><span class="n">postfix</span><span class="o">/</span><span class="n">smtp</span><span class="p">[</span><span class="mi">2175</span><span class="p">]</span><span class="o">:</span><span class="w"> </span><span class="mi">0901</span><span class="n">EC0AA0</span><span class="o">:</span><span class="w"> </span><span class="n">to</span><span class="o">=<</span><span class="n">a</span><span class="err">@</span><span class="n">b</span><span class="p">.</span><span class="n">c</span><span class="o">></span><span class="p">,</span><span class="w"> </span><span class="p">...</span><span class="w"> </span><span class="n">status</span><span class="o">=</span><span class="n">bounced</span><span class="w"> </span><span class="p">(</span><span class="n">mail</span><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="n">b</span><span class="p">.</span><span class="n">c</span><span class="w"> </span><span class="n">loops</span><span class="w"> </span><span class="n">back</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="n">myself</span><span class="p">)</span>
</pre>
<p>In my case just the wrong hostname was used in <em>/etc/postfix/main.cf</em>. Make sure you
have set the hostname correct and maybe restart the server and run ansible once again.</p>
<pre class="code c literal-block">
<span class="o"><</span><span class="n">date</span><span class="o">></span><span class="w"> </span><span class="n">babaco</span><span class="w"> </span><span class="n">postfix</span><span class="o">/</span><span class="n">smtp</span><span class="p">[</span><span class="mi">30796</span><span class="p">]</span><span class="o">:</span><span class="w"> </span><span class="n">connect</span><span class="w"> </span><span class="n">to</span><span class="w"> </span><span class="mf">127.0.0.1</span><span class="p">[</span><span class="mf">127.0.0.1</span><span class="p">]</span><span class="o">:</span><span class="mi">10025</span><span class="o">:</span><span class="w"> </span><span class="n">Connection</span><span class="w"> </span><span class="n">refused</span>
</pre>
<p>In my case clamAV wasn't running after the ansible-playbook, I had to start it manually.</p>
</div>
Tux - Stickmuster2013-04-03T01:00:00+02:002024-03-24T20:26:57+01:00Simon Drehertag:blog.simon-dreher.de,2013-04-03:/tux-stickmuster-de.html<p class="first last">Stickmuster um einen Tux-Aufnäher anzufertigen.</p>
<p><em>Short summary: I made a patch of a tux to sew it onto my bag. You can find a template down on this page.</em></p>
<div class="section" id="einleitung">
<h2>Einleitung</h2>
<p>Während einer Vorlesung war die Unterhaltung mit meinem Freund wieder einmal interessanter.
Wir kamen auf das Thema Aufnäher und ähnliches und stellten fest, dass wir gerne einen Aufnäher mit einem Tux für unsere Taschen hätten.
Eine Suche im Internet ergab jedoch, dass sich kaum solche Aufnäher finden lassen.
Vor allem nicht, da die englische Bezeichnung 'patch' im Zusammenhang nicht gerade selten ist und Google ganze 4,3 Millionen Ergebnisse liefert.
Zu finden waren nur amerikanische Shops, bei denen die Versandkosten aber einfach zu hoch waren.
Also beschloss ich einfach selbst einen Aufnäher anzufertigen.</p>
</div>
<div class="section" id="anfertigung">
<h2>Anfertigung</h2>
<p>Ein Muster anzufertigen war nicht besonders schwierig, es lässt sich auch einfach auf andere Motive anwenden.
Man nimmt einfach ein Bild des Tux (oder eines anderen Motives), skaliert es herunter, damit es pixelig wird, verringert die Anzahl der Farben und exportiert es in eine HTML-Tabelle.
Schritt für Schritt sieht das dann so aus:</p>
<ol class="arabic simple">
<li>Motiv aussuchen und herunterladen. In diesem fall den Tux von <a class="reference external" href="http://upload.wikimedia.org/wikipedia/commons/a/af/Tux.png">wikimedia</a>.</li>
<li>Motiv mit Gimp öffnen.</li>
<li>Bild skalieren (Menü: <em>Bild > Bild skalieren</em>). Ein Pixel entspricht später einem Kreuzstich. Beim skalieren sollte <em>Interpolation: keine</em> ausgewählt sein. Im Beispiel wurde auf eine Breite von 54 Pixeln skaliert.</li>
<li><em>Bild > Modus > Indiziert</em>. Dort dann die Anzahl der Farben einstellen. Als Faustregel kann man ungefähr Anzahl der Farben im Bild mal zwei nehmen aufgrund der Schattierungen. Wir nehmen nur fünf, da Schwarz keine Schattierung braucht, man kann mit der Anzahl der Farben aber auch etwas herumexperimentieren.</li>
<li>Das Stift-Werkzeug nehmen (Shortcut: <em>N</em>), auf Größe 1 einstellen und damit das Bild nachbearbeiten, wenn nötig. Wenn man möchte kann man Schritt 4 auch auslassen und alles von Hand nachzeichnen. Diese Methode dauert zwar etwas länger, liefert aber je nach Motiv bessere Ergebnisse.</li>
<li>Farben über <em>Bild > Modus > RGB</em> wieder zurückstellen und mit <em>Datei > Exportieren...</em> in eine html-Tabelle exportieren.</li>
</ol>
<p>Heraus kommt dann beispielsweise so etwas:</p>
<table class="stitch">
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="gray"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> </tr>
<tr> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> </tr>
<tr> <td class="white"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> </tr>
<tr> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="yellow"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="black"> </td> <td class="black"> </td> <td class="black"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
<tr> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="bronze"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> <td class="white"> </td> </tr>
</table><p><em>Downloadlink:</em> <a class="reference external" href="https://blog.simon-dreher.de/downloads/tux.html">Muster zum Ausdrucken</a></p>
<p>Für einen Aufnäher braucht man also fünf verschiedene Farben:</p>
<ul class="simple">
<li>Ein helleres Gelb oder Orange für die Flossen und den Schnabel</li>
<li>Ein dunkleres Gelb oder Orange für die passenden Schattierungen</li>
<li>Weiß für den Bauch und die Augen</li>
<li>Grau für die Highlights</li>
<li>Schwarz für den Rest</li>
</ul>
<p>Als Faden kann man dafür entweder Perlgarn oder Sticktwist verwenden.
Da ich noch massig Perlgarn hatte, verwendete ich dieses, Sticktwist dürfte aber
genauso funktionieren.</p>
<p>Zusätzlich benötigt man noch:</p>
<ul class="simple">
<li>Einen Stoff zum besticken, zum Beispiel Stramin. Im Prinzip geht jeder Stoff, der zählbar ist, bei dem sich die Fäden gut unterscheiden lassen und der sich nicht leicht verziehen lässt.</li>
<li>Sticknadel, um einen Pixellook zu erreichen sollten die Kreuze relativ klein sein, dann kann es schon einmal eng für die Nadel werden, also sollte sie spitz sein und nicht stumpf.</li>
<li>Zeit & Langeweile (zum Beispiel wenn etwas kompiliert...)</li>
</ul>
<p>Die Stickerei führt man einfach im Kreuzstich aus. Eine Anleitung dazu findet sich beispielsweise <a class="reference external" href="http://www.youtube.com/watch?v=42D200Rh08o">hier</a>.
Was man dabei nach Möglichkeit auch beachten sollte ist, dass man die Stiche möglichst immer in der selben Richtung macht. Bei meinem ersten Versuch habe ich das leider nicht beachtet...</p>
<p>Nachdem man alle Stiche fertig hat, schneidet man den Aufnäher aus und vernäht den Rand. Dazu kann man einfach mit einem Faden im Aufnäher nach oben stechen und außerhalb wieder nach unten führen und so weiter, oder man benutzt eine Nähmaschine und umnäht das Stück noch. Zu guter Letzt muss dann nur noch der Aufnäher an den gewünschten Platz aufgenäht werden.</p>
</div>
<div class="section" id="resultat">
<h2>Resultat</h2>
<a href="/images/tux1.jpg">
<img src="/images/tux1.tb.jpg"/>
</a><a href="/images/tux2.jpg">
<img src="/images/tux2.tb.jpg"/>
</a></div>