<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Everything is broken: Technology</title>
  <subtitle>Posts tagged with Technology</subtitle>
  <id>https://holgerjust.de</id>
  <link href="https://holgerjust.de"/>
  <link href="https://holgerjust.de/tag/technology/feed.xml" rel="self"/>
  <updated>2017-02-19T01:00:00+01:00</updated>
  <author>
    <name>Holger Just</name>
  </author>
  <entry>
    <title>Effectively using __method__ and __callee__ in Ruby</title>
    <link rel="alternate" href="https://holgerjust.de/2017/effectively-using-method-and-callee-in-ruby/"/>
    <id>https://holgerjust.de/2017/effectively-using-method-and-callee-in-ruby/</id>
    <published>2017-02-19T01:00:00+01:00</published>
    <updated>2017-02-19T17:22:13+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Ruby provides many useful methods out of the box which allows for some very effective programming techniques. Today, we are taking a look at the &lt;a href="https://ruby-doc.org/core/Kernel.html#method-i-__method__"&gt;&lt;code&gt;__method__&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://ruby-doc.org/core/Kernel.html#method-i-__callee__"&gt;&lt;code&gt;__callee__&lt;/code&gt;&lt;/a&gt; helper methods and how they can help us produce &lt;a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt; code.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Ruby provides many useful methods out of the box which allows for some very effective programming techniques. Today, we are taking a look at the &lt;a href="https://ruby-doc.org/core/Kernel.html#method-i-__method__"&gt;&lt;code&gt;__method__&lt;/code&gt;&lt;/a&gt; and &lt;a href="https://ruby-doc.org/core/Kernel.html#method-i-__callee__"&gt;&lt;code&gt;__callee__&lt;/code&gt;&lt;/a&gt; helper methods and how they can help us produce &lt;a href="https://en.wikipedia.org/wiki/Don't_repeat_yourself"&gt;DRY&lt;/a&gt; code.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Generally, both methods return the name of the currently running method as a Symbol. Using these methods, we can access the current method name without requiring us to duplicate the name in our code.&lt;/p&gt;

&lt;p&gt;Now let&amp;rsquo;s have a look at them in action. Consider the following example where we create a &lt;code&gt;Greeter&lt;/code&gt; class which allows us to give personalized greetings:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greetings&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;__method__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="n"&gt;greeter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Ben'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;greetings&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Greetings, Ben!"&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, using the &lt;code&gt;__method__&lt;/code&gt; helper we don&amp;rsquo;t have to duplicate the name of the method in our code, thus keeping it DRY. In case we later decide to change the formality of the greeting and thus changing the method name, we wouldn&amp;rsquo;t also have to remember to change the method body to return the new greeting.&lt;/p&gt;

&lt;p&gt;This with working and our software starting to get popular all over the world, we might decide to introduce a more familiar way to greet people using different localizations. If we are in Australia, people might prefer to use&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Oi, Mick!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;while in Sweden, it might be more appropriate to use&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Hej, Anja!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The first approach to implement this could be to add multiple new independent methods, one for each greeting variant. However, this would quickly get out of hand and would effectively duplicate lots of code.&lt;/p&gt;

&lt;p&gt;Since we are already using &lt;code&gt;__method__&lt;/code&gt; in our implementation, we could try to leverage this and use aliases instead.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greetings&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;__method__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;
  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;hej&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Now, when calling one of the alias methods, it turns out that unfortunately (for our use-case) &lt;code&gt;__method__&lt;/code&gt; always returns the name of the actual method, completely ignoring the alias we used:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Mick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;oi&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Greetings, Mick!"&lt;/span&gt;

&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Anja'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hej&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Greetings, Anja!"&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Fortunately, there is a very similar helper method named &lt;code&gt;__callee__&lt;/code&gt; which helps us solve our use-case.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Greeter&lt;/span&gt;
  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;initialize&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="vi"&gt;@name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;name&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;greetings&lt;/span&gt;
    &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;__callee__&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;to_s&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;capitalize&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;, &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="vi"&gt;@name&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;!"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;oi&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;
  &lt;span class="k"&gt;alias&lt;/span&gt; &lt;span class="n"&gt;hej&lt;/span&gt; &lt;span class="n"&gt;greetings&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;

&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'friend'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;greetings&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Greetings, friend!"&lt;/span&gt;

&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Mick'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;oi&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Oi, Mick!"&lt;/span&gt;

&lt;span class="no"&gt;Greeter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'Anja'&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;hej&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "Hej, Anja!"&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Using the &lt;code&gt;__callee__&lt;/code&gt; helper, we can get the name of the current method exactly as it was called. For normal methods, this returns the same name as &lt;code&gt;__method__&lt;/code&gt;. Once we use methods aliases however, the returned value differs since &lt;code&gt;__callee__&lt;/code&gt; always returns the name of the method as we actually called it, whichever alias that might be.&lt;/p&gt;

&lt;p&gt;Since both helper methods are provided by Ruby&amp;rsquo;s &lt;a href="https://ruby-doc.org/core/Kernel.html"&gt;&lt;code&gt;Kernel&lt;/code&gt;&lt;/a&gt; module, they are directly available in about all Ruby objects. Using them, we can keep our code nice and DRY but still add new functionality with just one line of code without having to change any existing methods.&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2017&amp;#x2F;effectively-using-method-and-callee-in-ruby&amp;#x2F;"&gt;Effectively using __method__ and __callee__ in Ruby&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Detecting default arguments in Ruby</title>
    <link rel="alternate" href="https://holgerjust.de/2016/detecting-default-arguments-in-ruby/"/>
    <id>https://holgerjust.de/2016/detecting-default-arguments-in-ruby/</id>
    <published>2016-12-27T21:08:00+01:00</published>
    <updated>2017-12-06T20:26:01+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;When defining a method in Ruby, you can define default values for optional parameters. When calling the method, Ruby sets the default value to the local variable &lt;em&gt;as if&lt;/em&gt; the user would have provided this argument. This automatism is really useful to support optional parameters with sensible defaults without having to think much about this. It even works exactly the same with the new keyword arguments introduced in Ruby 2.0.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;When defining a method in Ruby, you can define default values for optional parameters. When calling the method, Ruby sets the default value to the local variable &lt;em&gt;as if&lt;/em&gt; the user would have provided this argument. This automatism is really useful to support optional parameters with sensible defaults without having to think much about this. It even works exactly the same with the new keyword arguments introduced in Ruby 2.0.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Given this method:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"required: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"optional: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;When calling the method, you get the usual results:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# require: foo&lt;/span&gt;
&lt;span class="c1"&gt;# optional: value&lt;/span&gt;

&lt;span class="n"&gt;debug&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'overwritten'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# require: bar&lt;/span&gt;
&lt;span class="c1"&gt;# optional: overwritten&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;A commonly used default value for optional parameters is &lt;code&gt;nil&lt;/code&gt;. You can however use any value you like, including the result of a method call. This works great most of the time. That is, well, until you really have to test if an argument was actually provided by the caller or not since any value (including &lt;code&gt;nil&lt;/code&gt;) would be considered valid.&lt;/p&gt;

&lt;p&gt;A real-world example of such a method is &lt;a href="https://ruby-doc.org/core/Hash.html#method-i-fetch"&gt;&lt;code&gt;Hash#fetch&lt;/code&gt;&lt;/a&gt;. This method allows to fetch the value for a given key from a Hash object. If the key is in the hash, its value is returned. If the key could not be found however, the method will either return a given default value or raise an error if no default value was provided. Since any Ruby object including &lt;code&gt;false&lt;/code&gt; or &lt;code&gt;nil&lt;/code&gt; are potentially valid default values, we can&amp;rsquo;t just define a static default value here:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="nb"&gt;hash&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="ss"&gt;foo: :bar&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; :bar&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:missing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; KeyError: key not found: :missing&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:missing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'my default value'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; "my default value"&lt;/span&gt;
&lt;span class="nb"&gt;hash&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="ss"&gt;:missing&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kp"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; nil&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Luckily, there are several idioms which allow to detect whether there was actually an argument passed to an optional parameter which I will describe below.&lt;/p&gt;

&lt;h2 id="a-special-flag-variable"&gt;A Special Flag Variable&lt;/h2&gt;

&lt;p&gt;The first and most self-contained option is to use a guard flag in the method definition.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;omitted&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kp"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"required: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"omitted: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;omitted&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;inspect&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;omitted&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'no optional given'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"optional: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Now when calling this method and actually passing a value to the &lt;code&gt;optional&lt;/code&gt; parameter, it will be set normally. The default part, i.e. &lt;code&gt;omitted = true&lt;/code&gt; will not be executed here. Instead, the &lt;code&gt;omitted&lt;/code&gt; paremeter will be initialized with &lt;code&gt;nil&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;On the other hand, when omitting the argument and calling the method as &lt;code&gt;with_flag(&amp;#39;value&amp;#39;)&lt;/code&gt;, the default part will be executed and &lt;code&gt;omitted&lt;/code&gt; as well as &lt;code&gt;optional&lt;/code&gt; will be set to &lt;code&gt;true&lt;/code&gt;. This allows to determine whether an argument was passed by checking the &lt;code&gt;omitted&lt;/code&gt; flag. If it is &lt;code&gt;nil&lt;/code&gt;, an argument was passed. If it is the final default value (&lt;code&gt;true&lt;/code&gt; in our example) it was however omitted:&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="n"&gt;with_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# required: foo&lt;/span&gt;
&lt;span class="c1"&gt;# omitted: true&lt;/span&gt;
&lt;span class="c1"&gt;# no optional given&lt;/span&gt;

&lt;span class="n"&gt;with_flag&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# required: foo&lt;/span&gt;
&lt;span class="c1"&gt;# omitted: nil&lt;/span&gt;
&lt;span class="c1"&gt;# optional: value&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;h2 id="special-default-value"&gt;Special Default Value&lt;/h2&gt;

&lt;p&gt;Another option is to use a different special default value which we have determined to never represent a valid value. Again, this is only required if we can not come up with a &amp;ldquo;normal&amp;rdquo; default value like &lt;code&gt;nil&lt;/code&gt;, &lt;code&gt;0&lt;/code&gt; or an empty array or hash.&lt;/p&gt;

&lt;p&gt;In our example, we define a constant called &lt;code&gt;UNDEFINED&lt;/code&gt; with an empty Object instance and use it as a default value. Since the object is not equal to any other value, you can use it as a special flag to determine that no value was passed and just compare the argument to the same &lt;code&gt;UNDEFINED&lt;/code&gt; object.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="no"&gt;UNDEFINED&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;Object&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;
&lt;span class="c1"&gt;# =&amp;gt; #&amp;lt;Object:0x007fd87284af38&amp;gt;&lt;/span&gt;

&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="no"&gt;UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"required: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;equal?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="no"&gt;UNDEFINED&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"no optional given: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"optional: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;optional&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;When calling the method, the comparisons work as expected. As you can see, the default value is initialized with the &lt;code&gt;UNDEFINED&lt;/code&gt; constant when not passing the optional argument and thus is considered to be omitted.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="n"&gt;with_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'bar'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# required: foo&lt;/span&gt;
&lt;span class="c1"&gt;# no optional given: #&amp;lt;Object:0x007fd87284af38&amp;gt;&lt;/span&gt;

&lt;span class="n"&gt;with_value&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'foo'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s1"&gt;'value'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="c1"&gt;# required: foo&lt;/span&gt;
&lt;span class="c1"&gt;# optional: value&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;h2 id="using-a-splatted-parameter"&gt;Using a Splatted Parameter&lt;/h2&gt;

&lt;p&gt;A third option is to use a splat parameter in the method&amp;rsquo;s definition. This accepts an unlimited number of optional arguments and provides them to the method body in an array.&lt;/p&gt;
&lt;div class="highlight ruby"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;with_splat&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="c1"&gt;# Enforce the actually intended method interface by raising an error if too&lt;/span&gt;
  &lt;span class="c1"&gt;# many arguments were passed to the method.&lt;/span&gt;
  &lt;span class="k"&gt;unless&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;cover?&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;raise&lt;/span&gt; &lt;span class="no"&gt;ArgumentError&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s2"&gt;"wrong number of arguments (&lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;length&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; for 1..2)"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;

  &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"required: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;size&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s1"&gt;'no optional given'&lt;/span&gt;
  &lt;span class="k"&gt;else&lt;/span&gt;
    &lt;span class="nb"&gt;puts&lt;/span&gt; &lt;span class="s2"&gt;"optional: &lt;/span&gt;&lt;span class="si"&gt;#{&lt;/span&gt;&lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
  &lt;span class="k"&gt;end&lt;/span&gt;
&lt;span class="k"&gt;end&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;By inspecting the &lt;code&gt;args&lt;/code&gt; array, we can test whether we got an &lt;code&gt;optional&lt;/code&gt; argument or not. If the array is has exactly 1 element, no &lt;code&gt;optional&lt;/code&gt; argument was passed. If it has 2 elements, we use the second one as our &lt;code&gt;optional&lt;/code&gt; value.&lt;/p&gt;

&lt;p&gt;This variant more or less resembles what Ruby itself does in its implementation of the &lt;a href="https://ruby-doc.org/core/Hash.html#method-i-fetch"&gt;&lt;code&gt;Hash#fetch&lt;/code&gt;&lt;/a&gt; method for example. Since the method is implemented in C, arguments are extracted and validated from the &lt;code&gt;ARGV&lt;/code&gt; array passed to the method which resembles our &lt;code&gt;args&lt;/code&gt; array.&lt;/p&gt;

&lt;h2 id="which-variant-to-use"&gt;Which variant to use?&lt;/h2&gt;

&lt;p&gt;Which option to use depends a bit on which traits of the code should be emphasized.&lt;/p&gt;

&lt;p&gt;The first option with the &lt;code&gt;omitted&lt;/code&gt; flag can read a bit nicer in the method body and does not require the permanent allocation of an additional object to represent the empty default value. However, the code and its detailed semantics can be a bit surprising for people not accustomed to this pattern. Which can result in people misusing the method.&lt;/p&gt;

&lt;p&gt;The second option with the special default value however is pretty clear and follows the common pattern of assigning a known default value to a parameter. By defining our own null value, we can elegantly work around the issue of &lt;code&gt;nil&lt;/code&gt; being a valid intended value. However, we always need to be aware of the special null value and often have to handle it in special way to e.g. pass it as &lt;code&gt;nil&lt;/code&gt; to other methods. Since this pattern should be used only if &lt;code&gt;nil&lt;/code&gt; itself is not a suitable default value, this would be required anyways though.&lt;/p&gt;

&lt;p&gt;The third option of using splat parameters looks rather simple from the outside and doesn&amp;rsquo;t rely on static values or the intricacies of argument assignments in Ruby. However, it has the huge downside that the method interface isn&amp;rsquo;t clearly defined anymore. Just from looking at the method definition, we can no longer see how many arguments the method accepts but have to look into the method body. We even have to rely on custom error handling to check the number of passed arguments.&lt;/p&gt;

&lt;p&gt;As such, for one-off methods, the first option is quicker to write and has clear-enough semantics to experienced Ruby developers. The second option provides a more traditional method interface for the potential cost of a bit more checking in the method body. With a well-named default value, the intention becomes clear just from looking at the method definition. The third option however does not resemble idiomatic Ruby anymore but looks more like C or Perl where we have to deal with numeric indexes instead of well-named variables and arguments. as such, this option has a clear disadvantage to the others since it is much less intention-revealing.&lt;/p&gt;

&lt;p&gt;With that in mind, which ever variant you use, try to use one of these methods consistently throughout your module to allow people reading your code to recognize the pattern and thus to reduce the cognitive load required to understand what the code does.&lt;/p&gt;

&lt;p&gt;Most of the time, you should try to rely on &amp;ldquo;normal&amp;rdquo; default values. Using one of the techniques described in this article should generally be your last resort since they will never be as clear as a simple method definition with simple default values.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;Update 2016-12-28: After some discussion on &lt;a href="https://www.facebook.com/holger.just.9/posts/1198815266853010"&gt;Facebook&lt;/a&gt; it became clear that the motivation for why you would need these techniques is not clearly described. As such, I have added the real-world example of &lt;code&gt;Hash#fetch&lt;/code&gt;. I also added the third option of using a splatted parameter.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2016&amp;#x2F;detecting-default-arguments-in-ruby&amp;#x2F;"&gt;Detecting default arguments in Ruby&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Speeding up Git at Planio</title>
    <link rel="alternate" href="https://holgerjust.de/2016/speeding-up-git-at-planio/"/>
    <id>https://holgerjust.de/2016/speeding-up-git-at-planio/</id>
    <published>2016-02-05T01:00:00+01:00</published>
    <updated>2018-06-13T14:28:29+02:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;This is a story about how a significant increase in the number of Git repositories at Planio resulted in a noticeable service slowdown and how we were able to not only fix this but to provide a sustained speedup of the whole service.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;This is a story about how a significant increase in the number of Git repositories at Planio resulted in a noticeable service slowdown and how we were able to not only fix this but to provide a sustained speedup of the whole service.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;img alt="From sad server to happy server" width="500" height="297" src="/images/2016/speeding-up-git-at-planio/planio_speeding-up-git-at-planio-27648a36.jpg" /&gt;&lt;/p&gt;

&lt;p&gt;At &lt;a href="https://plan.io"&gt;Planio&lt;/a&gt;, we have always provided &lt;a href="https://plan.io/subversion-hosting-and-git-hosting/"&gt;unlimited Git repositories&lt;/a&gt; as part of our &lt;a href="https://www.redmine.org"&gt;Redmine&lt;/a&gt; hosting product. In fact, one of the &lt;a href="https://github.com/planio/redmine-gitosis"&gt;first open source plugins&lt;/a&gt; to provide full Git hosting integration to Redmine was developed by Planio and subsequently formed the basis of most of the currently popular plugins.&lt;/p&gt;

&lt;p&gt;About 6 years later, our internal codebase has changed significantly due to increased customer demand but the basic architecture of our Git service was still the same. At Planio, access to Git is provided over SSH where permissions are enforced by our internal fork of &lt;a href="https://github.com/res0nat0r/gitosis"&gt;Gitosis&lt;/a&gt;. It has served us well in the past and while the project is not maintained by its original authors anymore, we still use our own patched version due to its small footprint and its general absence of features we don&amp;rsquo;t need anyway.&lt;/p&gt;

&lt;p&gt;With Gitosis, access to repositories is provided based on a single configuration file which lists the access permissions of all users and their repositories. It also handles the management of SSH keys which are concatenated to a single &lt;code&gt;authorized_keys&lt;/code&gt; file for the SSH server. Each time, someone created or deleted a repository on Planio or when someone uploaded a new SSH key, we start a background job to synchronize the Gitosis configuration file with the new data.&lt;/p&gt;

&lt;p&gt;Unfortunately, it all broke down once we started to create new Git repositories for all new Planio accounts by default to make it easier to use Planio with the awesome &lt;a href="http://plan.io/blog/post/136664403343/a-data-safe-dropbox-alternative-git"&gt;Sparkleshare synchronisation tool&lt;/a&gt;. Before this change, only users who explicitly wanted to use a Git repositoriy created one in their account, resulting in a &amp;ldquo;manageable&amp;rdquo; number of repositories overall. With this change however, we now had almost doubled the number of configured Git repositories in a couple of weeks&amp;rsquo; time.&lt;/p&gt;

&lt;p&gt;Unfortunately, this resulted in a serious slowdown for many Git users while our backend servers where peaking at a &lt;a href="https://en.wikipedia.org/wiki/Load_(computing)"&gt;system load&lt;/a&gt; of 120 with most of the time spent in Gitosis before any actual Git interaction. Not good, not good at all&amp;hellip;&lt;/p&gt;

&lt;p&gt;&lt;img alt="A concerned cat" width="400" height="250" src="/images/2016/speeding-up-git-at-planio/concerned_cat-5f9c1b4d.gif" /&gt;&lt;/p&gt;

&lt;p&gt;Digging into the code, I quickly identified the &lt;a href="https://github.com/res0nat0r/gitosis/blob/b04fbb1df75c7f1f3f6bb4b4b37565f4a2ede54d/gitosis/group.py#L4-L37"&gt;lookup method&lt;/a&gt; in Gitosis which determines which repositories a user has access to as the main culprit. It turned out that the method loops over the whole list of repositories multiple times, resulting in a algorithmic complexity of O(2n&lt;sup&gt;2&lt;/sup&gt;) in our case. As we have about doubled the number of configured repositories, the lookup now took four times as long for each single Git operation. With only limited CPU power available, the processes began stepping on each others toes waiting for CPU time on their own. And as we were constantly adding new Git repositories, this problem only worsened over time.&lt;/p&gt;

&lt;p&gt;The solution to this problem came with inspiration from some old &lt;a href="https://github.com/chiliproject/chiliproject/pull/229"&gt;pull request&lt;/a&gt; I started on the now defunct ChiliProject which was intended to unify the authentication and authorization implementations of external services like Subversion. If we can provide a simple API in Redmine which can quickly tell us if a certain user has the permission to read or write a repository, we can use this in Gitosis with a single HTTP call per Git operation.&lt;/p&gt;

&lt;p&gt;Fortunately, we already used sane conventions to name repositories and users in the form of uniquely named SSH keys in Gitosis. This allows us to efficiently determine the affected Redmine user and project for each Git operation. As we have all the code to check for arbitrary permissions already in place in Redmine, all the new API endpoint has to do is to identify the correct user and check their permission in the respective project. This is a very common and quite optimized task in Redmine - even more so when utilizing the builtin Rails cache to improve response times for repeated authorization requests.&lt;/p&gt;

&lt;p&gt;On Gitosis&amp;rsquo; side, I was able to almost completely replace the existing authentication mechanism with a single HTTP call to Redmine and just checking the response. Besides being overall much faster, it also reduces latency during repository creation as users don&amp;rsquo;t have to wait anymore until the Gitosis config file was updated. But the best result? With this change, I was able to remove about half of the overall codebase in Gitosis. Seeing this at the end of a code review warms every developer&amp;rsquo;s heart. No code is better than &lt;em&gt;no&lt;/em&gt; code.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;code&gt;30 files changed, 283 insertions(+), 1924 deletions(-)&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Developing the API in Redmine and integrating it into Gitosis took me about 3 days. This included extensive correctness and performance tests to ensure that we do in fact enforce the defined permissions and can do this fast. In the end, we are now able to respond to an authorization request in about 300 ms end-to-end which is about 20 times faster than we were able to pull off during peak usage last week with the old authentication mechanism.&lt;/p&gt;

&lt;style&gt;
blockquote.twitter-tweet {
  overflow: hidden;
  color: #1c2022;
  background-color: #fff;
  border: 1px solid #e1e8ed;
  border-radius: 4px;
  width: 500px;
  max-width: 100%;
  min-width: 220px;
  padding: 1.25rem 1.25rem 0.725rem 1.25rem;
  margin: 10px auto;
}
blockquote.twitter-tweet:before {
  content: none;
}
blockquote.twitter-tweet p {
  white-space: pre-wrap;
  font: 16px/1.4 Helvetica, Roboto, 'Segoe UI', Calibri, sans-serif;
}
blockquote.twitter-tweet a {
  color: #2b7bb9;
}
blockquote.twitter-tweet a:visited {
  color: #2b7bb9;
}
&lt;/style&gt;

&lt;blockquote class="twitter-tweet"&gt;
  &lt;p lang="en" dir="ltr"&gt;The hard work on our Git hosting infrastructure pays off: Overall Git access is now 20x faster than last week! &lt;a href="https://t.co/fmM0b50DF5"&gt;https://plan.io/de/subversion-hosting-und-git-hosting/&lt;/a&gt;&lt;/p&gt;
  &amp;mdash; Planio (@planio) &lt;a href="https://twitter.com/planio/status/694548969096114177"&gt;February 2, 2016&lt;/a&gt;
&lt;/blockquote&gt;

&lt;p&gt;Directly after the deployment of the new authentication mechanism, the load of the backend servers dropped back from about 40 to just below 1, which is nice because we now get much less of these alarming monitoring pings about melting servers.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;This post originally appeared on &lt;a href="#"&gt;Planio&amp;rsquo;s blog&lt;/a&gt; on February 5, 2016.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2016&amp;#x2F;speeding-up-git-at-planio&amp;#x2F;"&gt;Speeding up Git at Planio&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>FrOSCon 2010: Redmine, und dann?</title>
    <link rel="alternate" href="https://holgerjust.de/2010/redmine-und-dann-auf-der-froscon-2010/"/>
    <id>https://holgerjust.de/2010/redmine-und-dann-auf-der-froscon-2010/</id>
    <published>2010-09-29T17:16:24+02:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Am 21. August 2010 war mal wieder &lt;a href="https://www.froscon.de"&gt;FrOSCon&lt;/a&gt; in St. Augustin (bei Bonn). Und ich war dabei, vor allem um einige Open Source Projekte näher kennen zu lernen, Leute zu treffen und vor allem, um dem Redmine-Vortrag von Felix Schäfer zu lauschen.&lt;/p&gt;

&lt;p&gt;Aus Gründen war der Felix leider verhindert, sodass ich mich spontan bereit erklärt habe, den Vortrag zu übernehmen. Damit hatte ich meinen ersten Talk auf einer Konferenz. Und mit nur ca. 3 Stunden Vorbereitung war der dann sogar ganz okay.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Am 21. August 2010 war mal wieder &lt;a href="https://www.froscon.de"&gt;FrOSCon&lt;/a&gt; in St. Augustin (bei Bonn). Und ich war dabei, vor allem um einige Open Source Projekte näher kennen zu lernen, Leute zu treffen und vor allem, um dem Redmine-Vortrag von Felix Schäfer zu lauschen.&lt;/p&gt;

&lt;p&gt;Aus Gründen war der Felix leider verhindert, sodass ich mich spontan bereit erklärt habe, den Vortrag zu übernehmen. Damit hatte ich meinen ersten Talk auf einer Konferenz. Und mit nur ca. 3 Stunden Vorbereitung war der dann sogar ganz okay.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Die Aufzeichnung des Vortrags ist jetzt bei &lt;a href="https://media.ccc.de/browse/conferences/froscon/2010/froscon10_-_563_-_de_-_redmine_und_dann_-_holger_just.html"&gt;CCC-TV&lt;/a&gt; online.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Redmine ist installiert, ein paar Projekte sind angelegt, und die Defaulteinstellungen scheinen gut zu klappen. Alles läuft gut, ein paar Kleinigkeiten scheinen allerdings noch zu fehlen, aber was? Redmine eignet sich nicht nur hervorragend zum Verwalten von “einfachen” Softwareprojekten, sondern dank der hohen Anpassbarkeit des System zu komplexeren oder gar nicht softwarebezogenen Projekten.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;figure class="center"&gt;&lt;iframe width="710" height="550" src="https://media.ccc.de/v/froscon10_-_563_-_de_-_redmine_und_dann_-_holger_just/oembed?width=700&amp;amps;height=525" frameborder="0" allowfullscreen&gt;&lt;/iframe&gt;&lt;figcaption&gt;Aufzeichnung &lt;a href="https://fronscon.de/"&gt;FrOSCon&lt;/a&gt; / &lt;a href="http://creativecommons.org/licenses/by-nc-sa/3.0/de/"&gt;cc-by-nc-sa&lt;/a&gt;&lt;/figcaption&gt;&lt;/figure&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2010&amp;#x2F;redmine-und-dann-auf-der-froscon-2010&amp;#x2F;"&gt;FrOSCon 2010: Redmine, und dann?&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Cross-browser CSS gradient</title>
    <link rel="alternate" href="https://holgerjust.de/2010/cross-browser-css-gradient/"/>
    <id>https://holgerjust.de/2010/cross-browser-css-gradient/</id>
    <published>2010-07-26T11:22:00+02:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Recently, I released a new version of the Redmine &lt;a href="https://github.com/meineerde/redmine_checkout"&gt;Checkout plugin&lt;/a&gt;. This release sports a nifty protocol selector with buttons styled entirely in CSS (as good as it gets). To be able to support as many browsers as possibly while not having to fall back to pixel graphics I had to apply some tricks which I want to describe here.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Recently, I released a new version of the Redmine &lt;a href="https://github.com/meineerde/redmine_checkout"&gt;Checkout plugin&lt;/a&gt;. This release sports a nifty protocol selector with buttons styled entirely in CSS (as good as it gets). To be able to support as many browsers as possibly while not having to fall back to pixel graphics I had to apply some tricks which I want to describe here.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;&lt;span class="left"&gt;&lt;img alt="Button with gradient" width="213" height="37" src="/images/2010/cross-browser-css-gradient/button_gradient-0dfdc24a.png"&gt;&lt;/span&gt;
The buttons take most of their appearance from a background gradient with a light color at the top and a darker color at the bottom. This gives them some kind of three-dimensional effect compared to the plain-colored background. We are going to style the unselected button on the right. The left selected button is styled equivalent with just some different colors.&lt;/p&gt;

&lt;p&gt;An unselected standard button is styled as follows:&lt;/p&gt;
&lt;div class="highlight css"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="nt"&gt;ul&lt;/span&gt;&lt;span class="nf"&gt;#checkout_protocols&lt;/span&gt; &lt;span class="nt"&gt;li&lt;/span&gt; &lt;span class="nt"&gt;a&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;background-color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;#eee&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="sx"&gt;url(button.svg)&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="nb"&gt;no-repeat&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c"&gt;/* Opera  needs an "image" :( - using svg for this so it will scale properly without looking too ugly */&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-khtml-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;#f8f8f8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt; &lt;span class="c"&gt;/* Konqueror */&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-webkit-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;linear&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nb"&gt;left&lt;/span&gt; &lt;span class="nb"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;#f8f8f8&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;to&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;   &lt;span class="c"&gt;/* Webkit (Chrome, Safari, ...) */&lt;/span&gt;
  &lt;span class="nl"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;-moz-linear-gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;top&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="m"&gt;#f8f8f8&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="m"&gt;#ddd&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* Gecko (Firefox, ...) */&lt;/span&gt;
  &lt;span class="nl"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;progid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DXImageTransform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startColorstr&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'#f8f8f8'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endColorstr&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'#dddddd'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* IE 5.5 - 7 */&lt;/span&gt;
  &lt;span class="nl"&gt;-ms-filter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;progid&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;DXImageTransform&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Microsoft&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gradient&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;startColorstr&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'#f8f8f8'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;endColorstr&lt;/span&gt;&lt;span class="err"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;'#dddddd'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c"&gt;/* IE 8 */&lt;/span&gt;
  &lt;span class="nl"&gt;position&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;relative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;As you can see, there are a multitude of rules which each target a specific browser. This is required as there is no standard defined on gradients yet. However every major browser supports a technique for this – just in its own syntax.&lt;/p&gt;

&lt;p&gt;The first rule on line 2 (and also line 3 as seen later) works as a default here. It is used in browsers which do not support one of the following rules. It forces a background color which does not look too bad and at least keeps the GUI element usable. Lines 3–8 each target a specific browser family to use a gradient instead of the simple background.&lt;/p&gt;

&lt;h2 id="khtml-konqueror-and-webkit-chrome-safari"&gt;KHTML (Konqueror) and Webkit (Chrome, Safari, &amp;hellip;)&lt;/h2&gt;

&lt;p&gt;Let&amp;rsquo;s start with line 4 and 5. These rules target KHTML browsers (like Konqueror) and the similar Webkit browsers (Chrome, Safari, &amp;hellip;) respectively. The rules are structured as follows (more information can be found in the &lt;a href="http://developer.apple.com/safari/library/documentation/internetweb/conceptual/safarivisualeffectsprogguide/Gradients/Gradients.html"&gt;Safari documentation&lt;/a&gt;).&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;linear&lt;/code&gt; — The gradient type. Can be one of &lt;em&gt;linear&lt;/em&gt; or &lt;em&gt;radial&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;left top&lt;/code&gt; — The starting point of the gradient. This is a X-Y coordinate.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;left bottom&lt;/code&gt; — The end point of the gradient. This is a X-Y coordinate.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;from(#f8f8f8)&lt;/code&gt; — The start color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;to(#ddd)&lt;/code&gt; — The end color.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="gecko-firefox-mozilla"&gt;Gecko (Firefox, Mozilla, &amp;hellip;)&lt;/h2&gt;

&lt;p&gt;Line 6 targets Gecko-based browsers like Firefox, Thunderbird or Mozilla. These define the gradient type inside the actual rule name. So &lt;code&gt;-moz-linear-gradient&lt;/code&gt; defines, well, a linear gradient while &lt;code&gt;-moz-radiant-gradient&lt;/code&gt; defines a radiant gradient. We obviously use &lt;code&gt;-moz-linear-gradient&lt;/code&gt; here.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;code&gt;top&lt;/code&gt; — Starting point of the gradient.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#f8f8f8&lt;/code&gt; — Start color.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;#ddd&lt;/code&gt; — End color.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2 id="internet-explorer"&gt;Internet Explorer&lt;/h2&gt;

&lt;p&gt;Line 7–9 focus on Internet Explorer. Here we use filters which are very old IE-only features, originally invented to allow DHTML animations. They are rather slow and show strange behavior sometimes, but it the only way to get gradients to IE. On the other hand, these even work on IE 5.5. The HTML element must have &lt;a href="http://www.satzansatz.de/cssd/onhavinglayout.html"&gt;layout&lt;/a&gt;. So we use &lt;code&gt;position: relative&lt;/code&gt; in line 9. If you omit this, it is showing some really strange renderings. The parameters of the filters should be rather self-explaining. As the filter syntax has slightly changed from IE7 to IE8 we include both variants here. Additional documentation is available from &lt;a href="http://msdn.microsoft.com/en-us/library/ms532997%28VS.85%29.aspx"&gt;Microsoft&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="opera"&gt;Opera&lt;/h2&gt;

&lt;p&gt;And finally there is Opera. This browser is targeted in line 3. Unfortunately Opera does not support the concept of a gradient out of the box, so we have to develop a fallback here. Fortunately though, it supports &lt;a href="http://en.wikipedia.org/wiki/Scalable_Vector_Graphics"&gt;SVG&lt;/a&gt; which allows us to define the gradient in an XML format to still benefit from the vector definition and not having to fallback to a pixel representation. As this is a fallback, it must be defined atop of the other rules which then overwrite this rule if one them is supported. If the SVG rule was put at the bottom, it would have a higher priority and all browsers would attempt to use it.&lt;/p&gt;

&lt;p&gt;This technique, however, allows us to even target browsers which do not match one of the explicitly supported browsers but do support SVG.&lt;/p&gt;

&lt;p&gt;The referenced SVG is rather simple:&lt;/p&gt;
&lt;div class="highlight xml"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="cp"&gt;&amp;lt;?xml version="1.0" standalone="no"?&amp;gt;&lt;/span&gt;
&lt;span class="cp"&gt;&amp;lt;!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;svg&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;version=&lt;/span&gt;&lt;span class="s"&gt;"1.1"&lt;/span&gt; &lt;span class="na"&gt;xmlns=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/2000/svg"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;defs&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;linearGradient&lt;/span&gt; &lt;span class="na"&gt;id=&lt;/span&gt;&lt;span class="s"&gt;"gradient"&lt;/span&gt; &lt;span class="na"&gt;x1=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;y1=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;stop&lt;/span&gt; &lt;span class="na"&gt;offset=&lt;/span&gt;&lt;span class="s"&gt;"0%"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"stop-color:#ddd; stop-opacity:1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;stop&lt;/span&gt; &lt;span class="na"&gt;offset=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"stop-color:#f8f8f8; stop-opacity:1"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/linearGradient&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/defs&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;rect&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;height=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt; &lt;span class="na"&gt;style=&lt;/span&gt;&lt;span class="s"&gt;"fill:url(#gradient)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/svg&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Note that the start color is defined on &lt;code&gt;offset=&amp;quot;100%&amp;quot;&lt;/code&gt; and the end color on &lt;code&gt;offset=&amp;quot;0%&amp;quot;&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2010&amp;#x2F;cross-browser-css-gradient&amp;#x2F;"&gt;Cross-browser CSS gradient&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>How to compile Postfix + SASL + LDAP on Opensolaris</title>
    <link rel="alternate" href="https://holgerjust.de/2010/howto-compile-postfix-sasl-ldap-opensolaris/"/>
    <id>https://holgerjust.de/2010/howto-compile-postfix-sasl-ldap-opensolaris/</id>
    <published>2010-06-14T20:44:00+02:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Currently, Opensolaris does &lt;a href="http://defect.opensolaris.org/bz/show_bug.cgi?id=6067"&gt;not provide&lt;/a&gt; a Postfix package. Although there exist packages on &lt;a href="http://www.blastwave.org/jir/pkgcontents.ftd?software=postfix&amp;amp;style=brief&amp;amp;state=5&amp;amp;arch=i386"&gt;blastwave&lt;/a&gt; and on &lt;a href="http://www.opencsw.org/packages/CSWpostfix/"&gt;OpenCSW&lt;/a&gt; they are either outdated or do not play well together.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="http://ihsan.dogan.ch"&gt;Ihsan Dogan&lt;/a&gt; did create a &lt;a href="http://ihsan.dogan.ch/postfix/"&gt;script&lt;/a&gt; to create Postfix packages from scratch as well as some precompiled packages. Unfortunately, these packages miss SASL support. So I was in need to compile these myself.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Currently, Opensolaris does &lt;a href="http://defect.opensolaris.org/bz/show_bug.cgi?id=6067"&gt;not provide&lt;/a&gt; a Postfix package. Although there exist packages on &lt;a href="http://www.blastwave.org/jir/pkgcontents.ftd?software=postfix&amp;amp;style=brief&amp;amp;state=5&amp;amp;arch=i386"&gt;blastwave&lt;/a&gt; and on &lt;a href="http://www.opencsw.org/packages/CSWpostfix/"&gt;OpenCSW&lt;/a&gt; they are either outdated or do not play well together.&lt;/p&gt;

&lt;p&gt;Fortunately, &lt;a href="http://ihsan.dogan.ch"&gt;Ihsan Dogan&lt;/a&gt; did create a &lt;a href="http://ihsan.dogan.ch/postfix/"&gt;script&lt;/a&gt; to create Postfix packages from scratch as well as some precompiled packages. Unfortunately, these packages miss SASL support. So I was in need to compile these myself.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;You will obviously need the Postfix sources and the package script:&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;wget http://de.postfix.org/ftpmirror/official/postfix-2.7.1.tar.gz
gunzip -c postfix-2.7.1.tar.gz | tar -xf -

wget http://ihsan.dogan.ch/postfix/downloads/makePostfixPkg.sh
chmod +x makePostfixPkg.sh

&lt;span class="nb"&gt;cd &lt;/span&gt;postfix-2.7.1
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Since Opensolaris b130, NIS+ was removed from the system. As Postfix does not know that, it will not compile as it defines a dependency to it. However, this can be disabled by simply applying the following patch:&lt;/p&gt;
&lt;div class="highlight diff"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="gd"&gt;--- src/util/sys_defs.h 2010-06-02 01:56:57.000000000 +0200
&lt;/span&gt;&lt;span class="gi"&gt;+++ src/util/sys_defs.h 2010-06-14 22:08:35.596113543 +0200
&lt;/span&gt;&lt;span class="gu"&gt;@@ -400,7 +400,6 @@
&lt;/span&gt; #define DEF_DB_TYPE  "dbm"
 #define ALIAS_DB_MAP "dbm:/etc/mail/aliases"
 #define HAS_NIS
-#define HAS_NISPLUS
 #define USE_SYS_SOCKIO_H   /* Solaris 2.5, changed sys/ioctl.h */
 #define GETTIMEOFDAY(t)  gettimeofday(t)
 #define ROOT_PATH  "/bin:/usr/bin:/sbin:/usr/sbin:/usr/ucb"
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Just put that patch into a file called &lt;code&gt;nisplus.patch&lt;/code&gt; and patch the code:&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;patch -p0 &amp;lt; nisplus.patch
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;&lt;em&gt;(found on &lt;a href="http://estseg.blogspot.com/2010/03/postfix-w-opensolaris-nis.html"&gt;estibi&amp;rsquo;s Solaris blog&lt;/a&gt;)&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Before actually compiling Postfix, we need some packages:&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# First install the sunstudio compilers and some additional&lt;/span&gt;
&lt;span class="c"&gt;# development tools&lt;/span&gt;
pkg install sunstudio12u1 object-file

&lt;span class="c"&gt;# ...and some additional libraries and tools&lt;/span&gt;
pkg install libsasl pcre
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Now we can generate the script compile and generate the SRV4 package. We will tell the compilers to include the default Cyrus SASL library for client authentication as well as the Dovecot library which I will use later to connect both servers and authenticate SMTP users.&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# Clean up first and after failed attempts&lt;/span&gt;
make tidy

&lt;span class="c"&gt;# Generate the makefile&lt;/span&gt;
make makefiles &lt;span class="nv"&gt;CCARGS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'-DUSE_TLS -DHAS_LDAP \
-DUSE_SASL_AUTH -DDEF_SERVER_SASL_TYPE=\"dovecot\" \
-DUSE_CYRUS_SASL -I/usr/include/sasl'&lt;/span&gt;
&lt;span class="nv"&gt;AUXLIBS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"-L/usr/lib -lsasl -lssl -lcrypto -lldap"&lt;/span&gt;
&lt;span class="nv"&gt;CC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/opt/sunstudio12.1/bin/cc

&lt;span class="c"&gt;# Build&lt;/span&gt;
make

&lt;span class="c"&gt;# Create the package if the build succeeded&lt;/span&gt;
../makePostfixPkg.sh
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;makePostfixPkg.sh&lt;/code&gt; script will create a Solaris package named something like &lt;code&gt;CNDpostfix-2.7.1,REV=100614-SunOS5.11-i386.pkg&lt;/code&gt; inside the Postfix directory. This package can then be installed like this:&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="c"&gt;# make sure you removed the default Sendmail package first if it installed&lt;/span&gt;
pkg uninstall sendmail

&lt;span class="c"&gt;# install the package&lt;/span&gt;
pkgadd -d CNDpostfix-2.7.1,REV&lt;span class="o"&gt;=&lt;/span&gt;100614-SunOS5.11-i386.pkg CNDpostfix

&lt;span class="c"&gt;# Configure the package to your needs. Then enable the service&lt;/span&gt;
svcadm &lt;span class="nb"&gt;enable &lt;/span&gt;svc:/network/postfix:default
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2010&amp;#x2F;howto-compile-postfix-sasl-ldap-opensolaris&amp;#x2F;"&gt;How to compile Postfix + SASL + LDAP on Opensolaris&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Sane Opensolaris Settings</title>
    <link rel="alternate" href="https://holgerjust.de/2010/sane-opensolaris-settings/"/>
    <id>https://holgerjust.de/2010/sane-opensolaris-settings/</id>
    <published>2010-02-05T13:46:00+01:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Opensolaris has done some huge steps towards being usable by a normal person. Sadly there are still some things lacking sane defaults which I try to provide here. I will try to update this post if I stumble over more of these hiccups.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Opensolaris has done some huge steps towards being usable by a normal person. Sadly there are still some things lacking sane defaults which I try to provide here. I will try to update this post if I stumble over more of these hiccups.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;h2 id="correct-colors-on-exit-of-an-ncurses-program"&gt;Correct colors on exit of an ncurses program&lt;/h2&gt;

&lt;p&gt;If an ncurses program (like &lt;code&gt;nano&lt;/code&gt;) exits, the default xterm-color does not properly restore the colors of the terminal. The background color is shown in a dark gray. For a quick relieve you can issue a short&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;tput rs1
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;As this is rather cumbersome, I think it is better to adjust out terminfo definitions.&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="nv"&gt;TERM&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;xterm-color infocmp &amp;gt; /tmp/xterm-color.src
sed -i -e &lt;span class="s1"&gt;'s/op=\\E\[100m,/op=\\E\[m,/'&lt;/span&gt; /tmp/xterm-color.src
pfexec tic -v /tmp/xterm-color.src
rm /tmp/xterm-color.src
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;The solution is from the &lt;a href="http://bugs.opensolaris.org/bugdatabase/view_bug.do?bug_id=6902588"&gt;Opensolaris Bug&lt;/a&gt;, the rough steps from &lt;a href="http://blogs.sun.com/peteh/entry/fixing_terminfo_so_that_terminal"&gt;Peter Harvey&lt;/a&gt;.&lt;/p&gt;

&lt;h2 id="fixing-some-key-bindings"&gt;Fixing some key bindings&lt;/h2&gt;

&lt;p&gt;By default some essential key bindings do not work properly. This can be fixed by just reassigning them. The following statement has to be run as root.&lt;/p&gt;
&lt;div class="highlight shell"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;cat &amp;gt;&amp;gt; /etc/profile &lt;span class="sh"&gt;&amp;lt;&amp;lt;BASH
# home key
bind '"\e[1~":beginning-of-line'
# del key
bind '"\e[3~":delete-char'
# end key
bind '"\e[4~":end-of-line'
# pgup key
bind '"\e[5~":history-search-forward'
# pgdn key
bind '"\e[6~":history-search-backward'
BASH
&lt;/span&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;You have to logout and login again for these settings to take effect. Alternatively you could just enter the individual &lt;code&gt;bind&lt;/code&gt; statements into your current terminal.&lt;/p&gt;

&lt;p&gt;The bindings are from &lt;a href="http://wiki.epiphanic.org/MiscOpenSolaris"&gt;Epiphanic Networks&amp;rsquo; Wikka&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2010&amp;#x2F;sane-opensolaris-settings&amp;#x2F;"&gt;Sane Opensolaris Settings&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Vertikales Ausrichten von LaTeX-Blöcken</title>
    <link rel="alternate" href="https://holgerjust.de/2008/vertikales-ausrichten-von-latex-bloecken/"/>
    <id>https://holgerjust.de/2008/vertikales-ausrichten-von-latex-bloecken/</id>
    <published>2008-01-13T23:46:00+01:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Der oder die Eine oder Andere wird vielleicht mal drauf stoßen, dass man in LaTeX-Tabellen die vertikale Ausrichtung von Elementen nicht direkt bestimmen kann. Das ist sehr ärgerlich, wenn man zum Beispiel Grafiken in einer Tabelle setzen will und sie vertikal zentriert in den Zellen ausrichten will.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Der oder die Eine oder Andere wird vielleicht mal drauf stoßen, dass man in LaTeX-Tabellen die vertikale Ausrichtung von Elementen nicht direkt bestimmen kann. Das ist sehr ärgerlich, wenn man zum Beispiel Grafiken in einer Tabelle setzen will und sie vertikal zentriert in den Zellen ausrichten will.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Hier hilft eine sogenannte Minipage. Das ist eine syntaktische Möglichkeit, eigene Boxen zu definieren, an denen man dann definieren kann, welche Ausrichtung ihre Inhalte gegenüber der Grundlinie haben. Das kann dann etwa so aussehen:&lt;/p&gt;
&lt;div class="highlight tex"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="nt"&gt;\begin{tabular}&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;c|c&lt;span class="p"&gt;}&lt;/span&gt;
  Links &lt;span class="p"&gt;&amp;amp;&lt;/span&gt; Rechts &lt;span class="k"&gt;\\&lt;/span&gt;
  &lt;span class="k"&gt;\hline&lt;/span&gt;
  &lt;span class="nt"&gt;\begin{minipage}&lt;/span&gt;[c]&lt;span class="p"&gt;{&lt;/span&gt;5cm&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;\begin{center}&lt;/span&gt;
      &lt;span class="k"&gt;\includegraphics&lt;/span&gt;&lt;span class="na"&gt;[width=4.5cm]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;img/klein&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;\end{center}&lt;/span&gt;
  &lt;span class="nt"&gt;\end{minipage}&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
  &lt;span class="nt"&gt;\begin{minipage}&lt;/span&gt;[c]&lt;span class="p"&gt;{&lt;/span&gt;5cm&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;\begin{center}&lt;/span&gt;
      &lt;span class="k"&gt;\includegraphics&lt;/span&gt;&lt;span class="na"&gt;[width=4.5cm]&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;img/sehr&lt;span class="p"&gt;_&lt;/span&gt;hoch&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="nt"&gt;\end{center}&lt;/span&gt;
  &lt;span class="nt"&gt;\end{minipage}&lt;/span&gt; &lt;span class="k"&gt;\\&lt;/span&gt;
&lt;span class="nt"&gt;\end{tabular}&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;

&lt;p&gt;Der interessante Teil ist das &lt;code&gt;c&lt;/code&gt; in eckigen Klammern nach &lt;code&gt;\begin{minipage}&lt;/code&gt;. Hier kann man die vertikale Ausrichtung als &lt;code&gt;t&lt;/code&gt;op, &lt;code&gt;c&lt;/code&gt;enter oder &lt;code&gt;b&lt;/code&gt;ottom angeben.&lt;/p&gt;

&lt;p&gt;Weitere Beispiele und eine genauere Beschreibung findet sich auch in &lt;a href="http://www.ctan.org/tex-archive/info/lshort/english/lshort.pdf"&gt;The Not so Short Introduction to LaTeX 2e&lt;/a&gt; im Kapiel 6.6.&lt;/p&gt;

&lt;h2 id="nachtrag"&gt;Nachtrag&lt;/h2&gt;

&lt;p&gt;Eine weitere (von mir jetzt nicht getestete) Möglichkeit, die auf dem &lt;a href="http://dante.ctan.org/CTAN/macros/latex/contrib/koma-script/"&gt;Koma-Script&lt;/a&gt;  basiert findet sich beim &lt;a href="http://www.komascript.de/node/718#comment-1710"&gt;KOMA-Script documentation project&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2008&amp;#x2F;vertikales-ausrichten-von-latex-bloecken&amp;#x2F;"&gt;Vertikales Ausrichten von LaTeX-Blöcken&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
  <entry>
    <title>Zeitsparen mit Word</title>
    <link rel="alternate" href="https://holgerjust.de/2008/zeitsparen-mit-word/"/>
    <id>https://holgerjust.de/2008/zeitsparen-mit-word/</id>
    <published>2008-01-12T14:17:00+01:00</published>
    <updated>2018-01-03T19:05:15+01:00</updated>
    <author>
      <name>Holger Just</name>
    </author>
    <summary type="html">&lt;p&gt;Es sind die kleinen Dinge, die einem viel Zeit sparen können. Bei Word geht es (zumindest, wenn man Vorlagen einsetzt) häufig darum, alle Felder mit z.B. Referenzen zu aktualisieren.&lt;/p&gt;

&lt;p&gt;</summary>
    <content type="html">&lt;p&gt;Es sind die kleinen Dinge, die einem viel Zeit sparen können. Bei Word geht es (zumindest, wenn man Vorlagen einsetzt) häufig darum, alle Felder mit z.B. Referenzen zu aktualisieren.&lt;/p&gt;

&lt;p&gt;&lt;/p&gt;

&lt;p&gt;Leider wird das von Microsoft nicht direkt ermöglicht. Es kann natürlich auch sein, dass ich es nur nicht gefunden habe.&lt;/p&gt;

&lt;p&gt;Solange man keine Felder in Kopf- und/oder Fußzeilen einsetzt reicht ja ein klassisches Strg+A gefolgt von F9, was sich aber nur auf den &amp;ldquo;normalen&amp;rdquo; Text auswirkt.&lt;/p&gt;

&lt;p&gt;Möchte man hingegen wirklich &lt;em&gt;alle&lt;/em&gt; Felder eines Dokuments aktualisieren, dann kann man das folgende einfache Makro hernehmen. Es ist getestet auf Word XP und 2003.&lt;/p&gt;
&lt;div class="highlight vb"&gt;&lt;table style="border-spacing: 0"&gt;&lt;tbody&gt;&lt;tr&gt;&lt;td class="gutter gl" style="text-align: right"&gt;&lt;pre class="lineno"&gt;1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17&lt;/pre&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre&gt;&lt;span class="k"&gt;Sub&lt;/span&gt; &lt;span class="nf"&gt;AlleFelderAktualisieren&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="c1"&gt;'  Update All Fields&lt;/span&gt;
    &lt;span class="k"&gt;Dim&lt;/span&gt; &lt;span class="nv"&gt;Part&lt;/span&gt; &lt;span class="ow"&gt;As&lt;/span&gt; &lt;span class="n"&gt;Range&lt;/span&gt;
    &lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="k"&gt;Each&lt;/span&gt; &lt;span class="n"&gt;Part&lt;/span&gt; &lt;span class="ow"&gt;In&lt;/span&gt; &lt;span class="n"&gt;ActiveDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;StoryRanges&lt;/span&gt;
        &lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;
        &lt;span class="k"&gt;While&lt;/span&gt; &lt;span class="k"&gt;Not&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextStoryRange&lt;/span&gt; &lt;span class="ow"&gt;Is&lt;/span&gt; &lt;span class="k"&gt;Nothing&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="k"&gt;Set&lt;/span&gt; &lt;span class="n"&gt;Part&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NextStoryRange&lt;/span&gt;
            &lt;span class="n"&gt;Part&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;
        &lt;span class="k"&gt;Wend&lt;/span&gt;
    &lt;span class="k"&gt;Next&lt;/span&gt;

    &lt;span class="c1"&gt;' Update Table of Contents&lt;/span&gt;
    &lt;span class="k"&gt;Dim&lt;/span&gt; &lt;span class="nv"&gt;TOC&lt;/span&gt; &lt;span class="ow"&gt;As&lt;/span&gt; &lt;span class="n"&gt;TableOfContents&lt;/span&gt;
    &lt;span class="k"&gt;For&lt;/span&gt; &lt;span class="k"&gt;Each&lt;/span&gt; &lt;span class="n"&gt;TOC&lt;/span&gt; &lt;span class="ow"&gt;In&lt;/span&gt; &lt;span class="n"&gt;ActiveDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TablesOfContents&lt;/span&gt;
        &lt;span class="n"&gt;TOC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Update&lt;/span&gt;
    &lt;span class="k"&gt;Next&lt;/span&gt;
&lt;span class="k"&gt;End&lt;/span&gt; &lt;span class="k"&gt;Sub&lt;/span&gt;
&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/tbody&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;p&gt;The post &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de&amp;#x2F;2008&amp;#x2F;zeitsparen-mit-word&amp;#x2F;"&gt;Zeitsparen mit Word&lt;/a&gt; appeared first on &lt;a href="https:&amp;#x2F;&amp;#x2F;holgerjust.de"&gt;holgerjust.de&lt;/a&gt;.&lt;/p&gt;</content>
  </entry>
</feed>
