<?xml version="1.0" encoding="UTF-8"?>
<feed
  xmlns="http://www.w3.org/2005/Atom"
  xmlns:thr="http://purl.org/syndication/thread/1.0"
  xml:lang="en"
   >
  <title type="text">Topdog.za.net</title>
  <subtitle type="text">A bored sysadmin</subtitle>

  <updated>2013-03-28T08:46:25Z</updated>
  <generator uri="http://blogofile.com/">Blogofile</generator>

  <link rel="alternate" type="text/html" href="http://www.topdog.za.net" />
  <id>http://www.topdog.za.net/feed/atom/</id>
  <link rel="self" type="application/atom+xml" href="http://www.topdog.za.net/feed/atom/" />
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Testing SSL client certificate authentication with curl]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/03/28/testing-ssl-client-certificate-authentication-with-curl" />
    <id>http://www.topdog.za.net/2013/03/28/testing-ssl-client-certificate-authentication-with-curl</id>
    <updated>2013-03-28T07:40:00Z</updated>
    <published>2013-03-28T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Security" />
    <summary type="html"><![CDATA[Testing SSL client certificate authentication with curl]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/03/28/testing-ssl-client-certificate-authentication-with-curl"><![CDATA[<p>When using SSL client certificate authentication you may need to
test it using command line tools.</p>
<p>To do so run the following command:</p>
<pre><code>curl -v -s -k --key client.key --cert client.pem https://servername
</code></pre>
<p>Thats it.</p>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Setup a OpenVPN server on Centos 6]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/02/02/setup-a-openvpn-server-on-centos-6" />
    <id>http://www.topdog.za.net/2013/02/02/setup-a-openvpn-server-on-centos-6</id>
    <updated>2013-02-02T07:40:00Z</updated>
    <published>2013-02-02T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Security" />
    <category scheme="http://www.topdog.za.net" term="Centos" />
    <summary type="html"><![CDATA[Setup a OpenVPN server on Centos 6]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/02/02/setup-a-openvpn-server-on-centos-6"><![CDATA[<h2>EPEL Repository</h2>
<p>OpenVPN 2 is available for Centos from the EPEL repository, so you
need to have EPEL enabled.</p>
<p>If you do not have EPEL enabled run:</p>
<pre><code>rpm -Uvh http://download.fedoraproject.org/pub/epel/6/i386/epel-release-6-8.noarch.rpm
</code></pre>
<h2>Installation</h2>
<p>To install OpenVPN run:</p>
<pre><code>yum install openvpn lzo -y
</code></pre>
<h2>Configuration</h2>
<p>Setup the SSL CA and keys:</p>
<pre><code>cp -r /usr/share/openvpn/easy-rsa/2.0 /etc/openvpn/open-rsa
</code></pre>
<p>Create and customize the <code>vars</code> file <code>/etc/openvpn/open-rsa/vars</code>,
Make sure you change the <code>KEY_</code> values to your own settings</p>
<div class="pygments_murphy"><pre><span class="nb">export </span><span class="nv">EASY_RSA</span><span class="o">=</span><span class="s2">&quot;`pwd`&quot;</span>
<span class="nb">export </span><span class="nv">OPENSSL</span><span class="o">=</span><span class="s2">&quot;openssl&quot;</span>
<span class="nb">export </span><span class="nv">PKCS11TOOL</span><span class="o">=</span><span class="s2">&quot;pkcs11-tool&quot;</span>
<span class="nb">export </span><span class="nv">GREP</span><span class="o">=</span><span class="s2">&quot;grep&quot;</span>
<span class="nb">export </span><span class="nv">KEY_CONFIG</span><span class="o">=</span><span class="sb">`</span><span class="nv">$EASY_RSA</span>/whichopensslcnf <span class="nv">$EASY_RSA</span><span class="sb">`</span>
<span class="nb">export </span><span class="nv">KEY_DIR</span><span class="o">=</span><span class="s2">&quot;/etc/openvpn/keys&quot;</span>
<span class="nb">echo </span>NOTE: If you run ./clean-all, I will be doing a rm -rf on <span class="nv">$KEY_DIR</span>
<span class="nb">export </span><span class="nv">PKCS11_MODULE_PATH</span><span class="o">=</span><span class="s2">&quot;dummy&quot;</span>
<span class="nb">export </span><span class="nv">PKCS11_PIN</span><span class="o">=</span><span class="s2">&quot;dummy&quot;</span>
<span class="nb">export </span><span class="nv">KEY_SIZE</span><span class="o">=</span>1024
<span class="nb">export </span><span class="nv">CA_EXPIRE</span><span class="o">=</span>3650
<span class="nb">export </span><span class="nv">KEY_EXPIRE</span><span class="o">=</span>3650
<span class="nb">export </span><span class="nv">KEY_COUNTRY</span><span class="o">=</span><span class="s2">&quot;ZA&quot;</span>
<span class="nb">export </span><span class="nv">KEY_PROVINCE</span><span class="o">=</span><span class="s2">&quot;Gauteng&quot;</span>
<span class="nb">export </span><span class="nv">KEY_CITY</span><span class="o">=</span><span class="s2">&quot;Johannesburg&quot;</span>
<span class="nb">export </span><span class="nv">KEY_ORG</span><span class="o">=</span><span class="s2">&quot;Topdog-software&quot;</span>
<span class="nb">export </span><span class="nv">KEY_EMAIL</span><span class="o">=</span><span class="s2">&quot;andrew@topdog.za.net&quot;</span>
<span class="nb">export </span><span class="nv">KEY_CN</span><span class="o">=</span><span class="s2">&quot;Topdog-software OpenVPN CA&quot;</span>
<span class="nb">export </span><span class="nv">KEY_NAME</span><span class="o">=</span><span class="s2">&quot;tdss&quot;</span>
<span class="nb">export </span><span class="nv">KEY_OU</span><span class="o">=</span><span class="s2">&quot;Topdog-software&quot;</span>
</pre></div>

<p>Create the keys directory:</p>
<pre><code>mkdir /etc/openvpn/keys
</code></pre>
<p>Create the CA:</p>
<pre><code>cd /etc/openvpn/open-rsa
source ./vars
./clean-all
./build-ca
</code></pre>
<p>Create the servers SSL certificate (replace <code>vpn.home.topdog-software.com</code> with
name of your server):</p>
<pre><code>./build-key-server vpn.home.topdog-software.com
</code></pre>
<p>Generate Diffie Hellman parameters:</p>
<pre><code>./build-dh
</code></pre>
<p>Create the leases file:</p>
<pre><code>touch /etc/openvpn/ipp.txt
</code></pre>
<p>Create the configuration file <code>/etc/openvpn/server.conf</code>:</p>
<div class="pygments_murphy"><pre>port 1194
proto udp
dev tun
ca keys/ca.crt
cert keys/vpn.home.topdog-software.com.crt
key keys/vpn.home.topdog-software.com.key
dh keys/dh1024.pem
cipher AES-128-CBC
server 10.0.0.0 255.255.255.0
ifconfig-pool-persist ipp.txt
client-config-dir ccd
keepalive 10 120
comp-lzo
persist-key
persist-tun
status /var/log/openvpn-status.log
verb 3
</pre></div>

<p>Create iptables rules to allow traffic through:</p>
<div class="pygments_murphy"><pre>*filter
..
..
-A INPUT -p udp -m state --state NEW -m udp --dport 1194 -j ACCEPT
-A FORWARD -i tun+ -o eth0 -j ACCEPT
-A FORWARD -i eth0 -o tun+ -j ACCEPT
</pre></div>

<p>Enable packet forwarding:</p>
<pre><code>echo 1 &gt; /proc/sys/net/ipv4/ip_forward
</code></pre>
<p>Make it permanent add the following to <code>/etc/sysctl.conf</code>:</p>
<div class="pygments_murphy"><pre>net.ipv4.ip_forward = 1
</pre></div>

<p>Your OpenVPN should be ready to go, start OpenVPN:</p>
<pre><code>service openvpn start
</code></pre>
<h2>Client configuration</h2>
<p>Each client requires a certificate &amp; key pairing, lets create one:</p>
<pre><code>./build-key client1.home.topdog-software.com
</code></pre>
<p>Copy the <code>client1.home.topdog-software.com.crt</code>, <code>ca.crt</code> and
<code>client1.home.topdog-software.com.key</code> files to the OpenVPN keys
directory on the client.</p>
<p>Create the client OpenVPN configuration <code>/etc/openvpn/server.conf</code>:</p>
<div class="pygments_murphy"><pre>remote vpn.home.topdog-software.com 1194
client 
remote-cert-tls server 
dev tun0 
proto udp
resolv-retry infinite 
nobind 
persist-key 
persist-tun 
float 
ca keys/ca.crt 
cert keys/client1.home.topdog-software.com.crt
key keys/client1.home.topdog-software.com.key
cipher AES-128-CBC
comp-lzo
status /var/log/openvpn-client.log
</pre></div>

<h2>Static addresses</h2>
<p>If you want some clients to get static addresses:</p>
<pre><code>mkdir /etc/openvpn/ccd
</code></pre>
<p>Create a client file for each of the clients you want to get a static
address in <code>/etc/openvpn/ccd</code> the file name should match the CN in
the client certificate.</p>
<div class="pygments_murphy"><pre>ifconfig-push 10.0.0.2 10.0.0.1
</pre></div>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Centos 6 Bonded network interfaces]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/02/01/centos-6-bonded-network-interfaces" />
    <id>http://www.topdog.za.net/2013/02/01/centos-6-bonded-network-interfaces</id>
    <updated>2013-02-01T07:40:00Z</updated>
    <published>2013-02-01T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Centos" />
    <summary type="html"><![CDATA[Centos 6 Bonded network interfaces]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/02/01/centos-6-bonded-network-interfaces"><![CDATA[<p>Bonding allows you to aggregate multiple ports, providing redundancy,
fault tolerance and load balancing.</p>
<p>There are various types of bonding available but i will show how to
bond in mode 1 which is active-backup. If your interested in the other
available types please refer to the
<a href="https://www.kernel.org/doc/Documentation/networking/bonding.txt">documentation</a>.</p>
<p>In this setup i have two connections to different switches in case one
fails the other takes over and services are not disrupted.</p>
<h2>Setup bonded interface</h2>
<p>Create a file in /etc/modprobe.d called bond.conf and add the following</p>
<div class="pygments_murphy"><pre><span class="nb">alias </span>bond0 bonding
</pre></div>

<p>Create the bonded interface file /etc/sysconfig/network-scripts/ifcfg-bond0
with the following contents</p>
<div class="pygments_murphy"><pre><span class="nv">DEVICE</span><span class="o">=</span>bond0
<span class="nv">IPADDR</span><span class="o">=</span>xxx.xxx.xxx.xxx
<span class="nv">NETMASK</span><span class="o">=</span>xxx.xxx.xxx.xxx
<span class="nv">ONBOOT</span><span class="o">=</span>yes
<span class="nv">BOOTPROTO</span><span class="o">=</span>none
<span class="nv">USERCTL</span><span class="o">=</span>no
<span class="nv">BONDING_OPTS</span><span class="o">=</span><span class="s2">&quot;bond0 miimon=80 mode=1&quot;</span>
</pre></div>

<p>Modify the interfaces you want to bond to look like:</p>
<div class="pygments_murphy"><pre><span class="nv">DEVICE</span><span class="o">=</span>ethX
<span class="nv">ONBOOT</span><span class="o">=</span>yes
<span class="nv">BOOTPROTO</span><span class="o">=</span>none
<span class="nv">USERCTL</span><span class="o">=</span>no
<span class="nv">MASTER</span><span class="o">=</span>bond0
<span class="nv">SLAVE</span><span class="o">=</span>yes
</pre></div>

<p>Restart networking for the changes to take effect:</p>
<pre><code>service network restart
</code></pre>
<h2>Checking the status</h2>
<p>You can check the status of the interface by running:</p>
<pre><code>cat /proc/net/bonding/bond0
</code></pre>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Commandline OpenVPN client on Mac OSX with macports]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/01/31/commandline-openvpn-client-on-mac-osx-with-macports" />
    <id>http://www.topdog.za.net/2013/01/31/commandline-openvpn-client-on-mac-osx-with-macports</id>
    <updated>2013-01-31T07:40:00Z</updated>
    <published>2013-01-31T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Mac OS X" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Security" />
    <category scheme="http://www.topdog.za.net" term="Unix" />
    <summary type="html"><![CDATA[Commandline OpenVPN client on Mac OSX with macports]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/01/31/commandline-openvpn-client-on-mac-osx-with-macports"><![CDATA[<p>Most people use TunnelBrick to setup OpenVPN client connections on Mac OSX,
i prefer using the command line.</p>
<p>To get OpenVPN up and running off the command line is a simple process. The
commands below need to be run as a privileged user if your root account is
not enabled use sudo to run the commands.</p>
<h2>Install OpenVPN</h2>
<p>To install OpenVPN 2 from macports run:</p>
<pre><code>port install openvpn2
</code></pre>
<h2>Install TunTap</h2>
<p>To install <a href="http://tuntaposx.sourceforge.net/">TunTap</a> from macports run:</p>
<pre><code>port install tuntaposx
</code></pre>
<p>Configure it to startup at boot:</p>
<pre><code>launchctl load -w /Library/LaunchDaemons/org.macports.tuntaposx.plist
</code></pre>
<p>You need <a href="http://tuntaposx.sourceforge.net/">TunTap</a> as it allows you
to create virtual interfaces using the supplied kernel extensions.
If you don't install TunTap you will get the error
<em>Cannot allocate TUN/TAP dev dynamically</em> when you try and make a
OpenVPN connection.</p>
<h2>Configuration</h2>
<p>Create a directory to hold your configuration and keys.</p>
<pre><code>mkdir /opt/local/etc/openvpn
</code></pre>
<p>Place your keys and configuration files in /opt/local/etc/openvpn/</p>
<p>A sample client configuration is provided below.</p>
<div class="pygments_murphy"><pre>client
dev tun
proto udp
remote vpn.home.topdog-software.com 1194
nobind
resolv-retry infinite
tls-client
ca /opt/local/etc/openvpn/ca.crt
cert /opt/local/etc/openvpn/client.crt
key /opt/local/etc/openvpn/client.key
ns-cert-type server
cipher BF-CBC
tls-cipher DHE-RSA-AES256-SHA
tls-remote vpn.home.topdog-software.com
tls-auth /opt/local/etc/openvpn/tls-auth.key 1
remote-cert-tls server
comp-lzo
persist-key
persist-tun
mute-replay-warnings
verb 3
mlock
</pre></div>

<h2>Connecting</h2>
<p>To connect simply run:</p>
<pre><code>openvpn2 --config /opt/local/etc/openvpn/openvpn.conf
</code></pre>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Automating translation of software using the Microsoft Translator and Python]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/01/25/automating-translation-of-software-using-the-microsoft-translator-and-python" />
    <id>http://www.topdog.za.net/2013/01/25/automating-translation-of-software-using-the-microsoft-translator-and-python</id>
    <updated>2013-01-25T07:40:00Z</updated>
    <published>2013-01-25T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Unix" />
    <category scheme="http://www.topdog.za.net" term="Linux" />
    <summary type="html"><![CDATA[Automating translation of software using the Microsoft Translator and Python]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/01/25/automating-translation-of-software-using-the-microsoft-translator-and-python"><![CDATA[<p>The <a href="http://msdn.microsoft.com/en-us/library/dd576287.aspx">Microsoft translator</a> provides an
API that you can use for automated translation. It currently supports about 39 languages.</p>
<p>True to the nature of open source i found that someone had already written
a <a href="https://github.com/openlabs/Microsoft-Translator-Python-API">python wrapper</a>
to the API. I extended the wrapper to use the <a href="http://docs.python-requests.org/en/latest/">requests</a>
and <a href="http://polib.readthedocs.org/en/latest/">pofile</a> packages.</p>
<p>My extended script is able to read gettext Portable Object <code>PO</code> source files and translate
the strings and write the translations back into <code>PO</code> files, here by automating the whole
translation process.</p>
<h2>Source</h2>
<div class="pygments_murphy"><pre><span class="c">#!/usr/bin/env python</span>
<span class="c"># -*- coding: utf-8 -*-</span>
<span class="c"># vim: ai ts=4 sts=4 et sw=4</span>

<span class="sd">&quot;&quot;&quot;Automatic translation using m$ translator</span>
<span class="sd">    :copyright: 2012 Andrew Colin Kissa</span>
<span class="sd">    :copyright: 2011 by Openlabs Technologies &amp; Consulting (P) Limited</span>
<span class="sd">    :license: BSD, see LICENSE for more details.</span>
<span class="sd">&quot;&quot;&quot;</span>

<span class="kn">import</span> <span class="nn">os</span>
<span class="kn">import</span> <span class="nn">re</span>
<span class="kn">import</span> <span class="nn">json</span>
<span class="kn">import</span> <span class="nn">time</span>
<span class="kn">import</span> <span class="nn">urllib</span>
<span class="kn">import</span> <span class="nn">logging</span>
<span class="kn">import</span> <span class="nn">datetime</span>

<span class="kn">import</span> <span class="nn">requests</span>

<span class="kn">from</span> <span class="nn">optparse</span> <span class="kn">import</span> <span class="n">OptionParser</span>

<span class="kn">from</span> <span class="nn">polib</span> <span class="kn">import</span> <span class="n">pofile</span>

<span class="n">__all__</span> <span class="o">=</span> <span class="p">[</span><span class="s">&#39;Translator&#39;</span><span class="p">,</span> <span class="s">&#39;TranslateApiException&#39;</span><span class="p">]</span>

<span class="k">class</span> <span class="nc">ArgumentException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Argument&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;ArgumentException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ArgumentException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">ArgumentOutOfRangeException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;ArgumentOutOfRange&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;ArgumentOutOfRangeException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">ArgumentOutOfRangeException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">TranslateApiException</span><span class="p">(</span><span class="ne">Exception</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;TranslateApi&quot;&quot;&quot;</span>
    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">message</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">):</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">message</span> <span class="o">=</span> <span class="n">message</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;TranslateApiException: &#39;</span><span class="p">,</span> <span class="s">&#39;&#39;</span><span class="p">)</span>
        <span class="nb">super</span><span class="p">(</span><span class="n">TranslateApiException</span><span class="p">,</span> <span class="bp">self</span><span class="p">)</span><span class="o">.</span><span class="n">__init__</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">message</span><span class="p">,</span> <span class="o">*</span><span class="n">args</span><span class="p">)</span>

<span class="k">class</span> <span class="nc">Translator</span><span class="p">(</span><span class="nb">object</span><span class="p">):</span>
    <span class="sd">&quot;&quot;&quot;Implements AJAX API for the Microsoft Translator service</span>
<span class="sd">    </span>
<span class="sd">    &quot;&quot;&quot;</span>
    <span class="n">lang_url</span> <span class="o">=</span> <span class="s">&#39;http://api.microsofttranslator.com/V2/Ajax.svc/GetLanguagesForTranslate&#39;</span>
    <span class="n">oauth_url</span> <span class="o">=</span> <span class="s">&#39;https://datamarket.accesscontrol.windows.net/v2/OAuth2-13&#39;</span>
    <span class="n">translate_url</span> <span class="o">=</span> <span class="s">&quot;http://api.microsofttranslator.com/V2/Ajax.svc/Translate&quot;</span>
    <span class="n">translate_array_url</span> <span class="o">=</span> <span class="s">&quot;http://api.microsofttranslator.com/V2/Ajax.svc/TranslateArray&quot;</span>

    <span class="k">def</span> <span class="nf">__init__</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">client_secret</span><span class="p">,</span>
            <span class="n">scope</span><span class="o">=</span><span class="s">&quot;http://api.microsofttranslator.com&quot;</span><span class="p">,</span> <span class="n">debug</span><span class="o">=</span><span class="bp">False</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>

<span class="sd">        :param client_id: The client ID that you specified when you registered</span>
<span class="sd">                          your application with Azure DataMarket.</span>
<span class="sd">        :param client_secret: The client secret value that you obtained when</span>
<span class="sd">                              you registered your application with Azure</span>
<span class="sd">                              DataMarket.</span>
<span class="sd">        :param scope: Defaults to http://api.microsofttranslator.com</span>
<span class="sd">        :param debug: If true, the logging level will be set to debug</span>
<span class="sd">        &quot;&quot;&quot;</span>

        <span class="bp">self</span><span class="o">.</span><span class="n">client_id</span> <span class="o">=</span> <span class="n">client_id</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">client_secret</span> <span class="o">=</span> <span class="n">client_secret</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">scope</span> <span class="o">=</span> <span class="n">scope</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">grant_type</span> <span class="o">=</span> <span class="s">&quot;client_credentials&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">debug</span> <span class="o">=</span> <span class="n">debug</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">logger</span> <span class="o">=</span> <span class="n">logging</span><span class="o">.</span><span class="n">getLogger</span><span class="p">(</span><span class="s">&quot;microsofttranslator&quot;</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="bp">None</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">langs</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="k">if</span> <span class="bp">self</span><span class="o">.</span><span class="n">debug</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">logger</span><span class="o">.</span><span class="n">setLevel</span><span class="p">(</span><span class="n">level</span><span class="o">=</span><span class="n">logging</span><span class="o">.</span><span class="n">DEBUG</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">create_session</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="s">&quot;create a requests session&quot;</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">session</span><span class="p">()</span>

    <span class="k">def</span> <span class="nf">get_access_token</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">force</span><span class="o">=</span><span class="bp">None</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;</span>
<span class="sd">        .. note::</span>
<span class="sd">            The value of access token can be used for subsequent calls to the</span>
<span class="sd">            Microsoft Translator API. The access token expires after 10</span>
<span class="sd">            minutes. It is always better to check elapsed time between time at</span>
<span class="sd">            which token issued and current time. If elapsed time exceeds 10</span>
<span class="sd">            minute time period renew access token by following obtaining</span>
<span class="sd">            access token procedure.</span>

<span class="sd">        :return: The access token to be used with subsequent requests</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">args</span> <span class="o">=</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">({</span>
            <span class="s">&#39;client_id&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">client_id</span><span class="p">,</span>
            <span class="s">&#39;client_secret&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">client_secret</span><span class="p">,</span>
            <span class="s">&#39;scope&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">scope</span><span class="p">,</span>
            <span class="s">&#39;grant_type&#39;</span><span class="p">:</span> <span class="bp">self</span><span class="o">.</span><span class="n">grant_type</span>
        <span class="p">})</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span> <span class="ow">or</span> <span class="n">force</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="n">response</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">post</span><span class="p">(</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">oauth_url</span><span class="p">,</span>
            <span class="n">data</span><span class="o">=</span><span class="n">args</span>
        <span class="p">)</span><span class="o">.</span><span class="n">content</span><span class="p">)</span>
        <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="n">response</span><span class="p">[</span><span class="s">&#39;access_token&#39;</span><span class="p">]</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span>

    <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">url</span><span class="p">,</span> <span class="n">params</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Calls the given url with the params urlencoded</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">get_access_token</span><span class="p">()</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="n">headers</span> <span class="o">=</span> <span class="p">{</span><span class="s">&#39;Authorization&#39;</span><span class="p">:</span> <span class="s">&#39;Bearer </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span><span class="p">}</span>
        <span class="n">translation_url</span> <span class="o">=</span> <span class="s">&#39;</span><span class="si">%s</span><span class="s">?</span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">urllib</span><span class="o">.</span><span class="n">urlencode</span><span class="p">(</span><span class="n">params</span><span class="p">))</span>
        <span class="n">response</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">translation_url</span><span class="p">,</span> <span class="n">headers</span><span class="o">=</span><span class="n">headers</span><span class="p">)</span>
        <span class="n">retval</span> <span class="o">=</span> <span class="n">json</span><span class="o">.</span><span class="n">loads</span><span class="p">(</span><span class="n">response</span><span class="o">.</span><span class="n">content</span><span class="o">.</span><span class="n">decode</span><span class="p">(</span><span class="s">&quot;UTF-8-sig&quot;</span><span class="p">))</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;ArgumentOutOfRangeException&quot;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="n">ArgumentOutOfRangeException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;TranslateApiException&quot;</span><span class="p">):</span>
            <span class="k">raise</span> <span class="n">TranslateApiException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">if</span> <span class="nb">isinstance</span><span class="p">(</span><span class="n">retval</span><span class="p">,</span> <span class="nb">basestring</span><span class="p">)</span> <span class="ow">and</span> \
                <span class="n">retval</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s">&quot;ArgumentException&quot;</span><span class="p">):</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">access_token</span> <span class="o">=</span> <span class="bp">None</span>
            <span class="k">raise</span> <span class="n">ArgumentException</span><span class="p">(</span><span class="n">retval</span><span class="p">)</span>

        <span class="k">return</span> <span class="n">retval</span>

    <span class="k">def</span> <span class="nf">languages</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Check languages supported&quot;&quot;&quot;</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">session</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">create_session</span><span class="p">()</span>

        <span class="k">if</span> <span class="ow">not</span> <span class="bp">self</span><span class="o">.</span><span class="n">langs</span><span class="p">:</span>
            <span class="bp">self</span><span class="o">.</span><span class="n">langs</span> <span class="o">=</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">lang_url</span><span class="p">,</span> <span class="p">{})</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">langs</span>

    <span class="k">def</span> <span class="nf">translate</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">text</span><span class="p">,</span> <span class="n">to_lang</span><span class="p">,</span> <span class="n">from_lang</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span>
            <span class="n">content_type</span><span class="o">=</span><span class="s">&#39;text/plain&#39;</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Translates a text string from one language to another.</span>

<span class="sd">        :param text: A string representing the text to translate.</span>
<span class="sd">        :param to_lang: A string representing the language code to</span>
<span class="sd">            translate the text into.</span>
<span class="sd">        :param from_lang: A string representing the language code of the</span>
<span class="sd">            translation text. If left None the response will include the</span>
<span class="sd">            result of language auto-detection. (Default: None)</span>
<span class="sd">        :param content_type: The format of the text being translated.</span>
<span class="sd">            The supported formats are &quot;text/plain&quot; and &quot;text/html&quot;. Any HTML</span>
<span class="sd">            needs to be well-formed.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;text&#39;</span><span class="p">:</span> <span class="n">text</span><span class="o">.</span><span class="n">encode</span><span class="p">(</span><span class="s">&#39;utf8&#39;</span><span class="p">),</span>
            <span class="s">&#39;to&#39;</span><span class="p">:</span> <span class="n">to_lang</span><span class="p">,</span>
            <span class="s">&#39;contentType&#39;</span><span class="p">:</span> <span class="n">content_type</span><span class="p">,</span>
            <span class="s">&#39;category&#39;</span><span class="p">:</span> <span class="s">&#39;general&#39;</span><span class="p">,</span>
            <span class="p">}</span>
        <span class="k">if</span> <span class="n">from_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">params</span><span class="p">[</span><span class="s">&#39;from&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">from_lang</span>
        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">translate_url</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>

    <span class="k">def</span> <span class="nf">translate_array</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">texts</span><span class="p">,</span> <span class="n">to_lang</span><span class="p">,</span> <span class="n">from_lang</span><span class="o">=</span><span class="bp">None</span><span class="p">,</span> <span class="o">**</span><span class="n">options</span><span class="p">):</span>
        <span class="sd">&quot;&quot;&quot;Translates an array of text strings from one language to another.</span>

<span class="sd">        :param texts: A list containing texts for translation.</span>
<span class="sd">        :param to_lang: A string representing the language code to </span>
<span class="sd">            translate the text into.</span>
<span class="sd">        :param from_lang: A string representing the language code of the </span>
<span class="sd">            translation text. If left None the response will include the </span>
<span class="sd">            result of language auto-detection. (Default: None)</span>
<span class="sd">        :param options: A TranslateOptions element containing the values below. </span>
<span class="sd">            They are all optional and default to the most common settings.</span>

<span class="sd">                Category: A string containing the category (domain) of the </span>
<span class="sd">                    translation. Defaults to &quot;general&quot;.</span>
<span class="sd">                ContentType: The format of the text being translated. The </span>
<span class="sd">                    supported formats are &quot;text/plain&quot; and &quot;text/html&quot;. Any </span>
<span class="sd">                    HTML needs to be well-formed.</span>
<span class="sd">                Uri: A string containing the content location of this </span>
<span class="sd">                    translation.</span>
<span class="sd">                User: A string used to track the originator of the submission.</span>
<span class="sd">                State: User state to help correlate request and response. The </span>
<span class="sd">                    same contents will be returned in the response.</span>
<span class="sd">        &quot;&quot;&quot;</span>
        <span class="n">options</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;Category&#39;</span><span class="p">:</span> <span class="s">&quot;general&quot;</span><span class="p">,</span>
            <span class="s">&#39;Contenttype&#39;</span><span class="p">:</span> <span class="s">&quot;text/plain&quot;</span><span class="p">,</span>
            <span class="s">&#39;Uri&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span><span class="p">,</span>
            <span class="s">&#39;User&#39;</span><span class="p">:</span> <span class="s">&#39;default&#39;</span><span class="p">,</span>
            <span class="s">&#39;State&#39;</span><span class="p">:</span> <span class="s">&#39;&#39;</span>
            <span class="p">}</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">options</span><span class="p">)</span>
        <span class="n">params</span> <span class="o">=</span> <span class="p">{</span>
            <span class="s">&#39;texts&#39;</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">texts</span><span class="p">),</span>
            <span class="s">&#39;to&#39;</span><span class="p">:</span> <span class="n">to_lang</span><span class="p">,</span>
            <span class="s">&#39;options&#39;</span><span class="p">:</span> <span class="n">json</span><span class="o">.</span><span class="n">dumps</span><span class="p">(</span><span class="n">options</span><span class="p">),</span>
            <span class="p">}</span>
        <span class="k">if</span> <span class="n">from_lang</span> <span class="ow">is</span> <span class="ow">not</span> <span class="bp">None</span><span class="p">:</span>
            <span class="n">params</span><span class="p">[</span><span class="s">&#39;from&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">from_lang</span>

        <span class="k">return</span> <span class="bp">self</span><span class="o">.</span><span class="n">call</span><span class="p">(</span><span class="bp">self</span><span class="o">.</span><span class="n">translate_array_url</span><span class="p">,</span> <span class="n">params</span><span class="p">)</span>

<span class="k">def</span> <span class="nf">format_date</span><span class="p">():</span>
    <span class="s">&quot;Return a date string in required format&quot;</span>
    <span class="k">return</span> <span class="n">time</span><span class="o">.</span><span class="n">strftime</span><span class="p">(</span><span class="s">&quot;%Y-%m-</span><span class="si">%d</span><span class="s"> %R+0200&quot;</span><span class="p">,</span> <span class="n">time</span><span class="o">.</span><span class="n">strptime</span><span class="p">(</span><span class="n">time</span><span class="o">.</span><span class="n">ctime</span><span class="p">()))</span>

<span class="k">def</span> <span class="nf">first_pass</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="n">thestring</span><span class="p">):</span>
    <span class="s">&quot;replace </span><span class="si">%(xxx)s</span><span class="s"> vars&quot;</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">thestring</span> <span class="o">=</span> <span class="n">thestring</span><span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="n">item</span><span class="p">,</span> <span class="s">&#39;|^^|&#39;</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">thestring</span>

<span class="k">def</span> <span class="nf">second_pass</span><span class="p">(</span><span class="n">items</span><span class="p">,</span> <span class="n">thestring</span><span class="p">):</span>
    <span class="s">&quot;replace </span><span class="si">%s</span><span class="s"> with actual </span><span class="si">%(xxx)s</span><span class="s">&quot;</span>
    <span class="k">for</span> <span class="n">item</span> <span class="ow">in</span> <span class="n">items</span><span class="p">:</span>
        <span class="n">thestring</span> <span class="o">=</span> <span class="n">thestring</span>\
                    <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;|^^|&#39;</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>\
                    <span class="o">.</span><span class="n">replace</span><span class="p">(</span><span class="s">&#39;| ^ ^ |&#39;</span><span class="p">,</span> <span class="n">item</span><span class="p">,</span> <span class="mi">1</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">thestring</span>

<span class="k">def</span> <span class="nf">getpofs</span><span class="p">(</span><span class="n">matched</span><span class="p">,</span> <span class="n">dirname</span><span class="p">,</span> <span class="n">files</span><span class="p">):</span>
    <span class="s">&quot;utility to get po files&quot;</span>
    <span class="n">matched</span><span class="o">.</span><span class="n">extend</span><span class="p">([</span><span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">dirname</span><span class="p">,</span> <span class="n">filename</span><span class="p">)</span>
                    <span class="k">for</span> <span class="n">filename</span> <span class="ow">in</span> <span class="n">files</span>
                    <span class="k">if</span> <span class="n">filename</span><span class="o">.</span><span class="n">endswith</span><span class="p">(</span><span class="s">&#39;.po&#39;</span><span class="p">)])</span>

<span class="k">def</span> <span class="nf">get_lang</span><span class="p">(</span><span class="n">dirname</span><span class="p">):</span>
    <span class="s">&quot;Get the language from directory name&quot;</span>
    <span class="k">return</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">basename</span><span class="p">(</span>
                <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span>
                    <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">dirname</span><span class="p">(</span><span class="n">dirname</span><span class="p">)</span>
                <span class="p">)</span>
            <span class="p">)</span>

<span class="k">def</span> <span class="nf">process</span><span class="p">(</span><span class="n">translator</span><span class="p">,</span> <span class="n">raw_entry</span><span class="p">,</span> <span class="n">language</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">regex</span><span class="p">):</span>
    <span class="s">&quot;Process and Translate the string&quot;</span>
    <span class="n">languages_bidi</span> <span class="o">=</span> <span class="p">[</span><span class="s">&quot;he&quot;</span><span class="p">,</span> <span class="s">&quot;ar&quot;</span><span class="p">,</span> <span class="s">&quot;fa&quot;</span><span class="p">,</span> <span class="s">&quot;yi&quot;</span><span class="p">]</span>
    <span class="n">found</span> <span class="o">=</span> <span class="n">regex</span><span class="o">.</span><span class="n">findall</span><span class="p">(</span><span class="n">raw_entry</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
        <span class="k">if</span> <span class="n">language</span> <span class="ow">in</span> <span class="n">languages_bidi</span><span class="p">:</span>
            <span class="k">return</span> <span class="bp">None</span>
        <span class="n">raw_entry</span> <span class="o">=</span> <span class="n">first_pass</span><span class="p">(</span><span class="n">found</span><span class="p">,</span> <span class="n">raw_entry</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">&gt;=</span> <span class="n">sentry</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Renewing token&quot;</span>
        <span class="n">translator</span><span class="o">.</span><span class="n">get_access_token</span><span class="p">(</span><span class="bp">True</span><span class="p">)</span>
        <span class="n">sentry</span> <span class="o">=</span> <span class="p">(</span><span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span>
                <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">8</span><span class="p">))</span>
    <span class="n">new_entry</span> <span class="o">=</span> <span class="n">translator</span><span class="o">.</span><span class="n">translate</span><span class="p">(</span><span class="n">raw_entry</span><span class="p">,</span> <span class="n">language</span><span class="p">)</span>
    <span class="k">if</span> <span class="n">found</span><span class="p">:</span>
        <span class="n">new_entry</span> <span class="o">=</span> <span class="n">second_pass</span><span class="p">(</span><span class="n">found</span><span class="p">,</span> <span class="n">new_entry</span><span class="p">)</span>
    <span class="k">return</span> <span class="n">new_entry</span>

<span class="k">def</span> <span class="nf">createps</span><span class="p">(</span><span class="n">filename</span><span class="p">,</span> <span class="n">client_id</span><span class="p">,</span> <span class="n">api_key</span><span class="p">,</span> <span class="n">meta</span><span class="p">,</span> <span class="n">default_lang</span><span class="p">):</span>
    <span class="s">&quot;update po file&quot;</span>
    <span class="n">do_save</span> <span class="o">=</span> <span class="bp">False</span>
    <span class="n">trans</span> <span class="o">=</span> <span class="n">Translator</span><span class="p">(</span><span class="n">client_id</span><span class="p">,</span> <span class="n">api_key</span><span class="p">)</span>
    <span class="k">print</span> <span class="s">&quot;Processing: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="n">filename</span>
    <span class="n">pobj</span> <span class="o">=</span> <span class="n">pofile</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
    <span class="n">lang</span> <span class="o">=</span> <span class="n">get_lang</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>

    <span class="k">if</span> <span class="p">(</span><span class="ow">not</span> <span class="n">lang</span> <span class="ow">in</span> <span class="n">trans</span><span class="o">.</span><span class="n">languages</span><span class="p">()</span> <span class="ow">or</span> <span class="n">lang</span> <span class="o">==</span> <span class="n">default_lang</span><span class="p">)</span> <span class="ow">and</span> <span class="n">lang</span> <span class="o">!=</span> <span class="s">&#39;zh&#39;</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Language: </span><span class="si">%s</span><span class="s"> not supported by API&quot;</span> <span class="o">%</span> <span class="n">lang</span>
        <span class="k">return</span>

    <span class="k">try</span><span class="p">:</span>
        <span class="n">match_re</span> <span class="o">=</span> <span class="n">re</span><span class="o">.</span><span class="n">compile</span><span class="p">(</span><span class="s">r&#39;((?:%\([^\W]{1,}\)(?:s|d))|(?:{{\w+}}))&#39;</span><span class="p">)</span>
        <span class="n">sentry</span> <span class="o">=</span> <span class="n">datetime</span><span class="o">.</span><span class="n">datetime</span><span class="o">.</span><span class="n">now</span><span class="p">()</span> <span class="o">+</span> <span class="n">datetime</span><span class="o">.</span><span class="n">timedelta</span><span class="p">(</span><span class="n">minutes</span><span class="o">=</span><span class="mi">8</span><span class="p">)</span>
        <span class="k">if</span> <span class="n">lang</span> <span class="o">==</span> <span class="s">&#39;zh&#39;</span><span class="p">:</span>
            <span class="n">lang</span> <span class="o">=</span> <span class="s">&#39;zh-CHS&#39;</span>
        <span class="k">for</span> <span class="n">entry</span> <span class="ow">in</span> <span class="n">pobj</span><span class="o">.</span><span class="n">untranslated_entries</span><span class="p">():</span>
            <span class="k">try</span><span class="p">:</span>
                <span class="n">msgstr</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">trans</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid</span><span class="p">,</span> <span class="n">lang</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">match_re</span><span class="p">)</span>
                <span class="k">if</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid_plural</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">msgstr</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr_plural</span><span class="p">[</span><span class="s">&#39;0&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">msgstr</span>
                    <span class="n">msgstr_plural</span> <span class="o">=</span> <span class="n">process</span><span class="p">(</span><span class="n">trans</span><span class="p">,</span> <span class="n">entry</span><span class="o">.</span><span class="n">msgid_plural</span><span class="p">,</span>
                                            <span class="n">lang</span><span class="p">,</span> <span class="n">sentry</span><span class="p">,</span> <span class="n">match_re</span><span class="p">)</span>
                    <span class="k">if</span> <span class="n">msgstr_plural</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr_plural</span><span class="p">[</span><span class="s">&#39;1&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">msgstr_plural</span>
                <span class="k">else</span><span class="p">:</span>
                    <span class="k">if</span> <span class="n">msgstr</span><span class="p">:</span>
                        <span class="n">entry</span><span class="o">.</span><span class="n">msgstr</span> <span class="o">=</span> <span class="n">msgstr</span>
                <span class="n">do_save</span> <span class="o">=</span> <span class="bp">True</span>
            <span class="k">except</span> <span class="p">(</span><span class="n">TranslateApiException</span><span class="p">,</span> <span class="n">ArgumentOutOfRangeException</span><span class="p">),</span> <span class="n">ermsg</span><span class="p">:</span>
                <span class="k">print</span> <span class="s">&#39;Error occured: </span><span class="si">%s</span><span class="s">&#39;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">ermsg</span><span class="p">)</span>

        <span class="k">if</span> <span class="n">do_save</span><span class="p">:</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">metadata</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">meta</span><span class="p">)</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">metadata</span><span class="p">[</span><span class="s">&#39;PO-Revision-Date&#39;</span><span class="p">]</span> <span class="o">=</span> <span class="n">format_date</span><span class="p">()</span>
            <span class="n">pobj</span><span class="o">.</span><span class="n">save</span><span class="p">(</span><span class="n">filename</span><span class="p">)</span>
    <span class="k">except</span> <span class="n">ArgumentException</span><span class="p">,</span> <span class="n">errstr</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;Access Error: </span><span class="si">%s</span><span class="s">&quot;</span> <span class="o">%</span> <span class="nb">str</span><span class="p">(</span><span class="n">errstr</span><span class="p">)</span>

<span class="k">if</span> <span class="n">__name__</span> <span class="o">==</span> <span class="s">&#39;__main__&#39;</span><span class="p">:</span>
    <span class="c"># Run tings mon</span>

    <span class="n">CLIENT_ID</span> <span class="o">=</span> <span class="s">&#39;xxxxx&#39;</span>
    <span class="n">API_KEY</span> <span class="o">=</span> <span class="s">&#39;xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx&#39;</span>

    <span class="n">metadata</span> <span class="o">=</span> <span class="p">{</span>
        <span class="s">&#39;Report-Msgid-Bugs-To&#39;</span><span class="p">:</span> <span class="s">&#39;baruwa@lists.baruwa.org&#39;</span><span class="p">,</span>
        <span class="s">&#39;Last-Translator&#39;</span><span class="p">:</span> <span class="s">&#39;Andrew Colin Kissa &lt;andrew@topdog.za.net&gt;&#39;</span><span class="p">,</span>
        <span class="s">&#39;Generated-By&#39;</span><span class="p">:</span> <span class="s">&#39;auto-translate.py 0.0.1&#39;</span><span class="p">,</span>
        <span class="s">&#39;Language-Team&#39;</span><span class="p">:</span> <span class="s">&#39;Baruwa Project&#39;</span><span class="p">,</span>
    <span class="p">}</span>

    <span class="n">usage</span> <span class="o">=</span> <span class="s">&quot;usage: %prog directory&quot;</span>
    <span class="n">parser</span> <span class="o">=</span> <span class="n">OptionParser</span><span class="p">(</span><span class="n">usage</span><span class="p">)</span>
    <span class="n">parser</span><span class="o">.</span><span class="n">add_option</span><span class="p">(</span><span class="s">&#39;-s&#39;</span><span class="p">,</span> <span class="s">&#39;--source&#39;</span><span class="p">,</span> <span class="n">dest</span><span class="o">=</span><span class="s">&quot;source_lang&quot;</span><span class="p">,</span> <span class="n">default</span><span class="o">=</span><span class="s">&quot;en&quot;</span><span class="p">)</span>
    <span class="n">opts</span><span class="p">,</span> <span class="n">arguments</span> <span class="o">=</span> <span class="n">parser</span><span class="o">.</span><span class="n">parse_args</span><span class="p">()</span>

    <span class="k">if</span> <span class="nb">len</span><span class="p">(</span><span class="n">arguments</span><span class="p">)</span> <span class="o">!=</span> <span class="mi">1</span><span class="p">:</span>
        <span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">&quot;Please specify the directory to process&quot;</span><span class="p">)</span>

    <span class="n">directory</span> <span class="o">=</span> <span class="n">arguments</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>

    <span class="k">if</span> <span class="ow">not</span> <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">exists</span><span class="p">(</span><span class="n">directory</span><span class="p">):</span>
        <span class="n">parser</span><span class="o">.</span><span class="n">error</span><span class="p">(</span><span class="s">&quot;Directory: </span><span class="si">%s</span><span class="s"> does not exist&quot;</span> <span class="o">%</span> <span class="n">directory</span><span class="p">)</span>

    <span class="k">try</span><span class="p">:</span>        
        <span class="n">pofiles</span> <span class="o">=</span> <span class="p">[]</span>
        <span class="n">os</span><span class="o">.</span><span class="n">path</span><span class="o">.</span><span class="n">walk</span><span class="p">(</span><span class="n">directory</span><span class="p">,</span> <span class="n">getpofs</span><span class="p">,</span> <span class="n">pofiles</span><span class="p">)</span>
        <span class="n">_</span> <span class="o">=</span> <span class="p">[</span><span class="n">createps</span><span class="p">(</span><span class="n">path</span><span class="p">,</span> <span class="n">CLIENT_ID</span><span class="p">,</span> <span class="n">API_KEY</span><span class="p">,</span> <span class="n">metadata</span><span class="p">,</span> <span class="n">opts</span><span class="o">.</span><span class="n">source_lang</span><span class="p">)</span>
            <span class="k">for</span> <span class="n">path</span> <span class="ow">in</span> <span class="n">pofiles</span><span class="p">]</span>
    <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span>
        <span class="k">print</span> <span class="s">&quot;</span><span class="se">\n</span><span class="s">CTRL-C pressed, exiting&quot;</span>
</pre></div>

<h2>Usage</h2>
<p>You need to obtain an access token from the Azure Marketplace instructions can be
found <a href="http://msdn.microsoft.com/en-us/library/hh454950.aspx">here</a></p>
<p>Set the <code>CLIENT_ID</code> and <code>API_KEY</code> variables in the script to the values you
obtain from Azure DataMarket.</p>
<p>Then point the script to the directory containing the <code>PO</code> files you want to translate
and let it do its thing.</p>
<pre><code>/auto-translate.py &lt;directory&gt;
</code></pre>
<h2>Download</h2>
<p>You can download the script from <a href="https://github.com/akissa/auto-translate">github</a></p>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Boot into single user mode on various unixes]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/01/24/boot-into-single-user-mode-on-various-unixes" />
    <id>http://www.topdog.za.net/2013/01/24/boot-into-single-user-mode-on-various-unixes</id>
    <updated>2013-01-24T07:40:00Z</updated>
    <published>2013-01-24T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Unix" />
    <category scheme="http://www.topdog.za.net" term="Linux" />
    <summary type="html"><![CDATA[Boot into single user mode on various unixes]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/01/24/boot-into-single-user-mode-on-various-unixes"><![CDATA[<h2>Linux/Grub</h2>
<p>Press <code>a</code> to append to the boot options then add <code>single</code></p>
<pre><code>grub append&gt; ro root=LABEL=/ single
</code></pre>
<h2>Solaris/OpenBoot PROM</h2>
<p>Press <code>L1+a</code> or <code>STOP+a</code> to enter OpenBoot PROM then type</p>
<pre><code>boot -s
</code></pre>
<h2>AIX</h2>
<p>Select <code>maintanance</code> mode from the boot menu or type <code>telinit S</code> on
a running machine</p>
<h2>HP-UX</h2>
<p>Interrupt the boot process when prompted and at the prompt type
<code>boot pri isl</code> to get the ISL prompt that allows you to boot into
single user mode. At the ISL prompt type</p>
<pre><code>ISL&gt; prompt: hpux -iS /stand/vmunix
</code></pre>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[How to update man keywords database]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2013/01/16/how-to-update-man-keywords-database" />
    <id>http://www.topdog.za.net/2013/01/16/how-to-update-man-keywords-database</id>
    <updated>2013-01-16T07:40:00Z</updated>
    <published>2013-01-16T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Centos" />
    <category scheme="http://www.topdog.za.net" term="Ubuntu" />
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="Unix" />
    <category scheme="http://www.topdog.za.net" term="RHEL" />
    <category scheme="http://www.topdog.za.net" term="Linux" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <summary type="html"><![CDATA[How to update man keywords database]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2013/01/16/how-to-update-man-keywords-database"><![CDATA[<p>Man keywords database allow you to search for man pages using keywords,
the database needs to be updated when ever man pages are added or removed.</p>
<p>This is how you do it for various *nix types.</p>
<h2>Debian/Ubuntu/SUSE</h2>
<pre><code>mandb
</code></pre>
<h2>RHEL/CENTOS/SL/Fedora</h2>
<pre><code>makewhatis
</code></pre>
<h2>AIX/Solaris/HP-UX</h2>
<pre><code>catman -w
</code></pre>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Strongswan now supports PAM authentication]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2012/11/07/strongswan-now-supports-pam-authentication" />
    <id>http://www.topdog.za.net/2012/11/07/strongswan-now-supports-pam-authentication</id>
    <updated>2012-11-07T07:40:00Z</updated>
    <published>2012-11-07T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Centos" />
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="RHEL" />
    <category scheme="http://www.topdog.za.net" term="Linux" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Security" />
    <category scheme="http://www.topdog.za.net" term="IPSEC" />
    <summary type="html"><![CDATA[Strongswan now supports PAM authentication]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2012/11/07/strongswan-now-supports-pam-authentication"><![CDATA[<p>Strongswan release 5.0.1 includes a XAuth PAM plugin which
requests username/password XAuth credentials and verifies them
against Pluggable Authentication Modules (PAM).</p>
<p>This plugin is not enabled by default to enable it you need
to add the following to your ./configure options</p>
<pre><code>--enable-xauth-pam
</code></pre>
<p>You do require the pam development headers and libraries on your
build machine to successfully compile.</p>
<h2>System Configuration</h2>
<p>The plugin is configurable in the strongswan.conf file, you are
able to change the pam service that is used for authentication.</p>
<p>By default the login pam service is used for authentication.</p>
<p>I will create a new service called ipsec for demonstration.</p>
<div class="pygments_murphy"><pre>charon {
    plugins{
        xauth-pam {
            pam_service = ipsec
        }
    }
}
</pre></div>

<p>The pam service configuration file is as follows.</p>
<div class="pygments_murphy"><pre>#%PAM-1.0
# /etc/pam.d/ipsec
auth        required      pam_env.so
auth        sufficient    pam_unix.so nullok try_first_pass
auth        requisite     pam_succeed_if.so uid &gt;= 500 quiet
auth        required      pam_deny.so

account     required      pam_unix.so
account     sufficient    pam_localuser.so
account     sufficient    pam_succeed_if.so uid &lt; 500 quiet
account     required      pam_permit.so

password    requisite     pam_cracklib.so try_first_pass retry=3 type=
password    sufficient    pam_unix.so sha512 shadow nullok try_first_pass use_authtok
password    required      pam_deny.so

session     optional      pam_keyinit.so revoke
session     required      pam_limits.so
session     [success=1 default=ignore] pam_succeed_if.so service in crond quiet use_uid
session     required      pam_unix.so
</pre></div>

<p>Now to use PAM authentication in your connections you set for XAuth:</p>
<pre><code>rightauth2=xauth-pam
</code></pre>
<p>Hybrid Authentication:</p>
<pre><code>rightauth=xauth-pam
</code></pre>
<p>You are good to go and should be able to use any pam module to
authenticate your users to your VPN. The options are endless: SQL,
LDAP, RADIUS, LOCAL etc.</p>
<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
</ul>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Strongswan now supports Cisco unity extensions]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2012/11/07/strongswan-now-supports-cisco-unity-extensions" />
    <id>http://www.topdog.za.net/2012/11/07/strongswan-now-supports-cisco-unity-extensions</id>
    <updated>2012-11-07T07:40:00Z</updated>
    <published>2012-11-07T07:40:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Centos" />
    <category scheme="http://www.topdog.za.net" term="Sysadmin" />
    <category scheme="http://www.topdog.za.net" term="RHEL" />
    <category scheme="http://www.topdog.za.net" term="Linux" />
    <category scheme="http://www.topdog.za.net" term="Tips" />
    <category scheme="http://www.topdog.za.net" term="Security" />
    <category scheme="http://www.topdog.za.net" term="IPSEC" />
    <summary type="html"><![CDATA[Strongswan now supports Cisco unity extensions]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2012/11/07/strongswan-now-supports-cisco-unity-extensions"><![CDATA[<p>I previously <a href="http://bit.ly/OIHOq4">wrote</a> about setting up split
tunneling on Strongswan using the <a href="http://bit.ly/NI7Mpx">attr-sql plugin</a></p>
<p>With the release of Strongswan 5.0.1 it is no longer the only way
to support split tunneling.</p>
<p>Strongswan 5.0.1 introduces the unity plugin which allows for the
configuration of split tunneling either using a charon option or
using the attr plugin which is enabled by default.</p>
<p>The unity plugin is not enabled by default to enable it you need
to add the following to your ./configure options</p>
<pre><code>--enable-unity
</code></pre>
<h2>Charon option</h2>
<p>To enable this option you need to edit the strongswan.conf file
and set</p>
<div class="pygments_murphy"><pre>charon {
    # ... other options
    cisco_unity = yes
    #...
}
</pre></div>

<p>As a client strongswan will install policies only for the received
Split-Include attributes and IPsec bypass policies for received
Local-LAN attributes.</p>
<p>As a server strongswan will send Split-Include attributes for leftsubnet
definitions containing multiple subnets to clients that support the
IKEv1 Cisco Unity Extensions.</p>
<h2>Attr plugin option</h2>
<p>It is also possible to configure split tunneling using the attr plugin.
Two new options have been added:</p>
<ul>
<li>split-include - Comma-separated list of subnets to tunnel</li>
<li>split-exclude - Comma-separated list of subnets not to tunnel</li>
</ul>
<div class="pygments_murphy"><pre>charon {
    # ... other options
    split-include = 192.168.1.0/24, 172.16.0.0/16
    split-exclude = 10.128.0.0/16
    #...
}
</pre></div>

<h2>Related articles</h2>
<ul>
<li><a href="http://bit.ly/WABVAZ">Iphone/Ipad/Mac OSX IPSEC VPN with Strongswan 5 on Centos/RHEL 6</a></li>
<li><a href="http://bit.ly/Ujih5I">Mac OSX IPSEC VPN via command line using builtin Racoon client</a></li>
<li><a href="http://bit.ly/SN5z1k">IPSEC split tunneling VPN with Mac OSX and Strongswan 5 on Centos/RHEL 6</a></li>
</ul>]]></content>
  </entry>
  <entry>
    <author>
      <name>Andrew Colin Kissa</name>
      <uri>http://www.topdog.za.net</uri>
    </author>
    <title type="html"><![CDATA[Book Review: Cloud Architecture Patterns By Bill Wilder]]></title>
    <link rel="alternate" type="text/html" href="http://www.topdog.za.net/2012/11/07/book-review:-cloud-architecture-patterns-by-bill-wilder" />
    <id>http://www.topdog.za.net/2012/11/07/book-review:-cloud-architecture-patterns-by-bill-wilder</id>
    <updated>2012-11-07T07:11:00Z</updated>
    <published>2012-11-07T07:11:00Z</published>
    <category scheme="http://www.topdog.za.net" term="Book review" />
    <summary type="html"><![CDATA[Book Review: Cloud Architecture Patterns By Bill Wilder]]></summary>
    <content type="html" xml:base="http://www.topdog.za.net/2012/11/07/book-review:-cloud-architecture-patterns-by-bill-wilder"><![CDATA[<p><strong>"Cloud Architecture Patterns By Bill Wilder"; O'Reilly Media</strong></p>
<p><img alt="Cloud Architecture Patterns By Bill Wilder;" src="/imgs/cloud-architecture-patterns.gif" /></p>
<p>This book is a must read for any one involved in software development
particularly cloud based applications.</p>
<p>The book describes the popular patterns used in development of scalable
applications, coverage is given to the following.</p>
<ul>
<li>Horizontal scaling</li>
<li>Queue centric workflows</li>
<li>Auto scaling</li>
<li>Eventual consistency</li>
<li>Mapreduce</li>
<li>Database sharding</li>
<li>Multitenancy</li>
<li>Busy signal handling</li>
<li>Node failure</li>
<li>Colocation</li>
<li>Valet Key</li>
<li>CDN</li>
<li>Multi site</li>
</ul>
<p>These are the patterns developed and used my most of the large web
properties. The patterns are explained and real world scenarios presented.
Great theoretical presentation of the concepts and ideas. I totally
recommend this to anyone involved in Information technology.</p>
<p>Product page <a href="http://shop.oreilly.com/product/0636920023777.do">http://shop.oreilly.com/product/0636920023777.do</a></p>]]></content>
  </entry>
</feed>
