<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title><![CDATA[pebra.net]]></title>
  <subtitle><![CDATA[Loving the web just like you]]></subtitle>
  <link href="/atom.xml" rel="self"/>
  <link href="http://pebra.net/"/>
  <updated>2018-12-05T17:03:42.000Z</updated>
  <id>http://pebra.net/</id>
  
  <author>
    <name><![CDATA[Pebra]]></name>
    
  </author>
  
  <generator uri="http://hexo.io/">Hexo</generator>
  
  <entry>
    <title><![CDATA[Useful commands when interacting with Apache Kafka from the command line]]></title>
    <link href="http://pebra.net/blog/2018/11/24/Useful-commands-when-interacting-with-Apache-Kafka-from-the-command-line/"/>
    <id>http://pebra.net/blog/2018/11/24/Useful-commands-when-interacting-with-Apache-Kafka-from-the-command-line/</id>
    <published>2018-11-24T15:50:49.000Z</published>
    <updated>2018-12-05T17:03:42.000Z</updated>
    <content type="html"><![CDATA[<p>When developing a new feature that involves <a href="https://kafka.apache.org" target="_blank" rel="noopener">Apache Kafka</a> I like to hook into a topic to check if everything is working as expected. Usually I do this with the Kafka command line tools but I always forget the exact command to run which I have to look from different sources.<br>This posts tries to put them together in order to have a single place to look them up.</p>
<p>If you are not familiar with Apache Kafka or want to learn about it, check out <a href="https://kafka.apache.org/" target="_blank" rel="noopener">their site!</a><br>To give you a rough idea, these are the three core features of Kafka:</p>
<blockquote cite="https://kafka.apache.org/intro" style="text-align: left;"><br><i>Publish and subscribe to streams of records, similar to a message queue or enterprise messaging system.</i><br><i>Store streams of records in a fault-tolerant durable way.</i><br><i>Process streams of records as they occur. </i><br><em style="font-size: 0.75em;">- <a href="https://kafka.apache.org/intro" target="_blank" rel="noopener">https://kafka.apache.org/intro</a></em><br></blockquote>

<p>In order to follow the example, you need to have the Kafka command line tools installed.<br>In <code>brew</code> you can do that by simply running <code>brew install kafka</code>.<br>If you don’t want to install via <code>brew</code> or are using linux, you can get kafka like this:<br><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">curl -OL http://ftp.fau.de/apache/kafka/2.1.0/kafka_2.11-2.1.0.tgz</span><br><span class="line">tar -xzf kafka_2.11-2.1.0.tgz</span><br><span class="line"><span class="built_in">cd</span> kafka_2.11-2.1.0/</span><br></pre></td></tr></table></figure></p>
<p>You find the cli commands in the <code>bin/</code> subdirectory.<br>All commands used assume that you are using the new-consumer api and that you added the kafka commands to your <code>PATH</code> or running them from the <code>bin/</code> directory from above.</p>
<h2 id="How_to_consume_messages_from_a_given_Kafka_Topic?">How to consume messages from a given Kafka Topic?</h2><h3 id="Start_to_consume_from_the_latest_offset">Start to consume from the latest offset</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">kafka-console-consumer --bootstrap-server &lt;one-of-your-brokers&gt; --topic &lt;topic-to-consume&gt;</span><br></pre></td></tr></table></figure>
<h3 id="Consume_from_the_beginning">Consume from the beginning</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kafka-console-consumer --bootstrap-server &lt;one-of-your-brokers&gt; \</span><br><span class="line">                       --topic &lt;topic-to-consume&gt; \</span><br><span class="line">                       --from-beginning</span><br></pre></td></tr></table></figure>
<h3 id="Consume_a_fixed_amount_of_messages">Consume a fixed amount of messages</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kafka-console-consumer --bootstrap-server &lt;one-of-your-brokers&gt; \</span><br><span class="line">                       --topic &lt;topic-to-consume&gt; \</span><br><span class="line">                       --max-messages &lt;number-of-messages&gt;</span><br></pre></td></tr></table></figure>
<h3 id="Consume_and_print_the_message_keys">Consume and print the message keys</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">kafka-console-consumer --bootstrap-server &lt;one-of-your-brokers&gt; \</span><br><span class="line">                       --topic &lt;topic-to-consume&gt; \</span><br><span class="line">                       --property print.key=<span class="literal">true</span> \</span><br><span class="line">                       --property key.separator=<span class="string">"---"</span></span><br></pre></td></tr></table></figure>
<p>This will print your messages in a format like <code>&lt;message-key&gt;---&lt;message-payload&gt;</code>.</p>
<h3 id="Consume_messages_encoded_in_Avro">Consume messages encoded in Avro</h3><p><strong>EDIT:</strong> The kafka-avro-console-consumer is not part of the package I linked above. It is part of the confluent suite. You can get it <a href="https://www.confluent.io/download/" target="_blank" rel="noopener">here</a>.<br>Another cool feature of Kafka is that it plays well with the <a href="http://avro.apache.org/docs/current/" target="_blank" rel="noopener">Apache Avro</a> format. To consume messages encoded in Avro simply run the following command to get the decoded messages.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">kafka-avro-console-consumer --bootstrap-server &lt;one-of-your-brokers&gt; \</span><br><span class="line">                            --topic &lt;topic-to-consume&gt; \</span><br><span class="line">                            --property schema.registry.url=http://&lt;your-schema-registry&gt;</span><br></pre></td></tr></table></figure>
<h3 id="Move_the_offset_of_a_specific_consumer_group_forward_by_consuming_messages">Move the offset of a specific consumer group forward by consuming messages</h3><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">kafka-console-consumer --bootstrap-server &lt;on-of-your-brokers&gt; \</span><br><span class="line">                       --topic &lt;topic-to-consume&gt; \</span><br><span class="line">                       --max-messages &lt;number-of-messages/moving the offset forward&gt; \</span><br><span class="line">                       --consumer-property group.id=&lt;consumer-group-to-forward-the-offset&gt; &gt; /dev/null</span><br></pre></td></tr></table></figure>
<p>I hope you can use this to speed up your work. If there are commands that you are frequently using that are not included here, let me know in the comments so I can add them.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>When developing a new feature that involves <a href="https://kafka.apache.org" target="_blank" rel="noopener">Apache Kafka</a> I like to ]]>
    </summary>
    
      <category term="apache" scheme="http://pebra.net/tags/apache/"/>
    
      <category term="kafka" scheme="http://pebra.net/tags/kafka/"/>
    
      <category term="avro" scheme="http://pebra.net/tags/avro/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Functional Programming by Example - Side Effects]]></title>
    <link href="http://pebra.net/blog/2016/03/20/fun-prog-3/"/>
    <id>http://pebra.net/blog/2016/03/20/fun-prog-3/</id>
    <published>2016-03-20T10:00:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>Long time no see! I want to continue my explorational series of functional programming with <strong>side effects</strong>.<br>After doing some research I came across <a href="https://www.youtube.com/watch?v=tQRtTSIpye4" target="_blank" rel="noopener">this excellent talk</a> by <a href="http://blog.jenkster.com/" target="_blank" rel="noopener">Kris Jenkins</a> about functional programming.</p>
<p>I my opinion he does an outstanding job in explaining the meaning of side effects and functional programming in general.<br>So instead of writing a long blog post, I leave you with this talk. Money quotes:</p>
<blockquote>
<p><em>Hidden inputs and outputs are called ‘side effects’</em></p>
<p><em>Functional Programming is eliminating &amp; controlling side effects</em></p>
<p>– <cite>Kris Jenkins</cite></p>
</blockquote>
<p>Let me know if things in this talk need clarification!</p>
<!-- First things first - side effects are almost unavoidable in every program that does something in the real world. -->
<!-- So what are side effects after all? -->
<!-- I recently watched [this excellent talk](https://www.youtube.com/watch?v=tQRtTSIpye4) by [Kris Jenkins](http://blog.jenkster.com/) about functional programming. -->
<!-- It gives the best clarification on the terms functional programming and side effects I've seen thus far. -->
<!-- You should definitely watch it. -->
<!-- ### Spot the Side Effect -->
<!-- In the realm of functional programming a function describes a realationship between its inputs and its outputs. -->
<!-- If you give it the same inputs, it will always produce the same outputs. This means that there should be no other dependencies of your function than its inputs. Lets look at this example. -->
<!-- ```ruby -->
<!-- module Moin do -->
<!--   def say_hello(name) do -->
<!--     IO.puts "Hello, #{name}!" -->
<!--   end -->
<!-- end -->
<!-- ``` -->
<!-- Nothing special here, your function takes a name as its input and then prints it to your shell or something like that. -->
<!-- But wait, by printing to the console you actually changed its*(stdout for example)* state! So your function is changing the state of an external resource, that's a side effect. -->
<!-- What about this example: -->
<!-- ```ruby -->
<!-- # example derived from Kris Jenkins' talk - credited in this post -->
<!-- module Foo do -->
<!--   def process_messages(n) do -->
<!--     count = InboxManager.process(n) -->
<!--     count >= 1 -->
<!--   end -->
<!-- end -->
<!-- ``` -->
<!-- Spotted the side effect? -->
<!-- Well there are actually two - one is that your output relies on the state of ```InboxManager``` the other one is that you eventually change its state when calling ```process(n)``` on it. -->
<!-- Therefore this function has one additional hidden input, the state of ```InboxManager``` when it comes in and a hidden output, the state of InboxManager after you called it. -->
<!-- No way you would see this when you didn't know the function body of ```process_messages```. -->
<!-- You can either read along this post or just watch [this excellent talk](https://www.youtube.com/watch?v=tQRtTSIpye4) by [Kris Jenkins](http://blog.jenkster.com/). -->
]]></content>
    <summary type="html">
    <![CDATA[<p>Long time no see! I want to continue my explorational series of functional programming with <strong>side effects</strong>.<br>After doing]]>
    </summary>
    
      <category term="functional programming" scheme="http://pebra.net/tags/functional-programming/"/>
    
      <category term="side effects" scheme="http://pebra.net/tags/side-effects/"/>
    
      <category term="Kris Jenkins" scheme="http://pebra.net/tags/Kris-Jenkins/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Functional Programming by Example - Higher Order Functions]]></title>
    <link href="http://pebra.net/blog/2015/12/25/fun-prog-2/"/>
    <id>http://pebra.net/blog/2015/12/25/fun-prog-2/</id>
    <published>2015-12-25T10:55:04.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>In my <a href="http://www.pebra.net/blog/2015/12/24/fun-prog-1/" target="_blank" rel="noopener">previous post</a> I tried to explain tail call optimization.<br>If you read it to the end you saw that <em>map</em> function that took a collection and a function as its arguments.<br>This already was a higher order function. The definition is straight forward:</p>
<blockquote>
<p><em>A higher order function takes a function as an argument or returns a function as its result, or both.</em></p>
</blockquote>
<p>So lets say you work in a big company and you have to calculate the bonuses for the employees. Of course, not everyone gets the same bonus, but you’re too lazy to pass the specific multiplier at every calculation. So you create seperate functions.<br>In this example the C-level department members get a bonus of 1.5 of their annual salary. While the salaries may differ, the multiplier stays the same.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">defmodule Salary <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">bonus_calculation</span><span class="params">(percentage)</span></span> <span class="keyword">do</span></span><br><span class="line">    fn(salary) -&gt; salary * percentage <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br><span class="line"></span><br><span class="line"><span class="comment"># c_level_bonuses = Salary.bonus_calculation(1.5)</span></span><br><span class="line"><span class="comment"># c_level_bonuses.(100_000)</span></span><br><span class="line"><span class="comment"># =&gt; 150000.0</span></span><br></pre></td></tr></table></figure>
<p>You may be wondering, why our <em>c_level_bonuses</em> function still knows about the percentage since we haven’t explicitly passed that value.<br>That’s because the function has knowledge about the environment it was created in - it’s a <a href="https://en.wikipedia.org/wiki/Closure_%28computer_programming%29" target="_blank" rel="noopener">closure</a>.</p>
<p>If you want to see an example for a function that takes another function as an argument, head to my <a href="http://www.pebra.net/blog/2015/12/24/fun-prog-1/#A_“real_world_example“_-_writing_your_own_map_function" target="_blank" rel="noopener">previous post</a> and take a look at the <em>map</em> function.</p>
<p>And in case you feel adventurous, try to find a use case to write a function that takes <em>and</em> returns a function =)</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>In my <a href="http://www.pebra.net/blog/2015/12/24/fun-prog-1/" target="_blank" rel="noopener">previous post</a> I tried to explain tail]]>
    </summary>
    
      <category term="elixir" scheme="http://pebra.net/tags/elixir/"/>
    
      <category term="functional" scheme="http://pebra.net/tags/functional/"/>
    
      <category term="programming" scheme="http://pebra.net/tags/programming/"/>
    
      <category term="higher order functions" scheme="http://pebra.net/tags/higher-order-functions/"/>
    
      <category term="learning" scheme="http://pebra.net/tags/learning/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Functional Programming by Example - Tail Call Optimization]]></title>
    <link href="http://pebra.net/blog/2015/12/24/fun-prog-1/"/>
    <id>http://pebra.net/blog/2015/12/24/fun-prog-1/</id>
    <published>2015-12-24T09:31:37.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>Since <a href="http://elixir-lang.org" target="_blank" rel="noopener">Elixir</a> came to my attention I really enjoy functional programming.<br>This series of posts aims to explain some of the terms used in functional programming contexts by using some straight forward and <em>(hopefully)</em> interesting examples.<br>The language of choice is, of course, Elixir<em>(could you have guessed? =))</em>.<br>If you are not familiar with Elixir, I hope you can still follow along, otherwise you might want to take a look at Elixir’s excellent <a href="http://elixir-lang.org/getting-started/introduction.html" target="_blank" rel="noopener">guides</a>.</p>
<h2 id="Recursion">Recursion</h2><p>When talking about tail call optimization it might be helpful to have a look at what happens when you call a function recursively.<br>Lets say we have the following function.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">defmodule Recur <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">multiply_forever</span><span class="params">(a)</span></span> <span class="keyword">do</span></span><br><span class="line">    b = <span class="number">5</span></span><br><span class="line">    b * multiply_forever(a)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>I you feel adventurous run this function and see what happens with your RAM usage<em>(spoiler: it will go up fast)</em>.</p>
<p>And that’s exactly what you expect to happen - a function calls itself forever, every time it uses some memory space for the stack to save what values <em>a</em> and <em>b</em> hold on each run.</p>
<h2 id="Tail_Call_Optimization">Tail Call Optimization</h2><p>Now we are using the same example, with a small modification.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">defmodule Recur <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">multiply_forever</span><span class="params">(a)</span></span> <span class="keyword">do</span></span><br><span class="line">    b = <span class="number">5</span></span><br><span class="line">    multiply_forever(a * b)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>Your RAM usage will not grow indefinitely.<br>Why?<br>Because the last thing we called in our function is just the function itself.</p>
<blockquote>
<p>A function is a subject to tail call optimization if the last thing it does is calling itself - <em>nothing</em> but itself.</p>
</blockquote>
<h3 id="How_does_it_work?">How does it work?</h3><p>In the first case the compiler may not know if he needs to keep those <em>a</em> and <em>b</em> values, so they have to be saved before every new function call.<br>This might be written down like this:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">call multiply_forever(a)</span><br><span class="line">save a,b</span><br><span class="line">call multiply_forever(a)</span><br><span class="line">    save a,b</span><br><span class="line">    call multiply_forever(a)</span><br><span class="line">        save a,b</span><br><span class="line">        call multiply_forever(a)</span><br><span class="line">            save a,b</span><br><span class="line">            call multiply_forever(a)</span><br><span class="line">            ...</span><br></pre></td></tr></table></figure>
<p>In contrary, in the second example, the compiler knows, that he only has to care about the new argument to <em>multiply_forever</em>.<br>So he just updates the argument and <em>JUMPS</em> back to when <em>multiply_forever</em> first got called.<br>That’s the difference  - <em>JUMP</em> vs. <em>CALL</em></p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">multiply_forever(a)</span><br><span class="line">jump back to multiply_forever, update what we know about a</span><br><span class="line">jump back to multiply_forever, update what we know about a</span><br><span class="line">jump back to multiply_forever, update what we know about a</span><br><span class="line">jump back to multiply_forever, update what we know about a</span><br><span class="line">...</span><br></pre></td></tr></table></figure>
<p>That’s basically what you have to know about tail call optimization<em>(imho)</em>.<br>The next section is just for the sake of a more interesting example, feel free to skip it, I hope this article was useful to you.</p>
<h2 id="A_“real_world_example“_-_writing_your_own_map_function">A “<em>real world example</em>“ - writing your own map function</h2><p>Lets say you want to write your own <em>Enum</em> module, it will need a <em>map</em> function. So we are going to write it.</p>
<p>First approach that is not suiting tail call optimization:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">defmodule MyEnum <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">map</span><span class="params">([], fun)</span></span> <span class="keyword">when</span> is_function(fun), <span class="symbol">do:</span> []</span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">map</span><span class="params">([head<span class="params">|tail], fun) <span class="keyword">do</span></span></span></span></span><br><span class="line"><span class="function"><span class="params"><span class="params">    [fun.(head) |</span> map(tail, fun)</span></span>]</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>Now the <em>“optimized”</em> version(<em>disclaimer: there are better ways to implement this for sure</em>):</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br></pre></td><td class="code"><pre><span class="line">defmodule MyEnum <span class="keyword">do</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">map</span><span class="params">(collection, fun)</span></span> <span class="keyword">when</span> is function(fun) <span class="keyword">and</span> is_list(collection) <span class="keyword">do</span></span><br><span class="line">    _map(collection, [], fun)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  defp _map([], acc, _fun), <span class="symbol">do:</span> Enum.reverse(acc) <span class="comment"># yeah it's cheating to use Enum here</span></span><br><span class="line">  defp _map([head<span class="params">|tail], acc, fun) <span class="keyword">do</span></span></span><br><span class="line"><span class="params">    _map(tail, [fun.(head) |</span> acc], fun)</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>As you can see, the tail call version takes more code, is not as straight forward as the first approach and we even have to reverse our result.<br>This is just to show, that even though tail optimization is necessary and you have to use it, sometimes it takes a litte bit more work.</p>
<p><em>Merry Christmas</em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Since <a href="http://elixir-lang.org" target="_blank" rel="noopener">Elixir</a> came to my attention I really enjoy functional programmi]]>
    </summary>
    
      <category term="elixir" scheme="http://pebra.net/tags/elixir/"/>
    
      <category term="functional" scheme="http://pebra.net/tags/functional/"/>
    
      <category term="programming" scheme="http://pebra.net/tags/programming/"/>
    
      <category term="tail call optimization" scheme="http://pebra.net/tags/tail-call-optimization/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Setting up Syncthing on Raspberry PI 2 as "always ON" device]]></title>
    <link href="http://pebra.net/blog/2015/08/23/syncthing/"/>
    <id>http://pebra.net/blog/2015/08/23/syncthing/</id>
    <published>2015-08-23T18:49:20.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p><a href="!--￼1--&gt;static/images/logo-horizontal.svg"><img src="/static/images/logo-horizontal.svg" class="center"></a></p>
<p>Yeah, uhm, I think I still <a href="/2014/02/07/keep-your-data-at-home/">owe you a post</a> for some dropbox’ish thing to sync files over multiple devices.<br>At first I was willing to give <a href="http://seafile.com" target="_blank" rel="noopener">seafile</a> a try, but after reading <a href="https://github.com/haiwen/seafile/issues/587" target="_blank" rel="noopener">this</a> it became a nono for me.</p>
<p>Fortunately there is <a href="http://syncthing.net" target="_blank" rel="noopener">Syncthing</a> - a peer to peer based syncing solution that runs on almost any platform.<br>Another plus: there is an <a href="https://github.com/syncthing/syncthing-android" target="_blank" rel="noopener">android app</a> and a third party iOS app seems to be in development, awesome!</p>
<p>There is already an impressive number of tutorials for installation and setup out there and the <a href="http://docs.syncthing.net/" target="_blank" rel="noopener">syncthing documentation</a> is great. Therefore I’ll only cover the very specific things to my setup.</p>
<h2 id="Setting_up_the_“Server”">Setting up the “Server”</h2><p>Syncthing is no client-server application.<br>Files will only sync if at least two devices are running and online. To make syncthing a Dropbox alternative I have one device that is online all the time. It always knows the most recent state of my files.<br>We will use a Raspberry PI 2 running Arch Linux as our <em>always online</em> device.<br>Consider the following commands to be executed on the PI.</p>
<h4 id="Step_1:_Get_the_Syncthing_Package">Step 1: Get the Syncthing Package</h4><pre><code><span class="comment"># Version might have changed when you are reading this.</span>
curl -<span class="constant">OL </span><span class="symbol">https:</span>/<span class="regexp">/github.com/syncthing</span><span class="regexp">/syncthing/releases</span><span class="regexp">/download/v</span><span class="number">0</span>.<span class="number">11.21</span>/syncthing-linux-arm-v<span class="number">0</span>.<span class="number">11.21</span>.tar.gz
</code></pre><h4 id="Step_2:_Unpack_the_Package">Step 2: Unpack the Package</h4><pre><code>mkdir syncthing
tar xfvz syncthing-linux-arm-v0<span class="number">.11</span><span class="number">.21</span>.tar.gz -C syncthing --strip-components=<span class="number">1</span>
</code></pre><p>Nice, Syncthing is now unpacked in a folder called syncthing.</p>
<h4 id="Step_3:_Make_the_Web_Interface_accessible_in_your_local_network">Step 3: Make the Web Interface accessible in your local network</h4><p>Syncthing brings a nice web GUI that lets you configure your peer. By default it is only accessible from the peer running syncthing.<br>Since I don’t have desktop environment installedon the PI, I want to access the web GUI from my laptop.<br>In order to get this working we have to tweak the syncthing config a bit.</p>
<p>First, run syncthing once so it creates all the default folders.</p>
<pre><code><span class="built_in">cd</span> syncthing/
./syncthing
<span class="comment"># hit CTRL + C after everything booted up.</span>
</code></pre><p>Now edit the syncthing config with your favorite editor.</p>
<pre><code>vim ~<span class="regexp">/.config/syncthing</span><span class="regexp">/config.xml</span>
</code></pre><p>Change this line</p>
<pre><code><span class="tag">&lt;<span class="title">gui</span> <span class="attribute">enabled</span>=<span class="value">"true"</span> <span class="attribute">tls</span>=<span class="value">"false"</span>&gt;</span>
    <span class="tag">&lt;<span class="title">address</span>&gt;</span>127.0.0.1:8384<span class="tag">&lt;/<span class="title">address</span>&gt;</span>
<span class="tag">&lt;/<span class="title">gui</span>&gt;</span>
</code></pre><p>to this</p>
<pre><code><span class="tag">&lt;<span class="title">gui</span> <span class="attribute">enabled</span>=<span class="value">"true"</span> <span class="attribute">tls</span>=<span class="value">"false"</span>&gt;</span>
    <span class="tag">&lt;<span class="title">address</span>&gt;</span>0.0.0.0:8384<span class="tag">&lt;/<span class="title">address</span>&gt;</span>
<span class="tag">&lt;/<span class="title">gui</span>&gt;</span>
</code></pre><p>We can now access the web GUI of the PI via <a href="http://IP_ADDRESS_OF_YOUR_PI:8384" target="_blank" rel="noopener">http://IP_ADDRESS_OF_YOUR_PI:8384</a></p>
<h4 id="Step_4:_Run_Syncthing_on_Startup">Step 4: Run Syncthing on Startup</h4><p>You may not want to start Syncthing by hand everytime you restart your Raspberry, the guys from Syncthing got your back.</p>
<pre><code><span class="comment"># do the next stuff as root</span>
su
cd syncthing <span class="comment"># if your aren't already there</span>
cp syncthing /usr/bin/
chmod a+x /usr/bin/syncthing

cp etc/linux-systemd/<span class="built_ins">user</span>/syncthing.service /usr/lib/systemd/<span class="built_ins">user</span>/
systemctl --<span class="built_ins">user</span> enable syncthing.service

reboot
</code></pre><p>Syncthing now starts at every boot!</p>
<p>I had some troubles figuring out how to do this proerly so I thought it would be worth mentioning.</p>
<h2 id="Other_Devices">Other Devices</h2><p>If you are running Arch Linux on your machine it is as easy as this</p>
<pre><code>pacman -S syncthing
systemctl <span class="comment">--user enable syncthing.service</span>
systemctl <span class="comment">--user start syncthing.service</span>
</code></pre><h2 id="Set_up_your_synced_Folders_and_such">Set up your synced Folders and such</h2><p>Please see the <a href="http://docs.syncthing.net/intro/getting-started.html" target="_blank" rel="noopener">documentation</a> for all the configuration and Web GUI stuff, it’s very comprehensive.</p>
<h2 id="Conclusion">Conclusion</h2><p>I am really satisfied with this solution as my Dropbox alternative, everything seems to work well and I hope my<br>few notes on setting it up on the Raspberry PI will save you some time while setting up your own Syncthing!</p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="!--￼1--&gt;static/images/logo-horizontal.svg"><img src="/static/images/logo-horizontal.svg" class="center"></a></p>
<p>Yeah, uhm]]>
    </summary>
    
      <category term="pi" scheme="http://pebra.net/tags/pi/"/>
    
      <category term="syncthing" scheme="http://pebra.net/tags/syncthing/"/>
    
      <category term="raspberry" scheme="http://pebra.net/tags/raspberry/"/>
    
      <category term="android" scheme="http://pebra.net/tags/android/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[TIL: Batch resize images and create animated gifs from command line]]></title>
    <link href="http://pebra.net/blog/2015/03/03/batch-resize-images-and-gif/"/>
    <id>http://pebra.net/blog/2015/03/03/batch-resize-images-and-gif/</id>
    <published>2015-03-03T11:31:08.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>Today I needed to combine some of my pictures from my mobile to an animated gif. Since using GUI tools is no option of course, here is how to do it from the command line.<br>First of all, make sure you have <a href="http://www.imagemagick.org/" target="_blank" rel="noopener">ImageMagick</a> installed on your system.</p>
<p>Once installed you are ready to go.<br>Assuming we have the following file structure and want all JPEG files to be resized.</p>
<figure class="highlight stylus"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">.</span><br><span class="line">├── <span class="number">1</span>.jpg</span><br><span class="line">├── <span class="number">2</span>.jpg</span><br><span class="line">├── <span class="number">3</span>.jpg</span><br><span class="line">├── <span class="number">4</span>.jpg</span><br><span class="line">└── output</span><br></pre></td></tr></table></figure>
<p>To make them, let’s say 25% smaller, you can run the following command:</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">mogrify</span> -resize <span class="number">25</span>% <span class="regexp">*.jpg</span></span><br></pre></td></tr></table></figure>
<p>You could also run something like:</p>
<figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="attribute">mogrify</span> -resize 1600x1200 <span class="regexp">*.jpg</span></span><br></pre></td></tr></table></figure>
<p><em>Note</em> that mogrify will replace your original files with the resized ones, so consider backing up your originals before running this.</p>
<p>After resizing, now create the gif using</p>
<figure class="highlight ada"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">convert -<span class="keyword">delay</span> <span class="number">35</span> -<span class="keyword">loop</span> <span class="number">0</span> *.jpg output/animated.gif</span><br></pre></td></tr></table></figure>
<p>and your done, your gif will be placed in the output folder.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Today I needed to combine some of my pictures from my mobile to an animated gif. Since using GUI tools is no option of course, here is ho]]>
    </summary>
    
      <category term="imagemagick" scheme="http://pebra.net/tags/imagemagick/"/>
    
      <category term="convert" scheme="http://pebra.net/tags/convert/"/>
    
      <category term="mogrify" scheme="http://pebra.net/tags/mogrify/"/>
    
      <category term="gif" scheme="http://pebra.net/tags/gif/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Installing Arch Linux on the Raspberry Pi]]></title>
    <link href="http://pebra.net/blog/2014/02/16/installing-arch-linux-on-the-raspberry-pi/"/>
    <id>http://pebra.net/blog/2014/02/16/installing-arch-linux-on-the-raspberry-pi/</id>
    <published>2014-02-16T10:22:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p><a href="!--￼15--&gt;/images/pisd.JPG"><img src="/static/images/pisd.JPG" class="center"></a></p>
<h3 id="Choosing_the_image">Choosing the image</h3><p>There are many use cases for the Pi and therefore you will find a lot of images, that will try to match your needs. Since I just want to run some server applications on the Pi, that need no GUI at all, I will go for the Arch Linux image. There are surely enough other images that will fit the needs as well or even better, feel free to try them out, the installation steps should be the same.<br>You can find the Arch and many other images on the <a href="http://www.raspberrypi.org/downloads" target="_blank" rel="noopener">download site</a> at <a href="http://raspberrypi.org" target="_blank" rel="noopener">raspberrypi.org</a></p>
<h3 id="Download_the_image_and_prepare_the_SD_card">Download the image and prepare the SD card</h3><p>Depending on your operating system, there are different ways to set up the SD card, so it will boot your Linux distribution of choice.<br>I will try to cover both Linux and OSX by sticking to the command line, since they have many commands in common.(differences will be marked)</p>
<p>First download and extract the image:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">curl -o arch_arm.img.zip -L http://downloads.raspberrypi.org/arch_latest</span><br><span class="line"><span class="comment"># if your system is missing curl, install it via your systems package manager</span></span><br><span class="line"><span class="comment"># some examples</span></span><br><span class="line"><span class="comment"># on ubuntu: apt-get install curl</span></span><br><span class="line"><span class="comment"># on mac with brew: brew install curl</span></span><br></pre></td></tr></table></figure>
<p>After downloading is finished, check the integrity of the image. This can save you a lot of pain!<br>A corrupted download will make you to have to repeat the whole setup again.<br>Generate the checksum of your download and compare it to the checksum on the <a href="http://www.raspberrypi.org/downloads" target="_blank" rel="noopener">downloads page</a>.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># generating the checksum of the downloaded file</span></span><br><span class="line">shasum arch_arm.img.zip</span><br><span class="line"><span class="comment"># the command could be named sha1sum for some folks</span></span><br></pre></td></tr></table></figure>
<p>If the checksums are matching, lets extract the zip file.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">unzip arch_arm.img.zip</span><br></pre></td></tr></table></figure>
<p>Note that the extracted file will be named something like ArchLinuxArm-some-release-date-rpi.img.</p>
<p>Put in the SD card format it with your tool of choice to FAT32 and remove it.</p>
<p>Then do</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">df -h</span><br></pre></td></tr></table></figure>
<p><a href="!--￼16--&gt;/images/df_before.png"><img src="/static/images/df_before.png" class="center"></a></p>
<p>Now insert the SD card.<br>Again run</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">df -h</span><br></pre></td></tr></table></figure>
<p><a href="!--￼17--&gt;/images/df_after.png"><img src="/static/images/df_after.png" class="center"></a><br>The additional device listed is your SD card.<br>In my case it’s <em>/dev/disk2</em>, this will differ from machine to machine. So if I use /dev/disk2 in some following commmands just see it as a placeholder for your device name.</p>
<p>The next step will differ a little whether you are using an OSX or a Linux OS.<br>The SD card needs to be unmounted now.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># only for mac users</span></span><br><span class="line">sudo diskutil unmountDisk /dev/disk2</span><br></pre></td></tr></table></figure>
<p>On Linux it should look something like this:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># only do this when you are on a linux machine</span></span><br><span class="line">umount /dev/disk2</span><br></pre></td></tr></table></figure>
<h3 id="Flashing_the_image">Flashing the image</h3><p>Alright, now it’s time to flash the image to the disk.<br>This step will again slightly differ from OSX to Linux.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># on a mac machine the m for bs=1m is written in lower case.</span></span><br><span class="line"><span class="comment"># using rdisk2 over disk2 will give you a nice speed boost in many cases but it's mac only</span></span><br><span class="line">sudo dd bs=1m <span class="keyword">if</span>=ArchLinuxARM-2014.01-rpi.img of=/dev/rdisk2</span><br></pre></td></tr></table></figure>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># on linux machines the M is written in upper case an the bs is set to 4</span></span><br><span class="line">dd bs=4M <span class="keyword">if</span>=/path/to/your/image.img of=/dev/disk2</span><br></pre></td></tr></table></figure>
<p>Ok, since the image is not that big, flashing will be quite fast.<br>As the final step eject the SD card.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># mac</span></span><br><span class="line">sudo diskutil eject /dev/rdisk2</span><br></pre></td></tr></table></figure>
<p>On Linux, clear the write cache, to safely remove the card.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># linux</span></span><br><span class="line">sudo sync</span><br></pre></td></tr></table></figure>
<p>Now the moment of truth has come. Pull your SD card out of your computer an put it in your Pi!<br><strong>Notice:</strong> put the SD card in <strong>before</strong> plugging in the power supply.</p>
<p>Login will be root, root. Change this immediately:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># after logging in to the Pi run</span></span><br><span class="line">passwd</span><br></pre></td></tr></table></figure>
<p>Now the Pi should be up and running, awesome!</p>
]]></content>
    <summary type="html">
    <![CDATA[<p><a href="!--￼15--&gt;/images/pisd.JPG"><img src="/static/images/pisd.JPG" class="center"></a></p>
<h3 id="Choosing_the_image">Choosing th]]>
    </summary>
    
      <category term="linux" scheme="http://pebra.net/tags/linux/"/>
    
      <category term="rapsberry" scheme="http://pebra.net/tags/rapsberry/"/>
    
      <category term="pi" scheme="http://pebra.net/tags/pi/"/>
    
      <category term="arch linux" scheme="http://pebra.net/tags/arch-linux/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Keep your data at home]]></title>
    <link href="http://pebra.net/blog/2014/02/07/keep-your-data-at-home/"/>
    <id>http://pebra.net/blog/2014/02/07/keep-your-data-at-home/</id>
    <published>2014-02-07T15:00:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>While services like Dropbox or Box.com are great for collaborative work and stuff, I always feel kind of afraid putting more personal data in there.<br>But I want to satisfy my desire to keep important files and media with me, while keeping them in sync with my devices.<br>I want to have my own dropbox, serving my files from home.</p>
<p>So I started with buying a <a href="http://raspberrypi.org" target="_blank" rel="noopener">Raspberry Pi(Model B)</a> and throwing Owncloud on it.<br>While installation and setup worked quite fluently, the performance was a desaster. A simple request to the webinterface of Owncloud on my Pi took about 20 seconds, which brings me to the conclusion, that Owncloud will be no fit for the Pi and it’s capabilities.</p>
<p>Fortunately there is a <a href="http://seafile.com" target="_blank" rel="noopener"> alternative to Owncloud </a> which looks promising plus it’s open source and free for personal use.<br>It has a free app for Android as well, therefore I will give it a shot.</p>
<p>My next blog posts will be about setting up useful server applications on the Pi such as</p>
<ul>
<li><a href="http://seafile.com" target="_blank" rel="noopener">Seafile</a> - private Owncloud-like file sync</li>
<li><a href="http://mumble.sourceforge.net/" target="_blank" rel="noopener">Mumble</a> - encrypted, low-latency voice chat</li>
<li>maybe <a href="http://jabber.org" target="_blank" rel="noopener">Jabber</a> - XMPP</li>
</ul>
<p>I will also cover and start with:</p>
<ul>
<li>Installing <a href="http://openwrt.org" target="_blank" rel="noopener">openwrt</a> on my <a href="http://wiki.openwrt.org/toh/wd/n600" target="_blank" rel="noopener">WD N600 Router</a> (to setup DDNS with <a href="https://no-ip.org" target="_blank" rel="noopener">no-ip.org</a>)</li>
<li>Installing <a href="http://archlinuxarm.org/" target="_blank" rel="noopener">arch linux</a> on the Pi</li>
</ul>
<p><strong>Disclaimer:</strong> I have no clue if the PI can handle the stuff I am going to install =)</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>While services like Dropbox or Box.com are great for collaborative work and stuff, I always feel kind of afraid putting more personal dat]]>
    </summary>
    
      <category term="arch linux" scheme="http://pebra.net/tags/arch-linux/"/>
    
      <category term="raspberry pi" scheme="http://pebra.net/tags/raspberry-pi/"/>
    
      <category term="privacy" scheme="http://pebra.net/tags/privacy/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Installing OpenWrt on WD MyNet N600]]></title>
    <link href="http://pebra.net/blog/2014/02/07/installing-openwrt-on-wd-mynet-n600/"/>
    <id>http://pebra.net/blog/2014/02/07/installing-openwrt-on-wd-mynet-n600/</id>
    <published>2014-02-07T11:00:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>In order to access the PI from outside my local network I need to keep track of my home’s IP address. Since I have no static IP at home I’ll have to deal with DDNS.<br><!-- (Please let me know if there are other solutions, maybe self hosted?) --><br><a href="!--￼9--&gt;/images/n600.jpg"><img src="/static/images/n600.jpg" class="center"></a></p>
<p>I researched some dynamic DNS providers and was surprised to find, that only a few free solutions were left.<br>In the past I was very happy with <a href="http://dyndns.org" target="_blank" rel="noopener">dnydns.org</a>, but they stopped their free plans.<br>Fortunately there is <a href="http://no-ip.org" target="_blank" rel="noopener">no-ip.org</a>, which is keeping up with free plans for single users.</p>
<p>Sadly, the stock firmware which ships with my N600 only supports tzo and dyndns.org as providers for dynDNS which are not quite the same company I guess.<br>So no satisfying solution here.<br>Which forces me install some cool stuff on my router: <a href="http://openwrt.org" target="_blank" rel="noopener">OpenWrt</a></p>
<p>According to their website, installation should be straight forward:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">1) Download the file openwrt-ar71xx-generic-mynet-n600-squashfs-sysupgrade.bin</span><br><span class="line">2) Configure your computers IP address to 192.168.1.10 and connect to a LAN port <span class="keyword">in</span> the router.</span><br><span class="line">3) Turn the router off.</span><br><span class="line">4) Using a paperclip, press and hold the reset button on the bottom of the router and turn it on. Hold the reset button <span class="keyword">for</span> at least 15 seconds.</span><br><span class="line">5) On your computer, visit http://192.168.1.1 NOTE: You will not be able to ping this address.</span><br><span class="line">6) Upload the file openwrt-ar71xx-generic-mynet-n600-squashfs-sysupgrade.bin as downloaded earlier.</span><br><span class="line">7) The router will now flash OpenWRT. This will take a couple of minutes to achieve. You can ping 192.168.1.1 and watch <span class="keyword">for</span> ping replies to see when your router has rebooted into OpenWRT</span><br></pre></td></tr></table></figure>
<p>Alright step 1 is easy. Step 2 can be tricky if you are using some linux-ish OS.<br>I did it on Mint with editing /etc/network/interfaces and adding following lines:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># /etc/network/interfaces</span></span><br><span class="line">iface eth0 inet static</span><br><span class="line">  address 192.168.1.10</span><br><span class="line">  netmask 255.255.255.0</span><br><span class="line">  gateway 192.168.1.1</span><br></pre></td></tr></table></figure>
<p>Did a</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">sudo /etc/init.d/networking restart</span><br></pre></td></tr></table></figure>
<p>after saving the file.</p>
<p>This enables me to connect my machine and the router directly via LAN.<br>Step 3 to 7 worked flawlessly.<br>After flashing OpenWrt ist done, you can telnet on the router.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">telnet 192.168.1.1</span><br></pre></td></tr></table></figure>
<p>Not lets install a web interface called LuCI.<br>Fortunately there are great <a href="http://wiki.openwrt.org/doc/howto/luci.essentials" target="_blank" rel="noopener">step-by-step instructions</a> already there!</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">opkg update</span><br><span class="line">opkg install luci</span><br><span class="line">opkg install luci-ssl</span><br><span class="line"><span class="comment"># Start the web server (uHTTPd)</span></span><br><span class="line">/etc/init.d/uhttpd start</span><br><span class="line"><span class="comment"># Enable the web server (uHTTPd)</span></span><br><span class="line">/etc/init.d/uhttpd <span class="built_in">enable</span></span><br></pre></td></tr></table></figure>
<p>It just works, great.</p>
<p>Now we need DDNS support, since it is not avaiable out-of-the-box by luci.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">opkg install luci-app-ddns</span><br><span class="line">opkg install ddns-scripts</span><br></pre></td></tr></table></figure>
<p>The DDNS service was disabled by default, so I turned it on via System -&gt; Startup</p>
<p><a href="!--￼10--&gt;/images/ddns-disabled.png"><img src="/static/images/ddns-disabled.png" class="center"></a></p>
<p>Now after refreshing the page there should be a new tab called “Services” at the web interface’s navigation.<br>You can choose a ton of providers here. As mentioned, I will go ahead with no-ip.org.</p>
<p><a href="!--￼11--&gt;/images/ddnsworking.png"><img src="/static/images/ddnsworking.png" class="center"></a></p>
<p>After setting up the PI we will need these prerequisites to use our applications from outside our local network, e.g. with the smartphone.</p>
<p>But this should be it for now.</p>
<p>Please do not forget to set up a root password and all the other stuff like ssh and the wifi(if needed).</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>In order to access the PI from outside my local network I need to keep track of my home’s IP address. Since I have no static IP at home I]]>
    </summary>
    
      <category term="n600" scheme="http://pebra.net/tags/n600/"/>
    
      <category term="openwrt" scheme="http://pebra.net/tags/openwrt/"/>
    
      <category term="western digital" scheme="http://pebra.net/tags/western-digital/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[[Vim] Toggle between Vim and Shell]]></title>
    <link href="http://pebra.net/blog/2013/11/14/slash-vim-slash-toggle-between-vim-and-shell/"/>
    <id>http://pebra.net/blog/2013/11/14/slash-vim-slash-toggle-between-vim-and-shell/</id>
    <published>2013-11-14T12:35:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>There is a binding I kind of use a lot in the past months. As you may know, you can switch to a shell from Vim with </p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">:sh</span><br></pre></td></tr></table></figure>
<p>in normal mode. If you type exit or hit CTR+D in your shell, you will get back to Vim. I like this behaviour when I am on a remote server via ssh.</p>
<p>Therefor I binded CTR+D in Vim to execute :sh, so I can toggle between shell and Vim with this shortcut.<br>To get it, include this snippet in your vimrc.</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="comment"># ~/.vimrc</span></span><br><span class="line">noremap &lt;C<span class="_">-d</span>&gt; :sh&lt;cr&gt;</span><br></pre></td></tr></table></figure>
]]></content>
    <summary type="html">
    <![CDATA[<p>There is a binding I kind of use a lot in the past months. As you may know, you can switch to a shell from Vim with </p>
<figure class="h]]>
    </summary>
    
      <category term="vim" scheme="http://pebra.net/tags/vim/"/>
    
      <category term="shell" scheme="http://pebra.net/tags/shell/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Find all records associated with an ActiveRecord::Base model]]></title>
    <link href="http://pebra.net/blog/2013/09/09/find-all-records-associated-with-an-activerecord-base-model/"/>
    <id>http://pebra.net/blog/2013/09/09/find-all-records-associated-with-an-activerecord-base-model/</id>
    <published>2013-09-09T19:54:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>If you are too lazy to look up the source file, just hit this up in the rails console.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">InterestingModel.reflect_on_all_associations.map&#123; <span class="params">|assoc|</span> [assoc.macro, assoc.name] &#125;</span><br><span class="line">  <span class="comment"># =&gt;[[:belongs_to, :foo_model],</span></span><br><span class="line">  <span class="comment">#    [:has_one, :bar_model],</span></span><br><span class="line">  <span class="comment">#    [:has_one, :other_model]</span></span><br><span class="line">  <span class="comment">#=&gt; ActiveRecord::Reflection::AssociationReflection</span></span><br></pre></td></tr></table></figure>
<p><em>Addtion:</em><br>You can also see all associations for an instance of a model.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">InterestingModel.new.reflections</span><br><span class="line">  <span class="comment">#=&gt; ActiveRecord::Reflection::AssociationReflection</span></span><br></pre></td></tr></table></figure>
<p>This also works with Classes themself</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">InterestingModel.reflections</span><br><span class="line">  <span class="comment">#=&gt; ActiveRecord::Reflection::AssociationReflection</span></span><br></pre></td></tr></table></figure>
<p>Note that <em>reflect_on_all_associations</em> returns an Array of all Associations and<br><em>reflections</em> will return a Hash like <em>{ :association_name =&gt; ActiveRecord::Relfection::AssociationReflection }</em></p>
]]></content>
    <summary type="html">
    <![CDATA[<p>If you are too lazy to look up the source file, just hit this up in the rails console.</p>
<figure class="highlight ruby"><table><tr><td ]]>
    </summary>
    
      <category term="ruby" scheme="http://pebra.net/tags/ruby/"/>
    
      <category term="ruby on rails" scheme="http://pebra.net/tags/ruby-on-rails/"/>
    
      <category term="activerecord" scheme="http://pebra.net/tags/activerecord/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[When struggling with postgresql and utf8/latin]]></title>
    <link href="http://pebra.net/blog/2013/06/10/when-struggling-with-postgresql-and-utf8-slash-latin/"/>
    <id>http://pebra.net/blog/2013/06/10/when-struggling-with-postgresql-and-utf8-slash-latin/</id>
    <published>2013-06-10T16:40:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>This is just a little information dump for me, you probably won’t have these issues.</p>
<p>Lately I tried to switch the database in a Rails app from SQLite to PostgreSQL.<br>However, after installing postgres and setting up my database.yml file on my vagrant ubuntu(precise32) box, I fire</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">rake <span class="symbol">db:</span>create</span><br></pre></td></tr></table></figure>
<p>and it greets me with</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">Couldn<span class="string">'t create database for &#123;"adapter"=&gt;"postgresql", "encoding"=&gt;"unicode", </span></span><br><span class="line"><span class="string">	"database"=&gt;"stuff_development", "pool"=&gt;5, "username"=&gt;"stuffer", "password"=&gt;nil&#125;</span></span><br><span class="line"><span class="string">PG::Error: ERROR:  encoding "UTF8" does not match locale "en_US"</span></span><br><span class="line"><span class="string">DETAIL:  The chosen LC_CTYPE setting requires encoding "LATIN1".</span></span><br><span class="line"><span class="string">: CREATE DATABASE "stuff_test" ENCODING = '</span>unicode<span class="string">'</span></span><br></pre></td></tr></table></figure>
<p>There are some encoding issues, yeah!<br>After some googeling I tried the solution provided by this <a href="https://coderwall.com/p/j-_mia" target="_blank" rel="noopener">post</a> which unfortunatly ended up with this:</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">postgres=<span class="comment"># create database template1 with owner=postgres template=template0 encoding='UTF8';</span></span><br><span class="line">ERROR:  encoding "UTF8" does not match locale "en_US"</span><br><span class="line">DETAIL:  The chosen LC_CTYPE setting requires encoding "LATIN1".</span><br></pre></td></tr></table></figure>
<p>But adding some additional options did the trick</p>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">create</span> <span class="keyword">database</span> template1 <span class="keyword">with</span> owner postgres <span class="keyword">encoding</span>=<span class="string">'UTF-8'</span> </span><br><span class="line">	lc_collate=<span class="string">'en_US.utf8'</span> lc_ctype=<span class="string">'en_US.utf8'</span> <span class="keyword">template</span> template0;</span><br></pre></td></tr></table></figure>
<p>In summary, when you get such errors try these steps</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">sudo su postgres</span><br><span class="line">psql</span><br></pre></td></tr></table></figure>
<figure class="highlight sql"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">update</span> pg_database <span class="keyword">set</span> datistemplate=<span class="literal">false</span> <span class="keyword">where</span> datname=<span class="string">'template1'</span>;</span><br><span class="line"><span class="keyword">drop</span> <span class="keyword">database</span> Template1;</span><br><span class="line"><span class="keyword">create</span> <span class="keyword">database</span> template1 <span class="keyword">with</span> owner=postgres <span class="keyword">encoding</span>=<span class="string">'UTF-8'</span> </span><br><span class="line">	lc_collate=<span class="string">'en_US.utf8'</span> lc_ctype=<span class="string">'en_US.utf8'</span> <span class="keyword">template</span> template0;</span><br><span class="line"><span class="keyword">update</span> pg_database <span class="keyword">set</span> datistemplate=<span class="literal">true</span> <span class="keyword">where</span> datname=<span class="string">'template1'</span>;</span><br></pre></td></tr></table></figure>
]]></content>
    <summary type="html">
    <![CDATA[<p>This is just a little information dump for me, you probably won’t have these issues.</p>
<p>Lately I tried to switch the database in a Ra]]>
    </summary>
    
      <category term="coding" scheme="http://pebra.net/tags/coding/"/>
    
      <category term="postgresql" scheme="http://pebra.net/tags/postgresql/"/>
    
      <category term="postgres" scheme="http://pebra.net/tags/postgres/"/>
    
      <category term="ubuntu" scheme="http://pebra.net/tags/ubuntu/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[Get recipes from chefkoch.de using ruby | Part 2]]></title>
    <link href="http://pebra.net/blog/2013/03/13/Get-recipes-from-chefkoch.de-using-ruby-Part-2/"/>
    <id>http://pebra.net/blog/2013/03/13/Get-recipes-from-chefkoch.de-using-ruby-Part-2/</id>
    <published>2013-03-13T10:20:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>Even it’s quite a while ago since part 1, I want to finish up this micro series about the chefkoch api.<br>As you may remember, we are able to search for recipes, whose titles are matching our search string.<br>Unfortunatly, the api response is not serving any link to the recipe itself.<br>So let’s fix this and add this url directly to our method’s result!</p>
<p>First we need to find out, how the recipe urls are built.<br>By checking some recipes on their site, we can see that recipe urls are built like that:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line">http://www.chefkoch.de/rezepte/:id</span><br></pre></td></tr></table></figure>
<p>Now we could extend our search method by telling it to call a method named “append_recipe_link” and passing our response to that method:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">require</span> <span class="string">'net/http'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'json'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'uri'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">module</span> <span class="title">ChefkochApi</span></span></span><br><span class="line">  @api_url = <span class="string">"http://api.chefkoch.de/api/1.0/api-recipe-search.php"</span></span><br><span class="line">  @rezept_url = <span class="string">"http://www.chefkoch.de/rezepte/"</span> <span class="comment"># this is new</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">search</span><span class="params">(search_text)</span></span></span><br><span class="line">    <span class="comment"># ... stil the same stuff</span></span><br><span class="line">    response = Net::HTTP.get_response(url)</span><br><span class="line"></span><br><span class="line">    <span class="keyword">self</span>.append_recipe_link response</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  private</span><br><span class="line"></span><br><span class="line">  <span class="comment"># our new helper method</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">append_recipe_link</span><span class="params">(response)</span></span></span><br><span class="line">    <span class="comment"># here comes some JSON magic to extract only the relevant information from the json response</span></span><br><span class="line">    JSON.parse(response.body.strip)[<span class="string">"result"</span>].each <span class="keyword">do</span> <span class="params">|r|</span></span><br><span class="line">      r[<span class="string">"RezeptUrl"</span>] = @rezept_url + r[<span class="string">"RezeptShowID"</span>]</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>And there you go. Your results should now have a url linking directly to the recipe show page.</p>
<p>The last thing I want to show is, how you get more detailed information about your recipes.<br>I am using another method for that, which does another api call. Please note the aditional api url at the top.</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br></pre></td><td class="code"><pre><span class="line"></span><br><span class="line"><span class="keyword">require</span> <span class="string">'net/http'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'json'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'uri'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">module</span> <span class="title">ChefkochApi</span></span></span><br><span class="line">  @api_url = <span class="string">"http://api.chefkoch.de/api/1.0/api-recipe-search.php"</span></span><br><span class="line">  @api_rezept_url = <span class="string">"http://api.chefkoch.de/api/1.0/api-recipe.php"</span></span><br><span class="line">  @rezept_url = <span class="string">"http://www.chefkoch.de/rezepte/"</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">search</span><span class="params">(search_text)</span></span></span><br><span class="line">    <span class="comment"># ...</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  <span class="comment"># here we go</span></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">show_recipe</span><span class="params">(id)</span></span></span><br><span class="line">    <span class="comment"># Remember "RezeptShowID" from our JSON response?</span></span><br><span class="line">    <span class="comment"># Thats the id which gets passed to this method here</span></span><br><span class="line">    params = &#123;&#125;</span><br><span class="line">    params[<span class="string">"ID"</span>] = id</span><br><span class="line"></span><br><span class="line">    url = URI.parse @api_rezept_url</span><br><span class="line">    url.query = URI.encode_www_form(params)</span><br><span class="line"></span><br><span class="line">    response = Net::HTTP.get_response(url)</span><br><span class="line">    JSON.parse(response.body.strip)[<span class="string">"result"</span>]</span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"></span><br><span class="line">  private</span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">append_recipe_link</span><span class="params">(response)</span></span></span><br><span class="line">    <span class="comment"># ...</span></span><br><span class="line">  <span class="keyword">end</span></span><br><span class="line"><span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>This gives us more detailed information about a recipe in response:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br><span class="line">32</span><br><span class="line">33</span><br><span class="line">34</span><br><span class="line">35</span><br><span class="line">36</span><br><span class="line">37</span><br><span class="line">38</span><br><span class="line">39</span><br><span class="line">40</span><br><span class="line">41</span><br><span class="line">42</span><br><span class="line">43</span><br><span class="line">44</span><br><span class="line">45</span><br><span class="line">46</span><br><span class="line">47</span><br><span class="line">48</span><br><span class="line">49</span><br><span class="line">50</span><br><span class="line">51</span><br><span class="line">52</span><br><span class="line">53</span><br><span class="line">54</span><br><span class="line">55</span><br><span class="line">56</span><br><span class="line">57</span><br><span class="line">58</span><br><span class="line">59</span><br><span class="line">60</span><br><span class="line">61</span><br><span class="line">62</span><br><span class="line">63</span><br><span class="line">64</span><br><span class="line">65</span><br><span class="line">66</span><br><span class="line">67</span><br><span class="line">68</span><br><span class="line">69</span><br><span class="line">70</span><br><span class="line">71</span><br><span class="line">72</span><br><span class="line">73</span><br><span class="line">74</span><br><span class="line">75</span><br><span class="line">76</span><br><span class="line">77</span><br><span class="line">78</span><br><span class="line">79</span><br><span class="line">80</span><br><span class="line">81</span><br><span class="line">82</span><br><span class="line">83</span><br><span class="line">84</span><br><span class="line">85</span><br><span class="line">86</span><br><span class="line">87</span><br><span class="line">88</span><br><span class="line">89</span><br><span class="line">90</span><br><span class="line">91</span><br><span class="line">92</span><br><span class="line">93</span><br><span class="line">94</span><br><span class="line">95</span><br><span class="line">96</span><br><span class="line">97</span><br><span class="line">98</span><br><span class="line">99</span><br><span class="line">100</span><br><span class="line">101</span><br><span class="line">102</span><br></pre></td><td class="code"><pre><span class="line">&#123;</span><br><span class="line">  <span class="string">"api"</span>:&#123;</span><br><span class="line">    <span class="string">"version"</span>:<span class="number">1.2</span></span><br><span class="line">  &#125;,</span><br><span class="line">    <span class="string">"total"</span>:<span class="number">1</span>,</span><br><span class="line">    <span class="string">"result"</span>:[</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="string">"rezept_id"</span>:<span class="string">"101077"</span>,</span><br><span class="line">      <span class="string">"rezept_show_id"</span>:<span class="string">"1010771206206427"</span>,</span><br><span class="line">      <span class="string">"rezept_name"</span>:<span class="string">"Apple Pie"</span>,</span><br><span class="line">      <span class="string">"rezept_name2"</span>:<span class="string">""</span>,</span><br><span class="line">      <span class="string">"rezept_zubereitung"</span>:<span class="string">"Mehl, Butter, Zucker, Zitronenschale (oder wahlweise eine Packung Citroback), Salz und die Eigelbe mischen und zu einem Teig verkneten. \r\n\r\nDie \u00c4pfel sch\u00e4len und in St\u00fccke schneiden, mit etwas Zucker und Wasser in einem Topf 5 min. kochen lassen (nach Geschmack noch ein wenig zerdr\u00fccken), die Masse abk\u00fchlen lassen. \r\n\r\nDen Teig in zwei St\u00fccke teilen. Den gr\u00f6\u00dferen Teil ausrollen und die Form (ca 20 cm Durchmesser) damit auslegen. Nun die abgek\u00fchlte Masse auf dem Teig verteilen. Den Rest des Teiges ausrollen und oben auf die Apfelmasse legen. An den Seiten andr\u00fccken. Das Ganze wird nun mit einem Eigelb (gemischt mit etwas Wasser) bestrichen.\r\n\r\nDas Ganze im vorgeheizten Ofen bei 180\u00b0C 45 \u0096 50 min. backen lassen. Am besten noch warm genie\u00dfen."</span>,</span><br><span class="line">      <span class="string">"rezept_portionen"</span>:<span class="string">"1"</span>,</span><br><span class="line">      <span class="string">"rezept_preparation_time"</span>:<span class="number">45</span>,</span><br><span class="line">      <span class="string">"rezept_cooking_time"</span>:<span class="number">0</span>,</span><br><span class="line">      <span class="string">"rezept_resting_time"</span>:<span class="number">60</span>,</span><br><span class="line">      <span class="string">"rezept_schwierigkeit"</span>:<span class="string">"simpel"</span>,</span><br><span class="line">      <span class="string">"rezept_kcal"</span>:<span class="string">"0"</span>,</span><br><span class="line">      <span class="string">"rezept_user_id"</span>:<span class="string">"3733fd403a13fb5f951c2369ae1acd22"</span>,</span><br><span class="line">      <span class="string">"rezept_user_name"</span>:<span class="string">"KaThePrincess"</span>,</span><br><span class="line">      <span class="string">"rezept_datum"</span>:<span class="string">"1206640697"</span>,</span><br><span class="line">      <span class="string">"rezept_videos"</span>:[</span><br><span class="line"></span><br><span class="line">        ],</span><br><span class="line">      <span class="string">"rezept_in_rezeptsammlung"</span>:[</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="string">"sammlungs_id"</span>:<span class="string">"946538"</span>,</span><br><span class="line">        <span class="string">"sammlungs_name"</span>:<span class="string">"Apfelkuchen"</span>,</span><br><span class="line">        <span class="string">"sammlungs_link"</span>:<span class="string">"\/rezeptsammlung\/946538\/Apfelkuchen.html"</span></span><br><span class="line">      &#125;,</span><br><span class="line">      &#123;</span><br><span class="line">        <span class="string">"sammlungs_id"</span>:<span class="string">"1803978"</span>,</span><br><span class="line">        <span class="string">"sammlungs_name"</span>:<span class="string">"Kuchen und andere s\u00fc\u00dfe sachen"</span>,</span><br><span class="line">        <span class="string">"sammlungs_link"</span>:<span class="string">"\/rezeptsammlung\/1803978\/Kuchen-und-andere-suesse-sachen.html"</span></span><br><span class="line">      &#125;</span><br><span class="line">      ],</span><br><span class="line">        <span class="string">"rezeptsammlungen_link"</span>:<span class="string">"\/rezeptsammlung\/0,30\/1010771206206427\/"</span>,</span><br><span class="line">        <span class="string">"rezept_zutaten_is_basic"</span>:[</span><br><span class="line">          <span class="string">"71"</span>,</span><br><span class="line">        <span class="string">"70"</span>,</span><br><span class="line">        <span class="string">"83"</span>,</span><br><span class="line">        <span class="string">"6"</span>,</span><br><span class="line">        <span class="string">"247"</span></span><br><span class="line">          ],</span><br><span class="line">        <span class="string">"rezept_zutaten"</span>:[</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="string">"id"</span>:<span class="string">"71"</span>,</span><br><span class="line">          <span class="string">"name"</span>:<span class="string">"Mehl"</span>,</span><br><span class="line">          <span class="string">"eigenschaft"</span>:<span class="string">""</span>,</span><br><span class="line">          <span class="string">"cominfo"</span>:<span class="string">"0"</span>,</span><br><span class="line">          <span class="string">"ist_basic"</span>:<span class="string">"1"</span>,</span><br><span class="line">          <span class="string">"menge"</span>:<span class="string">"225"</span>,</span><br><span class="line">          <span class="string">"einheit"</span>:<span class="string">"g"</span>,</span><br><span class="line">          <span class="string">"menge_berechnet"</span>:<span class="number">225</span>,</span><br><span class="line">          <span class="string">"has_additional_info"</span>:<span class="literal">false</span></span><br><span class="line">        &#125;,</span><br><span class="line">        &#123;</span><br><span class="line">          <span class="string">"id"</span>:<span class="string">"70"</span>,</span><br><span class="line">          <span class="string">"name"</span>:<span class="string">"Butter"</span>,</span><br><span class="line">          <span class="string">"eigenschaft"</span>:<span class="string">""</span>,</span><br><span class="line">          <span class="string">"cominfo"</span>:<span class="string">"0"</span>,</span><br><span class="line">          <span class="string">"ist_basic"</span>:<span class="string">"1"</span>,</span><br><span class="line">          <span class="string">"menge"</span>:<span class="string">"140"</span>,</span><br><span class="line">          <span class="string">"einheit"</span>:<span class="string">"g"</span>,</span><br><span class="line">          <span class="string">"menge_berechnet"</span>:<span class="number">140</span>,</span><br><span class="line">          <span class="string">"has_additional_info"</span>:<span class="literal">false</span></span><br><span class="line">        &#125;,</span><br><span class="line"></span><br><span class="line">      and so on and so on ...</span><br><span class="line"></span><br><span class="line">      ],</span><br><span class="line">        <span class="string">"rezept_tags"</span>:[</span><br><span class="line">          <span class="string">"Backen"</span>,</span><br><span class="line">        <span class="string">"Kuchen"</span>,</span><br><span class="line">        <span class="string">"USA oder Kanada"</span>,</span><br><span class="line">        <span class="string">"Weihnachten"</span></span><br><span class="line">          ],</span><br><span class="line">        <span class="string">"rezept_user_portionen"</span>:<span class="string">"1"</span>,</span><br><span class="line">        <span class="string">"rezept_votes"</span>:&#123;</span><br><span class="line">          <span class="string">"average"</span>:<span class="number">3.3333</span>,</span><br><span class="line">          <span class="string">"img"</span>:<span class="string">"3_5"</span>,</span><br><span class="line">          <span class="string">"votes"</span>:<span class="string">"1"</span>,</span><br><span class="line">          <span class="string">"result"</span>:<span class="string">"5"</span></span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="string">"rezept_statistik"</span>:&#123;</span><br><span class="line">          <span class="string">"total"</span>:&#123;</span><br><span class="line">            <span class="string">"viewed"</span>:<span class="string">"4095"</span>,</span><br><span class="line">            <span class="string">"saved"</span>:<span class="string">"12"</span>,</span><br><span class="line">            <span class="string">"printed"</span>:<span class="string">"71"</span>,</span><br><span class="line">            <span class="string">"mailed"</span>:<span class="string">"1"</span></span><br><span class="line">          &#125;,</span><br><span class="line">          <span class="string">"month"</span>:&#123;</span><br><span class="line">            <span class="string">"viewed"</span>:<span class="string">"16"</span>,</span><br><span class="line">            <span class="string">"saved"</span>:<span class="string">"0"</span>,</span><br><span class="line">            <span class="string">"printed"</span>:<span class="string">"1"</span>,</span><br><span class="line">            <span class="string">"mailed"</span>:<span class="string">"0"</span></span><br><span class="line">          &#125;</span><br><span class="line">        &#125;,</span><br><span class="line">        <span class="string">"rezept_frontend_url"</span>:<span class="string">"http:\/\/www.chefkoch.de\/rezepte\/1010771206206427\/Apple-Pie.html"</span></span><br><span class="line">    &#125;</span><br><span class="line">  ]</span><br><span class="line">&#125;</span><br></pre></td></tr></table></figure>
<p>Now our module has quite some functionality. Hope this was usefull for at least a few people.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Even it’s quite a while ago since part 1, I want to finish up this micro series about the chefkoch api.<br>As you may remember, we are ab]]>
    </summary>
    
      <category term="coding" scheme="http://pebra.net/tags/coding/"/>
    
      <category term="ruby" scheme="http://pebra.net/tags/ruby/"/>
    
      <category term="chefkoch.de" scheme="http://pebra.net/tags/chefkoch-de/"/>
    
      <category term="api" scheme="http://pebra.net/tags/api/"/>
    
      <category term="cooking" scheme="http://pebra.net/tags/cooking/"/>
    
  </entry>
  
  <entry>
    <title><![CDATA[How to get recipes from chefkoch.de using ruby | Part 1]]></title>
    <link href="http://pebra.net/blog/2012/10/31/how-to-get-recipes-fromchefkoch-dot-de/"/>
    <id>http://pebra.net/blog/2012/10/31/how-to-get-recipes-fromchefkoch-dot-de/</id>
    <published>2012-10-31T13:50:00.000Z</published>
    <updated>2017-01-20T19:48:31.000Z</updated>
    <content type="html"><![CDATA[<p>Driven by a seminar task at university we were free to create any kind of web/android/iphone app which takes care of<br>some contextual issues.</p>
<p>As I am a huge fan of Ruby and Ruby on Rails I convinced my partner to develop a web app for this seminar.</p>
<p>Since we both like to cook, we decided to create a web app with RoR which helps you to find a suitable recipe for<br>the ingedrients which are already present at your home.</p>
<p>To get us started finding some database we can work on, I stumbled across the ChefkochApi.<br>It’s fairly easy to interact with, you just search for lets say “apple pie” by firing this request:</p>
<figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">http://api.chefkoch.de/api/1.1/api-recipe-search.php?Suchbegriff=apple%20pie&amp;i=0&amp;z=1&amp;m=0&amp;o=0&amp;t=&amp;<span class="built_in">limit</span>=2</span><br></pre></td></tr></table></figure>
<p>… and will get a response like this one:</p>
<figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br></pre></td><td class="code"><pre><span class="line">&#123;<span class="string">"spellcheck"</span>:<span class="string">""</span>,<span class="string">"api"</span>:&#123;<span class="string">"version"</span>:<span class="number">1.1</span>&#125;,<span class="string">"total"</span>:<span class="number">48</span>,</span><br><span class="line">  <span class="string">"result"</span>:[</span><br><span class="line">    &#123;</span><br><span class="line">      <span class="string">"RezeptID"</span>:<span class="number">52749</span>,</span><br><span class="line">      <span class="string">"RezeptShowID"</span>:<span class="string">"527491149183211"</span>,</span><br><span class="line">      <span class="string">"RezeptName"</span>:<span class="string">"Apple Pie"</span>,</span><br><span class="line">      <span class="string">"RezeptName2"</span>:<span class="string">"Apfel \u0096Pie"</span>,</span><br><span class="line">      <span class="string">"Minuten"</span>:<span class="number">30</span>,</span><br><span class="line">      <span class="string">"Bild"</span>:<span class="literal">true</span>,</span><br><span class="line">      <span class="string">"Datum"</span>:<span class="string">"2006-06-01T19:36:12Z"</span>,</span><br><span class="line">      <span class="string">"SchwierigkeitsgradName"</span>:<span class="string">"simpel"</span>,</span><br><span class="line">      <span class="string">"user_id"</span>:<span class="string">"8617bcc7ecc7909ad61f52a52337f763"</span>,</span><br><span class="line">      <span class="string">"uservote_img"</span>:<span class="string">"3_5"</span>,</span><br><span class="line">      <span class="string">"RezeptBild"</span>:</span><br><span class="line">      <span class="string">"http:\/\/cdn.chefkoch.de\/ck.de\/rezepte\/52\/52749\/36051-thumbfix-apple-pie.jpg"</span>&#125;,</span><br><span class="line"></span><br><span class="line">    &#123;</span><br><span class="line">      <span class="string">"RezeptID"</span>:<span class="number">101077</span>,</span><br><span class="line">      <span class="string">"RezeptShowID"</span>:<span class="string">"1010771206206427"</span>,</span><br><span class="line">      <span class="string">"RezeptName"</span>:<span class="string">"Apple Pie"</span>,</span><br><span class="line">      <span class="string">"RezeptName2"</span>:<span class="string">"Mehl, Butter, Zucker, Zitronenschale (oder wahlweise eine Packung Citroback), Salz und die Eigelbe mischen und zu einem Teig ..."</span>,</span><br><span class="line">      <span class="string">"Minuten"</span>:<span class="number">45</span>,</span><br><span class="line">      <span class="string">"Bild"</span>:<span class="literal">false</span>,</span><br><span class="line">      <span class="string">"Datum"</span>:<span class="string">"2008-03-27T18:58:17Z"</span>,</span><br><span class="line">      <span class="string">"SchwierigkeitsgradName"</span>:<span class="string">"simpel"</span>,</span><br><span class="line">      <span class="string">"user_id"</span>:<span class="string">"3733fd403a13fb5f951c2369ae1acd22"</span>,</span><br><span class="line">      <span class="string">"uservote_img"</span>:<span class="string">"3_5"</span>&#125;</span><br><span class="line">  ]&#125;</span><br></pre></td></tr></table></figure>
<p>And this is how you can access the API with Ruby:</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br></pre></td><td class="code"><pre><span class="line"><span class="keyword">require</span> <span class="string">'net/http'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'json'</span></span><br><span class="line"><span class="keyword">require</span> <span class="string">'uri'</span></span><br><span class="line"></span><br><span class="line"><span class="class"><span class="keyword">module</span> <span class="title">ChefkochApi</span></span></span><br><span class="line">  @api_url = <span class="string">"http://api.chefkoch.de/api/1.0/api-recipe-search.php"</span></span><br><span class="line"></span><br><span class="line">  <span class="function"><span class="keyword">def</span> <span class="title">self</span>.<span class="title">search</span><span class="params">(search_text)</span></span></span><br><span class="line">    params = &#123;&#125;</span><br><span class="line">    params[<span class="string">"Suchbegriff"</span>] = search_text.strip</span><br><span class="line">    <span class="comment"># params["limit"] = 20 # you can pass the limit amount of results you like to receive</span></span><br><span class="line"></span><br><span class="line">    url = URI.parse @api_url</span><br><span class="line">    url.query = URI.encode_www_form(params)</span><br><span class="line"></span><br><span class="line">    response = Net::HTTP.get_response(url)</span><br><span class="line">    response.body</span><br><span class="line">    <span class="keyword">end</span></span><br><span class="line">  <span class="keyword">end</span></span><br></pre></td></tr></table></figure>
<p>Now you can invoke a recipe search by simply calling</p>
<figure class="highlight ruby"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ChefkochApi.search(<span class="string">"apple pie"</span>)</span><br></pre></td></tr></table></figure>
<p>That’s it for part one. In the next part I will try to modify the result and retrieve more detailed information from it like<br>ingredients and stuff.</p>
]]></content>
    <summary type="html">
    <![CDATA[<p>Driven by a seminar task at university we were free to create any kind of web/android/iphone app which takes care of<br>some contextual i]]>
    </summary>
    
      <category term="coding" scheme="http://pebra.net/tags/coding/"/>
    
      <category term="ruby" scheme="http://pebra.net/tags/ruby/"/>
    
      <category term="chefkoch.de" scheme="http://pebra.net/tags/chefkoch-de/"/>
    
      <category term="api" scheme="http://pebra.net/tags/api/"/>
    
      <category term="cooking" scheme="http://pebra.net/tags/cooking/"/>
    
  </entry>
  
</feed>
