<?xml version="1.0" encoding="UTF-8"?>
<rss xmlns:atom="http://www.w3.org/2005/Atom" version="2.0">
    <channel>
      <title>beac0n&#x27;s blog</title>
      <link>https://schempp.dev</link>
      <description></description>
      <generator>Zola</generator>
      <language>en</language>
      <atom:link href="https://schempp.dev/rss.xml" rel="self" type="application/rss+xml"/>
      <lastBuildDate>Sun, 30 Mar 2025 00:00:00 +0000</lastBuildDate>
      <item>
          <title>About</title>
          <pubDate>Sun, 30 Mar 2025 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/about/</link>
          <guid>https://schempp.dev/about/</guid>
          <description xml:base="https://schempp.dev/about/">&lt;h1 id=&quot;hi-there&quot;&gt;Hi there&lt;&#x2F;h1&gt;
&lt;p&gt;My name is beac0n &lt;img src=&quot;&#x2F;favicon.png&quot; style=&quot;vertical-align: middle; padding: 0; margin: 0; border: 0; height: 16px; display: inline;&quot;&gt; and this is my blog.&lt;&#x2F;p&gt;
&lt;p&gt;I&#x27;m a software engineer from germany and enjoy video gaming, hacking, coding.&lt;&#x2F;p&gt;
&lt;p&gt;I don&#x27;t write regularly, but I try to add new posts from time to time.&lt;&#x2F;p&gt;
&lt;p&gt;I hope you enjoy the things I&#x27;ve put up on this blog :).&lt;&#x2F;p&gt;
&lt;p&gt;So long and thanks for all the fish... 🐟&lt;&#x2F;p&gt;
&lt;h1 id=&quot;impressum&quot;&gt;Impressum&lt;&#x2F;h1&gt;
&lt;p&gt;Angaben gemäß § 5 TMG&lt;&#x2F;p&gt;
&lt;p&gt;Maximilian Schempp&lt;&#x2F;p&gt;
&lt;p&gt;Leonie-Ossowski-Promenade 11&lt;&#x2F;p&gt;
&lt;p&gt;68309 Mannheim&lt;&#x2F;p&gt;
&lt;p&gt;Deutschland&lt;&#x2F;p&gt;
&lt;p&gt;E-Mail: &lt;a href=&quot;mailto:&amp;#99;&amp;#111;&amp;#110;&amp;#116;&amp;#97;&amp;#110;&amp;#116;&amp;#64;&amp;#115;&amp;#99;&amp;#104;&amp;#101;&amp;#109;&amp;#112;&amp;#112;&amp;#46;&amp;#100;&amp;#101;&amp;#118;&quot;&gt;
contant@schempp.dev
&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Fair joint account transfer</title>
          <pubDate>Sun, 28 Jan 2024 19:49:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/fair-joint-account-transfer/</link>
          <guid>https://schempp.dev/blog/fair-joint-account-transfer/</guid>
          <description xml:base="https://schempp.dev/blog/fair-joint-account-transfer/">&lt;form id=&quot;fairTransfer&quot;&gt;
    &lt;label for=&quot;income_a&quot;&gt;Income Partner A:&lt;&#x2F;label&gt;
    &lt;input id=&quot;income_a&quot; placeholder=&quot;Income Partner A&quot; style=&quot;width: 300px&quot; min=&quot;0&quot; type=&quot;number&quot; required&gt;
    &lt;br&#x2F;&gt;
    &lt;label for=&quot;income_b&quot;&gt;Income Partner B:&lt;&#x2F;label&gt;
    &lt;input id=&quot;income_b&quot; placeholder=&quot;Income Partner B&quot; style=&quot;width: 300px&quot; min=&quot;0&quot; type=&quot;number&quot; required&gt;
    &lt;br&#x2F;&gt;
    &lt;label for=&quot;income_a_single&quot;&gt;Income Partner A as single with no kids:&lt;&#x2F;label&gt;
    &lt;input id=&quot;income_a_single&quot; placeholder=&quot;Income Partner A single&quot; style=&quot;width: 300px&quot; min=&quot;0&quot; type=&quot;number&quot; required&gt;
    &lt;br&#x2F;&gt;
    &lt;label for=&quot;income_b_single&quot;&gt;Income Partner B as single with no kids:&lt;&#x2F;label&gt;
    &lt;input id=&quot;income_b_single&quot; placeholder=&quot;Income Partner B single&quot; style=&quot;width: 300px&quot; min=&quot;0&quot; type=&quot;number&quot; required&gt;
    &lt;br&#x2F;&gt;
    &lt;label for=&quot;amount&quot;&gt;Amount of money needed for common expenses:&lt;&#x2F;label&gt;
    &lt;input id=&quot;amount&quot; placeholder=&quot;Amount&quot; style=&quot;width: 300px&quot; min=&quot;0&quot; type=&quot;number&quot; required&gt;
    &lt;br&#x2F;&gt;
    &lt;p id=&quot;amount_a&quot;&gt;&lt;&#x2F;p&gt;
    &lt;p id=&quot;amount_b&quot;&gt;&lt;&#x2F;p&gt;
    &lt;input type=&quot;submit&quot; value=&quot;Calculate Amounts&quot;&gt;
&lt;&#x2F;form&gt;
&lt;script type=&quot;text&#x2F;javascript&quot;&gt;
    document.getElementById(&quot;fairTransfer&quot;).addEventListener(&quot;submit&quot;, (e) =&gt; {
        e.preventDefault()
        var income_a = Number(document.getElementById(&quot;income_a&quot;).value)
        var income_b = Number(document.getElementById(&quot;income_b&quot;).value)

        var income_a_single = Number(document.getElementById(&quot;income_a_single&quot;).value)
        var income_b_single = Number(document.getElementById(&quot;income_b_single&quot;).value)

        var amount = Number(document.getElementById(&quot;amount&quot;).value)

        var swap = income_a &lt; income_b
        if (swap) {
            var cache = income_a
            income_a = income_b
            income_b = cache

            var cache = income_a_single
            income_a_single = income_b_single
            income_b_single = cache
        }

        var f = income_a_single &#x2F; income_b_single
        var p_a = ((amount - income_b)*f + income_a) &#x2F; (income_a * (f+1))
        var p_b = ( amount + income_b *f - income_a) &#x2F; (income_b * (f+1))

        var amount_a = (income_a * p_a).toFixed(2)
        var amount_b = (income_b * p_b).toFixed(2)

        if (swap) {
            var cache = amount_a
            amount_a = amount_b
            amount_b = cache
        }

        document.getElementById(&quot;amount_a&quot;).innerHTML=&quot;Amount Partner A: &quot; + amount_a + &quot;€&quot;
        document.getElementById(&quot;amount_b&quot;).innerHTML=&quot;Amount Partner B: &quot; + amount_b + &quot;€&quot;
        
    });
&lt;&#x2F;script&gt;
&lt;p&gt;The topic of &quot;who contributes how much&quot; in relationships, where partners live together often times leads to heated arguments.&lt;&#x2F;p&gt;
&lt;p&gt;I came up with a formular, that tries to calculate the most fair amount, that each partner has to contribute to a joint banking account, which is used to pay all common expenses.&lt;&#x2F;p&gt;
&lt;p&gt;I will use &quot;partner A&quot; and &quot;partner B&quot; to describe each partner in the relationshship.&lt;&#x2F;p&gt;
&lt;p&gt;The formular needs the following variables:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;income_a&lt;&#x2F;code&gt;: Current income of partner A &lt;strong&gt;after&lt;&#x2F;strong&gt; taxes&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;income_b&lt;&#x2F;code&gt;: Current income of partner B &lt;strong&gt;after&lt;&#x2F;strong&gt; taxes&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;income_a_single&lt;&#x2F;code&gt;: Income of partner A &lt;strong&gt;after&lt;&#x2F;strong&gt; taxes, &lt;strong&gt;if&lt;&#x2F;strong&gt; partner A would be &lt;strong&gt;single&lt;&#x2F;strong&gt; and had no kids&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;income_b_single&lt;&#x2F;code&gt;: Income of partner B &lt;strong&gt;after&lt;&#x2F;strong&gt; taxes, &lt;strong&gt;if&lt;&#x2F;strong&gt; partner B would be &lt;strong&gt;single&lt;&#x2F;strong&gt; and had no kids&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;amount&lt;&#x2F;code&gt;: Amount of money that the couple needs for their common expenses per month&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;f = max(income_a_single, income_b_single) &#x2F; min(income_a_single, income_b_single)&lt;&#x2F;code&gt;: fairness factor - how much more the &quot;higher earner&quot; partner earns, compared to the other partner&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Up until this point, everything can be calculated easily, because it is well known how much each partner earns and also what they would earn if they where single.&lt;&#x2F;p&gt;
&lt;p&gt;To calculate now how much each partner has to transfer to the joint account, we have to use that fairness factor, that we calculated earlier:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;income_a * p_a + income_b * p_b = amount&lt;&#x2F;code&gt;, where&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p_a&lt;&#x2F;code&gt;: how much percent partner A pays of &lt;code&gt;amount&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;p_b&lt;&#x2F;code&gt;: how much percent partner B pays of &lt;code&gt;amount&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;f = (income_a * (1 - p_a)) &#x2F; (income_b * (1 - p_b))&lt;&#x2F;code&gt;, where&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;income_a * (1 - p_a)&lt;&#x2F;code&gt;: the amount of money that partner A has, &lt;strong&gt;after&lt;&#x2F;strong&gt; they transfered their share to the joint account&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;income_b * (1 - p_b)&lt;&#x2F;code&gt;: the amount of money that partner B has, &lt;strong&gt;after&lt;&#x2F;strong&gt; they transfered their share to the joint account&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;To calculate &lt;code&gt;p_a&lt;&#x2F;code&gt; and &lt;code&gt;p_b&lt;&#x2F;code&gt;, we have to solve the equations for &lt;code&gt;p_a&lt;&#x2F;code&gt; and &lt;code&gt;p_b&lt;&#x2F;code&gt;:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;p_a = (amount*f - income_b*f + income_a) &#x2F; (income_a * (f+1))&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;p_b = (amount   + income_b*f - income_a) &#x2F; (income_b * (f+1))&lt;&#x2F;code&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Which leads us to the final amounts for partners A and B: &lt;code&gt;amount = amount_a + amount_b&lt;&#x2F;code&gt;, where&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;amount_a = income_a * p_a&lt;&#x2F;code&gt;: amount that partner A has to transfer to the joint account&lt;&#x2F;li&gt;
&lt;li&gt;&lt;code&gt;amount_b = income_b * p_b&lt;&#x2F;code&gt;: amount that partner B has to transfer to the joint account&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The idea is, that the ratio between the incomes of partner A and B that they earn if they would be single, is still the same after they have transferred their shares to the bank accounts.&lt;&#x2F;p&gt;
&lt;p&gt;Example:&lt;&#x2F;p&gt;
&lt;p&gt;Partner A earns 2000€ a month if they would be single, partner B earns 1000€ a month if they would be single: &lt;code&gt;f = 2&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;They both have common expenses of 1000€ a month.&lt;&#x2F;p&gt;
&lt;p&gt;Partner A and B are now married and partner A now earns 2500€ due to tax reasons and other benefits that they have because of their marriage and partner B now earns 850€, because they reduced the workload to take care of kids or for other reasons that contribute to the partnership (e.g. had to take a less well paid job, because both moved to further partner As carreer).&lt;&#x2F;p&gt;
&lt;p&gt;After calculation, this means that partner B would have to contribute 66.66€ and partner A would have contribute 933.33€.&lt;&#x2F;p&gt;
&lt;p&gt;Partner B would have left: &lt;code&gt;850 - 66.66 = 783.34€&lt;&#x2F;code&gt; and &lt;br&#x2F;&gt;
Partner A would have left: &lt;code&gt;2500 - 933.33 = 1566.67€&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The ration between the money that both partners have left is still &lt;code&gt;2&lt;&#x2F;code&gt;:
&lt;code&gt;783.34 * 2 = 1566.68€&lt;&#x2F;code&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Of course the values can change dramatically, depending on personal circumstances.&lt;&#x2F;p&gt;
&lt;p&gt;The general idea however is, that both partners contribute their fair share, given their current income, compared to what they could earn, if both would focus only on their carreer given their respective fields. This formular tries to factor in the care work that is often done by one partner, while the other one contributes more financially to the partnership.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Family Graph Tool</title>
          <pubDate>Mon, 11 Apr 2022 22:28:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/family-graph/</link>
          <guid>https://schempp.dev/blog/family-graph/</guid>
          <description xml:base="https://schempp.dev/blog/family-graph/">&lt;p&gt;I&#x27;ve developed a tool which allows the user to display their family tree.&lt;&#x2F;p&gt;
&lt;p&gt;The special thing about this tool: it can have multiple family roots. This means that you could display your whole
family tree together with the family tree of your spouse.&lt;&#x2F;p&gt;
&lt;p&gt;This makes this a family &quot;graph&quot; rather than a family &quot;tree&quot;, because it has multiple &quot;roots&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;You can check out the tool &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;family-graph.schempp.dev&quot;&gt;here&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Tools</title>
          <pubDate>Tue, 29 Sep 2020 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/tools/</link>
          <guid>https://schempp.dev/tools/</guid>
          <description xml:base="https://schempp.dev/tools/">&lt;p&gt;This page collects all the tools, which might come in handy in the daily work of a software developer.
Most tools are just reimplementation of existing tools, which I found too insufficient to use.
All tools are written in javascript and&#x2F;or WebAssembly and don&#x27;t require any network connection. Enjoy!&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;tools&#x2F;format-converter.html&quot;&gt;Number format converter&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;tools&#x2F;text-tools.html&quot;&gt;Text tools&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;tools&#x2F;timestamps.html&quot;&gt;Date and timestamps&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;tools&#x2F;hash.html&quot;&gt;Hash&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;tools&#x2F;permute.html&quot;&gt;Permute&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Cooking for nerds #1: Pumpkin one pot pasta</title>
          <pubDate>Sun, 01 Dec 2019 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/2019-12-1-cooking-for-nerds-pumpkin-one-pot-pasta/</link>
          <guid>https://schempp.dev/blog/2019-12-1-cooking-for-nerds-pumpkin-one-pot-pasta/</guid>
          <description xml:base="https://schempp.dev/blog/2019-12-1-cooking-for-nerds-pumpkin-one-pot-pasta/">&lt;p&gt;I don&#x27;t like cooking, but I like good food. I therefore like recipes which are easy to implement.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;breifreibaby.de&#x2F;kuerbis-one-pot-pasta&#x2F;&quot;&gt;https:&#x2F;&#x2F;breifreibaby.de&#x2F;kuerbis-one-pot-pasta&#x2F;&lt;&#x2F;a&gt;
is one of those recipes.&lt;&#x2F;p&gt;
&lt;p&gt;Unfortunately, like most recipes, it is written in running text.
I will therefore try to simplify this recipe as much as possible and add my own improvements and fixes.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;utensils&quot;&gt;Utensils&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;one big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;kitchen scale&lt;&#x2F;li&gt;
&lt;li&gt;chopping board&lt;&#x2F;li&gt;
&lt;li&gt;plastic gloves for slicing pumpkin&lt;&#x2F;li&gt;
&lt;li&gt;bowl for measuring weight of pasta&lt;&#x2F;li&gt;
&lt;li&gt;bowl for pumpkin pieces and cut carrots&lt;&#x2F;li&gt;
&lt;li&gt;bowl for kitchen scraps&lt;&#x2F;li&gt;
&lt;li&gt;big sharp knife for slicing pumpkin&lt;&#x2F;li&gt;
&lt;li&gt;sharp knife for cutting onion and carrots&lt;&#x2F;li&gt;
&lt;li&gt;small knife for peeling onion&lt;&#x2F;li&gt;
&lt;li&gt;small bowl for diced onion&lt;&#x2F;li&gt;
&lt;li&gt;small bowl for spices&lt;&#x2F;li&gt;
&lt;li&gt;wooden spoon&lt;&#x2F;li&gt;
&lt;li&gt;spoon to hollow out pumpkin&lt;&#x2F;li&gt;
&lt;li&gt;tablespoon&lt;&#x2F;li&gt;
&lt;li&gt;teaspoon&lt;&#x2F;li&gt;
&lt;li&gt;measuring cup&lt;&#x2F;li&gt;
&lt;li&gt;stove&lt;&#x2F;li&gt;
&lt;li&gt;(optional) tools for opening containers&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;ingredients&quot;&gt;&lt;a name=&quot;ingredients&quot;&gt;&lt;&#x2F;a&gt;Ingredients&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;350 g hokkaido pumpkin meat
&lt;ul&gt;
&lt;li&gt;wash&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;don&#x27;t&lt;&#x2F;strong&gt; remove skin&lt;&#x2F;li&gt;
&lt;li&gt;hollow out&lt;&#x2F;li&gt;
&lt;li&gt;cut into rectangular (~1cm) pieces&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;120 g	carrots
&lt;ul&gt;
&lt;li&gt;remove green stuff&lt;&#x2F;li&gt;
&lt;li&gt;wash&lt;&#x2F;li&gt;
&lt;li&gt;cut into thin slices&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;1 small onion
&lt;ul&gt;
&lt;li&gt;peel&lt;&#x2F;li&gt;
&lt;li&gt;dice&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;400-500 ml coconut milk&lt;&#x2F;li&gt;
&lt;li&gt;400 ml vegetable broth
&lt;ul&gt;
&lt;li&gt;use 1 flat teaspoon of vegetable broth powder and dissolve it in cooked water&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;250g pasta (not spaghetti)&lt;&#x2F;li&gt;
&lt;li&gt;2 tablespoons frying oil (no need for container -&amp;gt; fist ingredient)
&lt;ul&gt;
&lt;li&gt;use colza oil, sunflower oil or regular frying oil&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Spices - put all in small bowl:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;1 pinch of salt&lt;&#x2F;li&gt;
&lt;li&gt;1 flat teaspoon pepper&lt;&#x2F;li&gt;
&lt;li&gt;0.5 flat teaspoon nutmeg&lt;&#x2F;li&gt;
&lt;li&gt;1 flat teaspoon turmeric&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;recipe&quot;&gt;Recipe&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;prepare everything as described in &lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;2019-12-1-cooking-for-nerds-pumpkin-one-pot-pasta&#x2F;#ingredients&quot;&gt;Ingredients&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;prepare two timers for 2 and 3 minutes&lt;&#x2F;li&gt;
&lt;li&gt;set stove to level 5&#x2F;10&lt;&#x2F;li&gt;
&lt;li&gt;add frying oil to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;add cut onion to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;wait 2 - 4 minutes -&amp;gt; stir regularly&lt;&#x2F;li&gt;
&lt;li&gt;add carrots to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;add pumpkin to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;wait 3 minutes -&amp;gt; stir regularly&lt;&#x2F;li&gt;
&lt;li&gt;add vegetable broth to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;add coconut milk to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;add pasta to big cooking pot&lt;&#x2F;li&gt;
&lt;li&gt;stir everything well&lt;&#x2F;li&gt;
&lt;li&gt;wait 2 minutes&lt;&#x2F;li&gt;
&lt;li&gt;repeat stiring and waiting (approx. 11 minutes) until
&lt;ul&gt;
&lt;li&gt;pasta is al dente&lt;&#x2F;li&gt;
&lt;li&gt;pumpkin and carrots are well done&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;season the food with the spices mentioned in &lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;2019-12-1-cooking-for-nerds-pumpkin-one-pot-pasta&#x2F;#ingredients&quot;&gt;Ingredients&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;stir everything well so that the spices are evenly distributed&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
</description>
      </item>
      <item>
          <title>bye bye social media</title>
          <pubDate>Sun, 26 Mar 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/bye-bye-social-media/</link>
          <guid>https://schempp.dev/blog/bye-bye-social-media/</guid>
          <description xml:base="https://schempp.dev/blog/bye-bye-social-media/">&lt;p&gt;I recently deleted all my social media accounts &lt;strong&gt;gasp&lt;&#x2F;strong&gt; , which were exactly two: facebook and twitter.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;but-why&quot;&gt;But why?&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;They consume too much time&lt;&#x2F;li&gt;
&lt;li&gt;They provide little or no value for my live&lt;&#x2F;li&gt;
&lt;li&gt;I can communicate with the people I care about through other software.
Why do we have these messenger apps if we don&#x27;t use them?&lt;&#x2F;li&gt;
&lt;li&gt;Also I watched this &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.youtube.com&#x2F;watch?v=3E7hkPZ-HTk&quot;&gt;video&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;I now get my tech news through various newsletters (and boy... there are a lot of them)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
</description>
      </item>
      <item>
          <title>Optimizing my blog</title>
          <pubDate>Sun, 26 Mar 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/optimizing-my-blog/</link>
          <guid>https://schempp.dev/blog/optimizing-my-blog/</guid>
          <description xml:base="https://schempp.dev/blog/optimizing-my-blog/">&lt;p&gt;Recently, I optimized my blog for page speed and file size.
I did this, because I came across the
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;testmysite.thinkwithgoogle.com&#x2F;&quot;&gt;Mobile Website Speed Testing Tool&lt;&#x2F;a&gt;
and my blog did not have 100 points in every category.&lt;&#x2F;p&gt;
&lt;p&gt;It wasn&#x27;t that bad though. My blog was above the 90 points margin.
I still wanted to have 100 points in all categories, so I started optimizing my blog, which
took longer than expected.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;reading-the-detailed-report&quot;&gt;Reading the detailed report&lt;&#x2F;h2&gt;
&lt;p&gt;After google analyzed my blog, the report told me which party of my blog were not optimized.
The report is splitted in three categories:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;mobile friendliness (got 99&#x2F;100)&lt;&#x2F;li&gt;
&lt;li&gt;mobile speed (got 91&#x2F;100)&lt;&#x2F;li&gt;
&lt;li&gt;desktop speed (got 97&#x2F;100)&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;h3 id=&quot;mobile-friendliness-size-tap-targets-appropriately&quot;&gt;Mobile friendliness - size tap targets appropriately&lt;&#x2F;h3&gt;
&lt;p&gt;My &quot;tap targets&quot; were not big enough. Apparently size still matters.&lt;&#x2F;p&gt;
&lt;p&gt;Thanks to the report, which included
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;developers.google.com&#x2F;speed&#x2F;docs&#x2F;insights&#x2F;SizeTapTargetsAppropriately&quot;&gt;links&lt;&#x2F;a&gt;
to all problems found, this was an easy fix:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the distance between clickable elements should not be smaller than 32px (...done)&lt;&#x2F;li&gt;
&lt;li&gt;clickable targets should be at least 48px big (...done)&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;mobile-and-desktop-speed-eliminate-render-blocking-javascript-and-css-in-above-the-fold-content&quot;&gt;Mobile and desktop speed - Eliminate render-blocking JavaScript and CSS in above-the-fold content&lt;&#x2F;h3&gt;
&lt;p&gt;The categories &quot;mobile speed&quot; and &quot;desktop speed&quot; apparently measure the same thing
but have different impacts on the score, because, e.g. big pictures are worse on a mobile client
than on a desktop client.&lt;&#x2F;p&gt;
&lt;p&gt;The only point which I got wrong was the render-blocking JavaScript and CSS in above-the-fold.
I don&#x27;t use JavaScript on my blog, so the only not optimized thing was my CSS.&lt;&#x2F;p&gt;
&lt;p&gt;And this is the part where it gets a little bit ugly.
I first started to pull out the stuff which is clearly &quot;above-the-fold&quot; (e.g. CSS for the header).
This still didn&#x27;t produce the wanted results. My score was still not 100&#x2F;100.
After fiddleing around for some time, I realized, that almost all of my CSS was &quot;above-the-fold&quot;
(including blog posts).&lt;&#x2F;p&gt;
&lt;p&gt;So I just put all of my CSS in the header, which is not that bad, because my CSS is not that big.
I also optimized my CSS, using &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;css&#x2F;csso&quot;&gt;CSSO&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;not-done-yet&quot;&gt;Not done yet&lt;&#x2F;h2&gt;
&lt;p&gt;After having all scores maxed out (100&#x2F;100) I tried
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.webpagetest.org&#x2F;&quot;&gt;webpagetest.org&lt;&#x2F;a&gt;.
Turns out, that I haven actually enabled gzip compression for my favicon.ico.
Since the favicon is the only image on my start page,
which is not inlined, I got an F for compression T_T.&lt;&#x2F;p&gt;
&lt;p&gt;The fix was easy. I just had to put&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;gzip_types *;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;in the nginx config file.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Possible Frontend Architecture</title>
          <pubDate>Mon, 06 Mar 2017 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/possible-frontend-architecture/</link>
          <guid>https://schempp.dev/blog/possible-frontend-architecture/</guid>
          <description xml:base="https://schempp.dev/blog/possible-frontend-architecture/">&lt;p&gt;This post is about how a frontend architecture could look like.
The presented architecture is not the only way how to solve the problems in the frontend like
loading time, data retrieval, etc. but it can be one possible way.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-architecture&quot;&gt;The architecture&lt;&#x2F;h2&gt;
&lt;p&gt;In the architecture, the &quot;backend&quot; is behind an API-Gateway, which doesn&#x27;t really concern us.
The task of this API-Gateway is to handle REST-Calls.&lt;&#x2F;p&gt;
&lt;p&gt;The four main parts in the frontend are:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Data Fetcher:&lt;&#x2F;strong&gt; a server which fetches data from the API-Gateway. Could be
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;graphql.org&#x2F;&quot;&gt;GraphQL&lt;&#x2F;a&gt; or something like that.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Server Side Renderer:&lt;&#x2F;strong&gt; a server which prerenders the html&#x2F;css markup for you. This is relevant for
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Search_engine_optimization&quot;&gt;SEO&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;andrewhfarmer.com&#x2F;server-side-render&#x2F;&quot;&gt;performance&lt;&#x2F;a&gt; stuff.
And with performance I mean the time it takes for your webpage to display something
(If you code everything with React, you won&#x27;t have static html, until you prerender it of couse).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Frontend Deliverer:&lt;&#x2F;strong&gt; delivers the js, css and image files to the browser. This could be something like a
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;en.wikipedia.org&#x2F;wiki&#x2F;Content_delivery_network&quot;&gt;CDN&lt;&#x2F;a&gt; or a cookieless domain
(just search the web for &quot;cookieless domain&quot; and you will find many blogs,
suggesting that you should server static content from a cookieless domain...).&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Browser:&lt;&#x2F;strong&gt; the software which you are using right now to view this page, unless you are using curl, wget or something similar...&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;frontendArchitecture.png&quot; alt=&quot;alt text&quot; title=&quot;Frontend Architecture&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;request-order&quot;&gt;Request Order&lt;&#x2F;h2&gt;
&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;As seen in the image, the first thing the Browser has to do is send a request to some server.
This server has to return the prerendered html markup, so the server has to be the Server Side Renderer.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;After the browser got the html page, it loads the javascript bundles and the css files from the Frontend Deliverer.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;Finally the javascript code is executed. The javascript code gets it&#x27;s data from the Data Fetcher and&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;strong&gt;UPDATE:&lt;&#x2F;strong&gt; you could also store the data, using
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;graphql.org&#x2F;&quot;&gt;GraphQL&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;graphql.org&#x2F;learn&#x2F;queries&#x2F;#mutations&quot;&gt;Mutations&lt;&#x2F;a&gt;. But be aware, that
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;graphql.org&#x2F;&quot;&gt;GraphQL&lt;&#x2F;a&gt; and
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;www.ics.uci.edu&#x2F;~fielding&#x2F;pubs&#x2F;dissertation&#x2F;rest_arch_style.htm&quot;&gt;REST&lt;&#x2F;a&gt;
are &lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;philsturgeon.uk&#x2F;api&#x2F;2017&#x2F;01&#x2F;24&#x2F;graphql-vs-rest-overview&#x2F;&quot;&gt;two completely different things&lt;&#x2F;a&gt;.
Both have their strengths and weaknesses.&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;&#x2F;li&gt;
&lt;li&gt;
&lt;p&gt;sends PUT, POST or DELETE requests directly to the API Gateway.
As the user uses the site, more requests might be sent to either the Data Fetcher or the API Gateway.&lt;&#x2F;p&gt;
&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;To prerender the site, the Server Side Renderer executes the same code, which is executed in the browser.
Therefore the Server Side Renderer has to execute javascript at some point, which suggests that the Server Side Renderer
should be implemented in javascript (e.g. node.js)&lt;&#x2F;p&gt;
&lt;h2 id=&quot;benefits&quot;&gt;Benefits&lt;&#x2F;h2&gt;
&lt;p&gt;You might ask yourself, why you should do this. After all, you could just deliver everything from one server.
However, if you use this architecture you can:&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;deploy separately from the backend, thus deploy faster and more secure (you just need to exchange some js bundles to update the frontend)&lt;&#x2F;li&gt;
&lt;li&gt;optimize the size and count of http requests you need to send to the backend,
thus reducing the amount of data transfered over a possible small bandwidth medium&lt;&#x2F;li&gt;
&lt;li&gt;create an interface, which spereates the frontend from the backend in such a manner, that they are more exchangable&lt;&#x2F;li&gt;
&lt;li&gt;reuse some of the parts of this architecture to implement a second user interface, e.g. for an mobile app&lt;&#x2F;li&gt;
&lt;li&gt;write frontend integrationtests easier, because you don&#x27;t need a running server on your local machine&lt;&#x2F;li&gt;
&lt;li&gt;improve the developer experience by beeing able to develop the frontend much faster&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;drawbacks&quot;&gt;Drawbacks&lt;&#x2F;h2&gt;
&lt;p&gt;Of course, nothing is without drawbacks. Everything has a price.
This architecture&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;is more complex&lt;&#x2F;li&gt;
&lt;li&gt;is not necessarily suited for frontend newcomers or junior developers,
because it requires some expertise in how http, javascript and the browsers work&lt;&#x2F;li&gt;
&lt;li&gt;needs more effort to maintain, because if you deploy your frontend detached from your backend, your current frontend version has to match
the current backend version or be backwards compatible, and vice versa&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;conclusion&quot;&gt;Conclusion&lt;&#x2F;h2&gt;
&lt;p&gt;If you need a frontend, which &lt;strong&gt;has&lt;&#x2F;strong&gt; to look and feel homogeneous, you should use this architecture.&lt;&#x2F;p&gt;
&lt;p&gt;If you need a frontend, which &lt;strong&gt;can&lt;&#x2F;strong&gt; look and feel homogeneous, you should still use this architecture.&lt;&#x2F;p&gt;
&lt;p&gt;If you need a frontend, which &lt;strong&gt;musn&#x27;t&lt;&#x2F;strong&gt; look and feel homogenous, you could still use this architecture.
After all, why wouldn&#x27;t you want to have the benefits described above?&lt;&#x2F;p&gt;
&lt;p&gt;Of course if you are writing a small service, building such an architecture is way to oversized.
So for small services, you shouldn&#x27;t use this architecture.&lt;&#x2F;p&gt;
&lt;p&gt;In the end it all comes down to how big your frontend is going to be.
At some point you have to think about the problems which occur with big web applications
and this architecture might help you solve some of them.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>React-Redux Frontend Architecture</title>
          <pubDate>Sat, 22 Oct 2016 14:39:10 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/react-redux-architecture/</link>
          <guid>https://schempp.dev/blog/react-redux-architecture/</guid>
          <description xml:base="https://schempp.dev/blog/react-redux-architecture/">&lt;p&gt;This post is about how we used
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;react&#x2F;&quot;&gt;React&lt;&#x2F;a&gt; in combination with
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;&quot;&gt;Redux&lt;&#x2F;a&gt; in our project, to create a frontend architecture,
in which the code we write is easy to test, maintain and extend.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-categories-of-the-architecture&quot;&gt;The categories of the architecture&lt;&#x2F;h2&gt;
&lt;p&gt;We divided the files in our project in seven categories:&lt;&#x2F;p&gt;
&lt;ol&gt;
&lt;li&gt;(&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;medium.com&#x2F;@joshblack&#x2F;stateless-components-in-react-0-14-f9798f8b992d&quot;&gt;Stateless&lt;&#x2F;a&gt;)
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;react&#x2F;docs&#x2F;react-component.html&quot;&gt;Components&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;docs&#x2F;basics&#x2F;UsageWithReact.html#container-components&quot;&gt;Redux Containers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;docs&#x2F;basics&#x2F;Actions.html#action-creators&quot;&gt;Action Creators&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Controllers&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;docs&#x2F;basics&#x2F;Reducers.html&quot;&gt;Reducers&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;docs&#x2F;recipes&#x2F;ComputingDerivedData.html&quot;&gt;Selectors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;APIs&lt;&#x2F;li&gt;
&lt;&#x2F;ol&gt;
&lt;p&gt;How the different categories work together can be seen in the following graphic:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;reactReduxArchitecture.png&quot; alt=&quot;alt text&quot; title=&quot;React-Redux-Architecture&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Most of the categories are marked with either the react-icon
&lt;img src=&quot;&#x2F;images&#x2F;reactLogo.svg&quot; alt=&quot;react-icon&quot; class=&quot;iconImage&quot;&gt; or the redux-icon
&lt;img src=&quot;&#x2F;images&#x2F;reduxLogo.svg&quot; alt=&quot;redux-icon&quot; class=&quot;iconImage&quot;&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Categories marked with an icon are a common principle of the library, which the icon represents.
Looking at the graphic, you can see that most of the categories are already
a common part of either the react or redux library.
Only the &quot;Controllers&quot; and the &quot;APIs&quot; categories are different.
These categories provide abstractions, which make it easier to maintain and improve the code.&lt;&#x2F;p&gt;
&lt;p&gt;As seen in the graphic, components seem to always be inside a container. However, components do not
necessarily need to be in a container to be used. Sometimes components are used directly in other components and get their
properties in the components which are inside a container:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; ComponentWithContainer&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    {&lt;&#x2F;span&gt;&lt;span&gt;valueA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; valueB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; callbackA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span&gt; (&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;div&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            &amp;lt;p&amp;gt;{&lt;&#x2F;span&gt;&lt;span&gt;valueA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt;: &lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;{&lt;&#x2F;span&gt;&lt;span&gt;valueB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&amp;lt;&#x2F;p&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;        &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            &amp;lt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;ComponentWithoutContainer&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt;                doStuff&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;={&lt;&#x2F;span&gt;&lt;span&gt;callbackA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;}&lt;&#x2F;span&gt;&lt;span&gt; &lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;            &#x2F;&amp;gt;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;        &amp;lt;&#x2F;div&amp;gt;&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export default&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; connect&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)(ComponentWithContainer)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The &lt;strong&gt;APIs&lt;&#x2F;strong&gt; category contains APIs to communicate with webservices in the backend, but it can also encapsulate
other APIs, like e.g. an API to legacy code in the frontend or an API to a third-party frontend library like a tracking-API.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Controllers&lt;&#x2F;strong&gt; contain more complex logic and use the APIs and the Action Creators to fulfill their work.
The Controllers use the Action Creators to e.g. chain multiple Actions and API calls together by using promises.
In the following example, we are using
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;gaearon&#x2F;redux-thunk&quot;&gt;thunk&lt;&#x2F;a&gt; to be able to use function callbacks in addition
to action creators.&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import * as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; backend&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;..&#x2F;api&#x2F;backendRest&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;import * as&lt;&#x2F;span&gt;&lt;span style=&quot;color: #8FBCBB;&quot;&gt; actions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; from&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;..&#x2F;actions&#x2F;someActions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;export function&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; someController&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;    return&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; (&lt;&#x2F;span&gt;&lt;span&gt;dispatch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;,&lt;&#x2F;span&gt;&lt;span&gt; getState&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;        return backend&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;fetchSomeData&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;()&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .then(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;json&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;                dispatch&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;actions.actionA(json&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;            .catch(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;(&lt;&#x2F;span&gt;&lt;span&gt;error&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;)&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; {&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;                console&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span&gt;warn(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;ERROR:&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;#39;,&lt;&#x2F;span&gt;&lt;span&gt; error)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;            }&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;    }&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;}&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;In the example above, we first get data from the backend and then use said data with an action.
Of course we can do more complex things in the controllers, like e.g. more complex communication with
different backends.&lt;&#x2F;p&gt;
&lt;p&gt;How the other categories (marked with
&lt;img src=&quot;&#x2F;images&#x2F;reduxLogo.svg&quot; alt=&quot;redux-icon&quot; class=&quot;iconImage&quot;&gt; or
&lt;img src=&quot;&#x2F;images&#x2F;reactLogo.svg&quot; alt=&quot;react-icon&quot; class=&quot;iconImage&quot;&gt;)
are used together is already described on
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;redux.js.org&#x2F;&quot;&gt;redux.js&lt;&#x2F;a&gt; or
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;react&#x2F;docs&#x2F;hello-world.html&quot;&gt;React&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;&#x2F;h2&gt;
&lt;p&gt;To test our application, we use unit tests, as well as integration tests.
Everything that is reasonable testable without using the backend, is tested with unit tests.
Everything that would be really hard to mock, is tested with integration tests.&lt;&#x2F;p&gt;
&lt;p&gt;In our project, we unit test the react components, which is really easy, because they are almost always functional
components. This does not mean, that stateful components should never be used. However, stateful components should only be used
if necessary. Only use stateful components, if the state has something to do with the visual representation of the component.
Never put business logic in your components! Putting business logic in your components is like putting business logic in the
view of a &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;martinfowler.com&#x2F;eaaDev&#x2F;uiArchs.html#ModelViewController&quot;&gt;MVC&lt;&#x2F;a&gt; program.
More on stateful vs stateless components can be found
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;react&#x2F;docs&#x2F;state-and-lifecycle.html&quot;&gt;here&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, we also unit test the selectors and the actions together with the reducers.
To test our react components, we use
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;facebook.github.io&#x2F;jest&#x2F;&quot;&gt;jest&lt;&#x2F;a&gt; together with
&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;github.com&#x2F;airbnb&#x2F;enzyme&quot;&gt;enzyme&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;The Controllers and the APIs are tested (together with everything else) with integration tests,
since they are heavily dependent on an existing backend.
However, our integration tests test everything except the react components (which are already covered by the unit tests).
So the integration tests replace the react components (so to say) and trigger all the functionality,
stored in the Controllers and Action categories, which can be seen in the following graphic:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;reactReduxArchitectureIntegrationTesting.png&quot; alt=&quot;alt text&quot; title=&quot;React-Redux-Architecture - Integration testing&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;The integration tests run on node.js, as well as the unit tests.
This means, that we can test every category and every component in our application,
without starting the browser (which is awesome :-) ).&lt;&#x2F;p&gt;
&lt;p&gt;Of course we still need some &lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;docs.seleniumhq.org&#x2F;&quot;&gt;selenium&lt;&#x2F;a&gt; tests, to tests
the application in different browsers. However, the amount of selenium tests can be reduced significantly.&lt;&#x2F;p&gt;
&lt;p&gt;Furthermore, &quot;replacing&quot; the react components with integration tests makes it very easy to write said
integration tests, because you could say, that the integration tests are just another &quot;view&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;So instead of having react components, which the user can use (by clicking, typing),
you have the integration tests which take care of the interaction.
Thus an integration test can be written like a user story and is therefore easy to understand.&lt;&#x2F;p&gt;
&lt;p&gt;An integration test, involving two sites which are implementet with react and redux
and use the same backend could be testet as follows:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;javascript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; storeSiteA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createStoreFromRootReducer&lt;&#x2F;span&gt;&lt;span&gt;(rootReducerSiteA)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;const&lt;&#x2F;span&gt;&lt;span&gt; storeSiteB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; =&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt; createStoreFromRootReducer&lt;&#x2F;span&gt;&lt;span&gt;(rootReducerSiteB)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;&#x2F;&#x2F; changes something in the backend which affects the other site&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storeSiteA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dispatch&lt;&#x2F;span&gt;&lt;span&gt;(siteAactions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;someAction&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;&#x2F;&#x2F; expect the change to have an effect on the state&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(siteAselectors&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;someSelector&lt;&#x2F;span&gt;&lt;span&gt;(storeSiteA&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getState&lt;&#x2F;span&gt;&lt;span&gt;()))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;&#x2F;&#x2F; get data from backend&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;storeSiteB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;dispatch&lt;&#x2F;span&gt;&lt;span&gt;(siteBactions&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;pullData&lt;&#x2F;span&gt;&lt;span&gt;())&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #616E88;&quot;&gt;&#x2F;&#x2F; expect data to be what came from site A&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;expect&lt;&#x2F;span&gt;&lt;span&gt;(siteBselectors&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getData&lt;&#x2F;span&gt;&lt;span&gt;(storeSiteB&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;getState&lt;&#x2F;span&gt;&lt;span&gt;()))&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;.&lt;&#x2F;span&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;toBe&lt;&#x2F;span&gt;&lt;span&gt;(&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;...&lt;&#x2F;span&gt;&lt;span&gt;)&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;The actions and selectors which are used by the components are also used by the integration test.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>The importance of refactoring</title>
          <pubDate>Fri, 14 Oct 2016 14:39:10 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/the-importance-of-refactoring/</link>
          <guid>https://schempp.dev/blog/the-importance-of-refactoring/</guid>
          <description xml:base="https://schempp.dev/blog/the-importance-of-refactoring/">&lt;p&gt;Describing refactoring to a non-developer person can be tough.
Especially when this person does not understand the implications
of the absence of clean code or other code-quality improving techniques.&lt;&#x2F;p&gt;
&lt;p&gt;If you try to explain code-quality improving techniques to non-developer persons,
you might hear questions like &quot;why haven&#x27;t you done it right the first time?&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Even explaining why code-quality matters is really difficult, particularly when money is involved.
For a person who is only interested in making money with the resulting software, improving code-quality sounds like
a waste of time and money, because the software might work, even without improving the code-quality.&lt;&#x2F;p&gt;
&lt;p&gt;But if you want to continue developing the software, the code needs to be maintainable, well structured
and as small as possible but still understandable.
Because if it isn&#x27;t, developing new features and fixing bugs will become nearly impossible.&lt;&#x2F;p&gt;
&lt;p&gt;Communicating the importance of code-quality to a non-developer person verbally is hard.
To make the process of highlighting the importance of code-quality and refactoring more easy,
I created a four-quadrant matrix.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;the-refactoring-matrix&quot;&gt;The Refactoring-Matrix&lt;&#x2F;h3&gt;
&lt;p&gt;&lt;img src=&quot;&#x2F;images&#x2F;refactoringMatrix.png&quot; alt=&quot;alt text&quot; title=&quot;Refactoring-Matrix&quot; &#x2F;&gt;&lt;&#x2F;p&gt;
&lt;p&gt;As the old saying goes &quot;a picture is worth a thousand words&quot;, this graphic is meant to explain the importance
of refactoring and code-quality without going into detail too much.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;the-axes&quot;&gt;The axes&lt;&#x2F;h2&gt;
&lt;p&gt;In the grahpic, you can see two axes.
The x-axis describes the time, which is spent in the current project (the time spent on the software).&lt;&#x2F;p&gt;
&lt;p&gt;The y-axis describes the time, which is spent on the implementation of new features or the time spent on bug-fixing.&lt;&#x2F;p&gt;
&lt;p&gt;The matrix in general is meant to describe the correlation between time, which has passed, and the effort which is needed to
implement new features or fix existing bugs.&lt;&#x2F;p&gt;
&lt;p&gt;The red and green lines describe what happens if you do&#x2F;don&#x27;t do refactoring&lt;&#x2F;p&gt;
&lt;h2 id=&quot;&quot;&gt;?&lt;&#x2F;h2&gt;
&lt;p&gt;The quadrant on the lower left is the quadrant in which every new project starts.
It&#x27;s too early to say something about the quality of the code, because there simply isn&#x27;t much code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;this-should-not-happen&quot;&gt;This should not happen&lt;&#x2F;h2&gt;
&lt;p&gt;The quadrant on the upper left should never be reached in any project.
If this quadrant is reached, it means that you need a lot of time do implement new features in the early phase of the project.
This might still happen, if&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;people use a technology which is not suited for the task or outdated&lt;&#x2F;li&gt;
&lt;li&gt;people use a technology they are not familiar with, so they have to learn the whole language&#x2F;framework&lt;&#x2F;li&gt;
&lt;li&gt;people put to much effort in thinking about absolutely &lt;strong&gt;every&lt;&#x2F;strong&gt; little detail instead of writing code&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h2 id=&quot;no-problems&quot;&gt;no problems&lt;&#x2F;h2&gt;
&lt;p&gt;The quadrant on the lower right is the quadrant in which every project should be.
In this quadrant,&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;new features are easy to develop in a short amount of time&lt;&#x2F;li&gt;
&lt;li&gt;bugs are easy to detect and easy to fix&lt;&#x2F;li&gt;
&lt;li&gt;the code is as small as possible and as big as necessary&lt;&#x2F;li&gt;
&lt;li&gt;there are many tests&lt;&#x2F;li&gt;
&lt;li&gt;tests are easy to write&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;This quadrant can be reached by constantly doing refactoring and constantly thinking
about improvements of the code-quality and software architecture.&lt;&#x2F;p&gt;
&lt;p&gt;As you can clearly see in the graphic, the green line does &lt;strong&gt;not&lt;&#x2F;strong&gt; converge to zero, it&#x27;s more like a sinus curve.
This means, that you can&#x27;t develop the &quot;perfect&quot; software architecture and never need to think about this stuff again.
It means, that whatever is done in the project,
the developers have to think and do something about the software-architecture&#x2F;clean-code.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;danger-zone&quot;&gt;danger zone&lt;&#x2F;h2&gt;
&lt;p&gt;The quadrant on the upper left is the quadrant, which a project should never ever reach.
In this quadrant,&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;the code is unmaintainable,&lt;&#x2F;li&gt;
&lt;li&gt;the code is complicated&#x2F;hard to understand&lt;&#x2F;li&gt;
&lt;li&gt;new features take a (very) long time to implement&lt;&#x2F;li&gt;
&lt;li&gt;bugs are hard to fix&lt;&#x2F;li&gt;
&lt;li&gt;there are no or too little tests&lt;&#x2F;li&gt;
&lt;li&gt;tests are (really) hard to write&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;The red line in this quadrant looks like the half of a parabola, which means that the red curve will rise very fast.
Every feature implemented in such a project will take longer and longer for every feature that is developed.&lt;&#x2F;p&gt;
&lt;p&gt;This means, that after some time, the software will not be maintainable anymore. New features can&#x27;t be developed,
because they would break something somewhere.
It is therefore very important, that a project never gets too deep into the &quot;danger zone&quot;,
because it might never leave it again.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Fix bootloader problem with Linux in windows</title>
          <pubDate>Wed, 27 May 2015 20:34:30 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/fix-linux-windows-bootloader/</link>
          <guid>https://schempp.dev/blog/fix-linux-windows-bootloader/</guid>
          <description xml:base="https://schempp.dev/blog/fix-linux-windows-bootloader/">&lt;p&gt;If you install windows after you installed Linux, the Linux bootloader will be &quot;overwritten&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;To fix this, you don&#x27;t have to reinstall grub or syslinux or any other bootloader you are using.
Just boot into windows, figure out on which partition the bootloader is and set the active partition flag
on this partition.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;set-the-active-partition&quot;&gt;set the active partition&lt;&#x2F;h2&gt;
&lt;p&gt;to set the active partition, you simply can use diskpart.
Run diskpart:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;diskpart&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;then navigate to the disk, containing the Linux partition with the bootloader. For example:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; disk 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; partition 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;active&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;in this case, the bootloader of my Linux installation was on my first disk on partition three.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;update-problems&quot;&gt;update problems&lt;&#x2F;h2&gt;
&lt;p&gt;For some updates in windows 7, the active partition needs to be the partition with the windows bootloader on it.
The windows 7 bootloader partition is usually 100MB big and is the partition right before the partition with your windows 7
system.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;scripts&quot;&gt;scripts&lt;&#x2F;h2&gt;
&lt;p&gt;to make life easier, I wrote some scripts which set the active flag on either the partition with syslinux or the partition with
the windows bootloader.&lt;&#x2F;p&gt;
&lt;p&gt;file arch&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; disk 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; partition 2&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;active&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;file windows&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; disk 0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt;select&lt;&#x2F;span&gt;&lt;span&gt; partition 3&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;active&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;exit&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;file set_boot_loader.bat&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;diskpart&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; &#x2F;s&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt; &amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt;%~dpnx1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #ECEFF4;&quot;&gt;&amp;quot;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #81A1C1;&quot;&gt; &amp;gt;&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; logfile.txt&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;file set_boot_loader_arch.bat&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set_boot_loader.bat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; arch&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;file set_boot_loader_windows.bat&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;set_boot_loader.bat&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; windows&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;</description>
      </item>
      <item>
          <title>Apps you should have for rooted Android devices</title>
          <pubDate>Fri, 26 Dec 2014 12:33:51 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/apps-you-should-have/</link>
          <guid>https://schempp.dev/blog/apps-you-should-have/</guid>
          <description xml:base="https://schempp.dev/blog/apps-you-should-have/">&lt;p&gt;After rooting my android device, I realized, that there are a variety of apps which are very powerful if you have a
rooted device. In this post, I want to introduce you to my favorite apps which are &lt;strong&gt;only&lt;&#x2F;strong&gt; for rooted devices or are &lt;strong&gt;more
useful&lt;&#x2F;strong&gt; on rooted devices.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;voltage-control&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.darekxan.voltagecontrol&quot;&gt;Voltage Control&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This simple app allows you to change the CPU govenours, IO shedulers and the CPU frequency.
It does &lt;strong&gt;not&lt;&#x2F;strong&gt; have profiles and all this &quot;if screen turned of then...&quot; stuff which is, in my opinion,
positive in any way. Additionally, this app is completely free and has no advertisement what so ever.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;greenify&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.oasisfeng.greenify&quot;&gt;Greenify&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Another great app, which also works on not rooted devices. Of course the full potential of this app is only
accessible with root rights. Furthermore the power of this app can be extended by installing an extension called
&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;repo.xposed.info&#x2F;module&#x2F;de.robv.android.xposed.installer&quot;&gt;xposed framework&lt;&#x2F;a&gt;. So what does this app do? It simply puts all selected apps in a hibernate mode, which makes the
apps use much less power than they would normally do. With the additional exposed framework, one can unlock the
experimental features.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;os-monitor&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.eolwral.osmonitor&quot;&gt;OS Monitor&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Another app, which only works with root rights. This app is similar to &lt;strong&gt;htop&lt;&#x2F;strong&gt; in Linux or &lt;strong&gt;taskmanager&lt;&#x2F;strong&gt; in windows.
It allows the user to list and interact with all running process, connections and other stuff.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;afwall&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=dev.ukanth.ufirewall&quot;&gt;AFWall+&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;A must have for all rooted phones. This app simply is a firewall with blacklists or whitelists and some other stuff like logs.
You can select which app is allowed to connect via Wifi and&#x2F;or mobile Internet.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;gsam-battery-monitor&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.gsamlabs.bbm&amp;amp;hl=de&quot;&gt;GSam Battery Monitor&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;This is the best app for tracking your battery. It shows you which app sucks the most out of your battery and
shows you all sort of information about the battery drain. Definitely a must have.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;repetitouch&quot;&gt;&lt;a rel=&quot;external&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=com.cygery.repetitouch.free&amp;amp;hl=de&quot;&gt;RepetiTouch&lt;&#x2F;a&gt;&lt;&#x2F;h2&gt;
&lt;p&gt;Awesome app. Basically this app allows you to &lt;strong&gt;record&lt;&#x2F;strong&gt; your typing on the screen, and then allows you to &lt;strong&gt;play back&lt;&#x2F;strong&gt;
what you just recorded. You can also define how much you want your recording to be played back.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Reverse Tether mit Cyanogenmod 7.2.0 und Kubuntu 12.04 LTS</title>
          <pubDate>Mon, 27 May 2013 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/reverse-tether-mit-cyanogenmod-7-2-0-und-kubuntu-12-04-lts/</link>
          <guid>https://schempp.dev/blog/reverse-tether-mit-cyanogenmod-7-2-0-und-kubuntu-12-04-lts/</guid>
          <description xml:base="https://schempp.dev/blog/reverse-tether-mit-cyanogenmod-7-2-0-und-kubuntu-12-04-lts/">&lt;p&gt;Folgendes Tutorial beschreibt, wie man mit dem Smartphone per USB über den PC ins Internet zu verbindet:&lt;&#x2F;p&gt;
&lt;p&gt;Zuerst richtet man bei Kubuntu neben der Verbindung für das Internet eine neue Verbindung ein, die als Methode &quot;Gemeinsam&quot; verwendet.&lt;&#x2F;p&gt;
&lt;p&gt;Nun aktiviert man auf dem Smartphone USB-Tethering und verbindet, unter Kubuntu, über die eben erstellten Verbindung, mit dem Smartphone (sollte im Netzwerkmanager zu sehen sein).&lt;&#x2F;p&gt;
&lt;p&gt;Jetzt tippt man im Terminal in Kubuntu &quot;ifconfig&quot; ein und schaut welche IP die zum Smartphone gehörige Verbindung hat (z.B. 10.42.0.1) und wie die Verbindung heißt (z.B. usb0).&lt;&#x2F;p&gt;
&lt;p&gt;Anschließend öffnet man auf dem Smartphone einen Terminal Emulator, ich empfehle
&lt;a rel=&quot;external&quot; title=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=jackpal.androidterm&quot; href=&quot;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=jackpal.androidterm&quot;&gt;https:&#x2F;&#x2F;play.google.com&#x2F;store&#x2F;apps&#x2F;details?id=jackpal.androidterm&lt;&#x2F;a&gt;
und gibt folgendes ein:&lt;&#x2F;p&gt;
&lt;pre class=&quot;giallo&quot; style=&quot;color: #D8DEE9; background-color: #2E3440;&quot;&gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span style=&quot;color: #88C0D0;&quot;&gt;su&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; busybox ifconfig usb0&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.42.0.5&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; up route add default gw&lt;&#x2F;span&gt;&lt;span style=&quot;color: #B48EAD;&quot;&gt; 10.42.0.1&lt;&#x2F;span&gt;&lt;span style=&quot;color: #A3BE8C;&quot;&gt; dev usb0&lt;&#x2F;span&gt;&lt;&#x2F;span&gt;&lt;&#x2F;code&gt;&lt;&#x2F;pre&gt;
&lt;p&gt;Wobei 10.42.0.1 die zum Smartphone gehörige IP ist und usb0 die Kabelverbindung zum Smartphone. Die IP 10.42.0.5 kann eigentlich eine beliebige sein, muss aber im selben Netz wie die zum Smartphone gehörige liegen.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Drohne Relief-Darstellung</title>
          <pubDate>Thu, 28 Mar 2013 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/drohne-relief-darstellung/</link>
          <guid>https://schempp.dev/blog/drohne-relief-darstellung/</guid>
          <description xml:base="https://schempp.dev/blog/drohne-relief-darstellung/">&lt;p&gt;Im Rahmen des einwöchigen Autonome Systeme Labors wurde die nachfolgende Dokumentation in Zusammenarbeit mit meinem Kommilitonen Thorsten Z. angefertigt.&lt;&#x2F;p&gt;
&lt;h2 id=&quot;inhalt&quot;&gt;Inhalt&lt;&#x2F;h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Gruppenmitglieder&quot;&gt;Gruppenmitglieder&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Zusammenfassung_47_Abstract&quot;&gt;Zusammenfassung &#x2F; Abstract&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Keywords&quot;&gt;Keywords&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Arbeitsplan&quot;&gt;Arbeitsplan&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Einf_252hrung&quot;&gt;Einführung&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Aufgabenanalyse&quot;&gt;Aufgabenanalyse&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Relevante_Komponenten_des_RoboView_45Frameworks&quot;&gt;Relevante Komponenten des RoboView-Frameworks&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Mathematisches_Modell_f_252r_die_Erfassungseigenschaften_des_Ultraschall_45Sensors&quot;&gt;Mathematisches Modell für die Erfassungseigenschaften des Ultraschall-Sensors&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Idee&quot;&gt;Idee&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Modell&quot;&gt;Modell&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Bezeichnungen&quot;&gt;Bezeichnungen&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Ablauf&quot;&gt;Ablauf&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Algorithmus_in_Pseudocode&quot;&gt;Algorithmus in Pseudocode&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Modellierung_der_Datenstruktur_45_GridMap&quot;&gt;Modellierung der Datenstruktur - GridMap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Idee_AN1&quot;&gt;Idee&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Interface&quot;&gt;Interface&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Implementierung_der_GridMap&quot;&gt;Implementierung der GridMap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#HashMap&quot;&gt;HashMap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Hashing_45Verfahren&quot;&gt;Hashing-Verfahren&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Mapping_von_gemessenen_Punkt_45Daten_auf_Zellen_in_der_GridMap&quot;&gt;Mapping von gemessenen Punkt-Daten auf Zellen in der GridMap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Wahrscheinlichkeitswert_f_252r_eine_Zelle_setzen&quot;&gt;Wahrscheinlichkeitswert für eine Zelle setzen&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Ausdehnung_der_GridMap&quot;&gt;Ausdehnung der GridMap&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#GridMap_leeren&quot;&gt;GridMap leeren&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Ausblick&quot;&gt;Ausblick&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Abtastrate&quot;&gt;Abtastrate&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Grafische_Implementierung&quot;&gt;Grafische Implementierung&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Coverage_Maps&quot;&gt;Coverage Maps&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Referenzen&quot;&gt;Referenzen&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;a href=&quot;https:&#x2F;&#x2F;schempp.dev&#x2F;blog&#x2F;drohne-relief-darstellung&#x2F;#Ressourcen&quot;&gt;Ressourcen&lt;&#x2F;a&gt;&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;gruppenmitglieder&quot;&gt;&lt;a name=&quot;Gruppenmitglieder&quot;&gt;&lt;&#x2F;a&gt;Gruppenmitglieder&lt;&#x2F;h3&gt;
&lt;ul&gt;
&lt;li&gt;Thorsten Z.&lt;&#x2F;li&gt;
&lt;li&gt;Maximilian S.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;zusammenfassung-abstract&quot;&gt;&lt;a name=&quot;Zusammenfassung_47_Abstract&quot;&gt;&lt;&#x2F;a&gt;Zusammenfassung &#x2F; Abstract&lt;&#x2F;h3&gt;
&lt;p&gt;Die Arbeit beschreibt ein Modell für die Erfassungseigenschaften eines Ultraschall-Sensors. Ein Ultraschall-Sensor hat eine kegelförmige Abtastung. Wenn ein Objekt durch den Sensor erkannt wurde, bekommt man einen Distanzwert zurück gegeben, Informationen über die Lage des Objektes innerhalb des Kegels fehlen jedoch. Durch die mathematische Analyse des Abtastkegels, konnte ein Modell für den Sensor erstellt werden. In einem eigens dafür entwickelten Algorithmus wird der Ultraschall-Kegel mit Hilfe ausgesendeter Vektoren stückweise abgetastet und Wahrscheinlichkeitswerte über die abgetasteten Regionen berechnet. Dadurch wird eine Statistik über die Wahrscheinlichkeit des Ortes eines Objektes innerhalb des Kegels ermittelt. Weiter wird eine spezielle Datenstruktur, eine so genannte GridMap, vorgestellt, in die diese Wahrscheinlichkeitswerte abgelegt werden. Zuletzt wird die GridMap ausgelesen und die interpretierten Wahrscheinlichkeitswerte als Relief in OpenGL dargestellt.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;keywords&quot;&gt;&lt;a name=&quot;Keywords&quot;&gt;&lt;&#x2F;a&gt;Keywords&lt;&#x2F;h3&gt;
&lt;p&gt;Ultraschall, Sensor, GridMap, OpenGL, Topologie, Raumtopologie&lt;&#x2F;p&gt;
&lt;h3 id=&quot;arbeitsplan&quot;&gt;&lt;a name=&quot;Arbeitsplan&quot;&gt;&lt;&#x2F;a&gt;Arbeitsplan&lt;&#x2F;h3&gt;
&lt;p&gt;Montag 25.02.2013&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Aufgabenanalyse (Milestone 0)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Teilaufgaben festlegen und Arbeitsplan erstellen.&lt;&#x2F;li&gt;
&lt;li&gt;Bereits existierende Ansätze ermitteln.&lt;&#x2F;li&gt;
&lt;li&gt;Theoretische Einarbeitung in das Thema (Grid Maps).&lt;&#x2F;li&gt;
&lt;li&gt;Ziel: Allgemeines Verständnis was wie zu tun ist und Projektspezifikation.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Dienstag 26.02.2013&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;In Eclipse-Projektstruktur&#x2F;-Projektfunktionen einarbeiten (Milestone 1)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Bestimmung der für das Ziel relevant Projektkomponenten.&lt;&#x2F;li&gt;
&lt;li&gt;Bestimmen an welcher Stelle Komponenten erweitert werden müssen.&lt;&#x2F;li&gt;
&lt;li&gt;Bestimmen wie auf Sensordaten zugegriffen werden kann.&lt;&#x2F;li&gt;
&lt;li&gt;Ziel: Allgemeines Verständnis der bereits vorhandenen Projekstruktur&#x2F;-komponenten und Dokumentation der relevanten Komponenten.&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Entwicklung des Modelles für Erfassungseigenschaften des Ultraschall-Sensors (Milestone 2)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Analyse der Sensordaten.&lt;&#x2F;li&gt;
&lt;li&gt;Kegelproblematik lösen&lt;&#x2F;li&gt;
&lt;li&gt;Bestimmen welche mathematischen Lösungswege möglich&#x2F;sinnvoll sind.&lt;&#x2F;li&gt;
&lt;li&gt;Modell mathematisch formulieren und Algorithmus erarbeiten&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Mittwoch 27.02.2013&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Entwicklung des Modelles für Erfassungseigenschaften des Ultraschall-Sensors (Milestone 2)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;&lt;strong&gt;Implementierung des Modells mit einer Software-Architektur&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Implementierung der GridMap &lt;strong&gt;(Milestone 3)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Interface&lt;&#x2F;li&gt;
&lt;li&gt;Implementierung der kegelförmigen Ultraschallerfassung. &lt;strong&gt;(Milestone 4)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ziel: Fertiges Modell, welches in der Lage ist, per Ultraschallsensor eine Karte zu erstellen.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Donnerstag 28.02.2013&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementierung des Modells mit einer Software-Architektur&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Implementierung der kegelförmigen Ultraschallerfassung. &lt;strong&gt;(Milestone 4)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ziel: Fertiges Modell, welches in der Lage ist, per Ultraschallsensor eine Karte zu erstellen.&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;p&gt;Freitag 29.02.2013&lt;&#x2F;p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;Implementierung des Modells mit einer Software-Architektur&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Implementierung der kegelförmigen Ultraschallerfassung. &lt;strong&gt;(Milestone 4)&lt;&#x2F;strong&gt;&lt;&#x2F;li&gt;
&lt;li&gt;Ziel: Fertiges Modell, welches in der Lage ist, per Ultraschallsensor eine Karte zu erstellen&lt;&#x2F;li&gt;
&lt;li&gt;Dokumentation&lt;&#x2F;li&gt;
&lt;&#x2F;ul&gt;
&lt;h3 id=&quot;einfuhrung&quot;&gt;&lt;a name=&quot;Einf_252hrung&quot;&gt;&lt;&#x2F;a&gt;Einführung&lt;&#x2F;h3&gt;
&lt;p&gt;Ultraschall-Sensoren senden Schallwellen, die in ihrer Ausbreitung die Form eines Kegels bilden. Die gemessene Distanz enthält keine Informationen, wo innerhalb des Kegels ein Objekt lokalisiert ist. Für gewisse Anwendungen ist die Information über die Lage eines gefundenen Objektes jedoch gewünscht, zum Beispiel beim Kartografieren eines Geländes. Ein anderer Punkt betrifft die Kosten der Sensoren. Es könnte anstelle eines Ultraschall-Sensors auch ein Laser oder ein bildgebender Sensor eingesetzt werden, der die Lokalisierung deutlich vereinfacht. Durch den Einsatz eines günstigen Ultraschall-Sensors und die Entwicklung eines sinnvollen mathematischen Modells, wählt man die preisgünstigere Variante. Beide Aspekte sind beim vorliegenden Projekt der Flugdrohne von Bedeutung.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;aufgabenanalyse&quot;&gt;&lt;a name=&quot;Aufgabenanalyse&quot;&gt;&lt;&#x2F;a&gt;Aufgabenanalyse&lt;&#x2F;h3&gt;
&lt;p&gt;Im Zuge der Aufgabenanalyse sowie der Einarbeitung in die Entwicklungsumgebung und die gesamte Projektstruktur, soll die Aufgabe komplett verstanden und mögliche Lösungsansätze bereits skizziert werden. Innerhalb der Projektstruktur sollen die potenziell zu bearbeitenden Stellen herausgefunden werden. (siehe Milestone 0 und 1). Es soll analysiert werden, welche Informationen der Ultraschallsensor liefert und eine Strategie entwickelt werden, um das Problem der kegelförmigen Abtastung des Sensors zu lösen. Die Idee ist hierbei, über ein Zeitintervall hinweg die Wahrscheinlichkeiten für die Belegungen (Occupation) der Zellen zu ermitteln. Die Erfassungseigenschaften sollen in einem mathematischen Modell beschrieben und ein Algortithmus daraus abgeleitet werden. (Milestone 2) Die erfassten Wahrscheinlichkeitsdaten sollen in einer Gridmap persistiert werden, die als Grundlage der grafischen Ausgabe dient (siehe Milestone 3). Dieses Ultraschall-Modell soll innerhalb des RoboView-Projektes implementiert werden (siehe Milestone 4). Die Karten muss in OpenGL aufgebaut und mit den Sensordaten befüllt werden (siehe Milestone 5). Das gesamte Projekt wird zunächst auf Basis der zur Verfügung gestellten Software-Emulation entworfen und ausgeführt. Eine mögliche spätere Hardware-Emulation ist möglich aber nicht nötig.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;relevante-komponenten-des-roboview-frameworks&quot;&gt;&lt;a name=&quot;Relevante_Komponenten_des_RoboView_45Frameworks&quot;&gt;&lt;&#x2F;a&gt;Relevante Komponenten des RoboView-Frameworks&lt;&#x2F;h3&gt;
&lt;table border=&quot;1&quot;&gt;
	&lt;tbody&gt;
	&lt;tr&gt;
		&lt;th colspan=&quot;2&quot;&gt;Paket de.hska.lat.perception.observation&lt;&#x2F;th&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;DistanceObservation.java&lt;&#x2F;td&gt;
		&lt;td&gt;In dieser Klasse liegt die gesamte Logik der Implementierung. Die Methode distanceChanged() ​stellt den Event-Handler dar. Immer wenn der Sensor neue Daten liefert, wird diese Methode aufgerufen und die Logik ausgeführt.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;GridMap.java und GridMapHashTableImpl.java&lt;&#x2F;td&gt;
		&lt;td&gt;Die erste Klasse stellt das Interface, die zweite Klasse die Implementierung für die GridMap-Datenstruktur dar. (siehe unten)&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;Cell.java&lt;&#x2F;td&gt;
		&lt;td&gt;Objekte dieser Klasse repräsentieren einzelne Einträge in der GridMap.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;th colspan=&quot;2&quot;&gt;Paket de.hska.lat.robot.component.distanceSensor&lt;&#x2F;th&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;DistanceSensor.java&lt;&#x2F;td&gt;
		&lt;td&gt;Diese Klasse kapselt einen Sensor mit zugehörigen Informationen über die Position und Orientierung im Raum. Außerdem gibt der Sensor die Distanz zum gefundenen Objekt zurück.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;h3 id=&quot;mathematisches-modell-fur-die-erfassungseigenschaften-des-ultraschall-sensors&quot;&gt;&lt;a name=&quot;Mathematisches_Modell_f_252r_die_Erfassungseigenschaften_des_Ultraschall_45Sensors&quot;&gt;&lt;&#x2F;a&gt;Mathematisches Modell für die Erfassungseigenschaften des Ultraschall-Sensors&lt;&#x2F;h3&gt;
&lt;p&gt;Um die kegelförmigen Erfassungseigenschaften des Ultraschall-Sensors korrekt abzubilden, ist ein mathematisches Modell nötig. Dadurch wird garantiert, dass der Algorithmus zur Erfassung von Objekten im Raum, funktioniert. Im Folgenden sollen die Überlegungen zum Modell, die korrekte mathematische Formulierung und eine Skizze zum entworfenen Algorithmus widergegeben werden.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;idee&quot;&gt;&lt;a name=&quot;Idee&quot;&gt;&lt;&#x2F;a&gt;Idee&lt;&#x2F;h4&gt;
&lt;p&gt;Eine Drohne fliegt mit einer definierten Höhe über dem Boden. Der Ultraschall-Sensor sendet sein Signal in eine bestimmte Richtung, üblicherweise nach unten. Durch die vom Sensor zurück gegebene Distanz ist die Höhe des aktuell zu analysierenden Sensorkegels bekannt. Jeder Ultraschall-Sensor besitzt außerdem eine so genannte Beam-Width, die den Winkel zwischen der Kegel-Halbierenden und dem äußeren Rand (dem Mantel) des Kegels, beschreibt. Die Idee um herauszufinden, wo innerhalb des Kegels ein Objekt mit hoher Wahrscheinlichkeit zu finden ist, wird der gesamte Kegel stufenweise von der Spitze bis zur Bodenfläche abgetastet. Alle Vektoren die nicht in einer bestimmten Region nah der Grundfläche oder genau darauf liegen, korrespondieren mit Zellen die definitiv leer sind, in denen also keine Objekt gefunden werden können. Das liegt daran, dass die Distanz zum gefundenen Objekt länger ist, als er ausgesendete Vektor. Das ermöglicht es nicht nur besetzte Zellen in eine Datenstruktur einzutragen, sondern auch solche die definitiv unbesetzt sind. Solche Vektoren, die genau in der Region um die Grundfläche oder darauf liegen, liegen in einem Bereich der potentiell von einem Objekt besetzt wird. Um festzustellen, ob tatsächlich ein Objekt in einer Region liegt, müssen viele Messungen des Sensors ausgewertet werden und für alle Messungen eine Wahrscheinlichkeit berechnet werden, ob eine Region von einem Objekt besetzt ist. Diese Messungen werden in einer GridMap gespeichert (siehe nächster Abschnitt).&lt;&#x2F;p&gt;
&lt;h4 id=&quot;modell&quot;&gt;&lt;a name=&quot;Modell&quot;&gt;&lt;&#x2F;a&gt;Modell&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_kl.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_kl.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt; Grafik 0&lt;&#x2F;p&gt;
&lt;h5 id=&quot;bezeichnungen&quot;&gt;&lt;a name=&quot;Bezeichnungen&quot;&gt;&lt;&#x2F;a&gt;Bezeichnungen&lt;&#x2F;h5&gt;
&lt;table&gt;
	&lt;tbody&gt;
	&lt;tr&gt;
		&lt;td&gt;β&lt;&#x2F;td&gt;
		&lt;td&gt;Beamwinkel, β &gt; 0&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;α&lt;&#x2F;td&gt;
		&lt;td&gt;Orientierung des Sensors&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;U&lt;&#x2F;td&gt;
		&lt;td&gt;Position des Sensors im Raum&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;y&lt;&#x2F;td&gt;
		&lt;td&gt;Abstand des Sensors vom Boden&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;y&lt;sub&gt;t&lt;&#x2F;sub&gt;&lt;&#x2F;td&gt;
		&lt;td&gt;Distanz von Sensor bis letzte Zellebene&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;d&lt;&#x2F;td&gt;
		&lt;td&gt;Gemessene Distanz&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;r&lt;&#x2F;td&gt;
		&lt;td&gt;Zellbreite, r &gt; 0&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;φ&lt;&#x2F;td&gt;
		&lt;td&gt;Teilt Beamwinkel in gleiche Teile&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;V&lt;sub&gt;R&lt;&#x2F;sub&gt;&lt;&#x2F;td&gt;
		&lt;td&gt;(0, -1, 0)&lt;sup&gt;T&lt;&#x2F;sup&gt; Richtungsvektor von Sensor nach unten&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;V&lt;sub&gt;RRot&lt;&#x2F;sub&gt;&lt;&#x2F;td&gt;
		&lt;td&gt;Richtungsvektor V&lt;sub&gt;R&lt;&#x2F;sub&gt; um Orientierung des Sensors gedreht. Also V&lt;sub&gt;RRot&lt;&#x2F;sub&gt;= R * V&lt;sub&gt;R&lt;&#x2F;sub&gt;&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;R&lt;&#x2F;td&gt;
		&lt;td&gt;Rotationsmatrix für Rotation um Orientierung des Sensors&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;P[]&lt;&#x2F;td&gt;
		&lt;td&gt;Menge aller Vektoren, die zur Berechnung der Zellen benutzt werden. P[] = U + λ * R&lt;sub&gt;φ&lt;&#x2F;sub&gt; * V&lt;sub&gt;RRot&lt;&#x2F;sub&gt;, λ ∈ [0,d]&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;R&lt;sub&gt;φ&lt;&#x2F;sub&gt;&lt;&#x2F;td&gt;
		&lt;td&gt;Rotationsmatrix für schrittweise Rotation um die Abtastrate&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;h4 id=&quot;ablauf&quot;&gt;&lt;a name=&quot;Ablauf&quot;&gt;&lt;&#x2F;a&gt;Ablauf&lt;&#x2F;h4&gt;
&lt;p&gt;Um alle Zellen die in dem Kegel liegen, welcher von dem Sensor erfasst wird, zu bestimmen, wird zuersteinmal bestimmt welche Zellreihen überhaupt in dem Kegel liegen. Dazu wird zuerst die erste Zellreihe unterhalb des Sensors bestimmt, welche sich durch y-(y%r) errechnet. Dies erklärt sich dadurch, dass der Sensor ja theorethisch zwischen zwei Zellreihen liegen kann. Durch die Subtraktion von y%r wird also der Rest, welcher über der ersten Zellreihe unterhalb des Sensor steht, entfernt. Alle nachfolgenden Zellreihen sind nun immer ein vielfaches von r von der ersten Zellreihe entfernt, also y-(y%r)-r für die zweite Zellreihe unterhalb des Sensors, y-(y%r)-2r für die dritte Zellreihe unterhalb des Sensors, usw. Die letzte Zellreihe errechnet sich durch (y-y&lt;sub&gt;t&lt;&#x2F;sub&gt;)-((y-y&lt;sub&gt;t&lt;&#x2F;sub&gt;)%r). Dies erklärt sich dadurch, dass die letzte Zellreihe sich unterhalb oder auf der höhe befindet, welche mit d und y&lt;sub&gt;t&lt;&#x2F;sub&gt; ein rechtwinkliges Dreieck bildet. y&lt;sub&gt;t&lt;&#x2F;sub&gt; ist hierbei das Teilstück von y (siehe Grafik 1). Da nun alle Zellreihen bekannt sind kann dazu übergegangen werden die Zellen zu berechnen. Zellen können anhand von Punkten, welche in den Zellen liegen, leicht bestimmt werden (siehe Mapping von gemessenen Punkt-Daten auf Zellen in der GridMap). Wie an Grafik 1 zu sehen ist, werden vom Uhrsprungspunkt, also der Punkt im Raum an dem sich die Drohne befindet, Vektoren in Richtung der bekannten Zellreihen berechnet. Diese Vektoren bestimmen nun alle Punkte, die auf der jeweiligen Zellreihe und im Kegel liegen. Die einzelnen Vektoren werden wie folgt berechnet: Da V&lt;sub&gt;RRot&lt;&#x2F;sub&gt; bekannt ist und alle Vektoren die innerhalb des Kegels liegen zu V&lt;sub&gt;RRot&lt;&#x2F;sub&gt; den maximalen Winkel β haben (wäre der Winkel größer würde sich ja der Vektor ausserhalb des Beam-Winkelbereichs befinden), müssen logischerweise alle Vektoren die sich im Kegel befinden einen Winkel größer 0 und &amp;lt;= β zu V&lt;sub&gt;RRot&lt;&#x2F;sub&gt; haben. Dieser Winkel wird als vielfaches von φ bezeichnet. Es wird nun schrittweise der Winkel der einzelnen Vektoren mit folgender Formel berechnet: P[] = U + λ * R&lt;sub&gt;φ&lt;&#x2F;sub&gt; * V&lt;sub&gt;RRot&lt;&#x2F;sub&gt;. Hierbei ist R&lt;sub&gt;φ&lt;&#x2F;sub&gt; die Matrix mit der V&lt;sub&gt;RRot&lt;&#x2F;sub&gt; rotiert wird, so dass der neue Vektor den entsprechenden Winkel zu V&lt;sub&gt;RRot&lt;&#x2F;sub&gt; hat. λ ist die länge des Vektors, welche sich leicht errechnen lässt, da ja die Zellreihe und somit auch die Höhe bekannt ist.&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_vektoren_kl.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_vektoren_kl.png&quot; alt=&quot;skizze_vektoren_kl.png&quot; &#x2F;&gt;&lt;&#x2F;a&gt; Grafik 1&lt;&#x2F;p&gt;
&lt;p&gt;Da der Winkel im dreidimensionalen Raum errechnet werden muss, tritt noch ein weiteres Problem auf, welches sich aber leicht beheben lässt. Grafik 2 zeigt einen Schnitt des Kegels. Bei der Berechnung des Winkels wird die Rotation um die x- und z-Achse durchlaufen. Hierbei kann es passieren, dass Rotationen entstehen wodurch der resultierende Vektor nicht mehr im Kegel liegen würde. Durch eine einfache Kreisberechnung kann bestimmt werden ob der entstehende Vektor im Kegel liegen würde. Der Radius des Kreises ist hierbei der Beam Winkel β und die x- und z-Rotationen erstrecken sich von -β bis +β, da von der Achse des Kegels aus in alle Richtungen rotiert werden muss. Durch die allgemeine Formel x² + y² = r² kann bestimmt werden ob ein Punkt mit Koordinaten x und y im Kreis liegt, wobei r der Radius des Kreises ist. die x- bzw. y-Koordinaten sind in diesem Fall die Winkel der Rotationen um die x- bzw. z-Achse. Der Radius ist gleich dem Beam Winkel β. Ein Vektor liegt also im Kegel wenn gilt: (x-Roatation)² + (z-Roatation)² &amp;lt;= β². Ohne diese Berechnung würde durch die Vektoren kein Kegel sondern eine Pyramide beschrieben werden.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;circle.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;circle.png&quot; alt=&quot;circle.png&quot; title=&quot;circle.png&quot; &#x2F;&gt;&lt;&#x2F;a&gt;Grafik 2&lt;&#x2F;p&gt;
&lt;p&gt;Schlussendlich kann es noch passieren, dass die berechneten Vektoren über die Grenzen des Kegels hinaus &quot;schießen&quot; (siehe Grafik 3). Dies stellt jedoch keine weiteren Probleme dar, da ja bekannt ist, dass die Länge eines jeden Vektors nicht länger als d sein darf, da der Abstand vom Sensor zum Boden des Kegels immer gleich ist. Sollte also bei der berechnung eines Vektors die länge des Vektors länger sein als d, so wird die länge des Vektors einfach auf d gesetzt. Dadurch dass nun bekannt ist, dass der der Vektor übers die Grenzen des Kegels hinaus &quot;schießt&quot; und seine länge nun auf d begrenzt wurde, ist auch der Punkt in einer Zelle, in der sich möglicherweisse ein Objekt befindet. Hierdurch wurde nun bereits die Frage geklärt, wie man die Zellen bestimmt in denen sich möglicherweisse ein Objekt befinden könnte.&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_vektoren2_kl.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;skizze_vektoren2_kl.png&quot; alt=&quot;skizze_vektoren2_kl.png&quot; &#x2F;&gt;&lt;&#x2F;a&gt;Grafik 3&lt;&#x2F;p&gt;
&lt;h4 id=&quot;algorithmus-in-pseudocode&quot;&gt;&lt;a name=&quot;Algorithmus_in_Pseudocode&quot;&gt;&lt;&#x2F;a&gt;Algorithmus in Pseudocode&lt;&#x2F;h4&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;pseudocode.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;pseudocode.png&quot; alt=&quot;&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;h3 id=&quot;modellierung-der-datenstruktur-gridmap&quot;&gt;&lt;a name=&quot;Modellierung_der_Datenstruktur_45_GridMap&quot;&gt;&lt;&#x2F;a&gt;Modellierung der Datenstruktur - GridMap&lt;&#x2F;h3&gt;
&lt;h4 id=&quot;idee-1&quot;&gt;&lt;a name=&quot;Idee_AN1&quot;&gt;&lt;&#x2F;a&gt;Idee&lt;&#x2F;h4&gt;
&lt;p&gt;Eine GridMap ist eine Datenstruktur, die den dreidimensionalen Raum in einzelne Würfel unterteilt, die alle die Kantenlänge &lt;strong&gt;r&lt;&#x2F;strong&gt; besitzen. Neben einer x-, y- und z-Koordinate wird in jeder Zelle ein Wahrscheinlichkeitswert abgelegt, der darüber bestimmt ob ein Objekt oder auch nur ein Teil davon aus dem 3D-Raum innerhalb eines Würfels liegt. Die Würfel werden im folgenden als Zellen bezeichnet. Wenn der Ultraschallsensor ein Objekt lokalisiert hat, wird die korrespondierende Zelle aus der Gridmap ausgewählt und der Wahrscheinlichkeitswert dieser Zelle aktualisiert.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;interface&quot;&gt;&lt;a name=&quot;Interface&quot;&gt;&lt;&#x2F;a&gt;Interface&lt;&#x2F;h4&gt;
&lt;table&gt;
	&lt;tbody&gt;
	&lt;tr&gt;
		&lt;td&gt;setCellProbabilityByPoint(float x, float y, float z, boolean cellOccupied);&lt;&#x2F;td&gt;
		&lt;td&gt;Ändert den Wahrscheinlichkeitswert einer Zellen zu einem gegebenen Punkt.Wenn cellOccupied = false, ist die Zelle wahrscheinlich nicht mit einem Objekt belegt. Für cellOccupied = true dagegen sehr wahrscheinlich.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public int[] getCellCoordByPoint(float x, float y, float z);&lt;&#x2F;td&gt;
		&lt;td&gt;Ermittelt die Koordinaten einer Zelle zu einem gegebenen Punkt.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public float getCellProbability(int x, int y, int z);&lt;&#x2F;td&gt;
		&lt;td&gt;Ermittelt die Wahrscheinlichkeit einer Zelle zu einem gegebenen Punkt.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public LinkedList &lt;cell&gt;getAllCells();&lt;&#x2F;cell&gt;&lt;&#x2F;td&gt;
		&lt;td&gt;Gibt alle bisher in irgendeiner Art beeinflussten Zellen in einer Liste zurück.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public int[] getMaxBounds();&lt;&#x2F;td&gt;
		&lt;td&gt;Gibt die maximale Ausbreitung der GridMap zurück.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public int[] getMinBounds();&lt;&#x2F;td&gt;
		&lt;td&gt;Gibt die minimale Ausbreitung der GridMap zurück.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public float getCellSize();&lt;&#x2F;td&gt;
		&lt;td&gt;Gibt die Breite einer Zelle zurück.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;tr&gt;
		&lt;td&gt;public void clear();&lt;&#x2F;td&gt;
		&lt;td&gt;Setzt die GridMap auf Initial-Wert zurück. Jede Zelle hat die gleiche Initial-Wahrscheinlichkeit.&lt;&#x2F;td&gt;
	&lt;&#x2F;tr&gt;
	&lt;&#x2F;tbody&gt;
&lt;&#x2F;table&gt;
&lt;h3 id=&quot;implementierung-der-gridmap&quot;&gt;&lt;a name=&quot;Implementierung_der_GridMap&quot;&gt;&lt;&#x2F;a&gt;Implementierung der GridMap&lt;&#x2F;h3&gt;
&lt;p&gt;Die Implementierung der GridMap speichert die Zellgröße, die Anzahl der Zellen, sowie einen Initial-Wert für die Wahrscheinlichkeit jeder Zelle. Die Daten selbst werden in einer Hashmap&amp;lt;int[], Float&amp;gt; abgelegt. Das Integer-Array ist dreidimensional und repräsentiert die drei Koordinaten x, y und z der jeweiligen Zelle. Zu jedem Koordinaten-Tripel wird der Wahrscheinlichkeitswert als Float gespeichert. Wird die GridMap anfangs initialisiert, muss eine Zellgröße, die Initial-Wahrscheinlichkeit und eine Zellanzahl übergeben werden. Aus letzterem Wert wird die Größe der HashMap bestimmt.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hashmap&quot;&gt;&lt;a name=&quot;HashMap&quot;&gt;&lt;&#x2F;a&gt;HashMap&lt;&#x2F;h4&gt;
&lt;p&gt;Die der GridMap zurgunde liegende Datenstruktur ist eine HashMap. Diese wurde gezielt ausgewählt, da sie einen Zugriff von O(1) garantiert. Wenn die HashMap bei der Befüllungen einen Schwellwert überschreitet, wird sie durch die Laufzeitumgebung vergrößert und alles Hashes neu berechnet. Das erleichtert die Reorganisation erheblich. Zu Beginn der Implementierung war vorgesehen, die GridMap auf Basis einen dreidimensionalen Arrays zu erstellen. Bei Überläufen, insbesondere in den negativen Zahlenbereich, wären komplizierte Reorganisationen dieses Arrays zu tätigen, was durch die HashMap vom System selbst übernommen wird.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;hashing-verfahren&quot;&gt;&lt;a name=&quot;Hashing_45Verfahren&quot;&gt;&lt;&#x2F;a&gt;Hashing-Verfahren&lt;&#x2F;h4&gt;
&lt;p&gt;Um einen Wert in der GridMap abzulegen, wird der Hash-Wert über die (x,y,z)-Koordinaten der Zelle gebildet. Da Java die &lt;em&gt;hashcode()&lt;&#x2F;em&gt;-Methode für float-Arrays nicht selbstständig überschrieben hat, wählten wir die statische &lt;em&gt;hashcode(float[])&lt;&#x2F;em&gt;-Methode aus der Klasse &lt;em&gt;Arrays&lt;&#x2F;em&gt;.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;mapping-von-gemessenen-punkt-daten-auf-zellen-in-der-gridmap&quot;&gt;&lt;a name=&quot;Mapping_von_gemessenen_Punkt_45Daten_auf_Zellen_in_der_GridMap&quot;&gt;&lt;&#x2F;a&gt;Mapping von gemessenen Punkt-Daten auf Zellen in der GridMap&lt;&#x2F;h4&gt;
&lt;p&gt;Beim berechnen der Vektoren in dem Kegel des Sensors entstehen Punkte auf den Zellreihen. Diese Punkte liegen jeweils in genau einer Zelle. Im folgenden wird beschrieben wie zu einem Punkt im Raum die entsprechende Zelle errechnet wird. Die erste Zelle (also Zelle (0,0,0)) beginnt im Uhrsprung und erstreckt sich um die Zelllänge nach x, y und z. Alle weiteren Zellen bauen sich um die erste Zelle herrum auf. So beginnt die nächste Zelle in x-Richtung (also nach rechts) nach der ersten Zelle bei (r,0,0) (wobei r die Zelllänge ist), was bedeutet dass diese Zelle Zelle (1,0,0) ist. betrachtet man die Zelle in negativer x-Richtung von der ersten Zelle (also nach links) so beginnt diese bei (-r,0,0) und ist somit die Zelle (-1,0,0). Die Zelle links von Zelle (-1,0,0) beginnt bei (-2r,0,0) und ist somit die Zelle (-2,0,0). Das selbe Prinzip gilt auch für die y- und z-Achse. Die Zelle über der ersten Zelle beginnt bei (0,r,0) und ist somit Zelle (0,1,0). Die Zelle, welche räumlich vor der ersten Zelle liegt beginnt bei (0,0,r) und ist somit Zelle (0,0,1). Grafik 4 zeigt einen Teil einer GridMap und veranschaulicht das Prinzip.&lt;a href=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;grid.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2013&#x2F;03&#x2F;grid.png&quot; alt=&quot;grid.png&quot; title=&quot;grid.png&quot; &#x2F;&gt;&lt;&#x2F;a&gt;Grafik 4 Die Berechnung einer Zelle in Abhängigkeit von einem Gegebenen Punkt ist für positive x-, y- oder z-Werte nicht sehr kompliziert. Man berechnet hierfür erst einmal den Teil welcher &quot;übersteht&quot; und zieht diesen dann von den x-, y- und z-Werten des Punktes ab und teilt dann durch die Zelllänge, also: Seien x,y,z die Koordinaten des Punktes, welche alle &amp;gt;= 0 sind, r die Zelllänge und x&lt;sub&gt;z&lt;&#x2F;sub&gt;, y&lt;sub&gt;z&lt;&#x2F;sub&gt; und z&lt;sub&gt;z&lt;&#x2F;sub&gt; die Koordinaten der Zelle, dann gilt:&lt;&#x2F;p&gt;
&lt;p&gt;x&lt;sub&gt;z&lt;&#x2F;sub&gt; = (x-(x%r))&#x2F;r&lt;&#x2F;p&gt;
&lt;p&gt;y&lt;sub&gt;z&lt;&#x2F;sub&gt; = (y-(y%r))&#x2F;r&lt;&#x2F;p&gt;
&lt;p&gt;z&lt;sub&gt;z&lt;&#x2F;sub&gt; = (z-(z%r))&#x2F;r&lt;&#x2F;p&gt;
&lt;p&gt;Bei Punkten mit negativen x-, y- oder z-Werten funktioniert dieses Verfahren jedoch leider nicht. Angenommen man hätte eine Zelllänge von r = 10 und einen Punkt (-3,2,-1), so würde man die Zelle (-1,0,-1) erwarten. Das Ergebniss ist jedoch die Zelle (0,0,0). Das liegt daran, dass man bei negativen Werten &quot;abrunden&quot; und nicht &quot;aufrunden&quot; muss. Der Punkt (-3,2,-1) müsste also auf (-10,0,-10) fallen und somit die Zelle (-1,0,-1) ergeben. Für negative Werte eines Punktes gilt also folgendes: Seien x,y,z die Koordiaten des Punktes, welche alle &amp;lt; 0 sind, r die Zelllänge und x&lt;sub&gt;z&lt;&#x2F;sub&gt;, y&lt;sub&gt;z&lt;&#x2F;sub&gt; und z&lt;sub&gt;z&lt;&#x2F;sub&gt; die Koordinaten der Zelle, dann gilt:&lt;&#x2F;p&gt;
&lt;p&gt;x&lt;sub&gt;z&lt;&#x2F;sub&gt; = (x-(r+(x%r)))&#x2F;r , falls x%r &amp;lt; 0&lt;&#x2F;p&gt;
&lt;p&gt;x&lt;sub&gt;z&lt;&#x2F;sub&gt; = x&#x2F;r , falls x%r = 0&lt;&#x2F;p&gt;
&lt;p&gt;y&lt;sub&gt;z&lt;&#x2F;sub&gt; = (y-(r+(y%r)))&#x2F;r , falls y%r &amp;lt; 0&lt;&#x2F;p&gt;
&lt;p&gt;y&lt;sub&gt;z&lt;&#x2F;sub&gt; = y&#x2F;r , falls y%r = 0&lt;&#x2F;p&gt;
&lt;p&gt;z&lt;sub&gt;z&lt;&#x2F;sub&gt; = (z-(r+(z%r)))&#x2F;r , falls z%r &amp;lt; 0&lt;&#x2F;p&gt;
&lt;p&gt;z&lt;sub&gt;z&lt;&#x2F;sub&gt; = z&#x2F;r , falls z%r = 0&lt;&#x2F;p&gt;
&lt;h4 id=&quot;wahrscheinlichkeitswert-fur-eine-zelle-setzen&quot;&gt;&lt;a name=&quot;Wahrscheinlichkeitswert_f_252r_eine_Zelle_setzen&quot;&gt;&lt;&#x2F;a&gt;Wahrscheinlichkeitswert für eine Zelle setzen&lt;&#x2F;h4&gt;
&lt;p&gt;Um die Wahrscheinlichkeit einer Zelle zu setzen, muss zuerst die Zelle, die mit einem Punkt korrespondiert, mit dem obigen Verfahren bestimmt werden. Für diese Zelle wird die alte Wahrscheinlichkeit festgehalten. Wurde die Zelle bisher noch nicht tangiert, ist die A-Priori-Wahrscheinlichkeit gesetzt. In unserer Implementierung liegt diese bei 0.5. Mit der bool&#x27;schen Variable cellOccupied wird der Methode mitgeteilt, ob die betrachtete Zelle potentiell besetzt (true) oder unbesetzt (false) ist. Für den ersteren Fall wird die neue temporäre Wahrscheinlichkeit newProb für den aktuellen Zeitschritt berechnet aus (1.0 + oldProb) &#x2F; 2. Wenn die Zelle potentiell unbesetzt ist, wird die alte Wahrscheinlichkeit durch 2 geteilt und newProb zugewiesen ((0.0 + oldProb)&#x2F;2). Da die Formel, die die gesamte Wahrscheinlichkeit für eine Zelle bestimmt (siehe nächster Abschnitt) aus Brüchen besteht und in diesen durch Null geteilt werden könnte, wird für den Fall, dass die neue temporäre Wahrscheinlichkeit newProb Null wird, diese auf 0.001 gesetzt. Nun kann die im folgenden Abschnitt beschriebene Formel zur Berechnung der gesamten Wahrscheinlichkeit einer Zelle angewandt werden.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Neue Wahrscheinlichkeit = 1&#x2F;(1+((1-newProb)&#x2F;newProb) * (initProbability&#x2F;(1-initProbability))*((1-oldProb)&#x2F;oldProb)))&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Für viele Messungen, konvergiert diese Formel gegen 1, falls die Zelle mit einem Objekt besetzt ist und gegeben 0, falls sie unbesetzt ist. Es gibt alternative Formeln, die aber den Nachteil haben, dass die Wahrscheinlichkeit gegen einen Wert zwischen 0 und 1 konvergiert und man sich geeignete Schwellwerte überlegen muss, um zu bestimmen, ob eine Zelle besetzt oder unbesetzt ist.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;ausdehnung-der-gridmap&quot;&gt;&lt;a name=&quot;Ausdehnung_der_GridMap&quot;&gt;&lt;&#x2F;a&gt;Ausdehnung der GridMap&lt;&#x2F;h4&gt;
&lt;p&gt;Um die GridMap später zeichnen zu können, müssen die Dimensionen bekannt sein. Der GridMap liegt eine HashMap zu Grunde, die im Prinzip deutlich größer sein kann, als die belegten Werte. Beim Zeichnen will man aber nur den Bereich, der auch belegt ist, zeichnen. Für die Ermittlung des belegten Bereiches wurden die Methoden getMaxBounds() und getMinBounds() implementiert. Intern werden triviale Maximum- und Minimum-Suchen eingesetzt um die höchsten und niedrigsten x-, y- und z-Werte zu finden.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;gridmap-leeren&quot;&gt;&lt;a name=&quot;GridMap_leeren&quot;&gt;&lt;&#x2F;a&gt;GridMap leeren&lt;&#x2F;h4&gt;
&lt;p&gt;Für den Fall, dass eine GridMap komplett geleert werden soll, wurde die clear()-Methode implementiert. Die alte HashMap wird hierbei einfach durch eine neue Instanz ersetzt.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ausblick&quot;&gt;&lt;a name=&quot;Ausblick&quot;&gt;&lt;&#x2F;a&gt;Ausblick&lt;&#x2F;h3&gt;
&lt;p&gt;Durch diese Arbeit ist das mathematische Modell, sowie eine Implementierung des Modells gegeben. Folgende Arbeiten können an verschiedenen Punkten anknüpfen. Diese sollen nun erörtert werden.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;abtastrate&quot;&gt;&lt;a name=&quot;Abtastrate&quot;&gt;&lt;&#x2F;a&gt;Abtastrate&lt;&#x2F;h4&gt;
&lt;p&gt;Beim Abtasten der Kreisfläche des Kegels wird der doppelte Beam-Winkel in 1°-Schritten durchlaufen. Dadurch wird ein Quadrat mit Seitenlänge 2 * Beam-Winkel beschrieben. Mit der Abfrage der Kreisbedingung werden nur diejenigen Winkel-Konfigurationen beachtet, die sich tatsächlich in der Kreisfläche befinden. Bei dieser Vorgehensweise, werden die gleichen Zellen mehrmals von unterschiedlichen Punkten berührt und es muss festgehalten werden, welche Zellen schon betrachtet worden sind, damit nicht mehrmals die Wahrscheinlichkeit einer Zelle verändert wird. Hier könnte man sich eine dynamische Abtastrate für den Winkel Phi überlegen, der in jeder Zellebene die Kreisfläche durchläuft und dabei alle Kästchen genau einmal trifft. Hierfür wäre ein analytisches Verfahren notwendig. Da die Berechnung der Abtastung auf schnellen Rechnern abläuft, funktioniert die jetzige Implementierung ohne Probleme. Sollte es durch andere Konfigurationen Schwierigkeiten mit der Performanz geben, kann auch über eine stochastische Lösung der Abtastung nachgedacht werden. Die Idee wäre hierbei randomisiert Punkte innerhalb der Kreisfläche zu bestimmen. Durch die Statistik und die ständige Wiederholung des Verfahrens, würden alle Zellen im Schnitt abgedeckt sein und es wären weniger Berechnungen notwendig.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;grafische-implementierung&quot;&gt;&lt;a name=&quot;Grafische_Implementierung&quot;&gt;&lt;&#x2F;a&gt;Grafische Implementierung&lt;&#x2F;h4&gt;
&lt;p&gt;Da durch die vorliegende Implementierung eine Datenstruktur (GridMap) vorliegt, die die jeweiligen Wahrscheinlichkeitswerte für Objekte innerhalb der Zellen enthält, kann sie ohne größeren Aufwand durch Grafikbibliotheken, wie OpenGL, gezeichnet werden. Dadurch erhält man die Raumtopologie als Reliefdarstellung.&lt;&#x2F;p&gt;
&lt;h4 id=&quot;coverage-maps&quot;&gt;&lt;a name=&quot;Coverage_Maps&quot;&gt;&lt;&#x2F;a&gt;Coverage Maps&lt;&#x2F;h4&gt;
&lt;p&gt;In der vorliegenden Implementierung werden die Wahrscheinlichkeiten einer Belegung einer Zelle die Werte für 0 für nicht belegt, 0.5 für nicht beeinflusst und 1 für belegt annehmen. Damit kann eine Zelle komplett gemalt werden, sobald der Wert 1 darin enthalten ist. Diese Maps werden Occupancy Maps genannt und bilde eine binäre Struktur. Neben den Occupancy Maps gibt es aber auch solche Strukturen, die Teilbelegungen durch Objekte mit beachten. Wenn ein Teil eines Objektes eine Zelle nur zu 20% belegt, kann das in einer Struktur gespeichert werden, die sich Coverage Map nennt. Dadurch wird die Granularität der Reliefdarstellung erhöht und die Raumtopologie genauer beschrieben.&lt;&#x2F;p&gt;
&lt;h3 id=&quot;referenzen&quot;&gt;&lt;a name=&quot;Referenzen&quot;&gt;&lt;&#x2F;a&gt;Referenzen&lt;&#x2F;h3&gt;
&lt;p&gt;C. Stachniss: &lt;em&gt;Robotic Mapping and Exploration&lt;&#x2F;em&gt;, Springer-Verlag Berlin Heidelberg, 2009 Adam Milstein, University of Waterloo, Canada: &lt;em&gt;Occupancy Grid Maps for Localization and Mapping&lt;&#x2F;em&gt; (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;cdn.intechopen.com&#x2F;pdfs&#x2F;5368&#x2F;InTech-Occupancy_grid_maps_for_localization_and_mapping.pdf&quot;&gt;http:&#x2F;&#x2F;cdn.intechopen.com&#x2F;pdfs&#x2F;5368&#x2F;InTech-Occupancy_grid_maps_for_localization_and_mapping.pdf&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;C. Stachniss: Universität Freiburg, &lt;em&gt;Mapping and Exploration with Mobile Robots using Coverage Maps&lt;&#x2F;em&gt;: (&lt;a rel=&quot;external&quot; href=&quot;http:&#x2F;&#x2F;www.informatik.uni-freiburg.de&#x2F;~stachnis&#x2F;pdf&#x2F;stachniss03iros.pdf&quot;&gt;http:&#x2F;&#x2F;www.informatik.uni-freiburg.de&#x2F;~stachnis&#x2F;pdf&#x2F;stachniss03iros.pdf&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;h3 id=&quot;ressourcen&quot;&gt;&lt;a name=&quot;Ressourcen&quot;&gt;&lt;&#x2F;a&gt;Ressourcen&lt;&#x2F;h3&gt;
&lt;p&gt;RoboView-Framework&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Empire State Building in X3D</title>
          <pubDate>Sun, 18 Nov 2012 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/empire-state-bulding-x3d/</link>
          <guid>https://schempp.dev/blog/empire-state-bulding-x3d/</guid>
          <description xml:base="https://schempp.dev/blog/empire-state-bulding-x3d/">&lt;p&gt;Im Rahmen meines Computergrafik Labors musste ich mit meinem Kommilitonen ein 3D-Modell des Empire State Buildings modellieren. Das ganze war ein enormer Aufwand und ich möchte euch mein Modell nicht vorenthalten.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;data&#x2F;empirebuilding.x3d&quot; title=&quot;empirebuilding.x3d&quot;&gt;X3D-Datei&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;p&gt;Leider kann ich die Texturen nicht zur Verfügung stellen, da diese einem Copyright unterliegen.Ihr könnt euch die unteren beiden Ebenen aber selbst zusammen basteln.&lt;&#x2F;p&gt;
&lt;p&gt;Die unterste soll New York darstellen, die große Ebene darüber soll transparentes Wasser darstellen (der Effekt ist: New York steht unter Wasser und das Empire State Building ragt daraus empor). Wenn ihr eine Wasser Textur und eine &quot;New York&quot;-Textur findet könnt ihr das ganze so nachbauen.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>Facebook-Chat verschlüsseln (Miranda IM und OTR)</title>
          <pubDate>Sat, 28 Apr 2012 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/facebook-chat-verschlusseln-miranda-im-und-otr/</link>
          <guid>https://schempp.dev/blog/facebook-chat-verschlusseln-miranda-im-und-otr/</guid>
          <description xml:base="https://schempp.dev/blog/facebook-chat-verschlusseln-miranda-im-und-otr/">&lt;p&gt;Dieses Tutorial beschreibt, wie man mit Miranda IM und OTR (Off the Record) seinen Facebook-Chat verschlüsselt und sich dabei von dem Facebook-Chat im Browser unabhängig macht.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Was ist Miranda IM?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Zitat Wikipedia:&lt;&#x2F;p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Miranda IM&lt;&#x2F;strong&gt; (meist nur „Miranda“) ist ein &lt;a rel=&quot;external&quot; title=&quot;Freie Software&quot; href=&quot;http:&#x2F;&#x2F;de.wikipedia.org&#x2F;wiki&#x2F;Freie_Software&quot;&gt;freier&lt;&#x2F;a&gt;&lt;a rel=&quot;external&quot; title=&quot;Multi-Protokoll-Client&quot; href=&quot;http:&#x2F;&#x2F;de.wikipedia.org&#x2F;wiki&#x2F;Multi-Protokoll-Client&quot;&gt; Multi-Protokoll-Client&lt;&#x2F;a&gt; für &lt;a rel=&quot;external&quot; title=&quot;Microsoft Windows&quot; href=&quot;http:&#x2F;&#x2F;de.wikipedia.org&#x2F;wiki&#x2F;Microsoft_Windows&quot;&gt;Windows&lt;&#x2F;a&gt;.&lt;&#x2F;p&gt;
&lt;&#x2F;blockquote&gt;
&lt;p&gt;Ein Multi-Protokoll-Client ist eine Software, die es ermöglicht, mehrere Chat-Protokolle mit einem Programm zu benutzen (z.B. ICQ und Facebook).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Warum das ganze?&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Weil Facebook sämtlichen Chatverlauf mitlesen kann. Der Hauptgrund für mich war aber, dass ich eigentlich Facebook nur noch als Chat-Plattform verwenden wollte, weil mir Facebook selbst zu viel Zeit gestohlen hat.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Miranda einrichten&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 1: Miranda installieren&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Zuerst muss Miranda heruntergeladen und installiert werden. Die jeweils aktuelle Version gibt es hier: &lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;www.miranda-im.org&#x2F;download&#x2F;&quot; href=&quot;http:&#x2F;&#x2F;www.miranda-im.org&#x2F;download&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.miranda-im.org&#x2F;download&#x2F;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nachdem ihr die .exe-Datei heruntergeladen und ausgeführt habt, klickt einfach immer auf &quot;next &amp;gt;&quot;. Lasst bei &quot;Installation Mode&quot; die Auswahl auf &quot;Normal Install (recommendet)&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Sobald ihr dieses Fenster...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_1.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_1.png&quot; alt=&quot;&quot; title=&quot;Miranda 1&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;... vor euch habt, merkt euch den Pfad in dem Miranda installiert wird (in diesem Fall ist das &quot;E:\Program Files (x86)\Miranda IM&quot;). Der Pfad wird später benötigt um Plugins zu installieren.&lt;&#x2F;p&gt;
&lt;p&gt;Klickt nun auf &quot;Next &amp;gt;&quot; bis Miranda installiert wurde. Sollte Miranda nun starten, beendet es wieder (Rechtsklick auf das Miranda-Symbol in der Taskleiste =&amp;gt; Exit).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 2: Facebook Plugin installieren&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nun da Miranda installiert ist, muss noch das Plugin heruntergeladen werden.&lt;&#x2F;p&gt;
&lt;p&gt;Für 32-Bit Systeme (Für ältere Computer, Windows XP z.B.) gibt es das hier: &lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;id=4406&quot; href=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=4406&quot;&gt;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=4406&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Für 64-Bit Systeme (Für Computer ab c.a. 2002, also Windows 7) gibt es das hier: &lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;id=4407&quot; href=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=4407&quot;&gt;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=4407&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ladet die Datei herunter und entpackt die Ordner in den Pfad in dem Miranda installiert wurde (siehe Schritt 1).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 3: Off the Record installieren&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nun kommt der eigentlich wichtigste Teil. Wir installieren das Plugin, das es uns ermöglicht sämtlich Nachrichten zu verschlüsseln.&lt;&#x2F;p&gt;
&lt;p&gt;OTR gibt es hier: &lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;id=2644&quot; href=&quot;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=2644&quot;&gt;http:&#x2F;&#x2F;addons.miranda-im.org&#x2F;details.php?action=viewfile&amp;amp;id=2644&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Ladet die Datei herunter und entpackt sie in das euer Verzeichnis\Plugins. In meinem Fall wäre das &quot;E:\Program Files (x86)\Miranda IM\Plugins&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 4: Miranda starten und Facebook einrichten&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nun müssen wir nur noch unsere Daten von unserem Facebook Account in Miranda eintragen.&lt;&#x2F;p&gt;
&lt;p&gt;Miranda Starten =&amp;gt; Auf das Miranda Symbol oben links klicken =&amp;gt; Accounts auswählen =&amp;gt; auf das grüne Plus klicken =&amp;gt; Kontoname eingeben (z.b. &quot;Facebook&quot;) =&amp;gt;  Als Protokoll-Typ &quot;JABBER&quot; auswählen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_2.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_2.png&quot; alt=&quot;&quot; title=&quot;Miranda 2&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dann den eben erstellten Account auswählen und als Typ &quot;Facebook Chat&quot; auswählen, Benutzer und Passwort eintragen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_3.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_3.png&quot; alt=&quot;&quot; title=&quot;Miranda 3&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Der Benutzter ist der Nutzername in Facebook (siehe Bild)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_4.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_4.png&quot; alt=&quot;&quot; title=&quot;Miranda 5&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nach einem Klick auf &quot;Ok&quot; sollte in Miranda unten rechts nun der Facebook Account (Das Lämpchen) angezeigt werden (siehe Bild).&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_5.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_5.png&quot; alt=&quot;&quot; title=&quot;Miranda 6&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wenn ihr euren Nutzernamen gerade erst angelegt habt, kann es sein dass ein Fehler auftritt. Sollte dies der Fall sein: einfach später nochmal versuchen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Schritt 5: OTR benutzen&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wollt ihr nun OTR benutzen, braucht die Person mit der ihr schreibt ebenfalls OTR. Sobald ihr eine Konversation mit der anderen Person beginnt, wird die Verbindung verschlüsselt, was sich darin äussert, dass das Schloss (siehe Bild)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_6.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;04&#x2F;miranda_6.png&quot; alt=&quot;&quot; title=&quot;Miranda 7&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;nicht mehr das Rote durchgestrichene Schildchen hat.&lt;&#x2F;p&gt;
&lt;p&gt;Sollte ein Popup Fenster auftauchen dann bestätigt es mit &quot;Yes&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Zu Anfang kann es vorkommen, dass OTR nicht richtig funktioniert. Sollte dies der Fall sein, Miranda beenden und neu starten. Eventuell auch den Computer neu starten.&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>NextGEN Gallery: Thumbnails manuell erstellen</title>
          <pubDate>Wed, 22 Feb 2012 00:00:00 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/nextgen-gallery-thumbnails-manuell-erstellen/</link>
          <guid>https://schempp.dev/blog/nextgen-gallery-thumbnails-manuell-erstellen/</guid>
          <description xml:base="https://schempp.dev/blog/nextgen-gallery-thumbnails-manuell-erstellen/">&lt;p&gt;Bei Nutzung der NextGEN Gallery kann es vorkommen, dass manche oder gar alle Thumbnails nicht erstellt werden. Das folgende Tutorial erläutert wie dieser unangenehme Fehler (&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic9.png&quot; title=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic9.png&quot;&gt;Bild&lt;&#x2F;a&gt;) umgangen werden kann.&lt;&#x2F;p&gt;
&lt;p&gt;Benötigte Software:
Extreme Thumbnail Generator (&lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;www.exisoftware.com&#x2F;thumbnail_generator&#x2F;&quot; href=&quot;http:&#x2F;&#x2F;www.exisoftware.com&#x2F;thumbnail_generator&#x2F;&quot;&gt;download&lt;&#x2F;a&gt;)&lt;&#x2F;p&gt;
&lt;p&gt;Schritt 1:
Als erstes müssen die Bilder ganz normal auf den Server hochgeladen werden. Dann wird im Browser mit dem Pfad der Bilder eine neue Gallerie erstellt.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic8.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic8-300x164.png&quot; alt=&quot;&quot; title=&quot;pic8&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Schritt 2:&lt;&#x2F;p&gt;
&lt;p&gt;Nun werden, unglücklicherweise, mehrer Fehler auftreten.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic9.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic9-300x161.png&quot; alt=&quot;&quot; title=&quot;pic9&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Das bedeutet, dass keine Thumbnails erstellt wurden. Deswegen werden wir das nun selbst übernehmen.&lt;&#x2F;p&gt;
&lt;p&gt;Hier kommt der Extreme Thumbnail Generator ins Spiel.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic1.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic1-300x288.png&quot; alt=&quot;&quot; title=&quot;pic1&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Einfach alle Bilder per drag &amp;amp; drop in das Fenster ziehen, dannach auf &quot;Next&quot; klicken.&lt;&#x2F;p&gt;
&lt;p&gt;Auf der nächsten Seite am besten den Desktop als Zielpfad auswählen und auf &quot;Next&quot; klicken&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic2.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic2-300x287.png&quot; alt=&quot;&quot; title=&quot;pic2&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;auf der nächsten Seite werden die größe der Thumbs und andere Optionen eingestellt&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic3.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic3-300x289.png&quot; alt=&quot;&quot; title=&quot;pic3&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;nun auf &quot;Thumbnail image format klicken&quot;...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic4.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic4-300x288.png&quot; alt=&quot;&quot; title=&quot;pic4&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;... die Qualitätsstufe auf 100 stellen und &quot;OK&quot; klicken.&lt;&#x2F;p&gt;
&lt;p&gt;Jetzt auf &quot;Thumbnail file names&quot; klicken (WICHTIG!) ...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic5.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic5-300x288.png&quot; alt=&quot;&quot; title=&quot;pic5&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;... und wie in der Grafik gezeigt, den Beginn der Dateinamen der Thumbnails auf &quot;thumbs_&quot; setzen.
Das ist wichtig, das Wordpress die Thumbnails sonst nicht erkennt (ACHTUNG: die Dateiendungen müssen auch stimmen!).&lt;&#x2F;p&gt;
&lt;p&gt;Jetzt auf &quot;OK&quot; klicken und dannach auf &quot;Next&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Auf der letzten Seite...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic6.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic6-300x286.png&quot; alt=&quot;&quot; title=&quot;pic6&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;...auf &quot;Generate thumbnails only&quot; klicken, das Programm arbeiten lassen, fertig.&lt;&#x2F;p&gt;
&lt;p&gt;Schritt 3:
Zuguterletzt müssen die Thumbs (in dem Ordner &quot;thumns&quot;) noch auf den Server geladen werden...&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic10.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic10-300x181.png&quot; alt=&quot;&quot; title=&quot;pic10&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;... und zwar in den selben Ordner in dem auch die Bilder liegen für die die Thumbs erzeugt wurden.&lt;&#x2F;p&gt;
&lt;p&gt;Das Ergebniss:&lt;&#x2F;p&gt;
&lt;p&gt;Vor dem upload der Thumbs:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic11.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic11-300x187.png&quot; alt=&quot;&quot; title=&quot;pic11&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Nach dem upload der Thumbs:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic12.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2012&#x2F;02&#x2F;pic12-300x165.png&quot; alt=&quot;&quot; title=&quot;pic12&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
      <item>
          <title>How to google</title>
          <pubDate>Sun, 25 Dec 2011 01:02:52 +0000</pubDate>
          <author>Unknown</author>
          <link>https://schempp.dev/blog/how-to-google/</link>
          <guid>https://schempp.dev/blog/how-to-google/</guid>
          <description xml:base="https://schempp.dev/blog/how-to-google/">&lt;p&gt;Einige werden sich jetzt sicher fragen: warum dieser Artikel? Jeder weiss doch wie man googelt.&lt;&#x2F;p&gt;
&lt;p&gt;Leider ist dem nicht so, aber anstatt Leuten die nicht mit Google umgehen zu wissen zu helfen machen sich viele einen Spass mit diesen Menschen und leiten sie auf Seiten wie
&lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;www.lmgtfy.com&#x2F;&quot; href=&quot;http:&#x2F;&#x2F;www.lmgtfy.com&#x2F;&quot;&gt;http:&#x2F;&#x2F;www.lmgtfy.de&lt;&#x2F;a&gt; weiter.&lt;&#x2F;p&gt;
&lt;p&gt;Dieser Artikel richtet sich an all jene, die nicht wissen wie man mit Google umgeht bzw. immer viel zu wenig oder unzureichende Suchergebnisse bekommen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Keep it simple&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Es macht keinen Sinn lange Texte in das Suchfeld der Suchmaschine zu hämmern. Wörter wie &quot;der&quot;, &quot;es&quot; oder &quot;ein&quot; sind für das Suchergebnis in der Regel völlig irrelevant.&lt;&#x2F;p&gt;
&lt;p&gt;Man sollte sich bei der Suche auf das wesentliche beschränken. Stichworte sind für eine große Anzahl an Suchergebnissen am besten geeignet.&lt;&#x2F;p&gt;
&lt;p&gt;Im übrigen ignoriert Google sowieso Fragewörter wie &quot;wer&quot;, &quot;wie&quot; oder &quot;was&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;Die Kunst des richtigen Googelns ist, das was gesucht werden soll in so wenig wie möglichen Suchbegriffen zu beschreiben.&lt;&#x2F;p&gt;
&lt;p&gt;Außerdem können Suchergebnisse dadurch verfeinert werden, indem nicht nur deutsche Wörter benutzt werden, sondern auch englische. Wenn z.B. eine Suchanfrage mit ausschließlich deutschen Wörtern nicht zum gewünschten Ergebnis führt, könnte die selbe Suche in englischer Sprache wesentlich erfolgreicher sein.&lt;&#x2F;p&gt;
&lt;p&gt;Auch wenn es öfter den Anschein erweckt: Google ist &lt;strong&gt;nicht&lt;&#x2F;strong&gt; intelligent. Das einzige was Google macht ist, in Seiten nach den Wörtern zu suchen die vorgegeben werden. Google sucht nicht nach Synonymen. Wenn also nach &quot;Ritter Sport&quot; gesucht wird, sucht Google nicht nach &quot;Schokolade&quot;.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Sonderzeichen&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Die google-Suche bietet, neben der einfachen suche auch noch die Suche mit Sonderzeichen an, die da wären:&lt;&#x2F;p&gt;
&lt;p&gt;+, -, ~, . ., &quot; &quot;, *&lt;&#x2F;p&gt;
&lt;p&gt;Im folgenden wird nun die Funktionsweise der einzelnen Zeichen erläutert:&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Plus&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Durch das Plus vor einem Wort wird diese verstärkt gesucht, d.h. eine Suche wie &quot;Paris +Berlin&quot; wird Suchergebnisse bevorzugen die Berlin enthalten.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Minus&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Durch das Minus wird ein Wort vollständig ausgeschlossen. Dies ist vor allem dann sehr hilfreich wenn auf vielen Seiten zu dem gesuchten Begriff immer ein anderer unerwünschter auftaucht.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Synonym-Op&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Durch das ~ Zeichen ist es möglich nach Synonymen zu suchen.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Zwei Punkte&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Dieser Operator ist nur dann wichtig wenn man Zahlen in der Suchanfrage hat. Durch diesen Operator kann man einen Wert zwischen zwei Zahlen abfragen, z.B. 500 .. 1000. Google sucht dann nach einem Wert zwischen 500 und 1000.&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Anführungszeichen&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Die Anführungszeichen sind bei vielen Suchanfragen unverzichtbar. Soll nach einem Satz gesucht werden, so wird die Suche meist erschwert indem Google den Satz auseinander nimmt und nach den einzelnen Wörtern sucht. Durch die Anführungszeichen wird genau nach dem Satz zwischen den beiden Anführungszeichen gesucht.&lt;&#x2F;p&gt;
&lt;p&gt;Beispiel: &quot;Das ist ein Test&quot;&lt;&#x2F;p&gt;
&lt;p&gt;&lt;strong&gt;Stern&lt;&#x2F;strong&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Der Stern wird in Kombination mit den Anführungszeichen eingesetzt und steht für ein beliebiges Wort.&lt;&#x2F;p&gt;
&lt;p&gt;Beispiel: &quot;Das * ein Test&quot;&lt;&#x2F;p&gt;
&lt;p&gt;Neben diesen Sonderzeichen gibt es noch andere Möglichkeiten die Suche einzuschränken.&lt;&#x2F;p&gt;
&lt;p&gt;Beispielsweise kann mit &quot;site:de&quot; nur nach deutschen Seiten, also Webseiten die mit .de enden gesucht werden. Dies ist natürlich auch auf Seiten anwendbar die mit .com enden (site:com), sowie mit allen anderen Seiten.&lt;&#x2F;p&gt;
&lt;p&gt;Neben all diesen, für Anfänger etwas krpytisch wirkenden Befehlen, gibt es bei Google immer noch die &quot;Erweiterte Suche&quot; (siehe Bild)&lt;&#x2F;p&gt;
&lt;p&gt;&lt;a href=&quot;&#x2F;images&#x2F;2011&#x2F;12&#x2F;google.png&quot;&gt;&lt;img src=&quot;&#x2F;images&#x2F;2011&#x2F;12&#x2F;google-300x159.png&quot; alt=&quot;&quot; title=&quot;Google - Erweiterte Suche&quot; &#x2F;&gt;&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
&lt;p&gt;Wer sich intensiver mit der Suchmaschine von Google beschäftigen möchte:
&lt;a rel=&quot;external&quot; title=&quot;http:&#x2F;&#x2F;www.googleguide.com&#x2F;google_works.html&quot; href=&quot;http:&#x2F;&#x2F;www.googleguide.com&#x2F;google_works.html&quot;&gt;http:&#x2F;&#x2F;www.googleguide.com&#x2F;google_works.html&lt;&#x2F;a&gt;&lt;&#x2F;p&gt;
</description>
      </item>
    </channel>
</rss>
