<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0"><channel><title><![CDATA[Your Site's RSS Feed]]></title><description><![CDATA[Your Site's RSS Feed]]></description><link>https://opkode.com</link><generator>GatsbyJS</generator><lastBuildDate>Wed, 05 Aug 2026 11:34:23 GMT</lastBuildDate><item><title><![CDATA[Introducing Converse 11: A Major Leap Forward for XMPP Webchat]]></title><description><![CDATA[I’m thrilled to announce the official release of Converse version 11.0.0! 🚀 You can try it out online at chat.conversejs.org
or download…]]></description><link>https://opkode.com/blog/2025-05-21-converse-11/</link><guid isPermaLink="false">https://opkode.com/blog/2025-05-21-converse-11/</guid><pubDate>Wed, 21 May 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m thrilled to announce the official release of &lt;a href=&quot;https://conversejs.org&quot;&gt;Converse&lt;/a&gt; version 11.0.0! 🚀&lt;/p&gt;
&lt;p&gt;You can try it out online at &lt;a href=&quot;https://chat.conversejs.org&quot;&gt;chat.conversejs.org&lt;/a&gt;
or &lt;a href=&quot;https://github.com/conversejs/converse-desktop/releases/tag/v11.0.0&quot;&gt;download the desktop app&lt;/a&gt;
(the &lt;a href=&quot;https://v2.tauri.app/&quot;&gt;Tauri&lt;/a&gt; based releases are coming soon).&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2c2c69feeab22dd171e4de98f174bd68/29007/converse-enter-muc.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.22222222222222%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB3UlEQVR42j2RS4/aMBSF808GVAh5Oo7jRxIS550MASfAEBigqFOx6K6btrOrum5V9TfXDGqlb3FlnaNz7rWSVr1uEMsOq3pbJjlnc+TSmpU/xbdfq69/xOtv8VoFNUaM4AgTzmicMO65AfFCpapKVfOkX4ihalrmJ5RxSvl58+X6/ONl933ffXZg4Di+4waaSRlOz+uLZvvH+qiI0zVMhjg/9ZtLkJQ0qhCOAQxSLsTi0hRH0Z4ADHWTmjabqB7Cyeb4cTSFn/qr8rjcIlJIhHiGQQVQqhkEAB6H66kGVR2puuxFDZNJZjqhmJ+H08PE6dtBKcrW9WLbCevmKc2XRdWl+SrJVlneM7+4g2kiAz2SuogTP1sezuMpkjKFRZVh+cCN68UuLbu63RXNxo8aiBPX4wBGFghNO5Aa3WRTDROcHIfLwzuYl53iMi7LSFG/PsS8CaOaspzQTOZgkjpvZtnLBnJtps6wi+PVfj+euDdzUpQWmNtg/nT4gGhpO3Op1gwqkWrDuu15R76oGkEo2u42ownKi05JF2vg3Mzt8HIeVi4M5MEMU16IWiBw4Fz6/0FnOmaMbw/vR/fkOKvfasfdchB1AWFgWsyyb8jh/3xHfljkx4vHbqx6abb8C7Pki/FA8/hhAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Screenshot of Converse&quot;
        title=&quot;&quot;
        src=&quot;/static/2c2c69feeab22dd171e4de98f174bd68/1cfc2/converse-enter-muc.png&quot;
        srcset=&quot;/static/2c2c69feeab22dd171e4de98f174bd68/3684f/converse-enter-muc.png 225w,
/static/2c2c69feeab22dd171e4de98f174bd68/fc2a6/converse-enter-muc.png 450w,
/static/2c2c69feeab22dd171e4de98f174bd68/1cfc2/converse-enter-muc.png 900w,
/static/2c2c69feeab22dd171e4de98f174bd68/21482/converse-enter-muc.png 1350w,
/static/2c2c69feeab22dd171e4de98f174bd68/29007/converse-enter-muc.png 1600w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;First and foremost, thanks to all the contributors whose efforts helped make this release possible.&lt;/p&gt;
&lt;p&gt;Many people provided code contributions, bug reports, translations, feature
requests or just hung out in our &lt;a href=&quot;xmpp:discuss@conference.conversejs.org?join&quot;&gt;chatroom&lt;/a&gt; to provide feedback.&lt;/p&gt;
&lt;p&gt;I ran the numbers comparing this release to the previous major release.&lt;/p&gt;
&lt;p&gt;The previous major release was 933 days ago, that’s about 2.5 years, and over a
thousand commits have been made since then. Some of these commits
made it into subsequent minor 10.x.x releases, but there’s no denying that the
11.0.0 release is a big one. A quick look at the &lt;a href=&quot;https://github.com/conversejs/converse.js/releases/tag/v11.0.0&quot;&gt;release notes&lt;/a&gt;
also shows how much work has gone into it.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Running git rev-list --count v10.0.0..HEAD
1062&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I’m particularly excited about this release, because it addresses some long-standing
painpoints and issues.&lt;/p&gt;
&lt;p&gt;A friend of mine likes to talk about “embarrassment-driven development”.&lt;/p&gt;
&lt;p&gt;That’s a bit how I feel about this release. It fixes some problems that have
been particularly glaring and embarrassing since a number of years.&lt;/p&gt;
&lt;p&gt;Let’s take a closer look at some of the most exciting features and improvements in this latest release:&lt;/p&gt;
&lt;h2&gt;TypeScript&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;height: 12em; display: flex;&quot;&gt;&lt;img src=&quot;/c87187cad0ab07cb31c76fb8facda1e1/Typescript.svg&quot; alt=&quot;TypeScript logo&quot;&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I’ve always taken a fairly conservative approach with Converse, trying to avoid
jumping on any bandwagons and generally trying to evolve the codebase to keep
up with the times, instead of opting for huge rewrites.&lt;/p&gt;
&lt;p&gt;This project started in 2013, JavaScript developers who have been around since
that time, will appreciate the massive amount of churn and changes that have
happened in our ecosystem from then until now! There’s even a term coined for it:
&lt;em&gt;“JavaScript fatigue”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I was wary of just rewriting everything in TypeScript. I had limited time to
work on Converse, and didn’t want to spend all of it on a rewrite, instead of
adding new features and making bugfixes.&lt;/p&gt;
&lt;p&gt;Reading about the &lt;a href=&quot;https://news.ycombinator.com/item?id=35892250&quot;&gt;decision&lt;/a&gt;
of the team behind Svelte, to use JSDoc comments to
add types to their codebase, gave me confidence to try the same with the Converse
codebase. I felt that this would be a less disruptive change than trying to
rewrite everything in TypeScript, and would fit nicely with the approach I’ve
taken until now.&lt;/p&gt;
&lt;p&gt;Version 11.0.0 is the first release that includes TypeScript type definitions
for Converse.&lt;/p&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;tsc&lt;/code&gt; compiler is still not running in &lt;code class=&quot;language-text&quot;&gt;strict&lt;/code&gt; mode, and
there are still untyped sections of the code, but it’s a good start, and we’re
already reaping benefits.&lt;/p&gt;
&lt;h2&gt;Virtualized chat history&lt;/h2&gt;
&lt;p&gt;This is one update I’m particularly proud of. Until now, Converse was rendering
all messages it knew about in a particular chat.&lt;/p&gt;
&lt;p&gt;If a chat had 2000 messages, all those messages would be rendered, causing all
kinds of performance issues.&lt;/p&gt;
&lt;p&gt;List virtualization is a technique whereby only a subset of a list is rendered,
while the impression is maintained that the entire list is shown.&lt;/p&gt;
&lt;p&gt;Converse finally has list virtualization for the chat history.&lt;/p&gt;
&lt;span class=&quot;img-container&quot; style=&quot;display: flex; justify-content: center;&quot;&gt;
    &lt;video autoplay loop muted controls playsinline width=&quot;800&quot;&gt;
        &lt;source src=&quot;/2e8194486ea4af6046676d39185ab103/Converse-virtual-list.mp4&quot; type=&quot;video/mp4&quot; /&gt;
    &lt;/video&gt;
&lt;/span&gt;
&lt;h2&gt;Mind the gap&lt;/h2&gt;
&lt;p&gt;Related to history or list virtualization, another update to Converse is to
better deal with gaps in the chat history.&lt;/p&gt;
&lt;p&gt;Until now, when opening a chat, the entire history from the previous session
until now was fetched and shown. When opening Converse in a browser where it
didn’t run for, say, 8 months, everything would crawl to a halt as Converse
tried to fetch the entire history.&lt;/p&gt;
&lt;p&gt;I fixed this, but only fetching the most recent messages, and then placing a
special placeholder element in the gap where there are still missing messages.&lt;/p&gt;
&lt;p&gt;I then used the &lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API&quot;&gt;IntersectionObserver&lt;/a&gt;
API, to identify when this gap becomes
visible, which would happen example when the user scrolls up to read older messages.
As soon as this gap became visible, Converse would fetch a limited number of
the most recent messages in that gap, and then place a new placeholder above them,
in case there were still missing messages.&lt;/p&gt;
&lt;p&gt;In this way, we avoid fetching all messages immediately, but instead we load
them lazily as the user scrolls up to read older messages.&lt;/p&gt;
&lt;p&gt;I’m happy with the usability and performance improvements this change has
brought. One drawback, is that we can’t inform the user of being mentioned, if
he or she was mentioned in a message inside that gap of unfetched messages.&lt;/p&gt;
&lt;p&gt;This is however to a large extent a limitation of XMPP’s message archiving
extension (&lt;a href=&quot;https://xmpp.org/extensions/xep-0313.html&quot;&gt;MAM&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;An attempt has been made to address this limitation with the &lt;a href=&quot;https://xmpp.org/extensions/xep-0430.html&quot;&gt;Inbox
XEP&lt;/a&gt;, but it hasn’t seen any real
uptake, particularly among server developers.&lt;/p&gt;
&lt;p&gt;Hopefully this drawback will be addressed in due time.&lt;/p&gt;
&lt;h2&gt;PEP Bookmarks&lt;/h2&gt;
&lt;p&gt;Adding support for PEP (Personal Eventing Protocol)
&lt;a href=&quot;https://xmpp.org/extensions/xep-0402.html&quot;&gt;bookmarks&lt;/a&gt;, was some unglamorous
modernization work that was also long overdue.&lt;/p&gt;
&lt;p&gt;Converse was using an older bookmarks protocol extension, which was causing
compatibility issues with other XMPP clients, unless the user’s XMPP server
provided a compatibility layer between the two protocols.&lt;/p&gt;
&lt;p&gt;By updating to the PEP standard, these issues have now been resolved.&lt;/p&gt;
&lt;p&gt;Additionally, Converse now no longer lets the user manually bookmark or
unbookmark chats. By doing so, it was unnecessarily exposing protocol details
to users, making the app more confusing and difficult to use.&lt;/p&gt;
&lt;p&gt;Instead, bookmarks are automatically set and unset as users join and leave
groupchats, similarly to how some other XMPP clients already do it.&lt;/p&gt;
&lt;h2&gt;Updated retractions and moderation&lt;/h2&gt;
&lt;p&gt;Converse has supported &lt;a href=&quot;https://xmpp.org/extensions/xep-0424.html&quot;&gt;retracting&lt;/a&gt;
(i.e. deleting) and &lt;a href=&quot;https://xmpp.org/extensions/xep-0425.html&quot;&gt;moderating&lt;/a&gt; (i.e. deletion
by a moderator) of messages since a number of years already. In the meantime,
these protocol extensions have been updated based on community feedback. This
release has incorporated those changes.&lt;/p&gt;
&lt;h2&gt;MUC Private Messages&lt;/h2&gt;
&lt;p&gt;Finally Converse supports private messages in groupchats.&lt;/p&gt;
&lt;p&gt;This is another one of those embarrassment-driven features. Ideally Converse
would have had this feature long ago already, but hey, better late then never.&lt;/p&gt;
&lt;p&gt;What’s also nice is that some of the work done for this feature has opened up
the door for Slack-like threads.&lt;/p&gt;
&lt;h2&gt;Tagged template literals to render XML stanzas&lt;/h2&gt;
&lt;p&gt;This is more a new feature I made to &lt;a href=&quot;https://strophe.im/&quot;&gt;Strophe&lt;/a&gt;,
the underlying XMPP library that Converse uses, but it’s still something pretty cool.&lt;/p&gt;
&lt;p&gt;Previously, Strophe’s API for generating XML stanzas, looked like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const msg = $msg({
    to: buddy_jid,
    type: &apos;chat&apos;,
    id: u.getUniqueId()
}).c(&apos;body&apos;).t(&apos;Hello world&apos;).up()
    .c(&apos;active&apos;, {&apos;xmlns&apos;: &apos;http://jabber.org/protocol/chatstates&apos;});&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now, with the magic of JavaScript’s tagged template literals, you can write
them like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;const msg = stx`
    &amp;lt;message xmlns=&quot;jabber:client&quot; type=&quot;chat&quot; id=&quot;${u.getUniqueId()}&quot;&gt;
        &amp;lt;body&gt;Hello world&amp;lt;/body&gt;
        &amp;lt;active xmlns=&quot;http://jabber.org/protocol/chatstates&quot;/&gt;
    &amp;lt;/message&gt;`;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Much nicer and more readable to my eye. And it’s all standard JavaScript, no
compiler necessary.&lt;/p&gt;
&lt;h2&gt;Bootstrap 5&lt;/h2&gt;
&lt;p&gt;Converse now uses Bootstrap 5, and the markup has been updated to
follow the best practices and conventions for Bootstrap 5.&lt;/p&gt;
&lt;h2&gt;Right to left support&lt;/h2&gt;
&lt;p&gt;Converse is translated into over 40 languages. Four of these languages are
displayed right to left, namely Arabic, Farsi, Hebrew and Uyghur.&lt;/p&gt;
&lt;p&gt;When one of these languages is used (e.g. based on the user’s browser
language), Converse will render its UI inverted, from right to left, instead of
the usual left to right.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;Future directions&lt;/h2&gt;
&lt;p&gt;There are many features and improvements that could still be developed for a future release.&lt;/p&gt;
&lt;p&gt;Some highlights include:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Microblogging (&lt;a href=&quot;https://github.com/conversejs/converse.js/issues/3615&quot;&gt;Github issue&lt;/a&gt;, &lt;a href=&quot;https://xmpp.org/extensions/xep-0277.html&quot;&gt;XEP-0277&lt;/a&gt; and &lt;a href=&quot;https://xmpp.org/extensions/xep-0472.html&quot;&gt;XEP-0472&lt;/a&gt;).&lt;/li&gt;
&lt;li&gt;Slack-like message threads.&lt;/li&gt;
&lt;li&gt;Push notifications (&lt;a href=&quot;https://github.com/conversejs/converse.js/issues/1519&quot;&gt;Github issue&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;A mobile app (&lt;a href=&quot;https://github.com/conversejs/converse.js/issues/3481&quot;&gt;Github issue&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Audio/video calls integration (&lt;a href=&quot;https://github.com/conversejs/converse.js/issues/447&quot;&gt;Github issue&lt;/a&gt;)&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you’re considering sponsoring any of these features, please reach out to me via
the &lt;a href=&quot;https://opkode.com/contact.html&quot;&gt;contact form&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I’m also currently looking for shorter term freelance contracts, whether Converse-related
or not. If you’re interested in hiring me, please &lt;a href=&quot;https://opkode.com/contact.html&quot;&gt;reach out&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We also accept general donations and sponsorships via &lt;a href=&quot;https://www.patreon.com/jcbrand&quot;&gt;Patreon&lt;/a&gt;, &lt;a href=&quot;https://liberapay.com/jcbrand&quot;&gt;Liberapay&lt;/a&gt; and
&lt;a href=&quot;https://github.com/sponsors/jcbrand&quot;&gt;Github&lt;/a&gt;. Sponsors who donate $100 or more per month will have their logo
displayed on the Converse website and app.&lt;/p&gt;
&lt;h2&gt;Fin&lt;/h2&gt;
&lt;p&gt;That’s all, thanks for reading and I hope you enjoy the new release.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e5b5bb50d59bb89429753b318349fe0e/29007/converse-overlayed.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 50.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB0klEQVR42p3LX2/SUAAF8H4C45uKEBx1ox20a6FQKBRKSxmllN5y23sb/mxuGVsgY7AMMuhI1LDFBx+X+A1M9uCLiR9QFhOj883kl/NyziFehKL/jYiQ7BPhGBuJbZL57d/NLwSZLJHM31glxigUr9IpdZNUSt1my083yUcElQVUBuwIdnwjY79N220XT8/QPjwH3anpj1udSUbtbqo/PF7oLCD01qXZngFvDtES4qAFg+lwuZgs2mjZ6QZ+N/DwAqJrx10C9wZ4ge0GpjOvgyvdviIGzqcx/jzv3l/guyEMRnB11FydwfezHj6slf2q7uuVgYVm/bsLfDNGqwkKzvH6yLrF6or4Ah/uwdex8GGk91A1Z4tipyQcSnkgITGeE96IjWwZ5/1j29tPMq5cdArpodIXo6YcsYhvxo+HxnfDfKerndRui36lmMXGsXhSp0Z0pJSIVMp5MJIuFc6JhwoKD+WEfyoP98JylfWJtXz7sbLOIq9qoMxOgwnLTdl00z0tbnKklqe1pgoPuIHEmImYZuUsjbJOalM2quu8TzQ5w0jU/KgjhCTqZY57LVTFenGvXaa1recpkRSU3byX9vmtQuwZr3BSpmD35YPitmEK+Cf6GZg1pahyxQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Screenshot of Converse&quot;
        title=&quot;&quot;
        src=&quot;/static/e5b5bb50d59bb89429753b318349fe0e/1cfc2/converse-overlayed.png&quot;
        srcset=&quot;/static/e5b5bb50d59bb89429753b318349fe0e/3684f/converse-overlayed.png 225w,
/static/e5b5bb50d59bb89429753b318349fe0e/fc2a6/converse-overlayed.png 450w,
/static/e5b5bb50d59bb89429753b318349fe0e/1cfc2/converse-overlayed.png 900w,
/static/e5b5bb50d59bb89429753b318349fe0e/21482/converse-overlayed.png 1350w,
/static/e5b5bb50d59bb89429753b318349fe0e/29007/converse-overlayed.png 1600w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Adopting Bitcoin, Cape Town, 2025]]></title><description><![CDATA[I attended the Adopting Bitcoin conference in Cape Town the last weekend and
thought I’d do a quick writeup about some interesting things I…]]></description><link>https://opkode.com/blog/2025-01-30-adopting-bitcoin-2025/</link><guid isPermaLink="false">https://opkode.com/blog/2025-01-30-adopting-bitcoin-2025/</guid><pubDate>Thu, 30 Jan 2025 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I attended the Adopting Bitcoin conference in Cape Town the last weekend and
thought I’d do a quick writeup about some interesting things I learned.&lt;/p&gt;
&lt;p&gt;Some background, South Africa has quite high crypto adoption (Bitcoin in particular).
Our 2nd biggest retailer accepts crypto payments, there
are a bunch of circular bitcoin economy projects around the country and more
are popping up. Most of this activity is bottom-up, the government is not
pro-crypto.&lt;/p&gt;
&lt;h2&gt;Pick ‘n Pay adoption of crypto payments&lt;/h2&gt;
&lt;p&gt;The first presentation was about SA’s 2nd largest retailer, Pick ‘n Pay, who
has adopted crypto payments at its stores about 2 years ago. I don’t have a PnP
at the small town where I live, so I’ve never used them.&lt;/p&gt;
&lt;p&gt;While at the conf, I went to the local PnP and bought coffee and a magazine
with Bitcoin. You can use the self-custodial Blink wallet (previously Bitcoin
Beach) to pay. Apparently any wallet could work, but there is some
API call that it needs to make which only Blink and some South African
exchanges currently support.&lt;/p&gt;
&lt;p&gt;3% of Pick ‘n Pay’s sales are in Crypto (not just Bitcoin, but also Solana and others),
which is up from 0.5% 2 years ago. This is one million Rand per month, which is about
$50.000. So not a large absolute amount, but trending up.&lt;/p&gt;
&lt;h2&gt;Bitcoin: the South African story&lt;/h2&gt;
&lt;p&gt;This was a first presentations was from Stafford Masie and Carel de Jager about
their lobbying efforts to do the following:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Convince South Africa’s monopoly energy provider Eskom to embrace Bitcoin
mining to facilitate grid management and expansion. Carel showed some
calculations that if Eskom did CapEx of R1.7 Billion in 2021, and kept 50% of
the mining proceeds, they would have made a surplus of 400 Billion Rand,
which is equal to their total current debt (which is backstopped by the tax payer).
They hoped to announce a mining agreement at the conf, but the talks are still in progress.
Apparently the holdup is on the government’s side, which is the shareholder.&lt;/li&gt;
&lt;li&gt;Convince the Reserve Bank and Intergovernmental Fintech Working Group
(IFWG) to change legislation which currently blocks the creation of a Bitcoin holding
company modeled on Microstrategy.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;span class=&quot;img-container&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/99603645fb4a884a52130f4747a8389c/903c8/IMG_20250129_151944.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 71.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAMEAQL/xAAWAQEBAQAAAAAAAAAAAAAAAAACAAH/2gAMAwEAAhADEAAAAdXwmysjCv/EABkQAQEBAQEBAAAAAAAAAAAAAAIBABEDEv/aAAgBAQABBQIicZhPJvv0OqWj3//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABURAQEAAAAAAAAAAAAAAAAAAAAh/9oACAECAQE/AVf/xAAcEAACAAcAAAAAAAAAAAAAAAAAAQIQERIiMZH/2gAIAQEABj8CG5WprhlFU0f/xAAbEAACAwEBAQAAAAAAAAAAAAAAAREhMUFRkf/aAAgBAQABPyFid6+imzQnrX8HmXZEW1PIFpdH/9oADAMBAAIAAwAAABDXz//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQMBAT8Qjph//8QAFxEBAAMAAAAAAAAAAAAAAAAAARARIf/aAAgBAgEBPxCxMh//xAAbEAEBAQADAQEAAAAAAAAAAAABEQAhMUHB0f/aAAgBAQABPxBGykKIe3MdZHz8xDtAHtPfuVS4pW8tz3yApAOTcqaqpv/Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Carel de Jager discussing Bitcoin mining prospects for Eskom&quot;
        title=&quot;&quot;
        src=&quot;/static/99603645fb4a884a52130f4747a8389c/8e1fc/IMG_20250129_151944.jpg&quot;
        srcset=&quot;/static/99603645fb4a884a52130f4747a8389c/863e1/IMG_20250129_151944.jpg 225w,
/static/99603645fb4a884a52130f4747a8389c/20e5d/IMG_20250129_151944.jpg 450w,
/static/99603645fb4a884a52130f4747a8389c/8e1fc/IMG_20250129_151944.jpg 900w,
/static/99603645fb4a884a52130f4747a8389c/b768e/IMG_20250129_151944.jpg 1350w,
/static/99603645fb4a884a52130f4747a8389c/d9c39/IMG_20250129_151944.jpg 1800w,
/static/99603645fb4a884a52130f4747a8389c/903c8/IMG_20250129_151944.jpg 2340w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Circular Bitcoin economies and microgrids&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 25em&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3ea0c0d028d97fa739b3e80b790eebda/fa188/IMG_20250129_151830.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 97.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAATABQDASIAAhEBAxEB/8QAGAABAQADAAAAAAAAAAAAAAAAAAUBAwT/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABoa5grpROfIoWf//EABoQAAMBAAMAAAAAAAAAAAAAAAABAhIDEBH/2gAIAQEAAQUC1JHInOpRpqlZo9ff/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAGhAAAgIDAAAAAAAAAAAAAAAAAAEgISIxMv/aAAgBAQAGPwLpGVM3P//EABwQAAICAgMAAAAAAAAAAAAAAAABESFBcRAxUf/aAAgBAQABPyFpQSRlkQ43abosFM6Lcmw/YfH/2gAMAwEAAgADAAAAEIg4gf/EABcRAAMBAAAAAAAAAAAAAAAAAAABERD/2gAIAQMBAT8QhB5//8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxA13//EABwQAQEBAQACAwAAAAAAAAAAAAERACEQcTFBUf/aAAgBAQABPxCsUbIPb60MUp0Q/N2kBCKTBScJWzUYRCWTW/bLfnk32Xx//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Bitcoin Ekasi truck&quot;
        title=&quot;&quot;
        src=&quot;/static/3ea0c0d028d97fa739b3e80b790eebda/8e1fc/IMG_20250129_151830.jpg&quot;
        srcset=&quot;/static/3ea0c0d028d97fa739b3e80b790eebda/863e1/IMG_20250129_151830.jpg 225w,
/static/3ea0c0d028d97fa739b3e80b790eebda/20e5d/IMG_20250129_151830.jpg 450w,
/static/3ea0c0d028d97fa739b3e80b790eebda/8e1fc/IMG_20250129_151830.jpg 900w,
/static/3ea0c0d028d97fa739b3e80b790eebda/b768e/IMG_20250129_151830.jpg 1350w,
/static/3ea0c0d028d97fa739b3e80b790eebda/d9c39/IMG_20250129_151830.jpg 1800w,
/static/3ea0c0d028d97fa739b3e80b790eebda/fa188/IMG_20250129_151830.jpg 2025w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Other smaller talks were about establishing circular Bitcoin economies in South
Africa and other African countries (Kenya, Malawi, Burundi) of which there are
a bunch by now. One South African township shopkeeper mentioned that since he
accepts and saves in Bitcoin, he has stopped drinking alcohol and instead of
partying at the tavern over the weekend, he spends time with his wife and child.
Saving in Bitcoin changes people for the better.&lt;/p&gt;
&lt;p&gt;There was a talk about BTrust, which is a non-profit which received 500 Bitcoin
from Jack Dorsey and Jay-Z, and about Gridless, which has built 5000 micro-grids in
rural Africa to provide electricity to rural communities, subsidised by Bitcoin mining
and which would otherwise not have been economically feasible.&lt;/p&gt;
&lt;h2&gt;Politicians&lt;/h2&gt;
&lt;h3&gt;Helen Zille&lt;/h3&gt;
&lt;p&gt;Political Bigwig Helen Zille held a talk about her son who orange-pilled
her some years ago and how she’s now saving in Bitcoin.
Somewhat cynically I think she came mostly because her party didn’t want to be
upstaged by another politician, Mzwanele Manyi, who came to announce his party’s
proposal for a strategic Bitcoin reserve for South Africa.&lt;/p&gt;
&lt;h3&gt;Mzwanele Manyi&lt;/h3&gt;
&lt;p&gt;One very strange thing is that Manyi’s party, MK, is not just calling for a
strategic Bitcoin reserve, but also the nationalization of the central
bank, the private banks, mines, factories and forced land expropriation
without compensation, all to be owned by the state for the purposes of
redistribution. Doesn’t sound like the kind of party that would propose a
strategic Bitcoin reserve, does it?&lt;/p&gt;
&lt;p&gt;In Many’s talk, he highlighted illegal exchange rate manipulation from the private
banks in 2023 to enrich themselves (they were fined for this).&lt;/p&gt;
&lt;p&gt;He mentioned key advantages of Bitcoin that are well known to Bitcoiners.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The removal of unnecessary financial intermediaries, which according to him is where a lot of corruption happens.&lt;/li&gt;
&lt;li&gt;Fixed supply&lt;/li&gt;
&lt;li&gt;Operates on principles of transparency and fairness.&lt;/li&gt;
&lt;li&gt;Would reduce South Africa’s dependency on international institutions like the IMF.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Some other things he mentioned:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;El Salvador. They’ve demonstrated the benefits. They successfully repaid an $800M bond, helped by Bitcoin.&lt;/li&gt;
&lt;li&gt;Single biggest line item in SA’s budget is debt servicing. Higher than anything else.&lt;/li&gt;
&lt;li&gt;Wants to use Bitcoin to reduce SA’s debt burden. (Zille’s position was that
this would cause a currency crisis and is not a good idea).&lt;/li&gt;
&lt;li&gt;Proposal: that SA must allocate between 4-5% of reserves into Bitcoin, R50 billion. Expects it to grow to R380 billion in 5 years.&lt;/li&gt;
&lt;li&gt;He is explicit that he wants SA to front-run the USA.&lt;/li&gt;
&lt;li&gt;They are soon going to table a discussion on this in Parliament.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The game theory that Bitcoiners have mentioned since years is starting to play out.&lt;/p&gt;
&lt;p&gt;A question was asked about how to reconcile MK’s non-free market interventionist
policies with Bitcoin’s libertarian ethos. Manyi’s response is that he doesn’t
want to be boxed in ideologically and that he is interested in pragmatism and
not ideology. Says libertarians want the same as everyone, but the starting
position is not the same. He says “let’s level the playing field so that we can
then have a free market.” Says affirmative action must not be perpetual, must
eventually stop, but first needed to level the playing field.&lt;/p&gt;
&lt;h3&gt;Beverley Schafer&lt;/h3&gt;
&lt;p&gt;Up next, was Beverley Schafer, who was a politician for 15 years.&lt;/p&gt;
&lt;p&gt;35 million people in SA earning less than R1000 per month.
Complains that she can’t open accounts at exchanges because she’s been an
active politician in SA and is now a “politically exposed person”.&lt;/p&gt;
&lt;p&gt;Says she was forced to find non-KYC alternatives to stack sats.
Says existing fiat systems don’t prioritise freedom, they prioritise control.
In South Africa, the central bank ties us to a depreciating currency which between
2010 and 2023 lost 60% against the US dollar.&lt;/p&gt;
&lt;p&gt;She’s quite clued in. Quotes Jeff Booth. Encourages self custody and taking a
long-term approach. Says she made mistakes on her Bitcoin journey, but has
learned how to save and to commit to the long game.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container&quot; style=&quot;max-width: 30em&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7e5a90823982e90e938eaa3cbabde45f/93719/IMG_20250129_151756.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52.44444444444445%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEA//EABUBAQEAAAAAAAAAAAAAAAAAAAEA/9oADAMBAAIQAxAAAAFV0mGsQj//xAAZEAEAAwEBAAAAAAAAAAAAAAABAAISBBH/2gAIAQEAAQUCSFyUcHhOUGXqb//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EAB0QAAICAQUAAAAAAAAAAAAAAAABESECIjFBcYH/2gAIAQEABj8Cq+zGMt6I0+sbjgylDpH/xAAcEAADAAMAAwAAAAAAAAAAAAAAAREhMUFxkcH/2gAIAQEAAT8hc7GE2FkyXuT4e1A5C52FSh+UfCR//9oADAMBAAIAAwAAABD3z//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAwEBPxAxf//EABYRAAMAAAAAAAAAAAAAAAAAAAEQEf/aAAgBAgEBPxClf//EAB4QAQABBAMBAQAAAAAAAAAAAAERACExQVFxwaGx/9oACAEBAAE/EDnNk2YPPysESGCLzbvykZl7dffmKNM4IJmczQaeIiDzXXLXgr//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;A view of the main hall from the back&quot;
        title=&quot;&quot;
        src=&quot;/static/7e5a90823982e90e938eaa3cbabde45f/8e1fc/IMG_20250129_151756.jpg&quot;
        srcset=&quot;/static/7e5a90823982e90e938eaa3cbabde45f/863e1/IMG_20250129_151756.jpg 225w,
/static/7e5a90823982e90e938eaa3cbabde45f/20e5d/IMG_20250129_151756.jpg 450w,
/static/7e5a90823982e90e938eaa3cbabde45f/8e1fc/IMG_20250129_151756.jpg 900w,
/static/7e5a90823982e90e938eaa3cbabde45f/b768e/IMG_20250129_151756.jpg 1350w,
/static/7e5a90823982e90e938eaa3cbabde45f/d9c39/IMG_20250129_151756.jpg 1800w,
/static/7e5a90823982e90e938eaa3cbabde45f/93719/IMG_20250129_151756.jpg 4000w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Cross-border payments via Lightning&lt;/h2&gt;
&lt;p&gt;There was an announcement by Orange, which is using the Lightning network to
facilitate cross-border remittances across Africa. By using Lightning, you need zero float,
i.e. you don’t need to keep large pools of rapidly depreciating African fiat
currencies, because sats are so fungible. They partner with OTC desks on both
sides. In doing so, they drastically reduce fees for customers.&lt;/p&gt;
&lt;p&gt;They did two live demos.&lt;/p&gt;
&lt;p&gt;R104 worth of Nigerian Naira was sent from a Nigerian bank account to a South African one,
with the cross border payment made over Lightning. It took about 2 minutes for the money
to show up in the South African bank account.&lt;/p&gt;
&lt;p&gt;Another where Kenyan Pesa worth R111 was made from a Kenyan mobile account
(via MPesa, which is big in Kenya) to a South African bank account.&lt;/p&gt;
&lt;h2&gt;Chatting with the organizers&lt;/h2&gt;
&lt;p&gt;I had some conversations with the organizers and heard a few interesting tidbits.
Not everything appropriate for sharing publicly here.&lt;/p&gt;
&lt;p&gt;They ran their own BTCPay server and everyone who attended paid in Bitcoin,
with most paying via Lightning.&lt;/p&gt;
&lt;p&gt;People already started paying for tickets in the middle of 2024, so they made a
nice profit. They also saved around R40.000 in credit card processing fees.&lt;/p&gt;
&lt;h2&gt;The attendees&lt;/h2&gt;
&lt;p&gt;The attendees were an eclectic mix. There was a well known Billionaire, the
politicians, a think tank CEO, some civil society leaders, VCs, local
entrepreneurs and plebs.&lt;/p&gt;
&lt;p&gt;One guy raises chickens and sells the eggs for Bitcoin. I saw a lady I
know from outside of Bitcoin, who started an off-grid hippie community in a
nearby forest.&lt;/p&gt;
&lt;p&gt;The conference was small. Compared to the large overseas ones, it’s more like a
large meetup. The nice thing however was that this made everyone accessible,
and I had lots of interesting conversations.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container&quot; style=&quot;max-height: 30em&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5510ade4ccce6e48f2d322ee8867f260/b071e/cape-town.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 54.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAME/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgP/2gAMAwEAAhADEAAAAcyFbSo2Av/EABoQAAICAwAAAAAAAAAAAAAAAAABAhESITL/2gAIAQEAAQUC0yjEikxMjz//xAAXEQADAQAAAAAAAAAAAAAAAAAAARES/9oACAEDAQE/AYjCP//EABkRAAEFAAAAAAAAAAAAAAAAAAABAhESE//aAAgBAgEBPwG6wauP/8QAFxABAAMAAAAAAAAAAAAAAAAAAAERIP/aAAgBAQAGPwLFIf/EABoQAAIDAQEAAAAAAAAAAAAAAAABESFxMUH/2gAIAQEAAT8hTS/COaQfLxDy7HO3Ei2Z/9oADAMBAAIAAwAAABBPP//EABYRAQEBAAAAAAAAAAAAAAAAABEBEP/aAAgBAwEBPxBqZf/EABYRAQEBAAAAAAAAAAAAAAAAAAAxcf/aAAgBAgEBPxCpg//EABoQAQEBAAMBAAAAAAAAAAAAAAERACExUUH/2gAIAQEAAT8QYIs+POElUPSIalaHqJkCVAyr5ilqxDWpWpXnf//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Cape Town&quot;
        title=&quot;&quot;
        src=&quot;/static/5510ade4ccce6e48f2d322ee8867f260/8e1fc/cape-town.jpg&quot;
        srcset=&quot;/static/5510ade4ccce6e48f2d322ee8867f260/863e1/cape-town.jpg 225w,
/static/5510ade4ccce6e48f2d322ee8867f260/20e5d/cape-town.jpg 450w,
/static/5510ade4ccce6e48f2d322ee8867f260/8e1fc/cape-town.jpg 900w,
/static/5510ade4ccce6e48f2d322ee8867f260/b768e/cape-town.jpg 1350w,
/static/5510ade4ccce6e48f2d322ee8867f260/d9c39/cape-town.jpg 1800w,
/static/5510ade4ccce6e48f2d322ee8867f260/b071e/cape-town.jpg 3998w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Converse 8 has been released]]></title><description><![CDATA[I’m happy to announce that, after almost a year of development, the latest
major version of Converse has been released. Converse is an XMPP…]]></description><link>https://opkode.com/blog/2021-09-13-converse-8/</link><guid isPermaLink="false">https://opkode.com/blog/2021-09-13-converse-8/</guid><pubDate>Mon, 13 Sep 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m happy to announce that, after almost a year of development, the latest
major version of Converse has been released.&lt;/p&gt;
&lt;p&gt;Converse is an XMPP chat client, written in JavaScript, that runs in your
web browser. It can be used as a single application, or integrated into an
existing website and works with any standards-conforming &lt;a href=&quot;https://xmpp.org/software/servers.html&quot;&gt;XMPP server&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’d like to try out Converse, you can head over to &lt;a href=&quot;https://conversejs.org&quot;&gt;https://conversejs.org&lt;/a&gt;
(to use it with multiple overlayed chat boxes) or
&lt;a href=&quot;https://conversejs.org/fullscreen.html&quot;&gt;https://conversejs.org/fullscreen.html&lt;/a&gt; to use it as a fullpage app with one
chat visible at a time. If you need to register an account, you can find lists
of public servers at &lt;a href=&quot;https://list.jabber.at/&quot;&gt;jabber.at&lt;/a&gt;, &lt;a href=&quot;https://xmpp-servers.404.city/&quot;&gt;404.city&lt;/a&gt; or &lt;a href=&quot;https://xmpp.net/list.php&quot;&gt;xmpp.net&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This release contains multiple significant technological and architectural
updates, enough to provide fodder for multiple blogposts. Let’s look at a few
highlights.&lt;/p&gt;
&lt;h2&gt;Highlights&lt;/h2&gt;
&lt;h3&gt;Message Styling&lt;/h3&gt;
&lt;p&gt;XMPP’s &lt;a href=&quot;https://xmpp.org/extensions/xep-0393.html&quot;&gt;message styling&lt;/a&gt;
specification describes a way to add markdown-like highlighting to chat
messages.&lt;/p&gt;
&lt;p&gt;Converse 8 finally adds support for this form of text-styling.&lt;/p&gt;
&lt;p&gt;Here’s the output of one of the styling tests, showing how the different
styling directives are rendered:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/95ebd032b6d32a887bebde8ef2d444c9/99e81/converse-8-message-styling.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 74.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAPCAYAAADkmO9VAAAACXBIWXMAABYlAAAWJQFJUiTwAAACn0lEQVR42m1TS2sTYRTN33UjrlwKbkWLCMWNbkUK0kpFVLTNwia00KJQWpNJO5n3+510pjHp8dyvmbRVBw73zuOe79x7z3TMkQn73EYYRoiiCHEcKyRJssqjOEKZF3jb3caj7XU83F3HvY9P8ODzc9z/tIbX/U2EuofQC9AxDBOGbsCyLAXbtv8bPdfFxpctPN1+hWe9N1gj1g/f4eXPLWz++AbbsOD7JPR8Hy4/dhxHQXKB53mrKFDvbQdpmGCSFGjKKWaTBlhcqW7kYIkdTdMwGA6hEYPBQGHI/DZGoxFOTk4QJzGKsoDtOYhYnOQ56vkMfuCrOtM00dk/OECv30ef2Ov1cLC/r/I+855gb0/FbrcLfTxGVhRUksJPMgR5ibKZQdd17O7s4PDoCB2HLQ8MA6f8+HSsY+zY0AnDcZk7CLioNE0RM0ZZDiPKEVUTVCQqLxpML38jzTK10JyKO5K43s0MTc5CYJHU4sx8HiizaQvkPk5j1HWN9pLn4gZF6IcBdG5RJ4nNJURhqIozntridkHI9x5nlhc5ptMp5ovFXUKPhMaSTD5WrUU3nmxjEARKqWw8oMqQ92VZ/qtQZqhZJs5tek0sRMgzUSEx4CHJklAKXM7Wl7wqUFUVFn8rdPhSFiKLEZyReOw6MHwPJiELWRWwTSEO4xDVdKLmePW3QpsqzqjQ5EIM2SoLRFWwnGX7G8o4MpKL94ppg8nFJUlrNHVzl9AlgShrWwuXRAIhUki5Zf7rThogrgtkdYWUyOsJrDLEsaWpwwp6VBFqdPiYiwlF0VKVEKv2WqWE5o2RTHI0VzNczBvMscCv3MT74y7KlMpFocWWT43x9dzcazNb9GUcxastty0HdERrI4EY+pLWGeoWHm98xYsP3/EHb3FPK9Rx0eUAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Screenshot of Converse in fullpage mode, showing a URL preview&quot;
        title=&quot;&quot;
        src=&quot;/static/95ebd032b6d32a887bebde8ef2d444c9/1cfc2/converse-8-message-styling.png&quot;
        srcset=&quot;/static/95ebd032b6d32a887bebde8ef2d444c9/3684f/converse-8-message-styling.png 225w,
/static/95ebd032b6d32a887bebde8ef2d444c9/fc2a6/converse-8-message-styling.png 450w,
/static/95ebd032b6d32a887bebde8ef2d444c9/1cfc2/converse-8-message-styling.png 900w,
/static/95ebd032b6d32a887bebde8ef2d444c9/21482/converse-8-message-styling.png 1350w,
/static/95ebd032b6d32a887bebde8ef2d444c9/d61c2/converse-8-message-styling.png 1800w,
/static/95ebd032b6d32a887bebde8ef2d444c9/99e81/converse-8-message-styling.png 1946w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;OMEMO File Encryption&lt;/h3&gt;
&lt;p&gt;Converse now also supports OMEMO encryption of files, via the
&lt;a href=&quot;https://xmpp.org/extensions/xep-0454.html&quot;&gt;XEP-0454 OMEMO Media sharing&lt;/a&gt; spec.&lt;/p&gt;
&lt;p&gt;This means that sent files (like images, or PDFs), can be end-to-end
encrypted and then, when received on the other end, decrypted and shown in the
chat.&lt;/p&gt;
&lt;h3&gt;Room Activity Indicators&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://xmpp.org/extensions/xep-0437.html&quot;&gt;XEP-0437 Room Activity Indicators (RAI)&lt;/a&gt;
is a more obscure XMPP extension that deals with some of the drawbacks of the
presence-based model of XMPP’s &lt;a href=&quot;https://xmpp.org/extensions/xep-0045.html&quot;&gt;multi-user chat
(MUC)&lt;/a&gt; specification.&lt;/p&gt;
&lt;p&gt;The goal of RAI, is to let the chat client leave a MUC when it’s not longer
visible, while still receiving a notification when new messages have been sent
in that room.&lt;/p&gt;
&lt;p&gt;In collaboration with Matthew Wild and Seve Ferrer de la Peñita, I also wrote
(and added support for) a complementary XEP called
&lt;a href=&quot;https://xmpp.org/extensions/xep-0452.html&quot;&gt;XEP-0452 MUC mention notifications&lt;/a&gt; which informs you
when you’ve been mentioned in a MUC that you’re not currently joined to.&lt;/p&gt;
&lt;p&gt;Converse will automatically subscribe for activity and mention indicators as
soon as the &lt;code class=&quot;language-text&quot;&gt;hidden&lt;/code&gt; flag on a chat room is enabled.&lt;/p&gt;
&lt;p&gt;The only XMPP server that I’m aware of that currently supports these XEPs is Prosody,
via &lt;a href=&quot;https://modules.prosody.im/mod_muc_rai.html&quot;&gt;mod_muc_rai&lt;/a&gt; and
&lt;a href=&quot;https://modules.prosody.im/mod_muc_mention_notifications.html&quot;&gt;mod_muc_mention_notifications&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Rendering of URL previews&lt;/h3&gt;
&lt;p&gt;Converse can now render URL previews (aka “unfurls”), if it receives a message
with structured metadata in &lt;a href=&quot;https://ogp.me/&quot;&gt;Open Graph Protocol (OGP)&lt;/a&gt; format
for a particular URL.&lt;/p&gt;
&lt;p&gt;Most websites use OGP (one notable exception being Twitter) to provide unfurl
metadata.&lt;/p&gt;
&lt;p&gt;Prosody’s &lt;a href=&quot;https://modules.prosody.im/mod_ogp.html&quot;&gt;mod_ogp&lt;/a&gt; can be used to
send this metadata to Converse, and to render Tweet previews
&lt;a href=&quot;https://modules.prosody.im/mod_tweet_data.html&quot;&gt;mod_tweet_data&lt;/a&gt; can be used.&lt;/p&gt;
&lt;p&gt;Below is a screenshot showing the URL preview of a Youtube URL:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;https://conversejs.org/screenshots/Converse-fullscreen.png&quot; alt=&quot;Screenshot of Converse in fullpage mode, showing a URL preview&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Pausing of GIF images&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 17em&quot;&gt; &lt;img src=&quot;/3138f896b8cf9940e56b91f9aba6865e/converse-8-gif.gif&quot; alt=&quot;Recording showing how a GIF is paused in Converse&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Converse now lets you pause animated GIF images. When an animated GIF is
received, it’s passed to a &lt;code class=&quot;language-text&quot;&gt;converse-gif&lt;/code&gt; web component, which renders it with a
&lt;code class=&quot;language-text&quot;&gt;&amp;lt;canvas&gt;&lt;/code&gt; element.&lt;/p&gt;
&lt;p&gt;I’m considering releasing this code as a separate open source project, since it
might be useful to others outside of Converse as well.&lt;/p&gt;
&lt;h3&gt;Project layout changes&lt;/h3&gt;
&lt;p&gt;The layout of the project directories and source files has been changed.
The plugins used to be in single (quite large) files, but now they’re
broken up into multiple smaller files and moved into their own folders.
Tests and styles are now also broken up and put into the same plugin folders.&lt;/p&gt;
&lt;p&gt;More can be done here, especially concerning exracting plugin-specific CSS and
moving it to the relevant plugin folders, but we’ve made a very good start.&lt;/p&gt;
&lt;h3&gt;IndexedDB is the new storage mechanism&lt;/h3&gt;
&lt;p&gt;&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB&quot;&gt;IndexedDB&lt;/a&gt;
is now used as the default storage mechanism. This solves the problem
of users running into the storage limit of localStorage.&lt;/p&gt;
&lt;p&gt;IndexedDB has no storage limit, and it’s also asynchronous, so it doesn’t block
rendering of the UI.
I started working on adding IndexedDB quite a while back, but ran into
performance issues that were difficult to solve. Eventually I managed to find a solution, by using a utility method called
&lt;a href=&quot;&quot;&gt;mergebounce&lt;/a&gt;, which I originally wrote for a different use-case.
You can &lt;a href=&quot;https://opkode.com/blog/2021-05-05-mergebounce-indexeddb/&quot;&gt;read about that solution in my previous blogpost&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;There is no tool to migrate data from localStorage to IndexedDB. For almost all data this is no big
deal since the data can be fetched again from the XMPP server. However,
decrypted OMEMO messages cannot be fetched again from the server, since the
double ratchet makes it impossible to decrypt the messages again.&lt;/p&gt;
&lt;h3&gt;Web components&lt;/h3&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2e216e5c16f7c6851889650d575925fc/6297e/converse-8-webcomponents.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 30.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAABYlAAAWJQFJUiTwAAABBklEQVR42p2Qa3KDMAyEuf/9Ok0yZPKgKU8HG4yNbeCrSHqB1jP7Qyvtaq2sU5ris+T7VHDL73x8dhyOLddLxeGkOJ8rLnlNfmx4FC29tqje8tRv9GZinJzAv5CtbIytQeUV9VlR3wRfhvZh6FqH7mcGE7FDYBZh3we0DozCDUPET5HFJ5KLrGkl24DZBcyjobp2lLeex/VJUVjqasKYgJd+kuFlEaSFGLdXndIm9ZtbwsK2bmTiRwoJfVeYUvMsB6x8Q/+mCrMMx5kggnlOxDkwTQvOJbxf8NLf9UlSvgz3hJOy2G5iFWLb5Ag7ueMfL4uyVeUNjdxPdw5nRkxncdrzdv6b4Q+G3NAsQKFKuQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Screenshot of the DOM showing Converse web components&quot;
        title=&quot;&quot;
        src=&quot;/static/2e216e5c16f7c6851889650d575925fc/1cfc2/converse-8-webcomponents.png&quot;
        srcset=&quot;/static/2e216e5c16f7c6851889650d575925fc/3684f/converse-8-webcomponents.png 225w,
/static/2e216e5c16f7c6851889650d575925fc/fc2a6/converse-8-webcomponents.png 450w,
/static/2e216e5c16f7c6851889650d575925fc/1cfc2/converse-8-webcomponents.png 900w,
/static/2e216e5c16f7c6851889650d575925fc/21482/converse-8-webcomponents.png 1350w,
/static/2e216e5c16f7c6851889650d575925fc/d61c2/converse-8-webcomponents.png 1800w,
/static/2e216e5c16f7c6851889650d575925fc/6297e/converse-8-webcomponents.png 2044w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The Converse UI is now rendered declaratively via web components, using &lt;a href=&quot;https://lit.dev/&quot;&gt;Lit&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Previously Converse was using Backbone Views to render the UI, which reflects
the age of this project. Converse was started in 2012, when Backbone
was still widely used and many of the big JS projects and language features
that people rely on today didn’t exist yet.&lt;/p&gt;
&lt;p&gt;Around 2016, Backbone started to really stagnate I realized we’ll have to eventually
get rid of it.&lt;/p&gt;
&lt;p&gt;I decided it would be preferable to gradually “evolve” the codebase, instead of
doing a large rewrite with a newer framework, which could hold up feature development,
leave existing users and integrators in the lurch and potentially cause &lt;a href=&quot;https://en.wikipedia.org/wiki/Second-system_effect&quot;&gt;second system syndrome&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Over the years, I chipped away at the problem (e.g. removing jQuery, replacing undescore with lodash,
&lt;a href=&quot;https://opkode.com/blog/backbone-vdomview/&quot;&gt;adding a virtual DOM to Backbone Views&lt;/a&gt;), spent
a lot of time on modernizing the code (e.g. promises instead of callbacks)
and on introducing new tools. We were on the JavaScript treadmill, incurring
development costs that projects with more mature languages don’t have.&lt;/p&gt;
&lt;p&gt;Getting rid of Backbone however proved elusive and difficult.
I kept an eye on the developing web component standards, hoping that they might provide a way forward.&lt;/p&gt;
&lt;p&gt;One of my goals for Converse is to make it as customizable and hackable as
possible, to allow developers to tailor it to their needs.
By using web components, we could add a registery in Converse (via &lt;code class=&quot;language-text&quot;&gt;api.elements.define&lt;/code&gt;),
to allow developers to replace the core components with their own at runtime.&lt;/p&gt;
&lt;p&gt;Another goal is to make sure Converse can be integrated into any website.
Web components are framework agnostic, and because they’re actual DOM
elements, they can be used with existing JavaScript frameworks.&lt;/p&gt;
&lt;p&gt;Lit also allowed me to start rewriting and updating the code piecemeal, fitting
the desire to evolve the code instead of rewriting it.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;lit-html&lt;/strong&gt;, Lit’s templating library, uses tagged template literals to
render to the DOM, which allows it to update only those parts of the DOM that
have changed. It doesn’t require a virtual DOM and is blazing fast.&lt;/p&gt;
&lt;p&gt;From early on Converse used separate template files for HTML,
something which I considered desirable given the above-stated goal of
hackability, since separate template files make it easier for
developers and integrators to override and change the HTML that Converse renders.&lt;/p&gt;
&lt;p&gt;lit-html provided a way for us to keep using separate templates files, while
providing a faster and superior templating language. So the first thing I
did was to update all the templates to use lit-html.&lt;/p&gt;
&lt;p&gt;Once that was done, I started rewriting Backbone views into web components
using &lt;strong&gt;lit-element&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Frustrated with the lack of updates to Backbone, I also created a fork called
&lt;a href=&quot;https://github.com/conversejs/skeletor&quot;&gt;Skeletor&lt;/a&gt;, so that I could start
modernizing it.&lt;/p&gt;
&lt;p&gt;In Skeletor I created an &lt;code class=&quot;language-text&quot;&gt;ElementView&lt;/code&gt; class, which was almost exactly like a
Backbone View, but with the added benefit of also being a web component.&lt;/p&gt;
&lt;p&gt;Having the &lt;em&gt;ElementView&lt;/em&gt; made it easier to turn even more of our existing views
into web components, without rewriting lots of code. Over time, I could then refactor
these new web component views into Lit components.&lt;/p&gt;
&lt;p&gt;This is how I was able to gradually update the UI layer of Converse to use
web components without causing significant disruption.&lt;/p&gt;
&lt;h3&gt;Speed improvements&lt;/h3&gt;
&lt;p&gt;Converse now renders much faster than before, mainly due to the usage of Lit.
The easiest way to see this is by running the tests.&lt;/p&gt;
&lt;p&gt;Running the 483 tests for the 8.0.1 release, takes 71 seconds on my laptop.
Running 434 tests (49 fewer tests!) on the 7.x.x branch takes 160 seconds.&lt;/p&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;
&lt;p&gt;A big thanks goes out to everyone who contributed to this release, from development
to bug reports, ticket triage, pull requests and translations.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;A toast to messaging freedom!&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Mergebounce: Increasing performance by batching IndexedDB writes]]></title><description><![CDATA[Converse is a browser-based
XMPP chat client that I’ve been working on.
It stores lots of user-data in the browser, so much data, that users…]]></description><link>https://opkode.com/blog/2021-05-05-mergebounce-indexeddb/</link><guid isPermaLink="false">https://opkode.com/blog/2021-05-05-mergebounce-indexeddb/</guid><pubDate>Wed, 05 May 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;https://conversejs.org&quot;&gt;Converse&lt;/a&gt; is a browser-based
&lt;a href=&quot;https://xmppp.org&quot;&gt;XMPP&lt;/a&gt; chat client that I’ve been working on.
It stores lots of user-data in the browser, so much data, that users were regularly
running into the localStorage limit of about 10MB.&lt;/p&gt;
&lt;p&gt;Luckily there is an alternative storage solution in modern browsers, namely
&lt;a href=&quot;https://developer.mozilla.org/en-US/docs/Glossary/IndexedDB&quot;&gt;IndexedDB&lt;/a&gt;,
which doesn’t have a fixed size limit.&lt;/p&gt;
&lt;p&gt;IndexedDB has a very different API than localStorage, and it’s also
asynchronous, so updating Converse to use it would be a big task.&lt;/p&gt;
&lt;p&gt;Luckily I found the excellent &lt;a href=&quot;https://localforage.github.io/localForage/&quot;&gt;localForage&lt;/a&gt; library,
which provides a unified API for storing data in either localStorage or
IndexedDB (including other potential backends such as sessionStorage).&lt;/p&gt;
&lt;p&gt;localForage helped a lot, but it still took a long time to add Converse support for
IndexedDB (via localForage), mainly because of its asynchronous API.
The Converse code (and its test suite) was structured around quick synchronous
writes to localStorage, so there were implicit assumptions in the code that were
now broken.&lt;/p&gt;
&lt;p&gt;Eventually I managed to get Converse to use localForage, so that the user could
choose which persistent store they’d like to use, sessionStorage, localStorage
or IndexedDB.&lt;/p&gt;
&lt;p&gt;Unfortunately it soon became clear that Converse was painfully slow when
using IndexedDB for moderate to heavy chatting.&lt;/p&gt;
&lt;p&gt;Turns out the issue is that IndexedDB’s writes are slow, and even though
they were asynchronous, they were still slowing the app down. The reason for
this is because with XMPP, you can’t process subsequent messages until
processing of previous ones have been finalized, otherwise you can’t handle
messages that refer to earlier ones, such as
&lt;a href=&quot;https://xmpp.org/extensions/xep-0308.html&quot;&gt;corrections&lt;/a&gt; or
&lt;a href=&quot;https://xmpp.org/extensions/xep-0424.html&quot;&gt;retractions&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So Converse was first waiting until a message object was created (and persisted),
before handing the next incoming message.&lt;/p&gt;
&lt;p&gt;When you opened a chat room, you’d get a 100 messages, but they’d appear
slowly as Converse waits for IndexedDB writes to complete before processing
each subsequent message.&lt;/p&gt;
&lt;p&gt;It was clear that the number of writes to IndexedDB had to be reduced, but I
wasn’t sure how. So I left the problem and moved on to other things, believing
that I’ll eventually think of (or stumble upon) a solution.&lt;/p&gt;
&lt;p&gt;Eventually I did stumbled upon a partial solution in the form of the
&lt;a href=&quot;https://github.com/localForage/localForage-setItems&quot;&gt;localForage-setItems&lt;/a&gt;
plugin, which lets you write write multiple key-value pairs in a single transaction,
something which standard localForage doesn’t support.&lt;/p&gt;
&lt;p&gt;This was useful because while debugging the issue I noticed that whenever a
message was created, two localForage &lt;code class=&quot;language-text&quot;&gt;setItem&lt;/code&gt; calls were made. Once to add the
message to the collection of messages belonging to the chat room, and once to
save the attributes of the actual message.&lt;/p&gt;
&lt;p&gt;With &lt;code class=&quot;language-text&quot;&gt;localForage-setItems&lt;/code&gt; I could collapse these two calls into a single one.&lt;/p&gt;
&lt;p&gt;The second part of the puzzle came months later, when I had an insight while
thinking about reducing HTTP calls in an app.
Multiple function calls could be collapsed into one, if the parameters for
each call were objects that could be merged into a single object.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://lodash.com/docs/4.17.15#debounce&quot;&gt;Debouncing&lt;/a&gt; lets us reduce a number
of successive function calls into a single call, but only the parameters of the
final call of the debounced function are ever passed to the inner executing function.
Earlier passed in parameters are lost.&lt;/p&gt;
&lt;p&gt;If we could create a special kind of debounced function that merges the parameters
of each call, then we could in essence batch multiple function calls into a single one,
without losing any final data compared to executing all the calls separately.&lt;/p&gt;
&lt;p&gt;I set out to create such a function, and called it &lt;a href=&quot;https://github.com/conversejs/mergebounce&quot;&gt;mergebounce&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It uses lodash’s debounce and &lt;a href=&quot;https://lodash.com/docs/4.17.15#debounce&quot;&gt;merge&lt;/a&gt;
functions to create a &lt;code class=&quot;language-text&quot;&gt;mergebounce&lt;/code&gt; function.&lt;/p&gt;
&lt;p&gt;I then realized that this function, together with &lt;code class=&quot;language-text&quot;&gt;localForage-setItems&lt;/code&gt; could solve
the IndexedDB-related slowness in Converse, because the data that was being
saved was objects that could be merged into one and then persisted with a
single write.&lt;/p&gt;
&lt;p&gt;So I set about adding mergebounce to the storage-layer of Converse.&lt;/p&gt;
&lt;p&gt;What I did, was to use mergebounce to create a wrapper function of
&lt;code class=&quot;language-text&quot;&gt;localForage-setItems&lt;/code&gt; that intercepts all calls and after 50ms of inactivity
calls the inner function with a single merged object from all the individual
calls.&lt;/p&gt;
&lt;p&gt;Like debounce, mergebounce has a &lt;code class=&quot;language-text&quot;&gt;flush&lt;/code&gt; method which can be used to
immediately execute the inner bounced function. I added event handlers to flush
all writes when the user logs out of the app, and also when the tab unloads.&lt;/p&gt;
&lt;p&gt;There were a few other kinks to iron out, but I’m happy to report that it turned
out to be a big success.&lt;/p&gt;
&lt;p&gt;The effect on performance was drastic and immediately noticeable.&lt;/p&gt;
&lt;p&gt;I also did some rudimentary profiling. Without mergebounce, I counted over a
hundred and twenty IndexedDB writes when logging into Converse with my personal
XMPP account. With mergebounce, this dropped to about 17. An improvement of almost a factor of ten.&lt;/p&gt;
&lt;p&gt;Truth be told, I’m kind of suprised that I haven’t seen something like
mergebounce before. Maybe it’s out there and I just missed it. In any case, I’m
quite chuffed at having cracked this nut.&lt;/p&gt;
&lt;p&gt;This improvement has been merged to the &lt;code class=&quot;language-text&quot;&gt;master&lt;/code&gt; branch of Converse and will be included
as part of the upcoming 8.0.0 release.&lt;/p&gt;
&lt;p&gt;Since then I’ve also used mergebounce to reduce HTTP calls to fetch resources
in a different project and I expect to reach for it again in the future.&lt;/p&gt;
&lt;p&gt;Pehaps it can be of value to others as well.&lt;/p&gt;
&lt;p&gt;Feel free to reach out to me via my site’s contact form if you’d like to know
more.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Bitcoin as commons]]></title><description><![CDATA[I recently saw an interesting interview with former Canadian prime minister
Stephan Harper, where the topic of Bitcoin briefly came up, and…]]></description><link>https://opkode.com/blog/2021-02-04-bitcoin-as-commons/</link><guid isPermaLink="false">https://opkode.com/blog/2021-02-04-bitcoin-as-commons/</guid><pubDate>Thu, 04 Feb 2021 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently saw an interesting interview with former Canadian prime minister
Stephan Harper&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, where the topic of Bitcoin briefly came up, and I noticed that
he referred to Bitcoin as a “private digital currency”.&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 41.66666666666667%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/HAKetLKjCP8?start=1791&quot; frameborder=&quot;0&quot; allow=&quot;encrypted-media; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt;&lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;I think it’s wrong to call Bitcoin a private currency. In fact, I view Bitcoin
as a type of commons, a &lt;a href=&quot;https://en.wikipedia.org/wiki/Digital_commons_(economics)&quot;&gt;digital commons&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The word “commons” comes from the Latin &lt;em&gt;communis&lt;/em&gt;, the same root that gives us
“commoner”, “community”, “communism” and “commune”, and describes something
&lt;em&gt;“belonging to all, owned or used jointly, general, of a public nature or
character”&lt;/em&gt;&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a href=&quot;#fn-2&quot; class=&quot;footnote-ref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;According to Wikipedia (which is another spectacularly successful digital
commons):&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The commons is the cultural and natural resources accessible to all members of
a society […]. These resources are held in common, not owned privately.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;At first glance, the above sentence might seem to dispute the claim that Bitcoin
is a commons. After all, Bitcoins are privately owned, and no-one can spend or
take ownership of your Bitcoins without getting hold of your private key (which
amounts to stealing them from you).&lt;/p&gt;
&lt;p&gt;In fact, I posted a message on the Fediverse claiming that Bitcoin is a commons
and the argument that Bitcoins themselves are privately owned was brought up as
rebuttal by some people.&lt;/p&gt;
&lt;iframe src=&quot;https://mastodon.xyz/@jcbrand/105646757598892890/embed&quot;
class=&quot;mastodon-embed&quot; style=&quot;border: 0&quot; width=&quot;100%&quot; height=&quot;300px&quot;&gt;&lt;/iframe&gt;
&lt;p&gt;You can read the whole thread here: &lt;a href=&quot;https://mastodon.xyz/@jcbrand/105646757598892890&quot;&gt;https://mastodon.xyz/@jcbrand/105646757598892890&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;The paradox in calling a privately held asset a commons is resolved when one
zooms out and looks at the Bitcoin network as a whole, from which Bitcoins arise
and derive their utility.&lt;/p&gt;
&lt;p&gt;When I call Bitcoin a commons, I’m referring to the Bitcoin network.&lt;/p&gt;
&lt;p&gt;In fact, it’s debatable in which sense Bitcoins themselves actually exist. They
have no corporeal existence and no separate existence independent of the Bitcoin
network. They exist only as entries in a distributed ledger (the blockchain)
that is secured, updated and maintained via mining nodes on the network.&lt;/p&gt;
&lt;p&gt;It is the network that gives the Bitcoins value, how much value is
largely subjective and based on what people are willing to exchange for them&lt;sup id=&quot;fnref-3&quot;&gt;&lt;a href=&quot;#fn-3&quot; class=&quot;footnote-ref&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The next rebuttal that one might think of, is that the network isn’t a commons,
because it’s comprised of private entities that all act in their own
self-interest and use their own private hardware. As someone replied on Mastodon,
&lt;em&gt;“the network is just a metaphor for privately owned hardware”&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;I believe this to be an oversimplification of what the network really is.&lt;/p&gt;
&lt;p&gt;The network transcends the hardware, but even if it was just the
hardware, that hardware can be owned by anyone. It can be owned by
governments, public universities, book clubs, communes, worker cooperatives and any
other form of human organisation that one could imagine.&lt;/p&gt;
&lt;p&gt;You could also theoretically run Bitcoin without computer hardware on a pen and
paper system. People could do the proof of work (PoW) calculations (the factoring
of prime numbers) by hand and then mail copies to other participants,
who would verify them and update the blockchain (written on paper) with the new
transactions.&lt;/p&gt;
&lt;p&gt;Transactions would take days or weeks to clear and &lt;a href=&quot;https://en.bitcoin.it/wiki/Chain_Reorganization&quot;&gt;reorgs&lt;/a&gt;
would probably happen more frequently. Also the PoW difficulty would have to be
such that human beings could do the factoring by hand, but aside from that, I’m
not aware of anything about Bitcoin that intrinsically requires digital computers
and hardware (although they are a &lt;em&gt;practical&lt;/em&gt; requirement).&lt;/p&gt;
&lt;p&gt;The network comes into being as soon as the participants (aka nodes) are able to
connect to one another, agree on a protocol and adhere to the rules of the
protocol.&lt;/p&gt;
&lt;p&gt;Bitcoin is a peer-to-peer (p2p) network, which means that any node can connect
to any other node and there is no central hub through which traffic must be
routed (as would be the case in a centralized network like Facebook or Visa).&lt;/p&gt;
&lt;p&gt;The distributed consensus mechanism based on proof-of-work (aka the “mining” of
Bitcoins) is the way in which the rules of the protocol are enforced in a
decentralized, p2p manner without a central authority.&lt;/p&gt;
&lt;p&gt;The Bitcoin protocol is described and implemented by the
&lt;a href=&quot;https://github.com/bitcoin/bitcoin&quot;&gt;Bitcoin-core&lt;/a&gt; software,
which Satoshi Nakomoto wrote and published as free and open source software.&lt;/p&gt;
&lt;p&gt;It’s generally accepted that free and open source software forms a digital
commons, since anyone in the world is allowed to study, modify, run and
distribute the software without encumberance&lt;sup id=&quot;fnref-4&quot;&gt;&lt;a href=&quot;#fn-4&quot; class=&quot;footnote-ref&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The global database used by the Bitcoin network, the blockchain, is also a
commons in the sense that anyone can download it, study and modify it, and
distribute it to others.&lt;/p&gt;
&lt;p&gt;If you want others to accept your modifications to the blockchain as valid
updates to the ledger, you have to conform to the protocol rules and
also provide proof of work by way of generating a hash that conforms to a
specific difficulty function. This requirement is in order to maintain
the integrity of the ledger, the security of the network and to create
distributed consensus in a trustless environment.&lt;/p&gt;
&lt;p&gt;In fact, in order to fully participate in the Bitcoin network, you &lt;em&gt;have&lt;/em&gt; to
download the entire blockchain.&lt;/p&gt;
&lt;p&gt;One could argue that the requirement to fulfill the proof-of-work in order
to update the ledger in some way negates the proposition that Bitcoin is
a commons. To me this is akin to the argument that Wikipedia is not a commons
because there are moderators who delete unwanted edits to a page. I don’t think
this argument holds&lt;sup id=&quot;fnref-5&quot;&gt;&lt;a href=&quot;#fn-5&quot; class=&quot;footnote-ref&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;The Bitcoin protocol itself is designed in such a way as to make the network
permissionless. What this means is that no-one can interfere in the operations
of the network in order to prevent you from participating (in the form of mining,
sending or receiving Bitcoins or verifying transactions).&lt;/p&gt;
&lt;p&gt;With the caveat that no single entity acquires 51% of the hashing power of the
entire network. But even then, in such a scenario this would be seen as an
attack on the network and an attempt to break the agreed upon rules.&lt;/p&gt;
&lt;p&gt;If a successful attack or hard fork were to happen which changes the properties of
Bitcoin so that it becomes permissioned in some way, it would no longer
be a commons, but it would also no longer be Bitcoin.&lt;/p&gt;
&lt;p&gt;So, given the fact that the necessary software to bootstrap, run and maintain
the network is a digital commons, the fact that the network is permissionless
and allows anyone in the world to participate, the fact that the database is
public and accessible to all, and the fact that you’re not dependent on any
particular private entity’s hardware to participate, it’s clear to me that
the Bitcoin network (the thing that gives birth to Bitcoin the currency and
to some extent gives it value) is a digital commons.&lt;/p&gt;
&lt;p&gt;But let’s take this analysis a little further by comparing Bitcoin to something
that’s meant to be similar, but is actually very different.&lt;/p&gt;
&lt;p&gt;Various central banks are working on what’s called “Central bank digital
currencies”, or CBDCs. These CBDCs are directly inspired by Bitcoin and
cryptocurrencies in general and are in some sense a response to the existence
and rise of Bitcoin&lt;sup id=&quot;fnref-6&quot;&gt;&lt;a href=&quot;#fn-6&quot; class=&quot;footnote-ref&quot;&gt;6&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;In any case, CBDCs will most likely not form a commons. They won’t be
permissionless because only trusted parties (banks) will be able to “mine” new currency units,
and the software necessary to bootstrap, run and maintain the CBDC
network will most likely not be free and open source.&lt;/p&gt;
&lt;p&gt;In fact, given that central banks and their member banks are usually private
entities owned by private shareholders, I’d contend that CBDCs are actually
the real private currencies!&lt;/p&gt;
&lt;p&gt;Similarly, Libra, the proposed cryptocurrency initiative by Facebook and a
consortium of private componies, would also not be a commons because issuence
won’t be permissionless and the node software probably not free and open source either.&lt;/p&gt;
&lt;p&gt;Bitcoin, and some other cryptocurrencies, are special and different from CBDCs
and private currencies like the proposed Libra, and that comes from it’s nature
as commons. An open network that’s non-exclusionary, with the source code, protocol
and the database publicly visible for all to see and verify.&lt;/p&gt;
&lt;h2&gt;Footnotes&lt;/h2&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;I came away very impressed by Stephen Harper, especially since he’s willing to criticize central bank policies and is willing to admit that they’ve blown huge asset bubbles (thereby massively increasing income inequality).&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;a href=&quot;https://www.etymonline.com/word/common&quot;&gt;etymonline&lt;/a&gt;&lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;This would also largely be my response to Stephen Harpers question as to what makes them a store of value.&lt;a href=&quot;#fnref-3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;These are known as the four freedoms that define free software.&lt;a href=&quot;#fnref-4&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-5&quot;&gt;I like my puns intended.&lt;a href=&quot;#fnref-5&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-6&quot;&gt;I also believe that they arise out of the desire of central banks to do away with physical cash altogether and to have totalitarian control over the issuance and usage of money.&lt;a href=&quot;#fnref-6&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Report on the Dusseldorf XMPP sprint]]></title><description><![CDATA[Recently we held another XMPP sprint, this time in Dusseldorf at the Chaosdorf clubhouse. We had 10 participants and an ambitious agenda…]]></description><link>https://opkode.com/blog/xmpp-sprint-dusseldorf/</link><guid isPermaLink="false">https://opkode.com/blog/xmpp-sprint-dusseldorf/</guid><pubDate>Thu, 29 Nov 2018 17:30:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently we held another XMPP sprint, this time in Dusseldorf at the Chaosdorf clubhouse.&lt;/p&gt;
&lt;p&gt;We had 10 participants and an ambitious agenda with a long list of proposed
topics to sprint on. We didn’t get to work on everything, and we spent a considerable
amount of time discussing and prioritizing the agenda.
Some of the things not worked on can however easily be moved to future sprints.
After the sprint, iNPUTmice suggested that we consider having more focused
sprints, for example focusing only on implementing &lt;a href=&quot;https://xmpp.org/extensions/xep-0369.html&quot;&gt;XEP-369 MIX&lt;/a&gt;
in clients and servers.&lt;/p&gt;
&lt;p&gt;I think having a more focused, single-topic sprint is a great idea, and MIX is
a good topic to tackle. AFAIK there’s currently no FOSS MIX implementation for
either clients or servers. IMO this can partly be attributed to a
stalemate situation where everyone is waiting for someone else to make the
first move. By organizing a sprint around it we can break the deadlock by
starting to work on it together.
Discussions&lt;/p&gt;
&lt;h2&gt;Easy-muc-joining (jcbrand, Ge0rG, pep., Link Mauve)&lt;/h2&gt;
&lt;p&gt;This was related to the &lt;a href=&quot;https://github.com/ge0rg/easy-xmpp-invitation&quot;&gt;Easy XMPP Invitation&lt;/a&gt;
work already done by Ge0rG. When using a supporting client, you can
generate a URL to a landing page which makes it easy for someone to
create a new XMPP account and/or to join a groupchat (aka multi-user chat, MUC).&lt;/p&gt;
&lt;p&gt;For “easy MUC joining”, the goal is to figure out whether a MUC is
hosted somewhere in a webchat, and to present this to the user so that
they’re not forced to choose, download and install a desktop client.&lt;/p&gt;
&lt;p&gt;Various approaches were discussed and eventually we decided that since
the invitation URL is generated by a MUC service, that MUC service can
also encode in the URL whether it has an associated webchat or not.&lt;/p&gt;
&lt;p&gt;Initially we thought about using XEP-0156 service discovery on the MUC,
but after discussing it futher with Ge0rG, we agreed that
&lt;a href=&quot;https://xmpp.org/extensions/xep-0401.html&quot;&gt;XEP-0401 Easy User Onboarding&lt;/a&gt;
can be extended to MUCs as well, so that the MUC can be queried similarly to
how a &lt;a href=&quot;https://xmpp.org/extensions/xep-0401.html#create-invitation&quot;&gt;user invitation&lt;/a&gt;
is generated.&lt;/p&gt;
&lt;h2&gt;MUC Push Notifications (jcbrand, iNPUTmice, Ge0rG, MattJ, Link Mauve)&lt;/h2&gt;
&lt;p&gt;XMPP has an extension
&lt;a href=&quot;https://xmpp.org/extensions/xep-0357.html&quot;&gt;XEP-0357&lt;/a&gt; which allows you
to register an external push service (such as Google Play for Android)
to which messages can be pushed when you’re offline.&lt;/p&gt;
&lt;p&gt;This approach can also be used for registering a push service that sends
out email notifications. This is especially useful in a teamchat setup
(like Slack, Mattermost, etc.).&lt;/p&gt;
&lt;p&gt;XEP-0357 calls the push service the “app server”, but I find this
terminology confusing and too much tied to the mobile use-case, so I’ll
stick with “push service” instead.&lt;/p&gt;
&lt;p&gt;XEP-0357 currently doesn’t mention MUCs at all and we wanted to discuss
how registering a push service for MUCs would work.&lt;/p&gt;
&lt;p&gt;Before this sprint, I wrote a proof-of-concept Prosody module,
&lt;a href=&quot;https://modules.prosody.im/mod_muc_cloud_notify.html&quot;&gt;mod_muc_cloud_notify&lt;/a&gt;
which can be used with &lt;a href=&quot;http://conversejs.org/&quot;&gt;Converse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;That module has the requirement that the MUC knows the JID (Jabber ID)
of all the users, so that it can keep track of the push services
registered for them, and it needs to know the JID even when the user is
offline. Additionally the module requires that
&lt;a href=&quot;https://xmpp.org/extensions/xep-0372.html&quot;&gt;XEP-0372 references&lt;/a&gt; are used to make
it clear when someone is mentioned.&lt;/p&gt;
&lt;p&gt;This restriction means that anonymous rooms are excluded, and requires
that all users &lt;a href=&quot;https://xmpp.org/extensions/xep-0045.html#register&quot;&gt;register their nicknames on the MUC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;iNPUTmice proposed simply keeping some kind of token other than the JID,
to keep track of registered push services, removing the need for
nickname registrations.&lt;/p&gt;
&lt;p&gt;Additionally he suggested sending all messages to the push service,
instead of sending only messages in which the offline user is explicitly
mentioned. This opens the possibility of configuring the push service to
also notify you based on other criteria, for example when a particular
keyword or phrase is mentioned.&lt;/p&gt;
&lt;p&gt;We agreed that XEP-0372 is broad enough for this usecase and that we
don’t need a new XEP.&lt;/p&gt;
&lt;h2&gt;Sync open conversations across clients (pep., iNPUTmice, Ge0rG, Link Mauve, MattJ, jcbrand)&lt;/h2&gt;
&lt;p&gt;A common request I’ve received from customers, and something which
isn’t yet solved in a standardized way, is the ability keep track of
open conversations across multiple chat clients (e.g. Desktop, mobile
and web) or sessions and to quickly get information on the amount of
unread messages or mentions in those conversations.&lt;/p&gt;
&lt;p&gt;We spent a substantial amount of time discussing this feature, trying to
cover as many use-cases as possible while coming up with something
elegant.&lt;/p&gt;
&lt;p&gt;Eventually it was decided to split the requirement into two parts and to
only discuss one, leaving the other for a later date.&lt;/p&gt;
&lt;p&gt;The two new requirements are:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;To keep track of open conversations across chat clients (and chat sessions)&lt;/li&gt;
&lt;li&gt;To get an overview of unread messages and mentions for those open conversations&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;The proposed solution for #1 is to use a private PEP node containing a
list of JIDs representing open chats.&lt;/p&gt;
&lt;p&gt;Like the &lt;a href=&quot;https://xmpp.org/extensions/xep-0402.html&quot;&gt;Bookmarks2&lt;/a&gt;
specification, items should be stored separately, so that they can be
added and removed individually (i.e. without having to specify the whole
list).&lt;/p&gt;
&lt;p&gt;This will require us to fix
&lt;a href=&quot;https://xmpp.org/extensions/xep-0163.html&quot;&gt;PEP&lt;/a&gt; so that we can get
deletion notifications.&lt;/p&gt;
&lt;p&gt;MUC JIDs aren’t stored in this list, since we already have the
auto-join feature for MUC bookmarks. Private MUC chats will however be
stored as well.&lt;/p&gt;
&lt;h2&gt;XEP-0283 &amp;#x3C;moved/&gt; (pep., Ge0rG)&lt;/h2&gt;
&lt;p&gt;&lt;a href=&quot;https://xmpp.org/extensions/xep-0283.html&quot;&gt;XEP-0283&lt;/a&gt; provides a
mechanism for informing your contacts that you’re changed your account
and now have a new JID.&lt;/p&gt;
&lt;p&gt;pep. and Ge0rG had a discussion on how to automate the operation
entirely.&lt;/p&gt;
&lt;p&gt;Currently the security considerations contain a clause which to them
defeats the point of the XEP:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“In order to prevent other users from maliciously altering contacts the client SHOULD NOT automatically subscribe to a &lt;moved/&gt; JID when it receives an unsubscribe and SHOULD NOT automatically unsubscribe to a &lt;moved/&gt; JID when it receives a subscribe.”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Also the XEP uses presence stanza only, which makes the whole operation
rather ephemeral.&lt;/p&gt;
&lt;p&gt;The plan is to change the XEP to use PEP mostly.&lt;/p&gt;
&lt;h3&gt;Programming, documentation and various other tasks&lt;/h3&gt;
&lt;p&gt;iNPUTmice added two new tests to the &lt;a href=&quot;https://compliance.conversations.im/&quot;&gt;compliance
tester&lt;/a&gt;, one for MUC Avatars and a
check for CORS Headers on HTTP Upload, which is especially important for
webchat clients like Converse.&lt;/p&gt;
&lt;p&gt;He also tried to fix a bug in Conversations that happens intermittently
on Android 9.&lt;/p&gt;
&lt;p&gt;MattJ worked on the 0.11 release of Prosody. He also worked on adding
support for CORS in
&lt;a href=&quot;https://modules.prosody.im/mod_http_upload.html&quot;&gt;mod_http_upload&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;pep. registered an XMPP assembly for 35C3. He also worked on the slixmpp
OMEMO plugin and got decryption working. Additionally he and Link Mauve
worked on a French translation of the Prosody release announcement.&lt;/p&gt;
&lt;p&gt;Link Mauve worked on implementing Jingle in Converse, fixing bugs and
&lt;a href=&quot;https://github.com/jsxc/strophe.jinglejs/pull/7&quot;&gt;updating strophe.jingle.js to not use
jQuery&lt;/a&gt;. As part of
this, he and I looked at better exception handling in Converse.&lt;/p&gt;
&lt;p&gt;He also helped pep. and syndace with the slixmpp plugin interface and
spent some time trying to deploy &lt;a href=&quot;https://www.jsxc.org/&quot;&gt;JSXC&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Roel worked on the homebrewserver.club article on how to &lt;a href=&quot;https://homebrewserver.club/configuring-a-modern-xmpp-server.html&quot;&gt;configure a
modern XMPP
server&lt;/a&gt;.
MattJ helped out on Sunday as well and AFAIK their collaboration also
caused MattJ to add some clarifications and simplifications to the
Prosody config file.&lt;/p&gt;
&lt;p&gt;Roel and rtq3 also worked on a Spanish translation of the
homebrewserver.club article.&lt;/p&gt;
&lt;p&gt;Syndace worked on resurrecting a non-merged PR from Andy Straub for the
OMEMO XEP which adds various changes to the XEP, including using an
XML-based wire format. By choosing our own wire format, we also make
permissive OSS licensed OMEMO implementations possible. Such a change
will however not be backwards compatible with current OMEMO
implementations.&lt;/p&gt;
&lt;p&gt;Andy joined us on Sunday and participated in discussions around the PR
and OMEMO in general with iNPUTmice, pep and Syndace.&lt;/p&gt;
&lt;p&gt;Haeckse showed us a demo of Chatty, the chat (and SMS) client that she
is working on for the upcoming Purism phone.&lt;/p&gt;
&lt;p&gt;I worked on adding support for
&lt;a href=&quot;https://xmpp.org/extensions/xep-0156.html&quot;&gt;XEP-0156&lt;/a&gt; to Converse, based
on a PR from Link Mauve. The original PR was closed, due to being very
old and difficult to merge, and work is now continuing in a branch with
a new PR &lt;a href=&quot;https://github.com/conversejs/converse.js/pull/1340&quot;&gt;#1340&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I also made smaller fixes and changes, for example only rendering image
URLs inline if they use HTTPS (to avoid mixed-content warnings in the
browser).&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;h3&gt;Chaosdorf&lt;/h3&gt;
&lt;p&gt;Much thanks to &lt;a href=&quot;https://wiki.chaosdorf.de/Chaosdorf&quot;&gt;Chaosdorf&lt;/a&gt;, for
generously making their clubhouse available for the sprint.&lt;/p&gt;
&lt;p&gt;Kuro even made some chilli for lunch and baked a cake!&lt;/p&gt;
&lt;p&gt;In the evenings we went out to dinner. Dusseldorf has a large Japanese
population, so we were quite keen to try out some Japanese food.&lt;/p&gt;
&lt;p&gt;I had proper Ramen for the first time on Sunday night and on Saturday we
had some great sushi.&lt;/p&gt;
&lt;h2&gt;Future sprints&lt;/h2&gt;
&lt;p&gt;A sprint can be measured by its output in the form of code,
documentation, translations and so forth, but this only tells part of
the story.&lt;/p&gt;
&lt;p&gt;Much of what makes sprints valuable is the social aspect of making
friends and working together on something you all care about.&lt;/p&gt;
&lt;p&gt;One way to judge the success of the sprint, is to consider how excited
the participants are about organising and attending future sprints.&lt;/p&gt;
&lt;p&gt;Roel intends to organize a sprint in Brussels, around the time of the
XMPP summit and FOSDEM. This sprint will focus on UI/UX issues and on
finding a common user-facing terminology for XMPP clients. Roel comes
from a design background and will be inviting some fellow like-minded
designers to join.&lt;/p&gt;
&lt;p&gt;Link Mauve indicated that he’d like to organize a sprint in Paris in
2019 and pep. thinks we should go to Sweden.&lt;/p&gt;
&lt;p&gt;During our sprint we also found out that the Berlin XMPP Meetup group is
considering organizing a sprint there soon.&lt;/p&gt;
&lt;p&gt;Then there’s also the upcoming 35C3, where there will be an XMPP
assembly and the opportunity to hack together.&lt;/p&gt;
&lt;p&gt;Thanks to everyone who joined the Dusseldorf sprint, some of whom spent
a considerable sum of money in order to be there. I had a great time and
am looking forward to more such events coming in 2019.&lt;/p&gt;
&lt;h2&gt;Come chat with us&lt;/h2&gt;
&lt;p&gt;We hang out in the XMPP-Sprint groupchat and this is also where upcoming
XMPP sprints will be discussed and planned.&lt;/p&gt;
&lt;p&gt;You can visit the webchat at &lt;a href=&quot;https://chat.cluxia.eu/anon/#xmpp-sprint&quot;&gt;https://chat.cluxia.eu/anon/#xmpp-sprint&lt;/a&gt;
or click on
&lt;a href=&quot;xmpp:xmpp-sprint@chat.cluxia.eu?join&quot;&gt;&lt;a href=&quot;xmpp:xmpp-sprint@chat.cluxia.eu?join&quot;&gt;xmpp:xmpp-sprint@chat.cluxia.eu?join&lt;/a&gt;&lt;/a&gt;
to open it in an installed client.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c9b4bc9dfcd7476b9395881c06b4db0f/bcd4e/2018-11-29-dusseldorf-sprint.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 59.111111111111114%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAFRuXpLQJIf/8QAGhAAAgIDAAAAAAAAAAAAAAAAAQIAAxESM//aAAgBAQABBQJCmxNQbKwdmYiGx1n/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAcEAACAgIDAAAAAAAAAAAAAAABAgAREBIhMnH/2gAIAQEABj8CXZuDOxPgwI1Slap//8QAGRAAAwEBAQAAAAAAAAAAAAAAAAERITFB/9oACAEBAAE/IfZhsXDLpJW8BM1uiVhYNPMGtCRYj//aAAwDAQACAAMAAAAQIA//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREh/9oACAEDAQE/EEqqYf/EABYRAQEBAAAAAAAAAAAAAAAAAAAhMf/aAAgBAgEBPxDIr//EAB0QAQEAAgIDAQAAAAAAAAAAAAERADEhYUFRkbH/2gAIAQEAAT8QewKCwYOH7MgoVJX2t8c5SAlt3+YD3bDXGsOtY9g7yRlTQaM//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;2018 11 29 dusseldorf sprint&quot;
        title=&quot;&quot;
        src=&quot;/static/c9b4bc9dfcd7476b9395881c06b4db0f/8e1fc/2018-11-29-dusseldorf-sprint.jpg&quot;
        srcset=&quot;/static/c9b4bc9dfcd7476b9395881c06b4db0f/863e1/2018-11-29-dusseldorf-sprint.jpg 225w,
/static/c9b4bc9dfcd7476b9395881c06b4db0f/20e5d/2018-11-29-dusseldorf-sprint.jpg 450w,
/static/c9b4bc9dfcd7476b9395881c06b4db0f/8e1fc/2018-11-29-dusseldorf-sprint.jpg 900w,
/static/c9b4bc9dfcd7476b9395881c06b4db0f/b768e/2018-11-29-dusseldorf-sprint.jpg 1350w,
/static/c9b4bc9dfcd7476b9395881c06b4db0f/bcd4e/2018-11-29-dusseldorf-sprint.jpg 1632w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Converse 4 released]]></title><description><![CDATA[After more than 7 months of active development, Converse 4
has finally been released. Converse is an open source XMPP-based chat client…]]></description><link>https://opkode.com/blog/converse-4-released/</link><guid isPermaLink="false">https://opkode.com/blog/converse-4-released/</guid><pubDate>Fri, 21 Sep 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After more than 7 months of active development, &lt;a href=&quot;https://github.com/conversejs/converse.js/releases&quot;&gt;Converse 4&lt;/a&gt;
has finally been released.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://conversejs.org&quot;&gt;Converse&lt;/a&gt; is an open source &lt;a href=&quot;http://xmpp.org/&quot;&gt;XMPP&lt;/a&gt;-based chat client written in
JavaScript and which runs in your browser.&lt;/p&gt;
&lt;p&gt;This release contains lots of highlights, including rewriting the UI to use
Bootstrap 4, support for &lt;a href=&quot;https://conversations.im/omemo/&quot;&gt;OMEMO Encryption&lt;/a&gt;
of private messages, message corrections and file-sharing via HTTP file upload.&lt;/p&gt;
&lt;p&gt;XMPP is an IETF standardized messaging and presence protocol with multiple
independent server and client implementations.&lt;/p&gt;
&lt;p&gt;Unlike other popular open source teamchat applications like Mattermost and
Rocket.chat, Converse doesn’t depend on any particular server (e.g. backend) application.
Any XMPP server which supports the relevant extensions (aka XEPs) will do.&lt;/p&gt;
&lt;p&gt;Converse is 100% front-end JavaScript and CSS. The only backend you need is an
XMPP server, which you can either set up and host yourself or you can sign up on an
existing one.&lt;/p&gt;
&lt;h2&gt;XMPP’s killer feature&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;right images-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 486px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/84582b4bee6dfbfc699f9d5f95555fb6/d7db9/USS_Enterprise_(NCC-1701-A).jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAKABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAIDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB41mYhEv/xAAZEAADAQEBAAAAAAAAAAAAAAAAAQIRITH/2gAIAQEAAQUCnGW1JpPG/T//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAbEAACAQUAAAAAAAAAAAAAAAAAARICESAhMf/aAAgBAQAGPwJJU3ZGGzmH/8QAGxABAAICAwAAAAAAAAAAAAAAAQARITEQYZH/2gAIAQEAAT8h3EvZmmHdxC6RIo09Rq7b4//aAAwDAQACAAMAAAAQ7A//xAAVEQEBAAAAAAAAAAAAAAAAAAAQQf/aAAgBAwEBPxCn/8QAFREBAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQIBAT8Qh//EAB4QAAICAQUBAAAAAAAAAAAAAAERACExEEFRYXHR/9oACAEBAAE/ED5NVWPUrxuKL77HAA8hzTMkjDIQnkl6f//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;USS Enterprise  NCC 1701 A &quot;
        title=&quot;&quot;
        src=&quot;/static/84582b4bee6dfbfc699f9d5f95555fb6/d7db9/USS_Enterprise_(NCC-1701-A).jpg&quot;
        srcset=&quot;/static/84582b4bee6dfbfc699f9d5f95555fb6/863e1/USS_Enterprise_(NCC-1701-A).jpg 225w,
/static/84582b4bee6dfbfc699f9d5f95555fb6/20e5d/USS_Enterprise_(NCC-1701-A).jpg 450w,
/static/84582b4bee6dfbfc699f9d5f95555fb6/d7db9/USS_Enterprise_(NCC-1701-A).jpg 486w&quot;
        sizes=&quot;(max-width: 486px) 100vw, 486px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;XMPP allows for something called &lt;code class=&quot;language-text&quot;&gt;federation&lt;/code&gt;. Even if you’ve never
heard the word being used in this context, you already know what it
means if you’ve used email.&lt;/p&gt;
&lt;p&gt;When you sign up for an email account from one provider (for example
Gmail, Fastmail or Kolab), you can still send emails to people who have
accounts at other providers. That’s because Email is also federated.&lt;/p&gt;
&lt;p&gt;A federated protocol allows you to communicate with user-accounts on
foreign hosts. The network is decentralized between many providers (who
all adhere to a common protocol), instead of being controlled by a
single centralized behemoth (like Facebook, Twitter or LinkedIn).&lt;/p&gt;
&lt;p&gt;Federation is getting quite a lot of renewed attention lately, in large
part due to the hype around the federated social networking site
&lt;a href=&quot;https://joinmastodon.org/&quot;&gt;Mastodon&lt;/a&gt; which is based on the recently
published ActivityPub standard.&lt;/p&gt;
&lt;p&gt;You’re not forced to federate when running an XMPP server for your
organisation, friends or family, and sometimes it makes sense not to.&lt;/p&gt;
&lt;p&gt;However it’s in my opinion the killer feature of XMPP and one of the
main reasons why I’m working on Converse.&lt;/p&gt;
&lt;p&gt;Federation implies user-freedom and user-choice, and it’s one thing
that Slack or Discord simply cannot do. Not because it’s not
technically feasible, but because their business models, based on user
lock-in and control, don’t allow it.&lt;/p&gt;
&lt;p&gt;It’s also something which the open source Slack-alikes like Mattermost
and Rocket.chat don’t have.&lt;/p&gt;
&lt;p&gt;I believe people should have the freedom to use the chat app of their
choice, while still being able to effectively communicate with their
contacts who prefer to use a different chat app.&lt;/p&gt;
&lt;p&gt;XMPP and federation can make this a reality.&lt;/p&gt;
&lt;p&gt;In a world of federated chat apps, some people will use a commandline
client like &lt;a href=&quot;https://poez.io/en/&quot;&gt;Poezio&lt;/a&gt;, a desktop client like
&lt;a href=&quot;https://dino.im/&quot;&gt;Dino&lt;/a&gt; or a mobile client like
&lt;a href=&quot;https://conversations.im/&quot;&gt;Conversations&lt;/a&gt; (or a combination of all
three).&lt;/p&gt;
&lt;p&gt;There will also be a growing need for web-based chat clients, and
that’s were Converse comes in.&lt;/p&gt;
&lt;p&gt;Federation not only provides choice between chat clients, it can also
foster inter-departmental or inter-organisational communication.&lt;/p&gt;
&lt;p&gt;In Germany, where I currently live, there is a lot of talk of
digitization of government. Government bureaucracy often consists of
various different departments who need coordinate and send resources
around.&lt;/p&gt;
&lt;p&gt;The same of course applies to large enterprises.&lt;/p&gt;
&lt;p&gt;A decentralized and federation communications protocol can play a large
role here, and I’m not just talking about chat apps.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://salut-a-toi.org/&quot;&gt;Salut à Toi&lt;/a&gt; project has shown how you
can create a decentralized and federated issue tracker, while
&lt;a href=&quot;https://movim.eu/&quot;&gt;Movim&lt;/a&gt; has blogging and microblogging capabilities,
all based on XMPP.&lt;/p&gt;
&lt;h2&gt;Converse’s history&lt;/h2&gt;
&lt;p&gt;Converse was originally developed at
&lt;a href=&quot;https://en.syslab.com/homepage/&quot;&gt;Syslab.com&lt;/a&gt; as part of a web-based
intranet for the Star Alliance airline group.&lt;/p&gt;
&lt;p&gt;Back then it was developed as a Gtalk-like popover chat, like you still
see on LinkedIn.&lt;/p&gt;
&lt;p&gt;After open sourcing it, my initial goal was to make it as configurable
and capable as possible, so that it could be used in any website in
almost any conceivable manner.&lt;/p&gt;
&lt;p&gt;A powerful plugin architecture and API was added, which allows you to
add or remove features and change just about any behaviour.&lt;/p&gt;
&lt;p&gt;Over time, as the project matured and people started using it, it became
clear that there are many more usecases for a webchat than simply
popover chats.&lt;/p&gt;
&lt;p&gt;Full-page teamchat apps like Slack also became spectacularly successful.&lt;/p&gt;
&lt;p&gt;I subsequently updated Converse to have different “view modes”, which
enable you to use it in different ways, depending on your needs.&lt;/p&gt;
&lt;p&gt;The focus also shifted slightly from presenting it merely as something
to be integrated into an existing website, to showing that it can be an
independent chat client in its own right.&lt;/p&gt;
&lt;p&gt;There is the “overlay” mode, which matches the original UX design:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3e8aee0fd1b38b8ce9e064c06b59a131/86177/Screen-Shot-2018-09-19-at-19.15.16.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAADFElEQVR42jWS/U+TZxSG+6fsh32wSSYL4Qc23OY2zWRuC5sYtyxWO93MtIiFEUA+SgEzrEUU1m1kg1FRUuYUZYplGFDmmF9VBm1pFWr5sPaDvrQvlNdWuPZYs5M8eXKSkyv3fc6t0m7fhb6wgMaKA3Q0ltPziwFb1yGGTn/H1dOHuGKtY/BUDZdP6OnvqOXCz9X0ttZwxqyn+1gVJ42VtNcf5KeqgzQVl6L6+pMtVOxWc6xsL5bDRZw1l9HXVontZA1DZxoZ7jWL/zgD1qNc7DRxobUeq2E/J6q0tJXvw1T4JfV71Og1airUO1Fp8/Ko0XxOc5EGi+Ebfjftp+/4Aa437GG0SccdoxZ7g5Zbh3XcbtBhbSqnuFaDtno7u0u2YRbqOo8eof2IEVNZBarCzbnUfpFH897PsJSqsVbvoL+xEKn/N/x/dBHu60a6ZGXB1k30YjcDvadoGenhB/s5zNesDN+6zbKS5GnduXETVdHGd6jL30SL5iN+LdhCl+5Tzhm+wh8OIydXSK6upoaVJytElmQmnU48Li/BmQBSMIzT5SQmy6mZG9dGUH379hvUb15P87YNtGlysezayNmyHYQDAaILErFoFGVpicW4zGxohknHONMhidkFmSmf6D0e4stKCnj9LwEsyc6i7r1smj5cR+vW9bRtzaFrXz4zcwF8vmk8nntIEUnYiqfgnrFxHoUixATEPzeLy+VmOfHM8t9Dw0JhZgaGnEyM72bRkvs632/KomPnx8Qj8yjSPEk5CsL28mMFSSh2j44SfOQnkVAICODo+ASJlRSPq4NXUOnS06nMXEtddgbGtwQ451V+zH8fZXqSpHiJOR9Pgg+JRyXmJQmn3Y5vepagFBPqp3A6J1h5tmaGBgZFbF5Mo2TNGioz0jFkrUX/2suYPthAwj8DUojVSAjEMRQ5hry4iMsxxsNYlIDyGIf3Affcbv6vy7Y/RbCfe4GC59MoTnuFUqG2JO0lqta9ieOug/seL27XFO6JKf4V/dNYXOo5L6DiMA+83PxnhP4+G/a7Y9yf9NLZbuE/z6KZyuqiS58AAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;A screenshot of Converse with overlayed
chatboxes&quot;
        title=&quot;&quot;
        src=&quot;/static/3e8aee0fd1b38b8ce9e064c06b59a131/1cfc2/Screen-Shot-2018-09-19-at-19.15.16.png&quot;
        srcset=&quot;/static/3e8aee0fd1b38b8ce9e064c06b59a131/3684f/Screen-Shot-2018-09-19-at-19.15.16.png 225w,
/static/3e8aee0fd1b38b8ce9e064c06b59a131/fc2a6/Screen-Shot-2018-09-19-at-19.15.16.png 450w,
/static/3e8aee0fd1b38b8ce9e064c06b59a131/1cfc2/Screen-Shot-2018-09-19-at-19.15.16.png 900w,
/static/3e8aee0fd1b38b8ce9e064c06b59a131/21482/Screen-Shot-2018-09-19-at-19.15.16.png 1350w,
/static/3e8aee0fd1b38b8ce9e064c06b59a131/d61c2/Screen-Shot-2018-09-19-at-19.15.16.png 1800w,
/static/3e8aee0fd1b38b8ce9e064c06b59a131/86177/Screen-Shot-2018-09-19-at-19.15.16.png 2869w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Then there are the “embedded” and “mobile” modes:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/54cc45f50f76749e7eefc5c93b4978b7/416ee/converse4-embedded.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 85.33333333333334%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAARCAYAAADdRIy+AAAACXBIWXMAAAsTAAALEwEAmpwYAAAD/0lEQVR42oWSi0+TVxjG+zcsWcxmVLI53aZmhuhidIs4iZtumSIQbkMgBAXlIghUtFChchERpCJyKaWCCG7IBKNEuRUQRiZels055o2NaSgM2lJKy6X97fRzLmxx25M8eb/3nPM+73PO+8lOHo6hPDOBmnw59cWHuFyRSrMujZaqNHobC+i+mEPnhQz0tenoz6fTUZNOm05BS6WCaxoFV0tFTfFBGouSaShMQnYqJYoKVSw1xxOoVydx6XQi+rpcbl2vpL+5nLttVfzY08C9rq/46Zsm7rZWM9B3he4L+TSp4wUTuZgfz5d5+6nNjhOCyRFolFHUZEVTfyKOxsJ4WrQKOs4eoa0ihc6qI+h1qbS71rRKrpcepE2bztUiOQ25MdQfi6Yucx/VGXupVEYiK0oIQXs4nOr03aJDJA15+/g6L4rmkiS6a3MEj6E/l0W7LoPWShWtuqM0njxAnWoPNapIzqbtFvURlMvDOJMYgux0bACa5F3Up3zB9bRgWlVhdBwNoys7nJ7je+jJCac7I5hOZTAdYr9dIc7JA7iS4EPTfm8uxezkfLQv6ugACiL9kRXv9eVMrA+3cmKxarMwarOxVOUyoc3EXJGJqSSNcfFGxoIEEf9kwQFMJ5MwiSFY1cn8oIoiJ8SL7GAv4TBiB6Xhn9BeW8bAoydMmE2CZux2G06nU+I/4XA4MJrMjBtNUv7wTj/K7R+h9NkqHIZ+SnGQBzcbzzE2MYnZZHqJ0N9FZx2zTFjMzM7MSPmD298i99yAfNtmIRj0MUXe67h7uUaqs08IwWkbM8KhUTgwC7dWqxXnjF1ad3FOfM/NzeEUTl0YuNlH3IY1xHp8IKbsu4niHWtpqSjk/sNHjBoM2G22v67mouR2Hh1CbL7g/b5e9rivInLd+8jU2z/k1NbV4t9S82DwV8xGI/bpaf4LriYuQZewC/d6ewh9923C3N2RFWxbR+HmlVwrOcHPg79gE9d74eplA5kv+MLh9ze6CVi6lMAVq5Cd8FzD8fXL6dAUMTQ6ztDwKMPjZn63TGG2zfyr4NTUFJMWi5R/19XNzsVu+Cx7B1nuRndU7m7cqtNJm08fP+S3J48ZeTqEcWQYo2FYiubREUwjBqaNg8xMTWIYNmAQ7+3Cnc4uPnttEZ+/sRxZ1vrVKFcuobdM/by7dQKnfQqHTVxdFDqsludRogWnbVKIjvLs2TPJpQu39Z1seXUhWxe/hSxj7XscWraIGzqNtDk3O8v/YVacGR0ZYXxsTMr72/VseuV1PBe+iUyxagWKFcso2OZJZXgIml2BaEKDKAsJokSwKDgQdVAg+YK5/gFk+fmT7uNH6k4/Urz8kHsHEOGxhU0LlrBxgRt/AF+NIDjaRygdAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;A screenshot of Converse in embedded mode&quot;
        title=&quot;&quot;
        src=&quot;/static/54cc45f50f76749e7eefc5c93b4978b7/1cfc2/converse4-embedded.png&quot;
        srcset=&quot;/static/54cc45f50f76749e7eefc5c93b4978b7/3684f/converse4-embedded.png 225w,
/static/54cc45f50f76749e7eefc5c93b4978b7/fc2a6/converse4-embedded.png 450w,
/static/54cc45f50f76749e7eefc5c93b4978b7/1cfc2/converse4-embedded.png 900w,
/static/54cc45f50f76749e7eefc5c93b4978b7/416ee/converse4-embedded.png 930w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 320px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f04acb1e11c225204a346f3de74ad4a7/72799/converse4-mobile.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 149.7777777777778%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAeCAYAAAAsEj5rAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEyElEQVR42qVWWY8UVRSev2Lii9Fnf4LiAoGIDKhgXGKUAWFmgJ5hADMSlbgrEX3TF19MfDJo1AcEA4YXhp6eqeruWrqrurq79q7eu2vpz3NvL/TgAqM3Obm3Tt373bN851TNWMefxhY5ugPm3GMwjzwO8+gTfLbYeo7m4zthze8c7jv2FKwTe2Cf3s/3WW8+yfUzJgG4774Oe3kWJim9jxbhf34S3gfH4L1/hJ7n4X24AP/jBTpAIEd2cFB+7vyrqH15Ft6FObhvv8J1M/y2xd20aRe/wbtwGMHFFGoXl+ATYI2Aap+ehP/JCbirL8E5exA2WcYB33sDje++gLP6Mtx3XrsDaC/sgk2gTMzUXpQW98A48QwMNi/sRonESu0jsBfgnDsE+9RebqVz7iC/2HnrRThnnuNuz9ipZxGqAsJyAVFZRSO/DvG3n6HcuILizWvIXfsF2au/olPMITZkRLqEyFD53qgkIyyIfB3KG7CX9hEgBXXQ74KPwWA4YRtjfIYwGNaMvbwfCHu4/NMPWFlOoaDkIeVIJAme56Gka6gHwfj0BGACNEi4AYNeBwxrCBj3cCq1iEcefhTrmTRMs4pCsQjXdeH7PlzHRaPRRLPZQr1RR40u6LRaCGju9XpD4N7IQuf0AcTdNgRRwtrtLIGZEIQNbG4KSGcyKJUMiBubSN9OI5fPk+Rwe20NoiAglxWh0/soGQxd5hZOx5BGPagjTy7nczkUCioUVYYoiiioKizLQrVahSLJpFdh0lqS83DIC8Qh5/IQkMwN4xhxHKHVakLYELApiFBkCbKUJ+ACWaKPYkbWYCqOf0nK32T53okdbJEtgN7KAbTJqsVvv8f5b76GXlBgmRZZVYSm6zAMAzolyKhUENQbsC0Tfi34Z9p4Z55Hs+ZhZekQPls9DElY54lgYDmKo6ZpKJLLml6CSzSybYtAbQpNC+12m0uUEHX6vWFSWJaTbguycBXFzHW0ghp0AlMp6IqsokpZz+dFeibQogZFUYgJBOrYpM8ROwSYRC9E00mZynKn24Eqy8gQTTRGGTqwkc5wQFVRiVIiev3wXyrlrqQMs3gn+GwkxLOYWJAM2JxMksGeB8moUu4uvRt/3MBXly6hUtahU9xY7FglWORyk+K1vVpO+jiZmseDDzyEdHqNXK2goJXguD4R2YTrB2h3++iHEfpRhC653OmRMF0/Ig6TtdOll1Dp/X79Jn68fAVly0HWsKGZHmSaS04ApepC1qgqShZUWmd1E+uKgc1CGQrpCpZP7aALZ2wh6xTj0Wh3kS2WIRYNAqgiR4dFrQLd8iDpVWgVBzLpZMNCnmZB1SHTJSHRx5lOSjKu5XYHt5QKzKCNmJ4jClE0mtkepmM5jif6AUL2bmIhddnYKSNp1JAELqK6h45dReTbGAQO6cbiIq45XMbrZCSDZo1jDDs2kbEvrSPUstTSJfRztxCbGqJK8T5FQ0ifhb6yMSS2Q6UX22V+U+xZCAn8vhvFaA+33K2AYc0wv6N2EzERNI76nMCMrJPWdC9Jkjsdm9Wyy7pN4KFBHadJcQyolsMo2v5Hin1T/ms/vEelzCKmjLKOk7QaSMj9bQk7Q4UR+w6c5X2jP4elWe7//xGHfhi01Cz+BK6MQNKw38jvAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;A screenshot of Converse in mobile mode&quot;
        title=&quot;&quot;
        src=&quot;/static/f04acb1e11c225204a346f3de74ad4a7/72799/converse4-mobile.png&quot;
        srcset=&quot;/static/f04acb1e11c225204a346f3de74ad4a7/3684f/converse4-mobile.png 225w,
/static/f04acb1e11c225204a346f3de74ad4a7/72799/converse4-mobile.png 320w&quot;
        sizes=&quot;(max-width: 320px) 100vw, 320px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;And lastly there’s the “fullscreen” mode, more similar in UX to
teamchat applications like Slack and Discord.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3dc22a8ba1eee7788a9087111b77298a/d9ed5/Screen-Shot-2018-09-19-at-19.16.46.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 55.55555555555556%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAALCAYAAAB/Ca1DAAAACXBIWXMAABYlAAAWJQFJUiTwAAAB0klEQVR42n1Sy27UMBSd7+2mRazYF4kCC36AX+ieDRIVEqp4lQLtzJRkHp2ZTB5jJ7ETx3aSw7XpjFT6sHR0HOv6+Jx7MwiuY2it4RY7fovoxT6yN8+QHRG/euI5PTr4h5eO92/4AMnhHtLne56z10/9fhClKQoh0RuN+ekJgjBEYyzaHjs8tNq2hZAVOmJXpsY/MfhwfoV334Y4+THG6NNHrNYxuKggVANlW4/+AVFtDQTLELMILqMJLjBIeYlaW3TGYH32GdPZHCm53jBGQh0eW41pUBScnBr/7QVzqeCv0WvF+ALTxQrD0Qjz6yW67nFBTW3ieY7+pk57QSHQdj063aAcniFLEyilYMhxXdd+79hae09kDcaZ7+FOkIsSnBpbkbC4/IpkHSHbbCDpTOuaYvc73Bu5LLBtshdkRQlGQ9DkRNKUIhIUJO7iuiju9XYLcrmFO68VDU+K24Lul2GSJlpVaKZj5KVEFMfkknlhQ5dd+f/wQ2gt8pz7B7zgn98YLKkHvKKhdxb8/AvWsxkWkxDTIICkduhGkUJ3FyTbUG85GbrlMEpSLFIOURSQ4SUVVRSPIskC7WIC6xHeQbucoA5HSH59h5pdoUtWqE7f4y9DgD+x7f444gAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;A screenshot of Converse in fullpage mode&quot;
        title=&quot;&quot;
        src=&quot;/static/3dc22a8ba1eee7788a9087111b77298a/1cfc2/Screen-Shot-2018-09-19-at-19.16.46.png&quot;
        srcset=&quot;/static/3dc22a8ba1eee7788a9087111b77298a/3684f/Screen-Shot-2018-09-19-at-19.16.46.png 225w,
/static/3dc22a8ba1eee7788a9087111b77298a/fc2a6/Screen-Shot-2018-09-19-at-19.16.46.png 450w,
/static/3dc22a8ba1eee7788a9087111b77298a/1cfc2/Screen-Shot-2018-09-19-at-19.16.46.png 900w,
/static/3dc22a8ba1eee7788a9087111b77298a/21482/Screen-Shot-2018-09-19-at-19.16.46.png 1350w,
/static/3dc22a8ba1eee7788a9087111b77298a/d61c2/Screen-Shot-2018-09-19-at-19.16.46.png 1800w,
/static/3dc22a8ba1eee7788a9087111b77298a/d9ed5/Screen-Shot-2018-09-19-at-19.16.46.png 2880w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;All these modes use the same JavaScript and CSS, and you can switch
between the view modes. Currently it’s not possible to do so without
reloading the page, but we’ll work on making that possible as well.&lt;/p&gt;
&lt;h2&gt;Working on Converse fulltime&lt;/h2&gt;
&lt;p&gt;In the beginning of this year, I decided to drop other work commitments
and to dedicate this year fully to working on Converse and to see where
that leads me.&lt;/p&gt;
&lt;p&gt;This was in many ways a daunting leap into the unknown, because I knew I
would now have to find more ways to try and earn a living off this work.&lt;/p&gt;
&lt;p&gt;I’ve been doing consulting and custom development around Converse for a
few years, but never exclusively. I also wasn’t sure what business
model I should adopt.&lt;/p&gt;
&lt;p&gt;Consulting? Proprietary plugins? Hosting? Sponsorships?&lt;/p&gt;
&lt;p&gt;I decided to first just focus on building the product, to make Converse
better, and not to worry about making money just yet.&lt;/p&gt;
&lt;p&gt;In part this is due to my bias as engineer, and being out of my comfort
zone when trying to monetize something.&lt;/p&gt;
&lt;p&gt;But I also believe that a compelling product, that users love, can go a
long way to helping you come up with a sustainable and feasible business
model. I hoped that along the way people might appear who would help me
realize this vision.&lt;/p&gt;
&lt;p&gt;It’s the &lt;code class=&quot;language-text&quot;&gt;&quot;if you build it, they will come&quot;&lt;/code&gt; approach.&lt;/p&gt;
&lt;p&gt;During this time, various people did in fact reach out to me and some of
them funded further development.&lt;/p&gt;
&lt;p&gt;I also got enough consulting and development gigs to keep the lights on
and to keep me going.&lt;/p&gt;
&lt;p&gt;Marc Laporte from &lt;a href=&quot;https://wikisuite.org/Software&quot;&gt;Wikisuite&lt;/a&gt; funded
many hours of work moving the UI to Bootstrap 4, and then some more.&lt;/p&gt;
&lt;p&gt;Converse will become part of Wikisuite, together with the OpenFire XMPP
server.&lt;/p&gt;
&lt;p&gt;He gave me valuable advice on how to make a living off open source
software and encouraged me to make the leap.&lt;/p&gt;
&lt;p&gt;I also got a call from &lt;a href=&quot;https://www.happy-dev.fr/&quot;&gt;Happy Dev&lt;/a&gt;, who
needed a federated webchat solution for their Startin’ Blox project
(more on that in future posts). We’re doing some interesting work for
them, which addresses some pain points with XMPP and will be of benefit
to the larger community.&lt;/p&gt;
&lt;p&gt;Nicolas Vèrité, of &lt;a href=&quot;http://nayego.net/&quot;&gt;Nayego&lt;/a&gt; funded responsiveness
improvements while individuals like Christian Weiske and Rafael Munoz
generously contributed funds as well.&lt;/p&gt;
&lt;p&gt;Some people also backed me on &lt;a href=&quot;https://www.patreon.com/jcbrand&quot;&gt;Patreon&lt;/a&gt;
and &lt;a href=&quot;https://liberapay.com/jcbrand&quot;&gt;Liberapay&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Every gig or donation I got was for me a vote of confidence, and gave me
the opportunity to stay the course and continue down this path.&lt;/p&gt;
&lt;p&gt;Besides monetary contributions, many people contribute features and
bugfixes, and hang out in the Converse chatroom, answering questions,
providing their expertise and generally making it a more lively,
interesting place.&lt;/p&gt;
&lt;p&gt;In many ways this release would not have been possible without all of
their contributions, and I therefore dedicate it to everyone who has
contributed money, time or energy (all interchangeable actually) to this
project and therefore has contributed to its success. Thank you!&lt;/p&gt;
&lt;h2&gt;The archetypal nature of free software communities&lt;/h2&gt;
&lt;p&gt;Over the last year I’ve witnessed the Converse project becoming a
community and not just a collection of software. It’s a subset of the
larger XMPP community and one that overlaps with various other XMPP and
free software related communities.&lt;/p&gt;
&lt;p&gt;This has been for me one of the most magical and satisfying things about
being involved in open source.&lt;/p&gt;
&lt;p&gt;Community is archetypally feminine&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, in the sense that it’s
something that cannot be enforced, demanded or created out of
domination, control or rule-making (which are archetypally masculine
attributes). Instead, it’s something that arises seemingly
spontaneously, after an unknown period of gestation and only after the
groundwork has been laid and perhaps after enough loving care and
attention has been provided. Its organic, emergent nature means that it
doesn’t strictly adhere to top-down schedules and deadlines.&lt;/p&gt;
&lt;p&gt;My wife and I, both interested and fascinated by Jungian archetypes, are
amazed at the archetypally feminine aspects of her pregnancy, which is
soon coming to an end (and new beginning).&lt;/p&gt;
&lt;p&gt;As much as we as a society try to control, monitor and manage a
pregnancy, if you decide to have a natural birth, then you’re waiting
for it to happen on its own accord, and aren’t able to impose your will
and deadlines on it.&lt;/p&gt;
&lt;p&gt;In some ways the same is true for a software commons. A commons is a
shared resource which no-one has exclusive control or ownership of. This
lack of ownership and exclusive control makes people resilient against
the software being used as a tool for domination and exploitation. It
also means that the project (i.e. the software and its surrounding
community) is more organic.&lt;/p&gt;
&lt;p&gt;This coming together between software as inanimate artifact, and
community as a living breathing organic hive-mind, brings to mind a
Taoist union of Yin and Yang, the archetypal feminine and masculine.&lt;/p&gt;
&lt;p&gt;Incidentally, the Converse logo is a stylized Yin Yang symbol. Many
people don’t know this because I did such a poor job of designing it.
I’m still looking for a better logo design which encapsulates these
principles of harmony between community and software.&lt;/p&gt;
&lt;h2&gt;What does the future hold for Converse?&lt;/h2&gt;
&lt;p&gt;This has turned out to be a relatively strange blog post, where I wanted
to originally write about the features of the 4.0 release and instead
took an ever more esoteric detour.&lt;/p&gt;
&lt;p&gt;In any case, let’s try to salvage what’s left of the original intent
by closing off with what’s in the pipeline for future releases.&lt;/p&gt;
&lt;h3&gt;Message markup&lt;/h3&gt;
&lt;p&gt;Converse still doesn’t support markdown-like syntax highlighting. This
is a top-priority for future releases.&lt;/p&gt;
&lt;h3&gt;Voice messages&lt;/h3&gt;
&lt;p&gt;With voice messages I mean sending voice recordings, not audio streaming
(although that might also come sometime).&lt;/p&gt;
&lt;p&gt;My wife, friends and family use voice messages (via
&lt;a href=&quot;http://conversations.im/&quot;&gt;Conversations&lt;/a&gt;) a lot and I believe they’d
be a useful addition to Converse as well.&lt;/p&gt;
&lt;h3&gt;Email notifications&lt;/h3&gt;
&lt;p&gt;One area where XMPP needs to improve is sending (email) notifications
when you’re offline and mentioned in a groupchat. XMPP’s groupchat
presence rules have made this difficult. Together with Happy Dev and
Matthew Wild from &lt;a href=&quot;http://prosody.im/&quot;&gt;Prosody&lt;/a&gt; I’m working on a
potential solution.&lt;/p&gt;
&lt;p&gt;Some of the code for this solution is already in Converse, and we’ll
submit a specification for standardization (a so-called XEP) once the
time is right.&lt;/p&gt;
&lt;h3&gt;Making Converse a progressive web-app&lt;/h3&gt;
&lt;p&gt;There are various features of so-called progressive web apps which will
make Converse a much better client, such as:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Push notifications even when Converse is not open.&lt;/li&gt;
&lt;li&gt;Using IndexedDB for caching, thereby avoiding storage limitations of
&lt;code class=&quot;language-text&quot;&gt;localStorage&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;sessionStorage&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Offline support for editing and sending messages.&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Persistent login&lt;/h3&gt;
&lt;p&gt;Other webchat clients like Mattermost and Rocket.chat can keep you
constantly logged in via cookies or perhaps JWT.&lt;/p&gt;
&lt;p&gt;XMPP-authentication isn’t cookie-based and it’s not safe to store user
credentials in the browser cache. This means that users often have to
login anew when they open Converse in a browser tab.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://developers.google.com/web/fundamentals/security/credential-management/&quot;&gt;Credential Management API&lt;/a&gt;
might help here, but it’s still Chrome-only and I haven’t studied it
enough to know whether it’s a solution.&lt;/p&gt;
&lt;p&gt;Another approach is to allow Converse to also use authentication cookies
by adding support for them to XMPP servers.&lt;/p&gt;
&lt;p&gt;Matthew Wild has already added support for cookie authentication to
Prosody but more work needs to be done to get this working on
&lt;a href=&quot;https://conversejs.org&quot;&gt;conversejs.org&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;OAuth-based login&lt;/h3&gt;
&lt;p&gt;Converse already supports OAuth-based login, but it’s not yet deployed
to &lt;a href=&quot;https://conversejs.org&quot;&gt;conversejs.org&lt;/a&gt; and more work can be done to
fetch and show your user profile from the OAuth provider.&lt;/p&gt;
&lt;h2&gt;Let’s build this together&lt;/h2&gt;
&lt;p&gt;There are many more features and improvements planned, too many to list
here.&lt;/p&gt;
&lt;p&gt;The health and sustainability of this project depends in large part on
its community of users and contributors.&lt;/p&gt;
&lt;p&gt;The community is invaluable in finding bugs, making feature suggestions
and doing quality control that would otherwise not be possible given the
circumstances.&lt;/p&gt;
&lt;p&gt;Another important requirement for the long-term health and viability of
the project is funding.&lt;/p&gt;
&lt;p&gt;I and others are spending much of our own time working on Converse, but
to make this project sustainable we need more funding. Either through
donations (e.g. &lt;a href=&quot;https://www.patreon.com/jcbrand&quot;&gt;Patreon&lt;/a&gt;), funded
feature requests or by using my services as an XMPP and Converse
consultant and developer.&lt;/p&gt;
&lt;p&gt;Another option is allowing an employee to spend some of their paid time
on helping the project with bugfixes and other contributions.&lt;/p&gt;
&lt;p&gt;This applies in general to open source projects. Companies derive
immense value from them, and the vast majority don’t have wealthy
corporate backers like Facebook and Google.&lt;/p&gt;
&lt;p&gt;I also intend to soon start offering hosted solutions for organisations
who want to use Converse as their preferred teamchat solution.&lt;/p&gt;
&lt;p&gt;Please &lt;a href=&quot;http://opkode.com/contact.html&quot;&gt;reach out to me here&lt;/a&gt; if you’re
interested.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;I’ve been thinking a lot about archetypes (and Jungian-analysis)
the last while, in part due of various books I’ve read that deal
(partly) with the topic.&lt;/p&gt;
&lt;p&gt;Recommended reading, if you’re interested:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/205490.Gods_in_Everyman&quot;&gt;Gods in everyman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/174635.Goddesses_in_Everywoman?from_search=true&quot;&gt;Goddesses in everywoman&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/670089.The_Fourth_Turning?from_search=true&quot;&gt;The fourth turning&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://www.goodreads.com/book/show/30257963-12-rules-for-life?from_search=true&quot;&gt;12 rules for life&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Disabling Disqus comments on my blog]]></title><description><![CDATA[I’ve decided to disable Disqus comments on this website. I was quite
shocked recently when I saw tacky ads displayed in my blog. I’ve been…]]></description><link>https://opkode.com/blog/disabling-disqus/</link><guid isPermaLink="false">https://opkode.com/blog/disabling-disqus/</guid><pubDate>Fri, 01 Jun 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’ve decided to disable Disqus comments on this website. I was quite
shocked recently when I saw tacky ads displayed in my blog. I’ve been
using and ad blocker for so long that I never saw them, and only when I
loaded my site in a new browser were the ads visible.&lt;/p&gt;
&lt;p&gt;Advertising has its time and place. Being informed of a useful product
or service can be valuable.&lt;/p&gt;
&lt;p&gt;Like so many things in modern day society, the reality is far, far
removed from the ideal. Much of modern day advertising is manipulation,
trying to make you feel inadequate and lacking, so that you’ll be more
susceptible and willing to consume a new product.&lt;/p&gt;
&lt;p&gt;Adam Curtis’ documentary “Century of the Self” brilliantly lays out
the development of marketing as a tool of mass manipulation.&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/eJ3RzGoQC4s&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt; &lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;The dominant form of advertising on the web, so-called Adtech, is
outright fraudulent and user-hostile. Megabytes of JavaScript are
included in webpages with the sole purpose of tracking you as you visit
various websites so that they can build a more complete psychological
profile of you.&lt;/p&gt;
&lt;p&gt;In theory such a profile can help to inform you of products and services
more akin to your needs and taste. In practice, it gets used to
manipulate you and to reinforce your filter bubble.&lt;/p&gt;
&lt;p&gt;I knew that Disqus is in this game as well, and should have acted
sooner. I enabled Disqus comments probably about 5 or 6 years ago, when
I was less concerned or aware of the problems of privacy and
manipulation.&lt;/p&gt;
&lt;p&gt;As always with information silos, the comments that were made on this
website are now all locked away and lost to readers. Perhaps with the
GDPR I can ask for them to be downloaded and then I can create a static
representation of older comments.&lt;/p&gt;
&lt;p&gt;Eventually I’d like to create a comments plugin with Converse.js and
based on XMPP and use that on this site.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[2018 Gulaschprogrammiernacht and organizing sprints for XMPP]]></title><description><![CDATA[Recently I attended the Gulaschprogrammiernacht for the first time. It’s a hacker/maker event in the Zentrum für Kunst und Medien
(Centre…]]></description><link>https://opkode.com/blog/2018-gulaschprogrammiernacht/</link><guid isPermaLink="false">https://opkode.com/blog/2018-gulaschprogrammiernacht/</guid><pubDate>Thu, 31 May 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Recently I attended the Gulaschprogrammiernacht for the first time.&lt;/p&gt;
&lt;p&gt;It’s a hacker/maker event in the &lt;em&gt;Zentrum für Kunst und Medien&lt;/em&gt;
(Centre for Arts and Media) in Karlsruhe, Germany.&lt;/p&gt;
&lt;p&gt;AFAIK it’s organized by the local chapter of the infamous Chaos
Computer Club.&lt;/p&gt;
&lt;p&gt;I heard about it from Daniel Gultsch on Twitter. It sounded like fun, so
I decided to attend and spend the time adding OMEMO support to Converse.&lt;/p&gt;
&lt;p&gt;Guus der Kinderen and I intended to organize an XMPP sprint for that
weekend in Düsseldorf, but we were cutting it a bit fine with the
organization, so I hoped that we could just shift the whole sprint to
GPN.&lt;/p&gt;
&lt;p&gt;Unfortunately Guus couldn’t attend, but Daniel and Maxime Buquet (pep)
did and I spent most of the event hanging out with them and working on
XMPP-related stuff. The developers behind the &lt;a href=&quot;https://dino.im/&quot;&gt;Dino&lt;/a&gt;
XMPP client also attended and hung out with us for a while and there was
someone working on writing an XMPP connector for
&lt;a href=&quot;https://wiki.gnome.org/action/show/Apps/Empathy&quot;&gt;Empathy&lt;/a&gt; in C++.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ce559564a07b27ed1606cfd4ad16f7aa/0f98f/mWu9Zh21QpOSlOSVXzh-YQ.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAwEBAAAAAAAAAAAAAAAAAAQFAgb/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAByxz7qXiEH//EABkQAAIDAQAAAAAAAAAAAAAAAAECAAMREv/aAAgBAQABBQKnjS4LJcgUPkrJI4af/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPwE//8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAgEBPwE//8QAGhAAAgIDAAAAAAAAAAAAAAAAAAERIRAxYf/aAAgBAQAGPwJS0cgusM2f/8QAGxAAAgIDAQAAAAAAAAAAAAAAAAERITFBUWH/2gAIAQEAAT8hguMqmLXHRHmkQPSNdYE9UrWLP//aAAwDAQACAAMAAAAQZO//xAAVEQEBAAAAAAAAAAAAAAAAAAAQEf/aAAgBAwEBPxCH/8QAFhEBAQEAAAAAAAAAAAAAAAAAARBR/9oACAECAQE/EB2f/8QAHBABAAMAAwEBAAAAAAAAAAAAAQARITFBUXHB/9oACAEBAAE/ED4mg59lfoIaOGdXKk0VpdTpY5UKrveSaooKV9xl+KKEI41+T//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;mWu9Zh21QpOSlOSVXzh YQ&quot;
        title=&quot;&quot;
        src=&quot;/static/ce559564a07b27ed1606cfd4ad16f7aa/8e1fc/mWu9Zh21QpOSlOSVXzh-YQ.jpg&quot;
        srcset=&quot;/static/ce559564a07b27ed1606cfd4ad16f7aa/863e1/mWu9Zh21QpOSlOSVXzh-YQ.jpg 225w,
/static/ce559564a07b27ed1606cfd4ad16f7aa/20e5d/mWu9Zh21QpOSlOSVXzh-YQ.jpg 450w,
/static/ce559564a07b27ed1606cfd4ad16f7aa/8e1fc/mWu9Zh21QpOSlOSVXzh-YQ.jpg 900w,
/static/ce559564a07b27ed1606cfd4ad16f7aa/b768e/mWu9Zh21QpOSlOSVXzh-YQ.jpg 1350w,
/static/ce559564a07b27ed1606cfd4ad16f7aa/d9c39/mWu9Zh21QpOSlOSVXzh-YQ.jpg 1800w,
/static/ce559564a07b27ed1606cfd4ad16f7aa/0f98f/mWu9Zh21QpOSlOSVXzh-YQ.jpg 1920w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Maxime worked on adding OMEMO support, to &lt;a href=&quot;https://poez.io/en/&quot;&gt;Poezio&lt;/a&gt;,
and Daniel provided us with know-how and moral support. Daniel worked
mainly on the &lt;a href=&quot;https://github.com/iNPUTmice/p2&quot;&gt;Conversations Push Proxy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;We had some discussions around the value of holding regular sprints and
I told them about my experience with sprints in the
&lt;a href=&quot;http://plone.org/&quot;&gt;Plone&lt;/a&gt; community.&lt;/p&gt;
&lt;p&gt;The Plone community regulary organizes sprints and they’ve been
invaluable in getting difficult work done that no single company could
or would sponsor internally. To me it’s a beautiful example of what’s
been termed &lt;a href=&quot;https://en.wikipedia.org/wiki/Commons-based_peer_production&quot;&gt;Commons-based peer production&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The non-profit Plone foundation provides funding and an official seal of
approval to these sprints, and usually a sprint has a particular focus
(such as adding Python3 support). Sprints can range from 3 people to 30
or more.&lt;/p&gt;
&lt;p&gt;One difference between the Plone and XMPP communities, is that Plone is
a single open source product on which multiple companies and developers
build their businesses, whereas XMPP is a standardized protocol upon
which multiple companies and developers create multiple products, some
open source and some closed source.&lt;/p&gt;
&lt;p&gt;In both cases however there is a single commons which community members
have an incentive to maintain and improve as they build their businesses
around it.&lt;/p&gt;
&lt;p&gt;Another difference is between the Plone Foundation and the XMPP
Standards Foundation. The XSF, for better or worse, interprets its role
and function fairly strictly as being a standards organisation primarily
focused on standardising extensions to XMPP, and less on community
building or supporting software development.&lt;/p&gt;
&lt;p&gt;Despite these differences, I still consider sprints a great way to
foster community and to improve the extent and quality of XMPP-related
software and documentation.&lt;/p&gt;
&lt;p&gt;There is an interesting dynamic between cooperation and competition in
both the Plone and XMPP communities. Participants compete with one
another but they also have the shared goal of maintaining and growing a
healthy software ecosystem.&lt;/p&gt;
&lt;p&gt;Maxime was particularly excited by our discussion and very quickly put
word into action by planning and announcing an
&lt;a href=&quot;https://col.la/xmppsprint&quot;&gt;XMPP sprint in Cambridge, UK&lt;/a&gt; in August.&lt;/p&gt;
&lt;p&gt;There’s still time to vote on the date of the sprint and to suggest topics.&lt;/p&gt;
&lt;p&gt;Hopefully this will be first of many more sprints and communit events.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e4e708420a5894abbca0612a0ffe23d7/0f98f/Hmy7cKhqQS-40Buc_x89yg.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAgABA//EABUBAQEAAAAAAAAAAAAAAAAAAAAB/9oADAMBAAIQAxAAAAEnmpDZH//EABoQAAICAwAAAAAAAAAAAAAAAAECABETMTL/2gAIAQEAAQUCtWPJbGCjNNmf/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BV//EABYRAQEBAAAAAAAAAAAAAAAAAAARIf/aAAgBAgEBPwHUf//EABsQAAEEAwAAAAAAAAAAAAAAAAABEBEhMTKC/9oACAEBAAY/AqvkWokybEq3/8QAHBAAAwABBQAAAAAAAAAAAAAAAAERMSFRgaHw/9oACAEBAAE/IXZauxcxOO6GEX3Aish7gxyn/9oADAMBAAIAAwAAABC8/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEQH/2gAIAQMBAT8QuLf/xAAWEQEBAQAAAAAAAAAAAAAAAAAAARH/2gAIAQIBAT8QkMv/xAAbEAEBAQEBAAMAAAAAAAAAAAABESEAUUFhsf/aAAgBAQABPxDdGBzA+CclKyAwzHBfrzsRglbXeb9WSr+B0ND3TjSnf//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Hmy7cKhqQS 40Buc x89yg&quot;
        title=&quot;&quot;
        src=&quot;/static/e4e708420a5894abbca0612a0ffe23d7/8e1fc/Hmy7cKhqQS-40Buc_x89yg.jpg&quot;
        srcset=&quot;/static/e4e708420a5894abbca0612a0ffe23d7/863e1/Hmy7cKhqQS-40Buc_x89yg.jpg 225w,
/static/e4e708420a5894abbca0612a0ffe23d7/20e5d/Hmy7cKhqQS-40Buc_x89yg.jpg 450w,
/static/e4e708420a5894abbca0612a0ffe23d7/8e1fc/Hmy7cKhqQS-40Buc_x89yg.jpg 900w,
/static/e4e708420a5894abbca0612a0ffe23d7/b768e/Hmy7cKhqQS-40Buc_x89yg.jpg 1350w,
/static/e4e708420a5894abbca0612a0ffe23d7/d9c39/Hmy7cKhqQS-40Buc_x89yg.jpg 1800w,
/static/e4e708420a5894abbca0612a0ffe23d7/0f98f/Hmy7cKhqQS-40Buc_x89yg.jpg 1920w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Slack's bait and switch]]></title><description><![CDATA[Slack has finally decided to close down their IRC and XMPP gateways.
True to form, you can only read their announcement if you already have…]]></description><link>https://opkode.com/blog/slacks-bait-and-switch/</link><guid isPermaLink="false">https://opkode.com/blog/slacks-bait-and-switch/</guid><pubDate>Mon, 12 Mar 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Slack has finally decided to close down their IRC and XMPP gateways.
True to form, you can only read their announcement if you already have a Slack
account and are logged in to a workspace.&lt;/p&gt;
&lt;p&gt;Here ‘s the gist of their announcement:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;As Slack has evolved over the years, we’ve built features
and capabilities --- like Shared Channels, Threads,
and emoji reactions (to name a few) --- that the
IRC and XMPP gateways aren’t able to handle. Our priority is
to provide a secure and high-quality
experience across all platforms, and so the time has come to close the gateways.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;They’re of course being economical with the truth here.
Perhaps their XMPP gateway can’t handle “Shared Channels” and
“Threads”, but that’s because they purposefully stopped working on it.&lt;/p&gt;
&lt;p&gt;A “Shared Channel” simply means a chatroom which people from
outside your workspace can participate in. If
a workspace is mapped to a members-only
chatroom, then making something a shared channel simply means updating the members
list or making the chatroom open (so anybody can join it). Threads can be implemented by
adding a &lt;code class=&quot;language-text&quot;&gt;&amp;lt;thread&gt;&lt;/code&gt; element in the message stanza, as documented in
&lt;a href=&quot;https://xmpp.org/extensions/xep-0201.html&quot;&gt;XEP-0201&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Emoji reactions can be tacked to a particular message. There’s nothing
fundamental about XMPP that prevents emoji reactions, and [work is currently underway to add support for them](&lt;a href=&quot;https://github.com/jabber&quot;&gt;https://github.com/jabber&lt;/a&gt; t/jabbercat/issues/80).
The protocol is designed to be eXtensible (hence the X in XMPP) and new features are continuously being added.&lt;/p&gt;
&lt;h3&gt;bait and switch&lt;/h3&gt;
&lt;p&gt;We all know the real reason Slack has closed off their gateways. Their
business model dictates that they should.&lt;/p&gt;
&lt;p&gt;Slack’s business model is to record everything said in a workspace and
then to &lt;a href=&quot;https://get.slack.help/hc/en-us/articles/115002422943-Message-and-storage-limits-on-the-Free-plan&quot;&gt;sell you access to their record of your
conversations&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;They’re a typical walled garden, information silo or &lt;a href=&quot;https://opkode.com/blog/review-who-owns-the-future/&quot;&gt;Siren Server&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;So they have to close everything off, to make sure that people can’t
extract their conversations out of the silo.&lt;/p&gt;
&lt;p&gt;We saw it with Google, who built Gtalk on XMPP and even federated with
other XMPP servers, only to later stop federation and XMPP support in
favour of trying to herd the digital cattle into the Google+ enclosure.&lt;/p&gt;
&lt;p&gt;Facebook, who also built their chat app on XMPP at first allowed 3rd
party XMPP clients to connect and then later dropped interoperability.&lt;/p&gt;
&lt;p&gt;Twitter, although not using or supporting XMPP, had a vibrant 3rd party
client ecosystem which they killed off once they felt big enough.&lt;/p&gt;
&lt;p&gt;Slack, like so many others before them, pretend to care about
interoperability, opening up just so slightly, so that they can lure in
people with the promise of “openness”, before eventually closing the
gate once they’ve achieved sufficient size and lock-in.&lt;/p&gt;
&lt;h2&gt;On Federation&lt;/h2&gt;
&lt;p&gt;When we talk about “federation” in networks, we mean the ability to
communicate between different service providers.&lt;/p&gt;
&lt;p&gt;For example, email is federated. You can set up your own email server,
and then send emails to people with their own email servers, or to
people with Gmail or Yahoo! accounts.&lt;/p&gt;
&lt;p&gt;You can email any other email address in the world, regardless of where
that email address is hosted.&lt;/p&gt;
&lt;p&gt;If email never existed, and a company like Slack today would come out
with this brand new concept of “Electronic Mail”, let’s call it
&lt;code class=&quot;language-text&quot;&gt;digimail&lt;/code&gt;, do you think they would standardise the digimail protocol
and allow you to send messages to other digimail purveyors?&lt;/p&gt;
&lt;p&gt;We all know the answer to that. They won’t, and neither would Google,
Microsoft or Facebook.&lt;/p&gt;
&lt;p&gt;Heck, Facebook is actively trying to replace email since years.&lt;/p&gt;
&lt;p&gt;The reason email is federated, is because it was developed before
surveillance capitalism was a thing and because it was established and
entrenched long before these companies came around.&lt;/p&gt;
&lt;p&gt;There’s a reason why your email address is still the de facto way to
sign up for any service on the web (sometimes with one or two degrees of
separation), and it’s because of federation.&lt;/p&gt;
&lt;p&gt;XMPP is designed to allow federation. Think about that. Instead of
having to sign up to various different chat providers, all which try to
lock you in and monetize your conversations, you could instead have one
chat account, and use that to chat with anybody else, regardless of
which chat provider they are using.&lt;/p&gt;
&lt;p&gt;Alas, that’s the dream, but because XMPP came much later to the scene,
it didn’t develop the critical mass as email has, and here we are. With
dozens of chat apps, all non-interoperable and closed off.&lt;/p&gt;
&lt;h2&gt;What would it take for XMPP to take off?&lt;/h2&gt;
&lt;p&gt;One of the sad things that has come out of Slack’s meteoric rise to
success, has been how many free and open source projects have jumped
over to using it (after previously using IRC or XMPP).&lt;/p&gt;
&lt;p&gt;In so doing, they have closed off their discussions from search engines
and they prevent people from accessing their past archives.&lt;/p&gt;
&lt;p&gt;Slack has many cool features, and they work very well, I’m not going to
deny it.&lt;/p&gt;
&lt;p&gt;However, the XMPP Software Foundation has done a lot of work in recent
years to enable protocol extensions that provide features that people
have come to expect from chat applications, for example:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Message threading &lt;a href=&quot;https://xmpp.org/extensions/xep-0201.html&quot;&gt;XEP-0201&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Last message corrections &lt;a href=&quot;https://xmpp.org/extensions/xep-0308.html&quot;&gt;XEP-0308&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Message delivery receipts &lt;a href=&quot;https://xmpp.org/extensions/xep-0184.html&quot;&gt;XEP-0184&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Markdown-like syntax for messages &lt;a href=&quot;https://xmpp.org/extensions/xep-0393.html&quot;&gt;XEP-0393&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Unfortunately XMPP clients have been lagging far behind in various
respects.&lt;/p&gt;
&lt;p&gt;One of the main problems is funding. The modern digital economy is
largely set up around surveillance capitalism and user lock-in.&lt;/p&gt;
&lt;p&gt;So attempts to create software that doesn’t follow these precepts,
often end up unfunded or underfunded.&lt;/p&gt;
&lt;p&gt;However, our “weakness”, is also our strength.&lt;/p&gt;
&lt;p&gt;XMPP clients, and the XMPP network can provide something that Slack
never can. Federation, free and open software, interoperability,
extensibility and user choice.&lt;/p&gt;
&lt;h2&gt;Converse&lt;/h2&gt;
&lt;p&gt;For the last few years I’ve been working in my spare time on making a
JavaScript XMPP chat client, called &lt;a href=&quot;http://conversejs.org/&quot;&gt;Converse&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Originally the idea was to make a Gtalk like chat client that you
integrate in your website, and it can still be used like that.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/88029003dc0ba18777583ecb09a3a3c2/c1b63/converse-screenshot.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 61.77777777777778%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAYAAABiDJ37AAAACXBIWXMAABYlAAAWJQFJUiTwAAADUklEQVR42iWS/U+TZxSG+58sS/xhauaUZZthfiFqRiQLcxOySFDGWBQTtoUYIc4MFAe0uK4uinNiKdQCk0KHUGBDSi1tsawwylAEWvl4W1oKpQX6xceuvatPcnKSJ1fuc+47R6Itz6O98ku6fyzApCxjoL4ci1oq9ir6a2/Qr6zmSa2M7poK9Hel1JcVofg6F031NcrP51Cc/RmXs7Mo+jyLwtOZSH4ryaRLVsDMUC+ODiXDrTXYdSpGurQ80zVi0TbQU3sLwyM1pg4dddIbqORSWlQPuJqXQ86h/eSkHCY75RC5J1KRNH37MW0lWfRUXqT10qd0lp3DJsth6HoGttJ0Or5JR3/hFF1fpNF+5hhtmYdpO3Mc9ScfUpGfj0J2j9vS21z//h4ZGVeQaM6n0XQhDU3+MdS5RzDdL2XZWku0rxpsd5hWXyOglLHZpCAqxhCt+4FIQxVuRTE2bROv3ya+EFyVmZDUn03hYW4qjwpPofnqJC+e6AhH1lnz+xPo5MhfTDpHmAu4iEbCbG1vE47HmRE8WI1G1mMRVldDCdZmtSKpPZ3Mg6wDNJw7gersRxh6HzMa8LMWWklAE6Lgy4nnzAqzzMy68HgE1iKreObnMBr6CW1vsrW1hRAL09NnQFKT/j7/152T7yE/sps/WxsZEyeuhYIJwTGrhYkJB4JvHq/Xw0ogQDAcRHAL2J4OEN+IsbISSLDPBsQNFUf3oUhNQn78XSr276Sv5SHOWIiFRXcCcpgHsI9b+Mc9in/Jy0YsTiS2xrLPK1p+SngjjE/8h38xm8QMK5P3UHXgHaoO7qU06S2MjffxrjqZnxsTmS3+Nlt4MTWOEFzAs+wTN9okIloWXk0zaBxIDF1fWk90q9GCpDRpN8V7d1G0720KduzgcUMNzug0Tvd4QnCotxe7uZPZV8OE5l3EvAIhUXhuZp7f/2imfvFnVDO3qPPLuauXIynZtRPl0Q/QpyejObgHS0vz60MILomCcQa7OnHrG4kNG4jZ+9keEW26XSz5l2npbOMnRxu/jHQiH9Nxs/lXJAVvvElhXhbf3Szm4qU8tKo6MXwvU5OTLIqn063V4XCMiZn6cS94EcSadroYtJpp0bTycjzIqN3N1PNVmurb+Q92UeQSRiKEEQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;converse screenshot&quot;
        title=&quot;&quot;
        src=&quot;/static/88029003dc0ba18777583ecb09a3a3c2/1cfc2/converse-screenshot.png&quot;
        srcset=&quot;/static/88029003dc0ba18777583ecb09a3a3c2/3684f/converse-screenshot.png 225w,
/static/88029003dc0ba18777583ecb09a3a3c2/fc2a6/converse-screenshot.png 450w,
/static/88029003dc0ba18777583ecb09a3a3c2/1cfc2/converse-screenshot.png 900w,
/static/88029003dc0ba18777583ecb09a3a3c2/c1b63/converse-screenshot.png 1200w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;However, in the last year I’ve updated it further so that it can also
be used as a fullscreen application, like Slack is used.&lt;/p&gt;
&lt;p&gt;You can try the fullscreen version at &lt;a href=&quot;https://inverse.chat/&quot;&gt;https://inverse.chat/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/eb80bf259ffe41f16639da7afb1674ed/c1b63/inverse-screenshot.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 70.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAOCAYAAAAvxDzwAAAACXBIWXMAABYlAAAWJQFJUiTwAAACfUlEQVR42o2TSW8TQRCF8xvZLsAZ7kAQ2wUJiZ+BkLhyQkjhhCBSlCBMHDt2HDvYiffZZ3r27aNmlDghiRAlvamp7pnXVa+r1npDi/7IZjjxOVpkLD5+wH7zEOP1A5Yv77N8covF45srzB/dqFGta+u30Z/eYSnr2ou7LF/cYy1OQpI4oChycgqi/R0OmhsMeztoBy1mu9ss9naYNbdZtn/i9tuEox75bIQ32Mfs7hIfH5JrU/zNz6y5YUAQRRRliRvHhP09tk426Zp9XOVjK7WCimQ/TUnzgsrcQGG4LllRUEocdX+y5kchgZDmeY7KUoLDJsNpi2N9gPJc4lgOk70K1Td5lpEJKrM8E+V7UJZ1HHWEMJOPfMkkEBSyHkmG82lPyEzSJCFJEyGQrMTXcZIK4prUUZbIFXFmcZ1h7LJwpsytMSpxCA936Q3bjBcTZtMJ4+mYqfj5fIZh6jiOg1KeZB5jOzq+Y60I65Lfj9/xvLvO2/4bXh08Y9b5yu5km2PjBE1bYtsWQRDUGZVSWnlaXmWmZ2DZlwgbRzobjTHfWnO+/JpgtRscT5voxgTXNInkwqoSq5KLouCi+aGq91YaVoRcslg01OaHuI5GGIi2olF1cX4Y1j7JM0Fed8XqgFMfdxtXCZNBC3MxEK00lBD60iaeZBFUHVC9ywFK4lxI/oswGuyxd7JNX+vhWHatoes60jYFV6oR8kiyPiO8tuSo3+TXZIuu3sH35DalR9M4pJRJksc5pJVtx8Qw9H9r6PRaeNKT8jvZBaTlOTKBlxUsHQ9d2uhscq4ltJs/MDptvBOZ1dFv1ArDv+CNRlj9A6xOAyXzXWgT/O+f+AOgNhjQAIhzGwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;inverse screenshot&quot;
        title=&quot;&quot;
        src=&quot;/static/eb80bf259ffe41f16639da7afb1674ed/1cfc2/inverse-screenshot.png&quot;
        srcset=&quot;/static/eb80bf259ffe41f16639da7afb1674ed/3684f/inverse-screenshot.png 225w,
/static/eb80bf259ffe41f16639da7afb1674ed/fc2a6/inverse-screenshot.png 450w,
/static/eb80bf259ffe41f16639da7afb1674ed/1cfc2/inverse-screenshot.png 900w,
/static/eb80bf259ffe41f16639da7afb1674ed/c1b63/inverse-screenshot.png 1200w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If you have no-one to chat to, then come join the
&lt;a href=&quot;https://yax.im/i/#discuss@conference.conversejs.org?join&quot;&gt;&lt;a href=&quot;mailto:discuss@conference.conversejs.org&quot;&gt;discuss@conference.conversejs.org&lt;/a&gt;&lt;/a&gt;
chat room.&lt;/p&gt;
&lt;p&gt;This link will take you directly there (via inverse.chat):
&lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;&lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Converse still lacks lots of features that Slack has, but that’s not
because XMPP itself can’t support those features.&lt;/p&gt;
&lt;p&gt;What Converse however &lt;em&gt;does&lt;/em&gt; have, is that it’s free and open source
software, based on a standard protocol and it can be extended, updated
and improved upon, by anyone.&lt;/p&gt;
&lt;p&gt;We’re actively working on adding new features and more and more people
are joining in.&lt;/p&gt;
&lt;p&gt;Moreover, anybody can host it and you can integrate it into any website.&lt;/p&gt;
&lt;p&gt;Ultimately, I believe in the power and utility of interoperability and
software freedom, even though the current trend is to close off and lock
down.&lt;/p&gt;
&lt;p&gt;These information silos are as powerful as we make them. If enough
projects choose standardised protocols and FOSS software, we will be
able to create viable alternatives that foster freedom instead of
lock-in.&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
This blog post triggered a lively discussion on Hacker news, you can read that here: &lt;https://news.ycombinator.com/item?id=16567009&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[A badge for linking to your XMPP chat]]></title><description><![CDATA[You’ve probably noticed the coloured badges at the top of project READMEs on Github and Gitlab. These badges indicate various metrics about…]]></description><link>https://opkode.com/blog/xmpp-chat-badge/</link><guid isPermaLink="false">https://opkode.com/blog/xmpp-chat-badge/</guid><pubDate>Mon, 19 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;You’ve probably noticed the coloured badges at the top of project READMEs on Github and Gitlab.&lt;/p&gt;
&lt;p&gt;These badges indicate various metrics about the project’s current state and its supporting infrastructure.&lt;/p&gt;
&lt;p&gt;For example, the README page for &lt;a href=&quot;https://github.com/jcbrand/converse.js/&quot;&gt;Converse&lt;/a&gt; contains the following badge:
 &lt;a href=&quot;https://www.bountysource.com/teams/converse.js/issues?tracker_ids=194169&quot;&gt;&lt;img src=&quot;https://img.shields.io/bountysource/team/converse.js/activity.svg?maxAge=2592000&quot; alt=&quot;Bountysource bounties&quot;&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;It indicates how many open bounties there are for Converse on Bountysource.&lt;/p&gt;
&lt;p&gt;There are dozens such badges available nowadays, just take a look at &lt;a href=&quot;https://shields.io/&quot;&gt;shields.io&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Some projects have badges that link to a chatroom, hosted by Gitter, Slack etc.&lt;/p&gt;
&lt;p&gt;Converse, being an XMPP-based project, has its own XMPP chatroom at &lt;a href=&quot;xmpp:discuss@conference.conversejs.org&quot;&gt;discuss@conference.conversejs.org&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I created a badge for its README, which points to that chatroom and also indicates how many users are currently in it.&lt;/p&gt;
&lt;p&gt;It looks like this:   &lt;img src=&quot;https://inverse.chat/badge.svg?room=discuss@conference.conversejs.org&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Markdown syntax for showing the badge looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[Link to XMPP chat](https://inverse.chat/badge.svg?room=discuss@conference.conversejs.org)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The target URL for this badge is &lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&lt;/a&gt;,
which means that it takes the user to &lt;a href=&quot;https://inverse.chat&quot;&gt;https://inverse.chat&lt;/a&gt; and then
once the user has logged in, the room &lt;code class=&quot;language-text&quot;&gt;discuss@conference.conversejs.org&lt;/code&gt; will be opened.&lt;/p&gt;
&lt;p&gt;To go to a different room, just specify a different JID (Jabber ID) in the URL parameters.&lt;/p&gt;
&lt;p&gt;The image URL is &lt;a href=&quot;https://inverse.chat/badge.svg?room=discuss@conference.conversejs.org&quot;&gt;https://inverse.chat/badge.svg?room=discuss@conference.conversejs.org&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;Here you specify the room JID with the room URL parameter.&lt;/p&gt;
&lt;p&gt;The image is an SVG which is generated by a tiny &lt;a href=&quot;http://flask.pocoo.org/&quot;&gt;Flask&lt;/a&gt; app,
which includes a chatbot written with &lt;a href=&quot;http://sleekxmpp.com/&quot;&gt;SleekXMPP&lt;/a&gt; that checks how many users are
in a particular chatroom.&lt;/p&gt;
&lt;p&gt;The code is open source, and hosted on Github at &lt;a href=&quot;https://github.com/jcbrand/xmpp-chat-badge&quot;&gt;jcbrand/xmpp-chat-badge&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you’re using this badge for your project, I’d be happy to hear about it.&lt;/p&gt;
&lt;p&gt;You can let me know in the Converse XMPP chatroom at &lt;a href=&quot;xmpp:discuss@conference.conversejs.org&quot;&gt;discuss@conference.conversejs.org&lt;/a&gt;
(or through the web with &lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;inverse.chat&lt;/a&gt;)
or by using this website’s &lt;a href=&quot;http://opkode.com/contact.html&quot;&gt;contact form&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The 2018 XSF Summit]]></title><description><![CDATA[This year I again attended the XMPP Software Foundation’s summit in Brussels. The summit spans two days and is held at Cisco’s offices. It’s…]]></description><link>https://opkode.com/blog/2018-xsf-summit/</link><guid isPermaLink="false">https://opkode.com/blog/2018-xsf-summit/</guid><pubDate>Sat, 03 Feb 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This year I again attended the XMPP Software Foundation’s summit in Brussels.&lt;/p&gt;
&lt;p&gt;The summit spans two days and is held at Cisco’s offices.&lt;/p&gt;
&lt;p&gt;It’s a rare opportunity to get community members together to discuss and make
decisions around protocol extensions (&lt;a href=&quot;https://xmpp.org/extensions/&quot;&gt;the so-called XEPs&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;On the second day interesting discussions were had regarding the state of XMPP today,
for example how and by whom its used, how to foster and support client development and the merits of
federation (i.e. communication between different messaging providers).&lt;/p&gt;
&lt;p&gt;We heard that XMPP is heavily used and respected within the Telecoms industry, and that there’s a lot of
“hidden” use of XMPP that even most of the Summit participants were unaware of.&lt;/p&gt;
&lt;p&gt;The distinction was made between XMPP, which represents the protocol, and Jabber®, which represents the
ideal of federated instant messaging as used by end users.&lt;/p&gt;
&lt;p&gt;Besides what some people may think, XMPP is alive and well, and used extensively in many applications
and in various sectors. Jabber®, on the other hand, not so much. Mindshare has moved largely to
siloed (i.e. non-federated and non-standardized) messaging apps like Slack et al.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://tigase.im/&quot;&gt;Tigase&lt;/a&gt; guys Andrzej Wójcik and Daniel Wisnewski gave a demo of the new
Internet-of-things module of the Tigase XMPP server which also drew attention at the
realtime communications stand at FOSDEM.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/1c749c8a15ec32ed2485ee1e50b1c12a/e5166/2018-xsf-summit.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.55555555555554%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAOABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAQFA//EABUBAQEAAAAAAAAAAAAAAAAAAAMC/9oADAMBAAIQAxAAAAFFqTbO8BYU/wD/xAAaEAACAwEBAAAAAAAAAAAAAAABAgADEiIj/9oACAEBAAEFAlOm6AHUDZatTLR6/wD/xAAWEQEBAQAAAAAAAAAAAAAAAAAAEjH/2gAIAQMBAT8B1L//xAAXEQEAAwAAAAAAAAAAAAAAAAAAARIh/9oACAECAQE/AZxd/8QAGxAAAgMAAwAAAAAAAAAAAAAAABEBAiEicYH/2gAIAQEABj8CNr6NwdD4qS2Qf//EABoQAQEBAAMBAAAAAAAAAAAAAAERACExQVH/2gAIAQEAAT8hjRg7nCV68Zc4S/dC9FcwYHjMz0I7/9oADAMBAAIAAwAAABCrD//EABgRAQEAAwAAAAAAAAAAAAAAAAEAESEx/9oACAEDAQE/EAOpOdX/xAAXEQEBAQEAAAAAAAAAAAAAAAABACER/9oACAECAQE/EE7IXNL/xAAcEAEAAgIDAQAAAAAAAAAAAAABESEAMUFhgVH/2gAIAQEAAT8Q2hMCOnesRQotCCeXjJZUwK1BeTOKAd/cDrIbGTsefcig4ICleZ//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The summit participants sitting around the table at Cisco&quot;
        title=&quot;&quot;
        src=&quot;/static/1c749c8a15ec32ed2485ee1e50b1c12a/8e1fc/2018-xsf-summit.jpg&quot;
        srcset=&quot;/static/1c749c8a15ec32ed2485ee1e50b1c12a/863e1/2018-xsf-summit.jpg 225w,
/static/1c749c8a15ec32ed2485ee1e50b1c12a/20e5d/2018-xsf-summit.jpg 450w,
/static/1c749c8a15ec32ed2485ee1e50b1c12a/8e1fc/2018-xsf-summit.jpg 900w,
/static/1c749c8a15ec32ed2485ee1e50b1c12a/e5166/2018-xsf-summit.jpg 1200w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Photo by &lt;a href=&quot;http://www.goodbytes.nl/&quot;&gt;Guus der Kinderen&lt;/a&gt;&lt;/p&gt;
&lt;h2&gt;Minutes for the XSF Summit&lt;/h2&gt;
&lt;p&gt;I volunteered to be the minute taker this year, for which I used my
favorite notes-taking app: &lt;a href=&quot;https://vimwiki.github.io/&quot;&gt;Vimwiki&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;With Vimwiki you can generate HTML from your wiki files, so I was able
to make the notes available online roughly as I was typing them. which I
did by pushing the generated HTML to a git repo and then pulling again
via cron on a server and serving with Nginx.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ffb370b53347b9d8d70fb6beb7b9e54b/41099/2018-xsf-summit-reflection.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 84%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAARABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQFA//EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAGJ25OekywcuuFTAP8A/8QAHBABAAEEAwAAAAAAAAAAAAAAAgEAAxEyEiIx/9oACAEBAAEFApPaOOVas5StUEFRcRB3Hq2//8QAGBEAAwEBAAAAAAAAAAAAAAAAAAEREBL/2gAIAQMBAT8B5dpBZ//EABcRAAMBAAAAAAAAAAAAAAAAAAEQERL/2gAIAQIBAT8B0Iiv/8QAHhAAAgEDBQAAAAAAAAAAAAAAAAERAgMhEBIiQuH/2gAIAQEABj8CeSIPSvk2+sC3qptGbEi1/8QAHBABAAIDAAMAAAAAAAAAAAAAAQARITFBUaGx/9oACAEBAAE/ISqVvrGCug3rM6BGRCaR155CqAarDHgSuezPlN0//9oADAMBAAIAAwAAABAPEH//xAAZEQACAwEAAAAAAAAAAAAAAAAAARARITH/2gAIAQMBAT8QS9CxxH//xAAYEQADAQEAAAAAAAAAAAAAAAAAAREQMf/aAAgBAgEBPxBviFR2s//EAB0QAQACAgMBAQAAAAAAAAAAAAEAESExQVGhgZH/2gAIAQEAAT8QsQIqFqz7GDl2BPZ5AYD8TPd2Ls2BeCtXGbN0J/DvEtxA3qjg1xPNm6ffP//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;I N C E P T I O N (an original piece by Guus der Kinderen)&quot;
        title=&quot;&quot;
        src=&quot;/static/ffb370b53347b9d8d70fb6beb7b9e54b/41099/2018-xsf-summit-reflection.jpg&quot;
        srcset=&quot;/static/ffb370b53347b9d8d70fb6beb7b9e54b/863e1/2018-xsf-summit-reflection.jpg 225w,
/static/ffb370b53347b9d8d70fb6beb7b9e54b/20e5d/2018-xsf-summit-reflection.jpg 450w,
/static/ffb370b53347b9d8d70fb6beb7b9e54b/41099/2018-xsf-summit-reflection.jpg 500w&quot;
        sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I also wanted to make the minutes available on the &lt;a href=&quot;https://wiki.xmpp.org&quot;&gt;XMPP wiki&lt;/a&gt;,
but Vimwiki’s syntax is a little bit different than the Mediawiki syntax.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://pandoc.org/&quot;&gt;Pandoc&lt;/a&gt; came to the rescue, and with a one-liner I
could generate Mediawiki files from all my notes.&lt;/p&gt;
&lt;p&gt;So &lt;a href=&quot;https://wiki.xmpp.org/web/Summit_22#Minutes&quot;&gt;here are the 2018 XSF Summit minutes on the XMPP wiki&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Final thoughts&lt;/h2&gt;
&lt;p&gt;It was fun to meet up again with kindred spirits and to see some
familiar and friendly faces from the XMPP world.&lt;/p&gt;
&lt;p&gt;This year was also the first time I attended the fancy XSF dinner. I had
the sea bass with endive and beurre blanc.&lt;/p&gt;
&lt;p&gt;See you folks next year and thanks for all the fish!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8f100772de510bdb07868efce38e5dc1/a2510/2018-xsf-summit-dinner.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAABWnU9FZg2J//EABoQAQACAwEAAAAAAAAAAAAAAAIBAwAREhP/2gAIAQEAAQUCV3VhlOWtKmRlqjnyEZ//xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwGq/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQIBAT8BiP/EAB4QAAIBAwUAAAAAAAAAAAAAAAABIQIREiIxQlFh/9oACAEBAAY/AsqjbFDtPpqU9iVPIk//xAAbEAEAAgMBAQAAAAAAAAAAAAABABEhMUFxgf/aAAgBAQABPyF74xwmhsOau5qQ3xuW1RJ4PkMkr1XICC9z/9oADAMBAAIAAwAAABDLP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8QH//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/EAT/AP/EABsQAQADAAMBAAAAAAAAAAAAAAEAESExQVGB/9oACAEBAAE/EK4iMuoz35CVlmiXbPsrW40NXzAXeAgQO4AyymCDl3vgg0Z+z//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The XSF summit dinner.&quot;
        title=&quot;&quot;
        src=&quot;/static/8f100772de510bdb07868efce38e5dc1/8e1fc/2018-xsf-summit-dinner.jpg&quot;
        srcset=&quot;/static/8f100772de510bdb07868efce38e5dc1/863e1/2018-xsf-summit-dinner.jpg 225w,
/static/8f100772de510bdb07868efce38e5dc1/20e5d/2018-xsf-summit-dinner.jpg 450w,
/static/8f100772de510bdb07868efce38e5dc1/8e1fc/2018-xsf-summit-dinner.jpg 900w,
/static/8f100772de510bdb07868efce38e5dc1/a2510/2018-xsf-summit-dinner.jpg 1000w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Converse 3.3 has been released]]></title><description><![CDATA[Last night I released version 3.3.0
of Converse.js, and as often happens with big releases, I made a quick bugfix
release (3.3.1) today.
The…]]></description><link>https://opkode.com/blog/2018-01-16-converse-3.3.1-released/</link><guid isPermaLink="false">https://opkode.com/blog/2018-01-16-converse-3.3.1-released/</guid><pubDate>Thu, 18 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Last night I released &lt;a href=&quot;https://github.com/jcbrand/converse.js/releases/tag/v3.3.0&quot;&gt;version 3.3.0&lt;/a&gt;
of Converse.js, and as often happens with big releases, I made a quick bugfix
release (&lt;a href=&quot;https://github.com/jcbrand/converse.js/releases/tag/v3.3.1&quot;&gt;3.3.1&lt;/a&gt;) today.
The bugfix release turns off some CSS3 animations for new messages which caused
degraded performance on Firefox. On Chrome the animations render smoothly, so
if you’d like you can still turn them on with the
&lt;a href=&quot;https://conversejs.org/docs/html/configuration.html#show-message-load-animation&quot;&gt;show_message_load_animation&lt;/a&gt;
config option.&lt;/p&gt;
&lt;h2&gt;What’s in the release?&lt;/h2&gt;
&lt;p&gt;Maintaining a long-term open source front-end JavaScript library almost
feels like a Sisyphean task sometimes. As soon as you’ve rolled the big
stone up the hill, the whole JS ecosystem, best practices and tooling
changes and you find yourself at the bottom of the hill again.&lt;/p&gt;
&lt;p&gt;This release is therefore heavy on changes under the hood, with the aim
of modernizing and improving the quality of the code.&lt;/p&gt;
&lt;p&gt;Besides that, I also spent time squashing lots of small usability bugs
and on improving performance.&lt;/p&gt;
&lt;h2&gt;Converse.js now uses a Virtual DOM&lt;/h2&gt;
&lt;p&gt;Various views, such as the registration form, are now rendered by means
of a &lt;a href=&quot;https://github.com/snabbdom/snabbdom&quot;&gt;Virtual DOM&lt;/a&gt;. I wrote a new
Backbone view called &lt;a href=&quot;https://github.com/jcbrand/backbone.vdomview&quot;&gt;Backbone.VDOMView&lt;/a&gt; for
this, and &lt;a href=&quot;https://opkode.com/blog/backbone-vdomview&quot;&gt;blogged about it here&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;No more jQuery&lt;/h2&gt;
&lt;p&gt;Looking at the git log, I started rewriting code to not use jQuery in
January 2017.&lt;/p&gt;
&lt;p&gt;So this change has been a year in the works. I often asked myself
whether I should spend time on this and not rather do something else,
like adding new features, especially since removing jQuery has taken a
lot of time.&lt;/p&gt;
&lt;p&gt;However, there were some good reasons, or perhaps motivations, for me to
remove jQuery.&lt;/p&gt;
&lt;p&gt;Before ES6 promises were available, I used &lt;code class=&quot;language-text&quot;&gt;$.Deferred&lt;/code&gt;. However,
jQuery’s deferreds weren’t compatible with Promises, so when ES6
Promises came around, I had to rewrite lots of code to use Promises.&lt;/p&gt;
&lt;p&gt;I used &lt;code class=&quot;language-text&quot;&gt;$.show&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;$.hide&lt;/code&gt; quite a bit, and then it turned out that
the way jQuery was doing it (by adding/removing &lt;code class=&quot;language-text&quot;&gt;display: none&lt;/code&gt; to the
DOM element) is not good practice and also
&lt;a href=&quot;https://github.com/jquery/jquery.com/issues/88#issuecomment-72400007&quot;&gt;very slow&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;So I started writing my own utility functions to replace jQuery’s.&lt;/p&gt;
&lt;p&gt;The last straw for me was when jQuery 3 came out, and half of
Converse.js’s ~240 tests failed once I plugged it in.&lt;/p&gt;
&lt;p&gt;After spending some time trying to figure out what backward incompatible
changes they made and how I should update the code, I decided to instead
rip jQuery out entirely.&lt;/p&gt;
&lt;p&gt;It’s still used in the tests, but it’s no longer included in any
build.&lt;/p&gt;
&lt;p&gt;Since removing it, I’ve noticed a remarkable reduction in time to run
the tests.&lt;/p&gt;
&lt;p&gt;By looking at how quickly the tests run now, the code seems to run much
faster without jQuery.&lt;/p&gt;
&lt;h2&gt;Less weight&lt;/h2&gt;
&lt;p&gt;Besides removing jQuery, I also updated Converse.js to load translations
at runtime, and only the exact translation JSON file that’s needed.&lt;/p&gt;
&lt;p&gt;Due to these changes, the unminified built has shrunk from 3.38MB to
2.8MB, and the minified build from 1.66MB to 1.2MB.&lt;/p&gt;
&lt;p&gt;And this is while adding the virtual DOM code.&lt;/p&gt;
&lt;h2&gt;Route to a specific chat room via the URL&lt;/h2&gt;
&lt;p&gt;It’s now possible to directly link to a specific chat room, or to the
registration page (instead of the login page) via the URL.&lt;/p&gt;
&lt;p&gt;For example, the URL
&lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&lt;/a&gt;
will take you immediately to the Converse.js “Discuss” chat room, once
you’ve logged in.&lt;/p&gt;
&lt;h2&gt;What else?&lt;/h2&gt;
&lt;p&gt;Lots of other bugfixes and improvements have been added in this release.
For more details, check the
&lt;a href=&quot;https://github.com/jcbrand/converse.js/releases/tag/v3.3.0&quot;&gt;changelog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Notable absent from this release are some desired features, such as file
sharing, message corrections, message receipts and the like.&lt;/p&gt;
&lt;p&gt;I would love to add some of these often requested features, however I
had to get the house in order so to speak, by modernizing the code and
squashing lots and lots of little usability and performance bugs.&lt;/p&gt;
&lt;p&gt;That said, Converse.js takes up a LOT of my free time and not a single
line of code in this release was paid for.&lt;/p&gt;
&lt;p&gt;If you or your company make use of converse.js, please consider
sponsoring it on &lt;a href=&quot;https://www.patreon.com/jcbrand&quot;&gt;Patreon&lt;/a&gt; or
&lt;a href=&quot;https://liberapay.com/jcbrand&quot;&gt;Liberapay&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;Thanks&lt;/h2&gt;
&lt;p&gt;Thanks goes out to everyone who’s made pull requests and bug reports
over the last months.&lt;/p&gt;
&lt;p&gt;And thanks also to the folks who hang out in the &lt;a href=&quot;https://inverse.chat/#converse/room?jid=discuss@conference.conversejs.org&quot;&gt;Converse.js
Discusss&lt;/a&gt;
chat room and who have there provided valuable feedback.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using a virtual DOM with Backbone views]]></title><description><![CDATA[Backbone.js, first released in 2010, provided one-way event binding with
unidirectional data-flow and therefore a means to do reactive…]]></description><link>https://opkode.com/blog/backbone-vdomview/</link><guid isPermaLink="false">https://opkode.com/blog/backbone-vdomview/</guid><pubDate>Tue, 16 Jan 2018 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;a href=&quot;http://backbonejs.org/&quot;&gt;Backbone.js&lt;/a&gt;, first released in 2010, provided one-way event binding with
unidirectional data-flow and therefore a means to do reactive programming before it was cool.
Backbone views provide a &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method, which is supposed to insert HTML into the DOM.
How this was actually done was left up to the user as a homework assignment.
Generally, jQuery’s &lt;code class=&quot;language-text&quot;&gt;html&lt;/code&gt; method was used. Like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MyView &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Backbone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;View&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;change&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;render&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;$el&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;html&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Each view has an associated DOM element, &lt;code class=&quot;language-text&quot;&gt;this.$el&lt;/code&gt; if you’re
using jQuery or &lt;code class=&quot;language-text&quot;&gt;this.el&lt;/code&gt; otherwise. In the above
example, the element’s contents would be replaced.&lt;/p&gt;
&lt;p&gt;What this approach however lacks, is a way to rerender views
containing forms without losing the input focus or user-provided form values.&lt;/p&gt;
&lt;p&gt;This is because back in 2010, the virtual DOM as popularized by
React wasn’t yet around.&lt;/p&gt;
&lt;p&gt;Additionally, since rendering the HTML and inserting it into the
DOM were both done inside the &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method,
and the implementation details were left up to
the user, enough rope was provided for you to hang yourself by putting things
inside the &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method which shouldn’t be there.&lt;/p&gt;
&lt;p&gt;Contrast this to a React component’s &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method,
which is a “pure function” that doesn’t modify the DOM, and
instead simply returns JSX:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;MyComponent&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;extends&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;React&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Component&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;Hello World&lt;span class=&quot;token operator&quot;&gt;!&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;/&lt;/span&gt;p&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The markup is then inserted into the DOM separately with &lt;code class=&quot;language-text&quot;&gt;ReactDOM.render&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;ReactDOM.render(
&amp;#x3C;MyComponent /&gt;,
document.getElementById(‘root’)
);&lt;/p&gt;
&lt;p&gt;The fact that a component’s &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method &lt;strong&gt;must&lt;/strong&gt; return JSX, means that they
are pure functions without side-effects.&lt;/p&gt;
&lt;h2&gt;Backbone Views which use a virtual DOM&lt;/h2&gt;
&lt;p&gt;In &lt;a href=&quot;https://converse.js&quot;&gt;Converse&lt;/a&gt; we still use Backbone Models and
Views, and for the most part, Backbone still works beautifully. It’s a
small, lightweight library that’s fit for purpose and doesn’t get in
the way.&lt;/p&gt;
&lt;p&gt;However, we’ve been missing out on that sweet sweet virtual DOM.&lt;/p&gt;
&lt;p&gt;No more!&lt;/p&gt;
&lt;p&gt;To make our Backbone Views more reactive, as is done in React, I wrote
&lt;a href=&quot;https://github.com/jcbrand/backbone.vdomview&quot;&gt;Backbone.VDOMView&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This library adds a new view, called &lt;code class=&quot;language-text&quot;&gt;Backbone.VDOMView&lt;/code&gt;, which uses a
Virtual DOM (provided by
&lt;a href=&quot;https://github.com/snabbdom/snabbdom&quot;&gt;Snabbdom&lt;/a&gt;) to only update those
DOM elements (within the view) as necessary.&lt;/p&gt;
&lt;p&gt;Instead of writing a &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; method, for &lt;code class=&quot;language-text&quot;&gt;Backbone.VDOMView&lt;/code&gt; you need
to implement a &lt;code class=&quot;language-text&quot;&gt;toHTML&lt;/code&gt; method, which is a pure function that simply
returns the view’s HTML.&lt;/p&gt;
&lt;p&gt;Here’s what it looks like:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;const&lt;/span&gt; MyView &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; Backbone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;VDOMView&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;extend&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;initialize&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;on&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;change&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;render&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token function&quot;&gt;toHTML&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token keyword&quot;&gt;this&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;model&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;toJSON&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Backbone.VDOMView takes the output of &lt;code class=&quot;language-text&quot;&gt;toHTML&lt;/code&gt; and converts it into
virtual DOM nodes and automatically diffs and patches the DOM.&lt;/p&gt;
&lt;p&gt;When the view’s associated &lt;code class=&quot;language-text&quot;&gt;Backbone.Model&lt;/code&gt; (referenced via
&lt;code class=&quot;language-text&quot;&gt;this.model&lt;/code&gt;) changes, we can simply call &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt; again, knowing that
only the changed DOM elements will be updated.&lt;/p&gt;
&lt;p&gt;We write less to the DOM and we prevent the loss of form input values
and loss of element focus.&lt;/p&gt;
&lt;h2&gt;Include the root element in your HTML&lt;/h2&gt;
&lt;p&gt;There’s one important difference with normal Backbone.Views and that is
that &lt;code class=&quot;language-text&quot;&gt;toHTML&lt;/code&gt; (as opposed to &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt;) must including the view’s root
element in the returned HTML.&lt;/p&gt;
&lt;p&gt;With normal Backbone.View, you don’t include the view’s root element
when you render a template.&lt;/p&gt;
&lt;p&gt;React has a similar requirement to this. JSX returned in the &lt;code class=&quot;language-text&quot;&gt;render&lt;/code&gt;
method of a component must have a root node which contains everything
else.&lt;/p&gt;
&lt;h3&gt;jQuery not required&lt;/h3&gt;
&lt;p&gt;With Backbone, you can use
&lt;a href=&quot;https://github.com/akre54/Backbone.NativeView&quot;&gt;Backbone.NativeView&lt;/a&gt; to
remove the default dependency on jQuery.&lt;/p&gt;
&lt;p&gt;Backbone.VDOMView checks whether you are using &lt;code class=&quot;language-text&quot;&gt;Backbone.NativeView&lt;/code&gt; and
will then subclass it instead of &lt;code class=&quot;language-text&quot;&gt;Backbone.View&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Usage in Converse&lt;/h3&gt;
&lt;p&gt;In &lt;a href=&quot;https://github.com/jcbrand/converse.js/releases/tag/v3.3.0&quot;&gt;release 3.3.0 of Converse&lt;/a&gt;
I’ve removed jQuery as dependency and started integrating
Backbone.VDOMView.&lt;/p&gt;
&lt;p&gt;Various &lt;code class=&quot;language-text&quot;&gt;Backbone.View&lt;/code&gt; components from Converse have already been
migrated over to &lt;code class=&quot;language-text&quot;&gt;Backbone.VDOMView&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So far, I’m very happy with the results, and haven’t run into any
issues.&lt;/p&gt;
&lt;p&gt;If you’re using Backbone.VDOMView or have any feedback, feel free to
leave a comment or &lt;a href=&quot;https://opkode.com/contact.html&quot;&gt;contact me here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Custom SASL auth mechanisms in Strophe.js]]></title><description><![CDATA[If you’ve decided to read this fairly technical blogpost, then you
probably have at least a rough idea what SASL is about and why one would…]]></description><link>https://opkode.com/blog/strophe_custom_sasl_auth/</link><guid isPermaLink="false">https://opkode.com/blog/strophe_custom_sasl_auth/</guid><pubDate>Sat, 05 Nov 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’ve decided to read this fairly technical blogpost, then you
probably have at least a rough idea what SASL is about and why one would
want to create custom SASL auth mechanisms or whitelist the supported
mechanisms.&lt;/p&gt;
&lt;p&gt;I’ll therefore provide just a very brief recap of the topics involved:&lt;/p&gt;
&lt;p&gt;The Simple Authentication and Security Layer or SASL
&lt;a href=&quot;http://tools.ietf.org/html/rfc4422&quot;&gt;RFC 4422&lt;/a&gt; is a framework for adding
authentication support to connection-based protocols.&lt;/p&gt;
&lt;p&gt;It provides an abstraction layer for authentication mechanisms, so that
protocols, such as XMPP don’t have to deal with the intricacies and
complexities of supporting multiple authentication mechanisms.&lt;/p&gt;
&lt;p&gt;It therefore makes auth mechanisms pluggable (if they are SASL
compatible).&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://strophe.im&quot;&gt;Strophe.js&lt;/a&gt; has supported SASL since a long time,
but it didn’t provide an easy way add custom SASL mechanisms, or to
whitelist the mechanisms to be used.&lt;/p&gt;
&lt;p&gt;Until now… or rather, since the &lt;a href=&quot;https://github.com/strophe/strophejs/releases/tag/v1.2.9&quot;&gt;1.2.9 release&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Creating a custom SASL auth mechanism&lt;/h1&gt;
&lt;p&gt;To create a custom SASL authentication mechanism is fairly simple.&lt;/p&gt;
&lt;p&gt;You can glean what’s required by simply looking at how the default
mechanisms are created.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://github.com/strophe/strophejs/blob/v1.2.9/src/core.js#L3362&quot;&gt;See for example how the SASLPlain mechanism is defined.&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;And &lt;a href=&quot;https://github.com/strophe/strophejs/blob/v1.2.9/src/core.js#L3271&quot;&gt;look as the SASLMechanism prototype&lt;/a&gt;
to see the interface that the mechanism supports.&lt;/p&gt;
&lt;p&gt;Perty much it boils down to creating constructor, settings its prototype
to an invoked &lt;a href=&quot;https://github.com/strophe/strophejs/blob/v1.2.9/src/core.js#L3242&quot;&gt;Strophe.SASLMechanism&lt;/a&gt;
instance, providing its name, a boolean to indicate whether it should
proactively respond without an initial server challenge, and an integer
value specifying its priority amongst the supported mechanisms.&lt;/p&gt;
&lt;p&gt;The default mechanisms and their respective priorities are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;EXTERNAL - 60&lt;/li&gt;
&lt;li&gt;OAUTHBEARER - 50&lt;/li&gt;
&lt;li&gt;SCRAM-SHA1 - 40&lt;/li&gt;
&lt;li&gt;DIGEST-MD5 - 30&lt;/li&gt;
&lt;li&gt;PLAIN - 20&lt;/li&gt;
&lt;li&gt;ANONYMOUS - 10&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Then it’s a matter of implementing &lt;code class=&quot;language-text&quot;&gt;onChallenge&lt;/code&gt; and any of the other
methods provided by &lt;a href=&quot;https://github.com/strophe/strophejs/blob/v1.2.9/src/core.js#L3271&quot;&gt;the SASLMechanism prototype&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;code class=&quot;language-text&quot;&gt;onChallenge&lt;/code&gt; is called once the server challenges the client to
authenticate itself or proactively if the mechanism requires that the
client initiates authentication (configured with the &lt;code class=&quot;language-text&quot;&gt;isClientFirst&lt;/code&gt;
parameter of &lt;a href=&quot;https://github.com/strophe/strophejs/blob/v1.2.9/src/core.js#L3242&quot;&gt;Strophe.SASLMechanism&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;So, lets create a fictional auth mechanism called SASL-FOO which works
similarly to SASL-PLAIN, except that the password is encrypted with
double-encoding ROT13 (hint: &lt;a href=&quot;http://www.rot-n.com/&quot;&gt;this is a joke&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;We would then create the authentication mechanism like so:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;
Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;SASLFoo&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SASLFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SASLMechanism&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;FOO&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;true&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;60&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;

Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token class-name&quot;&gt;SASLFoo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;prototype&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function-variable function&quot;&gt;onChallenge&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;function&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token parameter&quot;&gt;connection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;let&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authzid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    auth_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;u0000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    auth_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;authcid&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    auth_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;u0000&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; auth_str &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;DoubleROT13&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;connection&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;pass&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
    &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; utils&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;utf16to8&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;auth_str&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Whitelisting the supported SASL auth mechanisms&lt;/h2&gt;
&lt;p&gt;Now with SASL-FOO in hand, we can whitelist the supported authentication
mechanisms by specifying a list of mechanisms in the &lt;code class=&quot;language-text&quot;&gt;options&lt;/code&gt; map
passed in when we instantiate a new Strohe.Connection.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; service &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;chat.example.org&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; options &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt; &lt;span class=&quot;token string-property property&quot;&gt;&apos;mechanisms&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;SASLFoo&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SASLPlain &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;var&lt;/span&gt; conn &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;new&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Connection&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;service&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; options&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Bonus: Whitelisting SASL auth mechanisms in Converse.js&lt;/h3&gt;
&lt;p&gt;Due to the above changes it’ll also be possible to whitelist SASL mechanisms in
&lt;a href=&quot;https://conversejs.org&quot;&gt;Converse.js&lt;/a&gt; (version 2.0.1 and upwards).&lt;/p&gt;
&lt;p&gt;This is done via the &lt;a href=&quot;https://conversejs.org/docs/html/configuration.html#connection-options&quot;&gt;connection_options&lt;/a&gt;
configuration setting:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;
converse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token function&quot;&gt;initialize&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
  &lt;span class=&quot;token literal-property property&quot;&gt;connection_options&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;token string-property property&quot;&gt;&apos;mechanisms&apos;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;converse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;token constant&quot;&gt;SASLMD5&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; converse&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;env&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Strophe&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;SASLPlain&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;
  &lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Happy hacking.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Strophe.js and Converse now support passwordless login with client certificates]]></title><description><![CDATA[Did you know that x509 certificates, the certificates
that webservers use to prove their identity during the establishment of
an HTTPS…]]></description><link>https://opkode.com/blog/strophe_converse_sasl_external/</link><guid isPermaLink="false">https://opkode.com/blog/strophe_converse_sasl_external/</guid><pubDate>Thu, 15 Sep 2016 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Did you know that &lt;a href=&quot;https://en.wikipedia.org/wiki/X.509&quot;&gt;x509 certificates&lt;/a&gt;, the certificates
that webservers use to prove their identity during the establishment of
an HTTPS connection, can also be used by a client (like your webbrowser)
to prove &lt;em&gt;its&lt;/em&gt; identity, and even to authenticate?&lt;/p&gt;
&lt;p&gt;I’m talking here about so-called client certificate authentication.&lt;/p&gt;
&lt;p&gt;Client certificate authentication is especially popular in environments
with high security requirements. They can even be used to enforce
2-factor authentication, if in addition to a client certificate you also
require a password. That usecase is however out of scope for this blog
post.&lt;/p&gt;
&lt;p&gt;With the release of &lt;a href=&quot;http://strophe.im&quot;&gt;Strophe.js&lt;/a&gt; 1.2.8, it’s now
possible to have passwordless login with TLS client certificates in
&lt;a href=&quot;https://conversejs.org&quot;&gt;Converse&lt;/a&gt; and any other Strophe.js-based webchat projects.&lt;/p&gt;
&lt;p&gt;For Converse, you’ll need at least version 2.0.0.&lt;/p&gt;
&lt;p&gt;Here’s what it looke like:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3733bc4a48bc764c1563bf19449071f0/client_auth_screencast.gif&quot; alt=&quot;Screencast of client authentication&quot;&gt;&lt;/p&gt;
&lt;h2&gt;The technical details and background&lt;/h2&gt;
&lt;h3&gt;XMPP and SASL&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;right img--transparent&quot; style=&quot;width: 8em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cc3b30a8ac67c08778f1667c49a8194c/e8950/xmpp_logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 102.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAYAAABG1c6oAAAACXBIWXMAAAsTAAALEwEAmpwYAAAECElEQVR42pWUD1DTZRjH323QoAuMUyqQNsQZpVd5h9DqSo8shlx3ctocC+YGwQb7C8rGScKOEhW9NDC9gEQY4sY6/ol2GPGnuuuSRDA4NLojiNVC5VIkr7G1p+e3/caNyszn7vP7vb/7Pc/3fd7nfZ+XkA05XSRBLiT8gmDy4MagHsF8xUoSrygncW+fJixBsZ2x2QjhOyWTuk5BleWyNqXym/TQ/1IBFLLpomPt+dEae0bE+ZeTdt4mKeUQKChuIw+JD30RIDoGEdpcl6Fnq/uT77VQd0k+XTuo5FHBRqORuSgkJCzqbddwE3/VcN2/F8bA7cwod6JQ5SIZx+FhUYWeBKlq32FrrLA8v8SZadnsPD2cBw1X8lyNY7l8jwj4CVq9gr9pOdvnd0XDjIa7MJEW5VyXvR+IyuQIU1U/S9i7TauC93ZeD91rgi01Anftt1l/msfU0DAsF1HBVhCy/p7hjJZjcBhi4IYi0tmdHucKL20DdsnZlsWahBzuK3+kahDWV8oWDvRsd7ZOFMCpIflhj6DVT5DehBk1p/2OfjXclD7m2qfMdDEqBxZWlHe+sigYVm1dFto4PRJZ1wzZ5k0LzVe1mKFi9NNxDdu3mwBesdm8yCdvaLmzN3XRMLkjwsGv6QVG01SVd0ZgUil4MnjUMrEx7Nzs3YQ6ufto/zaX5ZoOPh6Sp/qW3WckAZ766Tj6+aI1cCc95I8PSndDYNfdgZcq2kNoQYZ3flp0Wce8LOLMlyBuSsIslWC6ouwXCoUs37JnlNwnrufHTM4pH4eLWfHwdP3gFOmBWI+GEZhLDxctGlZjy1194oi78FyKs/UHHZy8JFf5XFDshGNXFEzIeLC17CMbaYP1/rH/NPpH6HuDonXv59/a95UIWsZUc4e+0z53KysyzaHnwHTOU6BQF14mjXRm9xTzmbHPU6uVhg5+3H7pcFGfBEzX1OO/7Im1j4p5oM/ObCLVcyv+n5jPhF7H1NRjy4uKEwc+NL8BvfVboPKo9Ii3ewiT+HXQfQ2k3KCRLF7SzzlRFpts1YUzgrXit0yCspJe4ejBz8VV7/Yr1hDvMWLc9+YY1/DY4+mcN3/M4MoupsVuoHbZ58DbwwuXmAUSqVlQIm1KSjXeI0sqgPkvY2+2uDzpJm5QcnIyGxbP2RJf6h1Aw/LPbkmBqc6ge5fxoJckdQnE0+MdyAvIRiSDnpUSFCKvIc8geYgOyUao3X4dUSMFSAqhP0aQg1QJkbVIi/cuIMlIAj1uR8qQKUSLXEWOI93IWWrzqWbyLbebDjLQmbYip5DP6H/1yEk6iBIspSevQM4jFxDqSNmo4GakDaFO/k+IhHbahjQgXcirSAdyAPkaeZEuQSAyRE+UiDz/F59LpjRuXl0EAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The XMPP logo&quot;
        title=&quot;&quot;
        src=&quot;/static/cc3b30a8ac67c08778f1667c49a8194c/1cfc2/xmpp_logo.png&quot;
        srcset=&quot;/static/cc3b30a8ac67c08778f1667c49a8194c/3684f/xmpp_logo.png 225w,
/static/cc3b30a8ac67c08778f1667c49a8194c/fc2a6/xmpp_logo.png 450w,
/static/cc3b30a8ac67c08778f1667c49a8194c/1cfc2/xmpp_logo.png 900w,
/static/cc3b30a8ac67c08778f1667c49a8194c/21482/xmpp_logo.png 1350w,
/static/cc3b30a8ac67c08778f1667c49a8194c/d61c2/xmpp_logo.png 1800w,
/static/cc3b30a8ac67c08778f1667c49a8194c/e8950/xmpp_logo.png 2000w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;XMPP supports authentication with client certificates, because it uses
SASL (Simple Authentication and Security Layer).&lt;/p&gt;
&lt;p&gt;SASL provides an abstraction that decouples authentication mechanisms
from application protocols.&lt;/p&gt;
&lt;p&gt;This means that XMPP developers don’t need to know about the
implementation details of any authentication mechanisms, as long as they
conform to SASL.&lt;/p&gt;
&lt;p&gt;Up til version 1.2.7, Strophe.js supported the SASL auth mechanisms:
ANONYMOUS, OAUTHBEARER, SCRAM-SHA1, DIGEST-MD5 and PLAIN.&lt;/p&gt;
&lt;p&gt;For client certificate auth, we need another SASL mechanism, namely
&lt;a href=&quot;https://tools.ietf.org/html/rfc4422#appendix-A&quot;&gt;EXTERNAL&lt;/a&gt;. What
EXTERNAL means, is that authentication happens externally, outside of
the protocol layer. And this is exactly what happens in the case of
client certificates, where authentication happens not in the XMPP layer,
but in the SSL/TLS layer.&lt;/p&gt;
&lt;p&gt;Strophe.js version 1.2.8 now supports SASL-EXTERNAL, which is why client
certificate authentication now also works.&lt;/p&gt;
&lt;h3&gt;How do you communicate with an XMPP server from a web-browser?&lt;/h3&gt;
&lt;p&gt;There are two ways that you can communicate with an XMPP server from a
web-browser (e.g. from a webchat client such as Converse).&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;You can use XMLHttpRequests and
&lt;a href=&quot;http://xmpp.org/extensions/xep-0206.html&quot;&gt;BOSH&lt;/a&gt;, which you can
think of as an XMPP-over-HTTP specification.&lt;/li&gt;
&lt;li&gt;You can use websockets.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Both of these protocols, HTTP and websocket, have secure SSL-reliant
versions (HTTPS and WSS), and therefore in both cases client certificate
authentication should be possible, as long as the server requests a
certificate from the client.&lt;/p&gt;
&lt;p&gt;I’m going to focus on BOSH and HTTPS, since this was my usecase.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://tools.ietf.org/html/rfc2818#section-3.2&quot;&gt;HTTPS protocol&lt;/a&gt;
makes provision for the case where the server might request a
certificate from the client.&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;NOTE: At the time of writing the only XMPP server that supports client certificate
authentication with BOSH is Openfire, and funnily enough, only Openfire
3. In Openfire 4, they refactored the certificate handling code and
broke client certificate authentication with BOSH. I’ve submitted a
ticket for this to their tracker: &lt;a href=&quot;https://issues.igniterealtime.org/browse/OF-1191&quot;&gt;https://issues.igniterealtime.org/browse/OF-1191&lt;/a&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;The authentication flow&lt;/h3&gt;
&lt;p&gt;So this is how the authentication flow works. I’ll illustrate how the
authentication flow works by using actual log output from Converse&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;NOTE: My XMPP server’s domain is called &lt;strong&gt;debian&lt;/strong&gt;, because I was
running it on a Debian server and because naming things is hard. In
hindsight, this wasn’t a good name since it might confuse the dear
reader (that means you).&lt;/p&gt;
&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;2016-09-15 12:07:05.481 converse-core.js:128 Status changed to: CONNECTING&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Firstly, Converse sends out a BOSH stanza to the XMPP server debian, to
establish a new BOSH session.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;2016-09-15 12:07:05.482 converse-core.js:128

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1421604076&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://jabber.org/protocol/httpbind&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;to&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;debian&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xml:&lt;/span&gt;lang&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;en&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;60&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;text/xml; charset=utf-8&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ver&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1.6&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xmpp:&lt;/span&gt;version&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1.0&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xmlns:&lt;/span&gt;xmpp&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:xmpp:xbosh&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;

2016-09-15 12:07:06.040 bosh.js:749 XHR finished loading: POST https://debian:7445/http-bind&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The above stanza was sent as an XMLHttpRequest POST, and the above XML was sent as the Request Payload.&lt;/p&gt;
&lt;p&gt;Strophe.js takes care of all this, so nothing to worry about, but
sometimes digging through the internals is fun right? Right?!&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;2016-09-15 12:07:06.042 converse-core.js:128

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://jabber.org/protocol/httpbind&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xmlns:&lt;/span&gt;stream&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://etherx.jabber.org/streams&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;from&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;debian&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;authid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fe0ee6ab&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fe0ee6ab&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;secure&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;true&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;requests&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;2&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;inactivity&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;30&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;polling&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;5&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;wait&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;60&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;hold&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ack&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1421604076&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;maxpause&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;300&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;ver&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1.6&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;stream:&lt;/span&gt;features&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mechanisms&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:ietf:params:xml:ns:xmpp-sasl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;mechanism&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;EXTERNAL&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mechanism&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;mechanisms&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;register&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://jabber.org/features/iq-register&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;bind&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:ietf:params:xml:ns:xmpp-bind&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;session&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:ietf:params:xml:ns:xmpp-session&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;optional&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;session&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;stream:&lt;/span&gt;features&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So now the XMPP server, debian, has responded, and it provides a list of
SASL mechanisms that it supports. In this case it only supports
EXTERNAL.&lt;/p&gt;
&lt;p&gt;Luckily our webchat client supports SASL-EXTERNAL, so it responds in
turn and asks to be authenticated.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;
2016-09-15 12:07:06.147 converse-core.js:128

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;rid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1421604077&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://jabber.org/protocol/httpbind&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;sid&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;fe0ee6ab&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;auth&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:ietf:params:xml:ns:xmpp-sasl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token attr-name&quot;&gt;mechanism&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;EXTERNAL&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;dXNlcjAxQGRlYmlhbg==&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;auth&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now here comes the tricky part. The XMPP server’s BOSH servlet, asks
the webbrowser (which is establishing the HTTPS connection on our
behalf) to give it the client certificate for this user.&lt;/p&gt;
&lt;p&gt;The webbrowser will now prompt the user to choose the right client
certificate. Once this is done, the XMPP server authenticates the user
based upon this certificate.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;
2016-09-15 12:07:06.177 bosh.js:749 XHR finished loading: POST
2016-09-15 12:07:06.180 converse-core.js:128

&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;body&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;http://jabber.org/protocol/httpbind&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;ack&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;1421604077&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;success&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;xmlns&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;urn:ietf:params:xml:ns:xmpp-sasl&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;body&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The XMPP server responds with success and we’re logged in!&lt;/p&gt;
&lt;h2&gt;How to set up client certificate authentication with Converse and OpenFire 3.10.3&lt;/h2&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;NOTE: Thanks goes out to Dennis Shtemberg from Infusion, who initially
tested client certificate authentication with BOSH on Openfire and on
whose notes the following is based.&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;1. Install Openfire 3.10.3&lt;/h3&gt;
&lt;p&gt;On Debian(-based) Linux, you can simply do the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://www.igniterealtime.org/downloadServlet?filename&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;openfire/openfire_3.10.3_all.deb
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; dpkg &lt;span class=&quot;token parameter variable&quot;&gt;-i&lt;/span&gt; openfire_3.10.3_all.deb&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;span class=&quot;img-container right img--transparent&quot; style=&quot;width: 18em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/16731de11f448308f1658abed28ae51e/aa440/openfire_logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 29.333333333333332%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAGCAYAAADDl76dAAAACXBIWXMAAAsTAAALEwEAmpwYAAABhklEQVR42mP4p8LA/r/JRP3/Zivbf7uNC//v0BJiAIL//xkYGUgHjAx/86QP/Z9p/v/verPPfzebtL/MsucBG8gANxDD4Pr6eiaP6Gg+EI1h5P9Jdv8/THd//2u22aefc822fu21kJb3ipeIj7fn8PYOlXaNieF2CQ3ld3WN4baPjBSxDw3lcQ+N8PMIicwCGeoeGCjpHRUl6O/vL+DkGyHOcG558SyQwX8WWGz932s0l0G/UNo3LKzdPSi8yCM4vM0jOKLQLThsgntIRCWQ3+kWFF7tHRFT5hEaXeEWHF7uHhqe7x4c3uAeEt7nEhCuyfBhRuCa/2fsRX51WVz5n6pRyOCer+ATHNrmFRpZ4RkW1QI0qMw9OGIaEOd5BIUne4VHBXmEhmd6BkekuoeEVbqFxqgA5Ro9QiLqge5iYvicp7PtS5Xxu8/ZerOuMDCwAWOD0Sc0VM4tMEzfPSQyHRhiTK6BgWIeoaGiVn5+vKFAL4OCAIRtgF61t7dn8faOEgR5HRSGAGpwiyOR/gufAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Openfire logo&quot;
        title=&quot;&quot;
        src=&quot;/static/16731de11f448308f1658abed28ae51e/1cfc2/openfire_logo.png&quot;
        srcset=&quot;/static/16731de11f448308f1658abed28ae51e/3684f/openfire_logo.png 225w,
/static/16731de11f448308f1658abed28ae51e/fc2a6/openfire_logo.png 450w,
/static/16731de11f448308f1658abed28ae51e/1cfc2/openfire_logo.png 900w,
/static/16731de11f448308f1658abed28ae51e/21482/openfire_logo.png 1350w,
/static/16731de11f448308f1658abed28ae51e/aa440/openfire_logo.png 1500w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;h3&gt;2. Configure Openfire’s system properties&lt;/h3&gt;
&lt;p&gt;Open the admin console: &lt;a href=&quot;http://localhost:9090/&quot;&gt;http://localhost:9090/&lt;/a&gt; (where localhost is the host the server is running on)&lt;/p&gt;
&lt;p&gt;Navigate to Server &gt; Server Manager &gt; System Properties and add the
following properties:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Property                                    Value
------------------------------------------- ----------
xmpp.client.cert.policy                     needed
xmpp.client.certificate.accept-selfsigned   true
xmpp.client.certificate.verify              true
xmpp.client.certificate.verify.chain        true
xmpp.client.certificate.verify.root         true
sasl.mechs                                  EXTERNAL&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Make sure the xmpp.domain value is set to the correct host. If you’re
running Openfire on localhost, then you need to set it to localhost. If
you’re not using localhost, then replace all mention of localhost below
with the xmpp.domain value.&lt;/p&gt;
&lt;h3&gt;3. Lay the groundwork for generating an SSL client certificate&lt;/h3&gt;
&lt;p&gt;First, make sure you have OpenSSL installed: aptitude install openssl
Then create a directory for certificate files: mkdir ~/certs&lt;/p&gt;
&lt;p&gt;Now create a config file called user01.cnf (~/certs/user01.cnf) with
the following contents:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;ini&quot;&gt;&lt;pre class=&quot;language-ini&quot;&gt;&lt;code class=&quot;language-ini&quot;&gt;
&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;req&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;x509_extensions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;v3_extensions&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;req_extensions&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;v3_extensions&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;distinguished_name&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;distinguished_name&lt;/span&gt;

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;v3_extensions&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;extendedKeyUsage&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;clientAuth&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;keyUsage&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;digitalSignature,keyEncipherment&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;basicConstraints&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;CA:FALSE&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;subjectAltName&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;@subject_alternative_name&lt;/span&gt;

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;subject_alternative_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;otherName.0&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;1.3.6.1.5.5.7.8.5;UTF8:user01@localhost&lt;/span&gt;

&lt;span class=&quot;token section&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token section-name selector&quot;&gt;distinguished_name&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token key attr-name&quot;&gt;commonName&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token value attr-value&quot;&gt;user01@localhost&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;code class=&quot;language-text&quot;&gt;otherName.0&lt;/code&gt; value under &lt;code class=&quot;language-text&quot;&gt;subject_alternative_name&lt;/code&gt; assigns the
user’s JID to an ASN.1 Object Identifier of “id-on-xmppAddr”. The
XMPP server will check this value to figure out what the JID is of the
user who is trying to authenticate.&lt;/p&gt;
&lt;p&gt;For more info on the id-on-xmppAddr attribute, read &lt;a href=&quot;http://xmpp.org/extensions/xep-0178.html#c2s&quot;&gt;XEP-178&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;4. Generate an SSL client certificate&lt;/h3&gt;
&lt;p&gt;Generate a self-signed, leaf SSL certificate, which will be used for client authentication.&lt;/p&gt;
&lt;p&gt;Generate a private RSA key&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl genrsa &lt;span class=&quot;token parameter variable&quot;&gt;-out&lt;/span&gt; user01.key &lt;span class=&quot;token number&quot;&gt;4096&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generate a sigining request:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl req &lt;span class=&quot;token parameter variable&quot;&gt;-key&lt;/span&gt; user01.key &lt;span class=&quot;token parameter variable&quot;&gt;-new&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-out&lt;/span&gt; user01.req &lt;span class=&quot;token parameter variable&quot;&gt;-config&lt;/span&gt; user01.cnf &lt;span class=&quot;token parameter variable&quot;&gt;-extensions&lt;/span&gt; v3_extensions&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;when prompted for a DN enter: &lt;code class=&quot;language-text&quot;&gt;user01@localhost&lt;/code&gt;&lt;/p&gt;
&lt;p&gt;Generate a certificate by signing user01.req&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl x509 &lt;span class=&quot;token parameter variable&quot;&gt;-req&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-days&lt;/span&gt; &lt;span class=&quot;token number&quot;&gt;365&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-in&lt;/span&gt; user01.req &lt;span class=&quot;token parameter variable&quot;&gt;-signkey&lt;/span&gt; user01.key &lt;span class=&quot;token parameter variable&quot;&gt;-out&lt;/span&gt; user01.crt &lt;span class=&quot;token parameter variable&quot;&gt;-extfile&lt;/span&gt; user01.cnf &lt;span class=&quot;token parameter variable&quot;&gt;-extensions&lt;/span&gt; v3_extensions&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Generate PKCS12 formatted certificate file, containing the private key and the certificate. This will be the client certificate which you will log in with.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;openssl pkcs12 &lt;span class=&quot;token parameter variable&quot;&gt;-export&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-inkey&lt;/span&gt; user01.key &lt;span class=&quot;token parameter variable&quot;&gt;-in&lt;/span&gt; user01.crt &lt;span class=&quot;token parameter variable&quot;&gt;-out&lt;/span&gt; user01.pfx &lt;span class=&quot;token parameter variable&quot;&gt;-name&lt;/span&gt; user01&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;when prompted for export password enter: &lt;code class=&quot;language-text&quot;&gt;user01&lt;/code&gt;&lt;/p&gt;
&lt;h3&gt;5. Install the PKCS12 certificate on your local machine&lt;/h3&gt;
&lt;p&gt;Double click the pfx file and follow the steps to import it into your machine’s keystore.&lt;/p&gt;
&lt;h3&gt;6. Import the x509 certificate into Openfire&lt;/h3&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; keytool &lt;span class=&quot;token parameter variable&quot;&gt;-importcert&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-keystore&lt;/span&gt; /etc/openfire/security/truststore &lt;span class=&quot;token parameter variable&quot;&gt;-alias&lt;/span&gt; user01 &lt;span class=&quot;token parameter variable&quot;&gt;-file&lt;/span&gt; ~/certs/user01.crt
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; keytool &lt;span class=&quot;token parameter variable&quot;&gt;-importcert&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-keystore&lt;/span&gt; /etc/openfire/security/client.truststore &lt;span class=&quot;token parameter variable&quot;&gt;-alias&lt;/span&gt; user01 &lt;span class=&quot;token parameter variable&quot;&gt;-file&lt;/span&gt; ~/certs/user01.crt
&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; systemctl restart openfire&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt; &lt;/p&gt;
&lt;div class=&quot;note&quot;&gt; NOTE: The default keystore password is &quot;changeit&quot; &lt;/div&gt;
&lt;h3&gt;7. Create the user associated with the SSL client certificate&lt;/h3&gt;
&lt;p&gt;Go back to Openfire admin console, navigate to &lt;code class=&quot;language-text&quot;&gt;Users/Groups &gt; Create New User&lt;/code&gt; and create a new user.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Username: &lt;code class=&quot;language-text&quot;&gt;user01&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Password: &lt;code class=&quot;language-text&quot;&gt;user01&lt;/code&gt; (This is not controlled by Openfire).&lt;/li&gt;
&lt;li&gt;Click &lt;code class=&quot;language-text&quot;&gt;Create User&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;8. (When using Java 1.7) Patch Openfire&lt;/h3&gt;
&lt;p&gt;When trying to log in, I received the following error:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;2016.09.08 00:28:20 org.jivesoftware.util.CertificateManager - Unkown exception while validating certificate chain: Index: 0, Size: 0&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Turns out the likely cause for this is the fact that I was using the outdated Java version 1.7.&lt;/p&gt;
&lt;p&gt;At the time, I didn’t know that Java is the culprit, so I patched the
&lt;a href=&quot;https://github.com/igniterealtime/Openfire/blob/v3.10.3/src/java/org/jivesoftware/util/CertificateManager.java#L302&quot;&gt;following code&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;If you read the comments in the link above, you’ll see there are two sections, with one being outcommented. I swopped out the two sections, and then recompiled Openfire.&lt;/p&gt;
&lt;p&gt;After that, client certificate auth worked. The best way to avoid doing this is apparently to just use Java 1.8.&lt;/p&gt;
&lt;h3&gt;9. Test login with Converse&lt;/h3&gt;
&lt;p&gt;Now you’re done with setting up Openfire and you can test logging in with Converse.&lt;/p&gt;
&lt;p&gt;Download the latest version of Converse from the &lt;a href=&quot;https://github.com/jcbrand/converse.js/releases&quot;&gt;releases page&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To hide the password field (since the password won’t be checked for anyway), you need to open index.html in your text editor and add
&lt;code class=&quot;language-text&quot;&gt;authentication: &apos;external&apos;&lt;/code&gt; to the converse.initialize call.&lt;/p&gt;
&lt;p&gt;Then open index.html in your browser.&lt;/p&gt;
&lt;p&gt;In the Converse login box, type the JID of the user, e.g. user01@localhost and click login.&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;NOTE: If things go wrong, pass debug: true to converse.initialize, then
open your browser’s developer console and check the output. Check
especially the XHR calls to http-bind. Checking the output in the
Network tab can also be very helpful. There you’ll see what Openfire
responds to requests to its BOSH URL.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;Client certificate authentication is a bit of a niche requirement, doing so with BOSH/HTTP even more so.&lt;/p&gt;
&lt;p&gt;However, I expect webchat XMPP clients to become more and more prevalent
in the coming years, even on the desktop, for example when packaged with
Github’s &lt;a href=&quot;http://electron.atom.io/&quot;&gt;Electron&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The fact that this works because of SASL-EXTERNAL authentication being
added to Strophe.js means that this functionality is not only possible
in Converse, but all webchat clients built on Strophe.js (granted that
they use version 1.2.8 or higher).&lt;/p&gt;
&lt;p&gt;Unfortunately XMPP server support is lacking, with only Openfire
supporting this usecase currently, and not yet (at the time of writing)
in the 4.0.x branch. To see whether this gets fixed, keep an eye on the
&lt;a href=&quot;https://issues.igniterealtime.org/browse/OF-1191&quot;&gt;relevant ticket&lt;/a&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Open Source software and the expection of free labor]]></title><description><![CDATA[Over the last few years of starting and then maintaining an open source project
that has received a decent amount of attention, converse.js…]]></description><link>https://opkode.com/blog/open-source-and-the-expectation-of-free-labor/</link><guid isPermaLink="false">https://opkode.com/blog/open-source-and-the-expectation-of-free-labor/</guid><pubDate>Sun, 29 Nov 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Over the last few years of starting and then maintaining an open source project
that has received a decent amount of attention, &lt;a href=&quot;https://conversejs.org&quot;&gt;converse.js&lt;/a&gt;,
I’ve noticed some interesting things about the expectations some people have
towards developers who work on FOSS (free and open source software).&lt;/p&gt;
&lt;h2&gt;Predictably irrational&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 326px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/a415a9cf709dcab0215053e8e5845610/8a553/predictably_irrational.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 152.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAfABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAUCAwYE/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgH/2gAMAwEAAhADEAAAAXkVS5XVlAZxr9GI1lob/8QAHRABAAEEAwEAAAAAAAAAAAAAAgEDBBASABETIv/aAAgBAQABBQKVB56DF4vszrNFbU7mjLk277B1Of/EABYRAQEBAAAAAAAAAAAAAAAAABARIf/aAAgBAwEBPwHCH//EABcRAAMBAAAAAAAAAAAAAAAAAAECEBL/2gAIAQIBAT8BzA0//8QAGhAAAwADAQAAAAAAAAAAAAAAAAERECAhMf/aAAgBAQAGPwLrPcQtEyokJp//xAAcEAEAAgEFAAAAAAAAAAAAAAABABEhECAxUaH/2gAIAQEAAT8h46IM0F0xLpiYU4ihCg2x13iVfXZ//9oADAMBAAIAAwAAABCrK/P/xAAYEQEAAwEAAAAAAAAAAAAAAAABABARUf/aAAgBAwEBPxA6p0wMn//EABYRAQEBAAAAAAAAAAAAAAAAAAERAP/aAAgBAgEBPxAoyRmUJlu//8QAHBABAAMAAwEBAAAAAAAAAAAAAQARITFBYRBx/9oACAEBAAE/ECxseLYKVPQwpLi4KWsnMKejNpT3PAIOyp8HVwzJq/Vyh5JRd18//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;predictably irrational&quot;
        title=&quot;&quot;
        src=&quot;/static/a415a9cf709dcab0215053e8e5845610/8a553/predictably_irrational.jpg&quot;
        srcset=&quot;/static/a415a9cf709dcab0215053e8e5845610/863e1/predictably_irrational.jpg 225w,
/static/a415a9cf709dcab0215053e8e5845610/8a553/predictably_irrational.jpg 326w&quot;
        sizes=&quot;(max-width: 326px) 100vw, 326px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;People of course love to receive something for nothing. Dan Ariely, in
his book “Predictably Irrational” illustrates some of the biases
people have when it comes to free stuff. When confronted with the words
“free” (as in &lt;em&gt;gratis&lt;/em&gt;), people do things that are irrational and are
at odds with how a rational actor (the mythical &lt;em&gt;homo economicus&lt;/em&gt;) is
expected to behave, which is the bedrock upon which most economic
theories are based.&lt;/p&gt;
&lt;p&gt;The outcome of the various studies Ariely conducted was consistent: when
faced with multiple choices, the free option was commonly chosen. With
the opportunity to receive something for free, the actual value of the
product or service is no longer considered.&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;“Most transactions have an upside and a downside, but when something
is FREE! we forget the downside. FREE! gives us such an emotional
charge that we perceive what is being offered as immensely more
valuable than it really is.”&lt;/p&gt;
&lt;p&gt;Dan Ariely&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The biases regarding “FREE!” apply not only to monetary costs, but
also to time. We forgo some of our time when we wait in line for free
popcorn or to enter a museum on a free-entrance day. We could have been
doing something else at that time, so there’s a resultant opportunity
cost.&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a href=&quot;#fn-2&quot; class=&quot;footnote-ref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;Freedom isn’t free, it costs folks like you and me&lt;/h2&gt;
&lt;p&gt;&lt;sup id=&quot;fnref-3&quot;&gt;&lt;a href=&quot;#fn-3&quot; class=&quot;footnote-ref&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;These biases of course can also come into play when people evaluate free
(as in beer) software. In the same way that people didn’t take into
consideration the cost of the time they spend in trying to get something
for “free”, people often also don’t consider the non-monetary costs
of using FOSS.&lt;/p&gt;
&lt;p&gt;A common retort that usually surfaces on Slashdot, Reddit or Hacker News
whenever a discussion around using a Linux distribution on the Desktop
takes place, is ”&lt;em&gt;Linux is only free if you don’t value your time&lt;/em&gt;“.&lt;/p&gt;
&lt;p&gt;That’s of course completely true. I do value my time, took that into
consideration and still concluded that I want to use GNU/Linux and free
and open source software.&lt;/p&gt;
&lt;p&gt;Using FOSS requires a certain amount of commitment, and it should be
clear to the user why they are willing to go that route (freedom from
vendor-locking, the ability to control and keep private your data, the
ability to modify the code to your liking etc.).&lt;/p&gt;
&lt;p&gt;I think people have been hyping the “FREE!” aspect of FOSS way too
much.&lt;/p&gt;
&lt;h2&gt;Software for nothing and your support for free&lt;/h2&gt;
&lt;p&gt;&lt;sup id=&quot;fnref-4&quot;&gt;&lt;a href=&quot;#fn-4&quot; class=&quot;footnote-ref&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;&lt;strong&gt;Disclaimer&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;I consider a certain amount of support and maintenance as a requirement
for a successful open source project and not something you (as the
developer) can ignore.&lt;/p&gt;
&lt;p&gt;I try to channel bug reports and feature requests to the Github issue
tracker and general support questions to a mailing list, where hopefully
other people would also be willing to share the load by answering
questions.&lt;/p&gt;
&lt;p&gt;So while I complain about people wanting “something for nothing”
below, I invariably mean people who write to me directly, instead of on
the issue tracker and who are often trying to get me to work on
something right away.&lt;/p&gt;
&lt;/div&gt;
&lt;p&gt;So, when considering that many people don’t properly evaluate the costs
involved in using FOSS, some requests and emails that I sometimes
receive start to make sense.&lt;/p&gt;
&lt;h3&gt;“Please guide me”&lt;/h3&gt;
&lt;hr&gt;
&lt;p&gt;One common recurrence, is to be contacted by someone who is integrating
converse.js into a project for a paying client, and somehow got stuck.
Perhaps they didn’t read the docs or perhaps they don’t have the
requisite technical skills to do the job. These emails sometimes have a
pleading, desparate tone to them. Perhaps to instill some sense of guilt
or obligation or perhaps just because the person is really desperate and
under time pressure.&lt;/p&gt;
&lt;p&gt;What gets me every time however, is that as far as I can tell, these are
people working for commercial businesses who get paid for the work they
do. They then trawl the web looking for hapless FOSS developers to do
their work for them for free, or as expressed in the commonly used
phrase in these kinds of emails: ”&lt;em&gt;Please guide me&lt;/em&gt;“.&lt;/p&gt;
&lt;p&gt;The novelty and warm fuzzy feeling of altruistically helping strangers
solve their problems disappears like mist before the sun when you
realise that they’re getting paid for the work you’re doing for them
right now.&lt;/p&gt;
&lt;p&gt;And make no mistake about it, maintenance and support for an open source
project is work and sometimes even drudgery. The fun part is writing new
code or trying out new things, not helping people who can’t be bothered
to study the documentation.&lt;/p&gt;
&lt;h3&gt;We need a feature and we hope you’ll do it for free&lt;/h3&gt;
&lt;p&gt;Another common theme is emails where people somehow just assume that
I’ll implement some feature for them. At first this presumptuousness
startled me.&lt;/p&gt;
&lt;p&gt;I think it’s totally fair to ask when the project is charitable and the
people involved don’t receive any payment themselves, but that’s often
not the case.&lt;/p&gt;
&lt;p&gt;Instead, the underlying assumption appears to be that I love working on
open source projects so much that I’ll do it all for free &lt;strong&gt;and&lt;/strong&gt; that
I don’t have ideas on what to work on next.&lt;/p&gt;
&lt;p&gt;Sometimes people qualify their requests by stating that they’re a small
non-profit. Non-profits do however pay out salaries, don’t they?&lt;/p&gt;
&lt;p&gt;I’d be willing to reduce my hourly rate when working for a non-profit
with a good cause, but I’m most likely not going to do work for free.&lt;/p&gt;
&lt;h2&gt;The software is free, but the time spent working on it costs money&lt;/h2&gt;
&lt;p&gt;A nuance that’s perhaps lost on many people, is that I have often
worked on converse.js for money. There was a rather long
“bootstrapping” phase in the beginning where the project wasn’t good
enough for anyone to actually use or pay money for further development,
but after the project stabilized I started getting small paying gigs of
custom development on converse.js.&lt;/p&gt;
&lt;p&gt;In all cases I made it clear that the Mozilla Public License forces me
to open source any changes I made to the covered files, and therefore
the work I did for these paying customers (bless their hearts) was open
sourced as well.&lt;/p&gt;
&lt;p&gt;The point is that while the software is free (as in beer and as in
speech), the time spent working on it costs money.&lt;/p&gt;
&lt;p&gt;Either someone else pays me to spend my time working on it, or I end up
paying by doing something for free while I might be getting paid doing
something else (opportunity costs) or by taking time away from other
activities.&lt;/p&gt;
&lt;p&gt;FOSS development costs money, either the developer is commissioned, or
they pay for it themselves (perhaps unwittingly).&lt;/p&gt;
&lt;h2&gt;Doing work for free devalues it and takes the piss out of actual paying customers&lt;/h2&gt;
&lt;p&gt;The last point I’d like to make, is that by taking on these requests to
do free work for commercial entities (and non-profits), I’m not only
devaluing my work, but I’m also disincentivising paying customers
(which includes non-profits).&lt;/p&gt;
&lt;p&gt;After all, why would anyone pay me to do anything if I’m so eager to
please that I’ll do it all for free?&lt;/p&gt;
&lt;p&gt;The only reason I could see to do that, is to get that mythical
“exposure” that’s often also sold to web and graphic designers.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 780px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/64c713bce95bcc0087c86790a2cf70a7/be796/oatmeal-exposure.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQADAAAAAAAAAAAAAAAAAAUBAwT/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAGjPoZJSqOGgGoH/8QAHBAAAwABBQAAAAAAAAAAAAAAAAECEwMRISIy/9oACAEBAAEFAvRcN0poybEdni0yXzDEz//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB0QAAIBBAMAAAAAAAAAAAAAAAEhAAIQERIiQVH/2gAIAQEABj8CA1lRBw7MVTfPHzEVMbfcCt//xAAcEAACAwADAQAAAAAAAAAAAAABEQAhMUFRcYH/2gAIAQEAAT8hZYgM0AgB3JZTT6hLCrmAprYXKdwvYQjgMRiAAXQhF9n/2gAMAwEAAgADAAAAEMAPAP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8QH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8QH//EABwQAQEAAwEBAQEAAAAAAAAAAAERACExQVGRgf/aAAgBAQABPxA9jAk0/uQK0pU7POaOusvIYgu39nuQQUtUHPn3DuKqJx7e+cwlXrfff3DKdQFPmQjegNG7l5qVWM9z/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Comit strip about exposure&quot;
        title=&quot;&quot;
        src=&quot;/static/64c713bce95bcc0087c86790a2cf70a7/be796/oatmeal-exposure.jpg&quot;
        srcset=&quot;/static/64c713bce95bcc0087c86790a2cf70a7/863e1/oatmeal-exposure.jpg 225w,
/static/64c713bce95bcc0087c86790a2cf70a7/20e5d/oatmeal-exposure.jpg 450w,
/static/64c713bce95bcc0087c86790a2cf70a7/be796/oatmeal-exposure.jpg 780w&quot;
        sizes=&quot;(max-width: 780px) 100vw, 780px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://theoatmeal.com/comics/exposure&quot;&gt;Image by “The Oatmeal”&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;&lt;sup id=&quot;fnref-5&quot;&gt;&lt;a href=&quot;#fn-5&quot; class=&quot;footnote-ref&quot;&gt;5&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;h2&gt;So what do you do if you need work done and can’t pay for it?&lt;/h2&gt;
&lt;p&gt;Free and open source software is a beautiful, world-changing and
paradigm shifting idea. However, software developers, like all people,
need to be paid for their work, also when they work on FOSS.&lt;/p&gt;
&lt;p&gt;If you can’t pay for software development, then you can still try to
incentivise FOSS developers in other ways, but be aware that it’ll be
more difficult.&lt;/p&gt;
&lt;p&gt;One important lesson that I’m glad I learned early in life, is that
when you’re asking someone to do something for you, then you need to
explain to them why it’s in their best interests to do so.&lt;/p&gt;
&lt;p&gt;People inherently look out for themselves. It’s perfectly natural and
doesn’t necessarily mean they’re selfish to the point of being
anti-social, it just means that they need to take care of themselves and
that they can’t expect other people to do it for them or to even have
their best interests at heart.&lt;/p&gt;
&lt;p&gt;So when desiring something from someone, such as their help, the best
approach is to explain to them what’s in it for them&lt;/p&gt;
&lt;p&gt;For example, if you want a friend to help you out with something, let’s
say to join a beach cleanup project, you don’t tell them why it’ll be
good for you, you explain to them that it’ll be an opportunity to chat,
to meet new people, to go for a swim and to have the enjoyment of a
clean unspoiled beach.&lt;/p&gt;
&lt;p&gt;This is simple stuff, but many people apparently don’t know this.&lt;/p&gt;
&lt;p&gt;So if you want someone to help you with a software project, explain to
them why it would be in their best interest. If you can’t find a reason
why, then perhaps it’s actually not in their best interest and you need
to create an incentive for them.&lt;/p&gt;
&lt;p&gt;Money works pretty well as an incentive, but there are other ways as
well. One sure-fire way to build up goodwill and gratitude (that might
translate into more help and assistance) is to contribute. If you can’t
write code, fix typos in the docs, evangelize the project or contribute
in other areas which you have some expertise, like translations, design,
UX, helpful feedback etc.&lt;/p&gt;
&lt;p&gt;FOSS development is a community effort and a team sport. There’ll
always be people who try to take more than they give, but on average,
humans are matchers. When given something, they want to reciprocate and
give back. Keep that in mind when you’re trying to get something for
nothing.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Predictably_Irrational#The_Truth_about_Relativity&quot;&gt;Wikipedia article on Predictable Irrational&lt;/a&gt;&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;&lt;a href=&quot;https://en.wikipedia.org/wiki/Predictably_Irrational#The_Truth_about_Relativity&quot;&gt;Wikipedia article on Predictable Irrational&lt;/a&gt;&lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;Sung to the tune of &lt;a href=&quot;https://www.youtube.com/watch?v=BVkTmnJkAN8&quot;&gt;Freedom isn’t free&lt;/a&gt;&lt;a href=&quot;#fnref-3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;Sung to the tune of “Money for nothing” by Dire Straits.&lt;a href=&quot;#fnref-4&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-5&quot;&gt;From &lt;a href=&quot;http://theoatmeal.com/comics/exposure&quot;&gt;The Oatmeal&lt;/a&gt;&lt;a href=&quot;#fnref-5&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Converting Youtube videos into mp3]]></title><description><![CDATA[If you’re using Linux or a Mac, then there are two neat commandline tools which
you can use to download and convert Youtube videos into mp…]]></description><link>https://opkode.com/blog/converting-youtube-videos-into-mp3/</link><guid isPermaLink="false">https://opkode.com/blog/converting-youtube-videos-into-mp3/</guid><pubDate>Sun, 29 Nov 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you’re using Linux or a Mac, then there are two neat commandline tools which
you can use to download and convert Youtube videos into mp3 files. They are
&lt;a href=&quot;https://rg3.github.io/youtube-dl&quot;&gt;Youtube-dl&lt;/a&gt; and &lt;a href=&quot;http://ffmpeg.org&quot;&gt;FFmpeg&lt;/a&gt;.
Installation&lt;/p&gt;
&lt;h2&gt;Installing youtube-dl&lt;/h2&gt;
&lt;p&gt;The download and install instructions for youtube-dl are &lt;a href=&quot;https://rg3.github.io/youtube-dl/download.html&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As a quick note, on Mac you can run:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; youtube-dl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And on GNU/Linux:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;curl&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;https://yt-dl.org/downloads/2015.11.27.1/youtube-dl&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-o&lt;/span&gt;
/usr/local/bin/youtube-dl &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;chmod&lt;/span&gt; a+rx /usr/local/bin/youtube-dl&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;For NixOS fans, it’s available via nix-env.&lt;/p&gt;
&lt;h2&gt;Installing FFmpeg&lt;/h2&gt;
&lt;p&gt;Many Linux distros come with FFmpeg installed I believe.&lt;/p&gt;
&lt;p&gt;If not, you can use your distros package manager. For example, on
Ubuntu:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;apt-get&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ffmpeg&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br/&gt; &lt;br/&gt; &lt;br/&gt;&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
Note: In some older versions of Ubuntu (and probably other distros), you
should use avconv instead of ffmpeg. AVConv was simply a fork of FFmpeg
and the two projects have subsequently been merged back into FFmpeg
again.
&lt;/div&gt;
&lt;p&gt;On Mac you can use homebrew:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;brew &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; ffmpeg&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Downloading the video&lt;/h3&gt;
&lt;p&gt;To download a Youtube video, you simply run the following line (making
sure to replace the URL with the one of the video you want to download):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;youtube-dl &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;https://www.youtube.com/watch?v&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;DLzxrzFCyOs&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h3&gt;Converting video to mp3&lt;/h3&gt;
&lt;p&gt;To now convert the mp4 video to mp3, you can use FFmpeg (comes standard
with most Linux distros I believe).&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;ffmpeg -i RickAstley-NeverGonnaGiveYouUp\[HQ\]-DLzxrzFCyOs.mp4
RickAstley-NeverGonnaGiveYouUp.mp3&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;br/&gt; &lt;br/&gt; &lt;br/&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[A common grammatical mistake that programmers make]]></title><description><![CDATA[I recently read a fascinating
profile
about a guy who made about 50 000 edits to Wikipedia to correct a
relatively obscure grammatical…]]></description><link>https://opkode.com/blog/common-grammatical-mistake-programmers-make/</link><guid isPermaLink="false">https://opkode.com/blog/common-grammatical-mistake-programmers-make/</guid><pubDate>Fri, 06 Feb 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I recently read a fascinating
&lt;a href=&quot;https://medium.com/backchannel/meet-the-ultimate-wikignome-10508842caad&quot;&gt;profile&lt;/a&gt;
about a guy who made about 50 000 edits to Wikipedia to correct a
relatively obscure grammatical mistake. The mistake of using “comprised
of” when one should be using “composed of” or “consists of”. He is
the ultimate wikignome. A name given to people who spend most of their
time on the site making small corrections and fixes.&lt;/p&gt;
&lt;p&gt;This reminded me of a grammatical mistake that programmers frequently
make. I notice it in source code, on IRC, in mailing lists and in
documentation.&lt;/p&gt;
&lt;p&gt;Here are a few examples from actual code, which I found by using “grep”:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;cleanupInstance&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;teardownSite&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;setup_test_class&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;javascript&quot;&gt;&lt;pre class=&quot;language-javascript&quot;&gt;&lt;code class=&quot;language-javascript&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;case&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&quot;default&quot;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token comment&quot;&gt;// setup event handlers&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;What is the grammatical mistake in all these examples?&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 25em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 270px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/ad901dad7ff27751b79c87ef6aeecc7b/6f81f/programmer.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 94.66666666666667%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAATABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAQF/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABnoz7y1IM+4Jgf//EABsQAAIDAQEBAAAAAAAAAAAAAAABAgMREhND/9oACAEBAAEFAlOUSqzTcINyPPiKu4VSPlp//8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHRAAAgEEAwAAAAAAAAAAAAAAAAERAhASITJhcf/aAAgBAQAGPwIcnFvwxFtR0QVDdv/EABsQAQADAQEBAQAAAAAAAAAAAAEAESExQVGB/9oACAEBAAE/IcsbHdii2y5keDsJg1OX5L2NVfcTLYc2Fr2fqJd6z//aAAwDAQACAAMAAAAQsMc8/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPxAf/8QAHxABAAMAAgEFAAAAAAAAAAAAAQARITFBgVFhcZGh/9oACAEBAAE/EDyxuGvq4i8gE/QlgB0IFkoZxv3NfjZRn0XV253MfMMV7E6qMtMBT5hnamn0wjSbM7J//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Programmers making grammar mistakes (1970)&quot;
        title=&quot;&quot;
        src=&quot;/static/ad901dad7ff27751b79c87ef6aeecc7b/6f81f/programmer.jpg&quot;
        srcset=&quot;/static/ad901dad7ff27751b79c87ef6aeecc7b/863e1/programmer.jpg 225w,
/static/ad901dad7ff27751b79c87ef6aeecc7b/6f81f/programmer.jpg 270w&quot;
        sizes=&quot;(max-width: 270px) 100vw, 270px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The compound nouns &lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;teardown&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;cleanup&lt;/code&gt; are confused with
the verbs &lt;code class=&quot;language-text&quot;&gt;set up&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;tear down&lt;/code&gt; and &lt;code class=&quot;language-text&quot;&gt;clean up&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;In the above examples, they are used as verbs but spelled as nouns.&lt;/p&gt;
&lt;p&gt;I ask you to &lt;code class=&quot;language-text&quot;&gt;set&lt;/code&gt; something &lt;code class=&quot;language-text&quot;&gt;up&lt;/code&gt; for me. I don’t ask you to &lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt;
something for me.&lt;/p&gt;
&lt;div class=&quot;note&quot; style=&quot;clear: both&quot;&gt;
EDIT: Some readers misunderstood the point and thought I implied that
there must always be a clause between the two words in the verb. This is
not true. The point is that they are written separately.
&lt;/div&gt;
&lt;p&gt;For Example: “Please set up the server for me:.&lt;/p&gt;
&lt;p&gt;However, when I want to refer to the task you did (the noun), I refer to
the &lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;When used as an adjective, &lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt; also stays one word:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Go to the setup menu. [adjective]
The server&apos;s setup is not yet done. [noun]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This mistake happens mostly with &lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt;, however here are similar words
which also often get used incorrectly:&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;turnover&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Turn over the documents.
Our company increased our yearly turnover.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;handover&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Hand yourself over to the police.
The hostage handover went smoothly.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;cleanup&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Clean up your room.
The cleanup took hours.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;strong&gt;teardown&lt;/strong&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;Tear down this wall!
This test needs a teardown method.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;UPDATE: Here are some more:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Callback &amp;#x3C;=&gt; Call back&lt;/li&gt;
&lt;li&gt;Checkout &amp;#x3C;=&gt; Check out&lt;/li&gt;
&lt;li&gt;Layout &amp;#x3C;=&gt; Lay out&lt;/li&gt;
&lt;li&gt;Login &amp;#x3C;=&gt; Log in&lt;/li&gt;
&lt;li&gt;Logout &amp;#x3C;=&gt; Log out&lt;/li&gt;
&lt;li&gt;Lookup &amp;#x3C;=&gt; Look up&lt;/li&gt;
&lt;li&gt;Plugin &amp;#x3C;=&gt; Plug in&lt;/li&gt;
&lt;li&gt;Popup &amp;#x3C;=&gt; Pop up&lt;/li&gt;
&lt;li&gt;Runaround &amp;#x3C;=&gt; Run around&lt;/li&gt;
&lt;li&gt;Shutdown &amp;#x3C;=&gt; Shut down&lt;/li&gt;
&lt;li&gt;Showtime &amp;#x3C;=&gt; Show time&lt;/li&gt;
&lt;li&gt;Startup &amp;#x3C;=&gt; Start up&lt;/li&gt;
&lt;li&gt;Takeoff &amp;#x3C;=&gt; Take off&lt;/li&gt;
&lt;li&gt;Workout &amp;#x3C;=&gt; Work out&lt;/li&gt;
&lt;li&gt;Writedown &amp;#x3C;=&gt; Write down&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;p&gt;Another interesting case is “maybe”. It can be used as an adverb (one
word), noun (one word) and verb (two words, a modal verb “may” and the
main verb “be”):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;At the moment it&apos;s definitely still just a maybe. (noun)
I&apos;ll maybe come over tonight. (adverb)
He may be waiting for us. (verb)&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;What about something like &lt;code class=&quot;language-text&quot;&gt;download&lt;/code&gt;?&lt;/p&gt;
&lt;p&gt;We don’t say &lt;code class=&quot;language-text&quot;&gt;load it down&lt;/code&gt;. We say &lt;code class=&quot;language-text&quot;&gt;download it&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;That’s different. In the first category of compound nouns (&lt;code class=&quot;language-text&quot;&gt;setup&lt;/code&gt;,
&lt;code class=&quot;language-text&quot;&gt;teardown&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;handover&lt;/code&gt;), the part of the word that denotes the act is
first, followed by an adverb such as &lt;code class=&quot;language-text&quot;&gt;up&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;down&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;over&lt;/code&gt; or &lt;code class=&quot;language-text&quot;&gt;under&lt;/code&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;setup = set [verb] + up [adverb]&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;In the second category, the acting word is second (&lt;code class=&quot;language-text&quot;&gt;load&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;grade&lt;/code&gt;,
&lt;code class=&quot;language-text&quot;&gt;take&lt;/code&gt;, &lt;code class=&quot;language-text&quot;&gt;throw&lt;/code&gt;) and the first word denotes position:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;download = down [preposition] + [load] verb or noun&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Other examples of the second category are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;upgrade&lt;/li&gt;
&lt;li&gt;downgrade&lt;/li&gt;
&lt;li&gt;undertake&lt;/li&gt;
&lt;li&gt;overthrow&lt;/li&gt;
&lt;li&gt;understand&lt;/li&gt;
&lt;li&gt;overcome&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These do not get split up.&lt;/p&gt;
&lt;p&gt;I hope I made things clear and that programmers will now “undertake” to
“clean up” their code by removing these grammatical mistakes. ;)&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
EDIT: I&apos;ve thought about this some more, especially in light of some of
the comments provided by readers. I can see how using the word &quot;setup&quot;
as a type of shorthand for &quot;set up&quot;, to avoid unnecessary underscores
or capitals, can be useful and valid. If you undersand the distinction
and prefer writing it as one word, then go for it. I think however
what&apos;s important is for people to at least understand that it&apos;s an
exception and not the general rule outside of computer science.
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Sprint Report: Merging Mockup and Patternslib]]></title><description><![CDATA[This is a report on what I did at the Plone. Alpine City Sprint organized by Jens Klein and Christina Baumgartner in Innsbruck between 2…]]></description><link>https://opkode.com/blog/merging-mockup-and-patternslib/</link><guid isPermaLink="false">https://opkode.com/blog/merging-mockup-and-patternslib/</guid><pubDate>Sun, 25 Jan 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 640px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/6a3759458575d91a6a7c6708f26ea6a4/6af66/alpine_city_sprint.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 40.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAA3UAAAN1AHvkboVAAACQ0lEQVR42j1R70+SURi9gLzYlNVw6ERA5qswGanFC8NXME1QLFoh0gANKlP8HVhYlpqmrbU++gHrgx9ca9W3Nre27JcuZ1mDlmv9MXdyuq+1Ppyde8/znHOfZ5dsrD+lz7JZ+nL9CV1fW6UP55bp4yWG+0t0ZnqWLs4t0gcLC/TO9BSdv3mdPprP0Dcvnh/sf8kVfu58LWxtfCp8fPu5sLfzvfArnz8g9zIjWMyksbI8g9RYDIlIH8aHJ5AeGsLd9CQG+/vgdtoxOzmKGyNJXE30Yy27gt97eexvbyH3bhPfPrxHbncXP3a2C8Tl8UKjLQchBLZ6C25PJZEcPI/klSDivVHUGY0wVVVhoi+GeDiES7GLGBuI4dbkNaSHBxAIXoDY1gGxtR3Bs92U6AxmVOlNaDjeAMfJZsQjYYR6PfD6BHS3+1BjrEZtDQ/hhB2n3a3wd3QgEQ6i50wnoqEAznV1wdMswiU40elyUTaYAnK5ApxSCYWiCEWcGqVqLTiuhN3lDFJdjmKOg+aoBpXaCpRpjqFCp0etxQybtR5CgxVm3gReVykFkkODTCb7z5ImBalUqsOzBGURe4xpf+syxgSlR9RQKov/9Ui6nJLGxkakUikEg2yNnh5EIlF4vV4IgoBEIoF4PA6r1Qqn0wm32wOp390iorquDjoW9LrLj83Rcbw61Qae4yjheR5+vx+BQAB2ux2iKKKpqQlG9hmS2efzwWazQa/Xw+FwwGAwoJZ5ysrLUcICo4yHW1pw2WKBhhD6ByOmIYF8NYMYAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Alpine City Sprint, 21 to 26 January 2015&quot;
        title=&quot;&quot;
        src=&quot;/static/6a3759458575d91a6a7c6708f26ea6a4/6af66/alpine_city_sprint.png&quot;
        srcset=&quot;/static/6a3759458575d91a6a7c6708f26ea6a4/3684f/alpine_city_sprint.png 225w,
/static/6a3759458575d91a6a7c6708f26ea6a4/fc2a6/alpine_city_sprint.png 450w,
/static/6a3759458575d91a6a7c6708f26ea6a4/6af66/alpine_city_sprint.png 640w&quot;
        sizes=&quot;(max-width: 640px) 100vw, 640px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This is a report on what I did at the &lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Alpine City Sprint organized by &lt;a href=&quot;http://kleinundpartner.at&quot;&gt;Jens Klein and Christina Baumgartner&lt;/a&gt; in Innsbruck between 21 and 26 January 2015.&lt;/p&gt;
&lt;p&gt;Firstly, I want to thank to them for organizing and hosting a great sprint and for being such friendly and generous hosts.
My goal for this sprint was to work on merging the &lt;a href=&quot;http://plone.org&quot;&gt;Patternslib&lt;/a&gt; and &lt;a href=&quot;https://plone.github.io/mockup/dev&quot;&gt;Mockup&lt;/a&gt;
Javascript frameworks and I’m happy to report that very good progress was made.&lt;/p&gt;
&lt;p&gt;Long story short, the merge was successful and it’s now possible to use patterns written for either project within a single framework.
Before I expand on how this was achieved during this sprint, I’ll first provide some necessary background
information to place things into context and to explain why this work was necessary.&lt;/p&gt;
&lt;h2&gt;What is Patternslib?&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;img-container img--transparent&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e755d0bea7f5f59e0d839a74ed2c17db/e9140/patternslib.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 36.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAHCAYAAAAIy204AAAACXBIWXMAAAsTAAALEwEAmpwYAAABvElEQVR42k2QzWsTURTF5/8TunPtyp2bdKGCQhdSKGJVrJZiYRCjEmtpbYrWEqLFkkQziXViJxkm8+bjvsxnmhRXLoR3vDNWcPHj3Pt43HPu1dLYpywOyBm0KYkEnc9zmk8TionrPAzWa+9/3dV3f08TP4yloOQfkUfSH5E9PKG+ZZJ0TBKjPmmzLETn4Dnerl/H8d4G2oevYBzt4iwj/JxN0GgZ2P/UwflUYp5LzJh5UZ9NMI19SN+G6ztIgyGkOIXmWl31+mFF1fU7Sl++ql6sLir9/g0V0VglE6HE2IJwLJBvK9+1VOiNlMfqjS0lnB9K2N9V4Jhq4lmKxFBpWRJg0PmAur6M3tEePu5s4vO7l+CVkHECa9BD32jhpN/Gt14bvW4Ljm0icAujUzgjs9SU/7MptCh0YDTf4Liu47D2CI9vX8GDxQV8aWzxWgli6SJh+H7gxGWfc4hpGpaaXhgXcHpoHBdGo4avB1XsPF3C2s3LWLl2CfvPVvheMbLIRx4H/xHyW1i+FwYFxbBCy4HjQQfd5jaa2xuorlZwr7KA6toStp7c4mTFMMnQBbIkixjuiyFpafi35hvjDyFV3XWW+pkcAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Patternslib logo&quot;
        title=&quot;&quot;
        src=&quot;/static/e755d0bea7f5f59e0d839a74ed2c17db/1cfc2/patternslib.png&quot;
        srcset=&quot;/static/e755d0bea7f5f59e0d839a74ed2c17db/3684f/patternslib.png 225w,
/static/e755d0bea7f5f59e0d839a74ed2c17db/fc2a6/patternslib.png 450w,
/static/e755d0bea7f5f59e0d839a74ed2c17db/1cfc2/patternslib.png 900w,
/static/e755d0bea7f5f59e0d839a74ed2c17db/e9140/patternslib.png 1226w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Patternslib’s goal is to allow website designers to build rich
interactive prototypes without having to write any Javascript. Instead
the designer simply writes normal HTML and then adds dynamism and
interactivity by adding special HTML classes and data-attributes to
selected elements.&lt;/p&gt;
&lt;p&gt;For example, here is a Pattern which injects a list of recent blog posts
into a element in this page:&lt;/p&gt;
&lt;p&gt;The declarative markup for this pattern looks as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;html&quot;&gt;&lt;pre class=&quot;language-html&quot;&gt;&lt;code class=&quot;language-html&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;section&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;id&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;alpine-blog-injected&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;href&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;#portlet-recent-blogs&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
       &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;pat-inject&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;data-pat-inject&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;target: #alpine-blog-injected&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        Click here to show recent blog posts
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;a&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;section&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The dynamic behavior comes from the fact that I have the Patternslib
Javascript library loaded in this page.&lt;/p&gt;
&lt;p&gt;On pageload, Patternslib scans the DOM looking for elements which
declare any of the already registered patterns. If it finds such an
element, it invokes a Javacript module associated with that pattern.&lt;/p&gt;
&lt;p&gt;In the above example, the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;a&gt;&lt;/code&gt; element declares that it wants the
&lt;em&gt;Inject&lt;/em&gt; pattern applied to it, by virtue of it having the &lt;code class=&quot;language-text&quot;&gt;pat-inject&lt;/code&gt;
HTML class.&lt;/p&gt;
&lt;p&gt;Patterns are configured with specific HTML5 data properties. In the
example above, it is the &lt;code class=&quot;language-text&quot;&gt;data-pat-inject&lt;/code&gt; property which specifies that
the target for injection is the &lt;code class=&quot;language-text&quot;&gt;#alpine-blog-injected&lt;/code&gt; element in the
current page and the content being injected is specified by the &lt;code class=&quot;language-text&quot;&gt;href&lt;/code&gt;
attribute of the &lt;code class=&quot;language-text&quot;&gt;&amp;lt;a&gt;&lt;/code&gt; element. In this case, the &lt;code class=&quot;language-text&quot;&gt;href&lt;/code&gt; points to an
anchor inside the current page, but it might just as well be a link to
another page which will then get injected via Ajax.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://patternslib.com/demo/inject/index.html&quot;&gt;More information&lt;/a&gt; on how
to configure &lt;code class=&quot;language-text&quot;&gt;pat-inject&lt;/code&gt; can be found on the patternslib website.&lt;/p&gt;
&lt;p&gt;Each pattern has a corresponding Javascript module which is often just a
wrapper around an existing Javascript library (such as
&lt;a href=&quot;http://parsleyjs.org&quot;&gt;Parsley&lt;/a&gt;, &lt;a href=&quot;https://select2.github.io&quot;&gt;Select2&lt;/a&gt; or
&lt;a href=&quot;http://amsul.ca/pickadate.js&quot;&gt;Pickadate&lt;/a&gt;) that properly defines the
configuration options for the pattern and properly invokes or applies
the 3rd party library.&lt;/p&gt;
&lt;p&gt;So, in order to do all this, Patternslib can be broken down into the
folowing components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A registry which lists all the available patterns.&lt;/li&gt;
&lt;li&gt;A scanner which scans the DOM to identify declared patterns.&lt;/li&gt;
&lt;li&gt;A parser which parses matched DOM elements for configuration
settings.&lt;/li&gt;
&lt;li&gt;The individual Javascript modules which implement the different
patterns.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What is Mockup?&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;img-container img--transparent right&quot; style=&quot;width: 14em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 250px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/86439547c7a93822e70e981aeabeee3f/63868/mockup-logo.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEtklEQVR42nVUWU9bRxQevOAFHBYbMDbEbAXK4ly8YYONsTFgdmzAYAyYHUoEZFNJAGMIS0MJXdRWPLR/gJf+iEp9aFr1pY3ah0qVuihUapQHHlpw7j09M5SoSM1Ic++VPefM+b7zfYeQqyuJPXOMKSKlbVSs9uxKs5rGNFWDp3pb9EyW6z8UpzUEicwyiadkFyFxEfnfFSeiEr+fHlKkFHR+bgzGgBuIn4syGn+tHd0G3/LHcK2495nWFP3TFNqk399m6FryWax5VvqqmIs1IKZPRU7zgaqo+0nK9Y4f7NFdqOy6m2hceF+oaL8t6C1jgvutQ7CEN3h7dAcKnHPPicTymVzjWb+C7jKZOKtp80ZfDJwzj3nz0IaAgYBwQVM5KEi1LYD/QzY3LCj0bcKbbbfhRvA+z4ViierAOsi0Le9ega/O9+lIsu1TbmAdDM6ZRL59UpDntYFI7QFRpgck2T6Q5PggKaMRktLdINP5oaLjDhhcs+fO6QOE3/0FppFf4k1WFQe+yXdM/VXd+3aiqvsekLQGUBo62abVsYRYIU2kKuqBlIIulrzAOSNwfaugyGv/SZnXcYxkKgkRWYfN4S2wj+3wZS1LGNANXP8D4PoeUL4AL2LBNGm5fxlskU38PU75BYqCnnFMPOKre1eBJNsDhKhcHbnm0RemwRi9SaDV6a1R8CwcgnP6EeUKknNbQFXcA67Zfaifegfs0W1QV4SAIHxpTjNrnikUA3LNuUoUev9jhPG8ceE9yOEiAlE5IaO8nwVa8XYnvrU1I1DQMAuO8R2wRuJYZRzSS4OMGk31kIBKAJTX7+JMb4Dk2WdOmpY/Ah3KQpKFxGMT6O2W4Q0odM9D7ehD3FtsY7NYQsfELqSV9LKzMr2fUsHXRvdAXTX0lKALntEglIKQjA0gyJe6YoBxlVU9xLiswwSUK9oM2wjyjZVSCkQaL0L2gdY0wjffOYI8+9T3RKr2DKPFTpqWPgR1ZUggqU5WoWN8G+T6C3k0zO3j4QmQ5bZC/eQFh4r8duTMhdqMMMGnl/X9Ide1xgh2cLsmtAGVnXcTVBq0SmNghTWkxHsTtFyEcYfiZV12YDIKmXZZjBVSoVuHN0FjDJ8SVV07qtAa4PpjUDu2LZhC6wyWwTkNpc2LlFdIeyMAOuvFm3J6vW6KQmQVp6BOS32LSMPDl+bBOBBiCaKujSmphs5jpaHjR7QcEj8hUKhFjfNY0S0oa1lk38beFSj2LEApahXRQCpeTN/IcaLQNXeaVhr8EpNJLt0iSS3q+co1c0DtdFbZdQ9d0Yq2Q6tluNHHXmZBKnDkm4nfUD8toJTOub41IGLuSKdrUv+bC9iUQIHicFjHkbWW4IL3z2glcuQn2xgWqHip7WjT6HfNwBrdfP30vmAMrKLnvSv/HTSvljzbu0qktqNC1/wLW2RLMIc3XrrnD3ltTYQvb13iPTc/4FFe547xPVBe7/wuvST4RJHbvPmaQetm+BWZXj2K9mtLZBu05uhvKIcT361PUCp7VHe/WMJbf3P9G6DMazumVJnNZjpcXzO1WVJ2k4zIbWGxsq4d/b2X75j8OcsYfirNaByUZHrj4rR6ajEFATpUr8L8B2vlF7/06cusAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Mockup looo&quot;
        title=&quot;&quot;
        src=&quot;/static/86439547c7a93822e70e981aeabeee3f/63868/mockup-logo.png&quot;
        srcset=&quot;/static/86439547c7a93822e70e981aeabeee3f/3684f/mockup-logo.png 225w,
/static/86439547c7a93822e70e981aeabeee3f/63868/mockup-logo.png 250w&quot;
        sizes=&quot;(max-width: 250px) 100vw, 250px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Mockup was inspired by, and originally based upon, Patternslib and was
meant to bring the power of declarative interaction patterns to Plone.&lt;/p&gt;
&lt;p&gt;When Mockup started, Patternslib was undergoing significant refactoring
and development and it was decided that Mockup should fork and go its
own way.&lt;/p&gt;
&lt;p&gt;What this means is that the 4 different components mentioned above, were
all changed and due to these changes the Mockup project diverged from
Patternslib and started developing in a similar but different direction.&lt;/p&gt;
&lt;h2&gt;So what’s the problem?&lt;/h2&gt;
&lt;p&gt;While Mockup was being developed for the upcoming Plone 5 release, we at
&lt;a href=&quot;http://syslab.com&quot;&gt;Syslab&lt;/a&gt; continued using and improving Patternslib in
our projects.&lt;/p&gt;
&lt;p&gt;Syslab built an intranet for the Star Alliance, which was based on a
prototype design by Cornelis Kolbach, the conceptual creator of
Patternslib. This design became the inspiration and blueprint for the
Plone Intranet Consortium (PIC), which consists of 12 companies working
together in a consortium to build an intranet solution on top of Plone.&lt;/p&gt;
&lt;p&gt;So, the PIC are building a product using Patternslib, while Plone 5
itself is being built with Mockup, an incompatible fork of Patternslib.&lt;/p&gt;
&lt;p&gt;This was clearly a bad situation because we now had:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Two incompatible Javascript frameworks being used with Plone.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Not only were the two frameworks incompatible in the sense that
patterns written for the one don’t work on the other, but they
could also not be used on the same page since the two
implementations would compete with one another in invoking
Javascript to act upon the same DOM elements.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Duplication of effort&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The same or similar patterns were being developed for both
frameworks, and when one framework had a pattern which the other
wanted, it could only be used after being modified such that it
couldn’t be used in the original framework anymore.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;A splitting of the available workforce.&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Developers were either working on Mockup or Patternslib, but
almost never on both, which meant that the expertise and
experience of developers wasn’t being shared between the two
projects.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;How could this be fixed?&lt;/h2&gt;
&lt;p&gt;To solve the 3 main problems mentioned above, we needed to merge the
common elements of Mockup (specifically the registry, scanner and
parser) back into Patternslib.&lt;/p&gt;
&lt;p&gt;This will allow developers from both projects to work on the same
codebase and enable us to use patterns from both projects together.&lt;/p&gt;
&lt;p&gt;At the Alpine City Sprint in Innsbruck, I worked on achieving these
goals.&lt;/p&gt;
&lt;h3&gt;Changes brought in by Mockup&lt;/h3&gt;
&lt;p&gt;After the fork, Mockup introduced various changes and features which set
it apart from Patternslib.&lt;/p&gt;
&lt;p&gt;In order to merge Mockup back into Patternslib, I studied these changes
and with the help of others came up with strategies on what needed to be
done.&lt;/p&gt;
&lt;p&gt;Here are some differences and what was done about them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mockup allows patterns to also be configured via JSON, whereas Patternslib used a &lt;code class=&quot;language-text&quot;&gt;keyword:argument;&lt;/code&gt; format&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;A week before the sprint I added JSON parsing ability to the Patternslib parser, thereby resolving this difference.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;“Leaves first” parsing versus “root first” parsing&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Mockup parses the DOM from the outside in (“root first”), while
Patternslib parses the DOM from the inside out (“leaves first”).&lt;/p&gt;
&lt;p&gt;According to Rok Garbas, the creator of Mockup, the outside-in parsing
was done because it reduced complexity in the scanner and the individual patterns.&lt;/p&gt;
&lt;p&gt;Wichert Akkerman who originally wrote the Patternslib scanner however
provided a good reason why he chose “leaves first” DOM scanning:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;If I remember correctly there are several patterns that rely on any
changes in child nodes to have already been made.This is true for
several reasons: 1) a pattern may want to attach event handlers to
child nodes, which will break of those child nodes are later
replaced, and 2) child nodes changing size might impact any
measurements made earlier.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Indeed, while refactoring the Mockup code during the merge, I ran into
just such a case where a pattern couldn’t yet be initialized because
patterns inside it weren’t yet initialized. By turning around the
order of DOM scanning, this problem was resolved and the code in that
pattern could be simplified.&lt;/p&gt;
&lt;p&gt;So, now after the merge, scanning is “leaves-first” for Mockup patterns as well.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;Mockup patterns are classes extended from a Base object&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Patternslib patterns on the other hand are simple JavaScript objects without constructors.&lt;/p&gt;
&lt;p&gt;The Patternslib patterns are conceptually very simple and more explicit.&lt;/p&gt;
&lt;p&gt;However, what I like about the Mockup approach is that you have a
separate instance with its own private
&lt;a href=&quot;https://developer.mozilla.org/en/docs/Web/JavaScript/Guide/Closures&quot;&gt;closure&lt;/a&gt;
for each DOM element for which it is invoked.&lt;/p&gt;
&lt;p&gt;After merging, we now effectively have two different methods for
writing patterns for Patternslib. The original “vanilla” way, and
the Mockup way.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;strong&gt;The Mockup parser was completely rewritten&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The Mockup parser looks nothing like the Patternslib one and also
supports one less configuration syntax (the so-called “shorthand”
notation).&lt;/p&gt;
&lt;p&gt;This was one piece of code which could not be merged within the time
available at the Alpine City Sprint.&lt;/p&gt;
&lt;p&gt;So currently we still have two different argument parsers. The
Patternslib parser needs to be configured much more expicitly, while
the Mockup one is more implicit and makes more assumptions.&lt;/p&gt;
&lt;p&gt;Merging these two parsers will probably have to be done at some future
sprint.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There are some other more minor differences, such as that every Mockup
pattern is automatically registered as a jQuery plugin, but merging
these was comparatively easier and I’ll won’t go into further detail
on them.&lt;/p&gt;
&lt;h2&gt;What I did during the Alpine Sprint&lt;/h2&gt;
&lt;p&gt;So, in summary:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;I refactored the Patternslib registry, scanner and some core utils to
let them handle Mockup patterns as well. Luckily the eventual patch for
this was quite small and readable.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I changed the Mockup Base pattern so that patterns derived from it now
rely on the registry and scanner from Patternslib.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;I fixed lots of tests and also wrote some new tests.&lt;br/&gt;&lt;br/&gt;
This whole task would have been much more difficult and error prone if
either Patternslib or Mockup had fewer tests. The Mockup team deserves
praise for taking testing very seriously and this allowed me to refactor
and merge with much more confidence.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;What else is there to still be done?&lt;/h2&gt;
&lt;p&gt;Being able to use patterns from both projects and merging most of the
forked code was a big win, but there are still various things that need
to be done to make the merge complete and viable.&lt;/p&gt;
&lt;p&gt;I’ve ranked them from what I think is most important to least
important.&lt;/p&gt;
&lt;h4&gt;1. Update the documentation&lt;/h4&gt;
&lt;p&gt;Currently documentation is scattered and silo’d in various places
(the Patternslib website, the Plone Intranet developer docs and the
Mockup developer docs).&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;https://plone.github.io/mockup/dev/#learn&quot;&gt;Mockup docs&lt;/a&gt; are now
out of date ater this merge and need to be brought up to date on these
recent changes.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://patternslib.com/#documentation&quot;&gt;Patternslib docs&lt;/a&gt; are less
of a problem because they don’t have to deal with Mockup (which can
now be seen as an enhancement suite for it), but they can definitely
still be improved upon, specifically with an eye on Mockup developers
who will start relying on them.&lt;/p&gt;
&lt;p&gt;The Plone Intranet consortium also has a useful walkthrough explaining
&lt;a href=&quot;http://docs.ploneintranet.org/development/patterns.html&quot;&gt;how to create a Patternslib pattern from
scratch.&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;2. Devise a way to also use the Patternslib parser for Mockup patterns&lt;/h4&gt;
&lt;p&gt;As mentioned, the Mockup patterns still use their own argument parser.&lt;/p&gt;
&lt;p&gt;Letting them use the Patternslib’s parser will either require
extending the Mockup Base pattern to configure the Patternslib parser
on a pattern’s behalf or instead doing it explicitly in each of the
individual patterns.&lt;/p&gt;
&lt;h4&gt;3. Decide on coding and configuration standards&lt;/h4&gt;
&lt;p&gt;Unfortunately the coding standards between the two projects differ
significantly.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The Mockup developers use &lt;code class=&quot;language-text&quot;&gt;camelCase&lt;/code&gt; as declarative argument
names while Patternslib uses &lt;code class=&quot;language-text&quot;&gt;dash-separated&lt;/code&gt; names.&lt;/li&gt;
&lt;li&gt;The Mockup source code uses 2 spaces for indentation, Patternslib uses 4 spaces.&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;4. Remove unnecessary, duplicated patterns&lt;/h4&gt;
&lt;p&gt;Both projects have patterns for modals, injection, select2 and file
upload. These should be merged to get rid of duplication.&lt;/p&gt;
&lt;h4&gt;5. Move generic patterns (e.g. pat-pickadate, pat-moment etc.) out of Mockup&lt;/h4&gt;
&lt;p&gt;Mockup has some generic patterns which might also be useful as
Patternslib core patterns, in which case they should ideally be moved there.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;The sprint was a big success and I’m very happy that all the work has
already been merged into the master branches of the matternslib, mockup
and mockup-core repositories.&lt;/p&gt;
&lt;p&gt;Core code from Mockup is now succesfully merged back into Patternslib
and we can use patterns from both projects in the same site.&lt;/p&gt;
&lt;p&gt;I had a lot of fun working with talented and motivated software
developers and had a lot of opportunities to improve my German.&lt;/p&gt;
&lt;p&gt;Thanks again Jens and Christine for organising a great sprint and I look
forward to doing such a sprint again!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 900px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2fa09d85c5b7544a0e4352488a4e2a6e/4f982/innsbruck.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 37.77777777777778%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAIABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAAED/8QAFQEBAQAAAAAAAAAAAAAAAAAAAQL/2gAMAwEAAhADEAAAAcaDAz//xAAZEAACAwEAAAAAAAAAAAAAAAAAFAECAxH/2gAIAQEAAQUCavxrQck//8QAFREBAQAAAAAAAAAAAAAAAAAAARD/2gAIAQMBAT8BSf/EABURAQEAAAAAAAAAAAAAAAAAABAR/9oACAECAQE/Aaf/xAAYEAADAQEAAAAAAAAAAAAAAAAAAQIhMv/aAAgBAQAGPwLJk2Uco//EABkQAAMBAQEAAAAAAAAAAAAAAAABEVGBkf/aAAgBAQABPyF0RPaQ9Rh1Z//aAAwDAQACAAMAAAAQhD//xAAVEQEBAAAAAAAAAAAAAAAAAAABEP/aAAgBAwEBPxABn//EABURAQEAAAAAAAAAAAAAAAAAAAEQ/9oACAECAQE/ECP/xAAcEAEAAgEFAAAAAAAAAAAAAAABABExIUFhodH/2gAIAQEAAT8QoBA1SeriUw8rfYttuWf/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Photo of Innsbruck&quot;
        title=&quot;&quot;
        src=&quot;/static/2fa09d85c5b7544a0e4352488a4e2a6e/8e1fc/innsbruck.jpg&quot;
        srcset=&quot;/static/2fa09d85c5b7544a0e4352488a4e2a6e/863e1/innsbruck.jpg 225w,
/static/2fa09d85c5b7544a0e4352488a4e2a6e/20e5d/innsbruck.jpg 450w,
/static/2fa09d85c5b7544a0e4352488a4e2a6e/8e1fc/innsbruck.jpg 900w,
/static/2fa09d85c5b7544a0e4352488a4e2a6e/b768e/innsbruck.jpg 1350w,
/static/2fa09d85c5b7544a0e4352488a4e2a6e/d9c39/innsbruck.jpg 1800w,
/static/2fa09d85c5b7544a0e4352488a4e2a6e/4f982/innsbruck.jpg 3462w&quot;
        sizes=&quot;(max-width: 900px) 100vw, 900px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The Solution to Jaron Lanier's Siren Servers]]></title><description><![CDATA[In his book [Jaron Lanier](https://en.wikipedia.org/ wiki/Jaron_Lanier)
claims that the information on the web is undervalued and…]]></description><link>https://opkode.com/blog/review-who-owns-the-future/</link><guid isPermaLink="false">https://opkode.com/blog/review-who-owns-the-future/</guid><pubDate>Tue, 06 Jan 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In his book [Jaron Lanier](&lt;a href=&quot;https://en.wikipedia.org/&quot;&gt;https://en.wikipedia.org/&lt;/a&gt; wiki/Jaron_Lanier)
claims that the information on the web is undervalued and underpriced.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 20em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 490px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/2028f0a28e39ffdea974571eba36ac67/6b254/whoownsthefuture.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAABQAC/8QAFQEBAQAAAAAAAAAAAAAAAAAAAgH/2gAMAwEAAhADEAAAASmhWIiLEV//xAAaEAEBAAIDAAAAAAAAAAAAAAABAgASBBEU/9oACAEBAAEFAiFx4ZqTGR2X7jSp2f/EABYRAQEBAAAAAAAAAAAAAAAAAAABgf/aAAgBAwEBPwGsf//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EAB8QAAIBAwUBAAAAAAAAAAAAAAERAAIhIgMSMTNRsf/aAAgBAQAGPwIIWJQc7HVMqtp8UY5F5bTyj+z/xAAcEAEAAgMAAwAAAAAAAAAAAAABACERQVFhcYH/2gAIAQEAAT8hbDURbiDYTZXqKzgyQRbaqdjaSvaiOPvlP//aAAwDAQACAAMAAAAQpP8A/8QAGREAAgMBAAAAAAAAAAAAAAAAAREAIZHR/9oACAEDAQE/EGdQUEp3s//EABgRAAIDAAAAAAAAAAAAAAAAAAABEUGB/9oACAECAQE/EFFmn//EAB0QAQACAwEAAwAAAAAAAAAAAAERIQAxQVGBobH/2gAIAQEAAT8QVmuRRVfzkCigVv8AQc3k7MMZGLxCAgxxcs/eVb3AmL76k8xaUdTyuzrl5//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Who owns the future? by Jaron Lanier&quot;
        title=&quot;&quot;
        src=&quot;/static/2028f0a28e39ffdea974571eba36ac67/6b254/whoownsthefuture.jpg&quot;
        srcset=&quot;/static/2028f0a28e39ffdea974571eba36ac67/863e1/whoownsthefuture.jpg 225w,
/static/2028f0a28e39ffdea974571eba36ac67/20e5d/whoownsthefuture.jpg 450w,
/static/2028f0a28e39ffdea974571eba36ac67/6b254/whoownsthefuture.jpg 490w&quot;
        sizes=&quot;(max-width: 490px) 100vw, 490px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;According to him this is hollowing out the middle class because people
aren’t being sufficiently valued for their information-producing work,
while a new rich elite is making vast sums of money by collecting and analysing
this cheap information.&lt;/p&gt;
&lt;p&gt;In many cases the information being collected and analysed is given freely to
companies by the users themselves in return for email, calendaring and
social networking features.&lt;/p&gt;
&lt;p&gt;This results in information assymmetry (e.g. who knows what about whom) and
therefore a large disparity in power and wealth. Google knows everything
about you and yet you know nothing of value about Google.&lt;/p&gt;
&lt;h2&gt;Siren Servers&lt;/h2&gt;
&lt;p&gt;These online services are hosted on
&lt;a href=&quot;https://en.wikipedia.org/wiki/Server_(computing)&quot;&gt;servers&lt;/a&gt;, which
Lanier has termed &lt;em&gt;Siren Servers&lt;/em&gt;&lt;sup id=&quot;fnref-1&quot;&gt;&lt;a href=&quot;#fn-1&quot; class=&quot;footnote-ref&quot;&gt;1&lt;/a&gt;&lt;/sup&gt;, after the
&lt;a href=&quot;https://en.wikipedia.org/wiki/Siren_(mythology)&quot;&gt;Sirens&lt;/a&gt; of Greek
Mythology. The Sirens are beautiful but dangerous creatures who lure
nearby sailors with their enchanting music and voices, thereby letting
them shipwreck on the rocky coast of their island.&lt;/p&gt;
&lt;p&gt;These &lt;em&gt;Siren Servers&lt;/em&gt; lure us into opening up our lives, so that they
might freely gather data from us, on a truly massive scale, which they
then analyse and profit from.&lt;/p&gt;
&lt;p&gt;The results of this analysis is ”&lt;em&gt;kept secret and used to manipulate
the rest of the world to advantage.&lt;/em&gt;”&lt;/p&gt;
&lt;p&gt;So much value is extracted from this data, that these &lt;em&gt;Siren Servers&lt;/em&gt;
are valued in the billions of dollars.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 30em&quot;&gt; &lt;img src=&quot;/4d023f189656dc25aa98ac40bb39d6e0/Armitage_Siren.jpg&quot; alt=&quot;The Siren, Edward Armitage, 1888&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Lanier claims that the users of these servers are shortchanged, in that
they don’t get their data’s worth in return. Not to mention the
broader societal damage wrought by the surveillance-as-business-model
engendered by this approach as well as the decimation of the middle
class as software takes over many industries.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Siren Servers&lt;/em&gt; reduce risk for themselves, but in the process increase
the risk for all the other smaller players.
&lt;a href=&quot;https://en.wikipedia.org/wiki/Uber_(company)&quot;&gt;Uber’s&lt;/a&gt; business model
for example is all about shifting risks onto its drivers. They would not
be profitable if they had to carry the costs of commercial insurance,
licensing, vehicle maintenance and oversight of drivers.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;The total amount of risk in the market as a whole stays the same,
perhaps, but it’s not distributed evenly. Instead the smaller players
take on more risk while the player with the biggest computer takes on
less.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Lanier’s solution to the emergence of &lt;em&gt;Siren Servers&lt;/em&gt; is to “properly
account” for the wealth created by people online. In other words,
people need to be paid for what they do online, no matter how small and
seemingly insignificant.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;If information age accounting were complete and honest, as much
information as possible would be valued in economic terms. If, however
“raw” information, or information that hasn’t yet been routed by
those who run the most central computers, isn’t valued, then a
massive disenfranchisement will take place.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;The decimation of the middle class&lt;/h2&gt;
&lt;p&gt;Lanier says this process started in the creative industry, with
musicians and photographers impacted quite early on, and that it’s now
spreading to other occupations, such as travel agents, estate agents and
journalists.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 18em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 180px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/57a5abf9aeba962fb4a762bb1e242d77/4ec73/steve_albini.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 144.44444444444443%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAdABQDASIAAhEBAxEB/8QAGQAAAwEBAQAAAAAAAAAAAAAAAAECBAMF/8QAFgEBAQEAAAAAAAAAAAAAAAAAAQAC/9oADAMBAAIQAxAAAAHzdGdY1YhFE96xECf/xAAdEAACAQQDAAAAAAAAAAAAAAABAgADERIhIzIz/9oACAEBAAEFAit4osMxClo2mqABg3HuMciej+E//8QAFREBAQAAAAAAAAAAAAAAAAAAIDH/2gAIAQMBAT8Bg//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB8QAAECBgMAAAAAAAAAAAAAAAARMQEQISJBYQISkf/aAAgBAQAGPwJ6i6xLjupa4xdhjslBYkDyX//EAB0QAQACAwADAQAAAAAAAAAAAAEAESExYRBRcbH/2gAIAQEAAT8hqXl0wwBaZW3GFkuXIOpWiwPTgmqFS1cWwEbuffIqt13exYmPzuP8PH//2gAMAwEAAgADAAAAEEjYTv/EABgRAAMBAQAAAAAAAAAAAAAAAAABERBx/9oACAEDAQE/EEJCtrmf/8QAGBEAAwEBAAAAAAAAAAAAAAAAAAERECH/2gAIAQIBAT8QfS0iTz//xAAiEAEAAgIBAwUBAAAAAAAAAAABESEAMUFhkaEQUXGBsdH/2gAIAQEAAT8QiLRtIO7k85y/zHmGvBiWtfWaPzSdBPxgM60rL1J4w/MnJsMoGtYVNghND3eMAgWiCyx+4uS3xlANpl3yQgRBRzv+en//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Steve Albini playing guitar (2007)&quot;
        title=&quot;&quot;
        src=&quot;/static/57a5abf9aeba962fb4a762bb1e242d77/4ec73/steve_albini.jpg&quot;
        srcset=&quot;/static/57a5abf9aeba962fb4a762bb1e242d77/4ec73/steve_albini.jpg 180w&quot;
        sizes=&quot;(max-width: 180px) 100vw, 180px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Lanier writes:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;Making information free is survivable so long as only limited
numbers of people are disenfranchised. As much as it pains me to say
so, we can survive if we only destroy the middle classes of musicians,
journalists and photographers. What is not survivable is the
additional destruction of the middle classes in transportation,
manufacturing, energy, office work, education and health care. And all
that destruction will come surely if the dominant idea of an
information economy isn’t improved.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In other words, until we reconfigure the economic system to value raw
data by compensating the people that generate it, we will have massive
inequality.&lt;/p&gt;
&lt;p&gt;Not everybody is of course as pessimistic or draws these same
conclusions. Steve Albini, producer of Nirvana and Pixies albums and
himself a touring musician, says in &lt;a href=&quot;http://www.theguardian.com/music/2014/nov/17/steve-albinis-keynote-address-at-face-the-music-in-full&quot;&gt;this keynote&lt;/a&gt;
that the Internet has solved many problems for musicians and audiences
alike and that things are actually better now than before.&lt;/p&gt;
&lt;h3&gt;Finance got networked in the wrong way&lt;/h3&gt;
&lt;p&gt;As an example of the destruction being wrought by the &lt;em&gt;Siren Servers&lt;/em&gt;,
Lanier asserts that the &lt;em&gt;Great Recession&lt;/em&gt; was in part caused by their
existence in the financial sector.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;Consider the expansion of the financial sector prior to the Great
Recession. It’s not as if that sector was accomplishing any more than
it ever had. If it’s product is to manage risk, it clearly did a
terrible job. It expanded purely because of its top positions on
networks. Moral hazard has never met a more efficient amplifier than a
digital network. The more influential digital networks become, the
more potential moral hazard we’ll see, unless we change the
architecture.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;It’s clear that Lanier believes that this problem can be solved by
reconfiguring and improving the architecture of our digital networks.&lt;/p&gt;
&lt;h2&gt;Siren Servers and the rise of surveillance as a business model&lt;/h2&gt;
&lt;p&gt;As has become increasingly clear in the past few years, the dominant
business model in Silicon Valley is one based upon surveillance.&lt;/p&gt;
&lt;p&gt;Surveillance is the mechanism by which the &lt;em&gt;Siren Servers&lt;/em&gt; gather much
of the data they analyse and profit from.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 18em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 180px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 116.1111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAXABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/aAAwDAQACEAMQAAAB1S1YJekkqdMB1Bj/xAAdEAACAgEFAAAAAAAAAAAAAAAAAgMRAQQSISIz/9oACAEBAAEFApWZDe9ryr4kvuaa8wjpZF5//8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHhAAAgEEAwEAAAAAAAAAAAAAAAERAhIhMRBBgbH/2gAIAQEABj8CxV5Bn4JisiO5Kr7tCnhtbEf/xAAdEAEAAwABBQAAAAAAAAAAAAABABEhEDFBUWGB/9oACAEBAAE/IahMvDvQPevMP3E2E/RGlgmwywp4ykudWFN9n//aAAwDAQACAAMAAAAQO/8AAf/EABgRAQEAAwAAAAAAAAAAAAAAAAEAEBEx/9oACAEDAQE/EBNYGe3/xAAXEQEBAQEAAAAAAAAAAAAAAAABABEx/9oACAECAQE/EEdiY5f/xAAdEAEBAAMAAgMAAAAAAAAAAAABEQAhMUFRYXGR/9oACAEBAAE/EGHHdUv4cGDyMWoBfruK50XGjslBR6TGiLhOgeP7iWhVlOF5hTJtDJ4kyoCiuvNz/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Surveillance cameras&quot;
        title=&quot;&quot;
        src=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg&quot;
        srcset=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg 180w&quot;
        sizes=&quot;(max-width: 180px) 100vw, 180px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;According to Lanier, many Silicon Valley techno-libertarians handwave
any concerns about corporate surveillance.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;Surveillance by the technical few on the less technical many can be
tolerated for now because of hopes for an endgame on which everything
will become transparent to everyone. Network entrepeneurs and
cyber-activists alike seem to imagine that today’s elite network
servers in positions of information supremacy will eventually become
eternally benign or just dissolve.&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;However, what good reason is there for owners of these immensely
powerful and valuable &lt;em&gt;Siren Servers&lt;/em&gt; to one day willingly become
transparent and open up in order for this power imbalance to be
resolved?&lt;/p&gt;
&lt;p&gt;On the supposed emergence of some kind of sharing/socialist utopia
arising out of the aggressive right-wing libertarian practices of
Silicon Valley, Lanier mocks:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;”&lt;em&gt;Free Google tools and free Twitter are leading to a world where
everything is free because people share, but isn’t it great that we
can corner billions of dollars by gathering data no on else has?” If
everything will be free, why are we trying to corner anything? Are our
fortunes only temporary? Will they become moot when we’re done?&lt;/em&gt;”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;These ”&lt;em&gt;network servers in positions of information supremacy&lt;/em&gt;” hide
their code and algorithms behind patents, IP-laws and copyright.&lt;/p&gt;
&lt;p&gt;A whole legal facade has been erected precisely to prevent the hopeful
scenario of “elite network servers” dissolving into an utopian
abundance.&lt;/p&gt;
&lt;h2&gt;Lanier’s proposed solutions&lt;/h2&gt;
&lt;h3&gt;Cyber-keynesianism&lt;/h3&gt;
&lt;p&gt;Lanier describes his proposed solution as a sort of Cyber-Keynesianism.
Based upon the idea from the economist &lt;a href=&quot;https://en.wikipedia.org/wiki/John_Maynard_Keynes&quot;&gt;J.M. Keynes&lt;/a&gt;
that “stimulus” might be able to kick an economy out of a rut.&lt;/p&gt;
&lt;p&gt;Lanier provides a qualitative explanation of the stimulus theory which I
haven’t heard before.&lt;/p&gt;
&lt;p&gt;On a multi-dimensional mathematical landscape (as could be plotted based
on the parameters of an economy), there are peaks and valleys. Let’s
assume that peaks are “optimal” economical configurations, where the
greater good is best served, and valleys are horror scenarios
(depressions, recession, collapse etc.).&lt;/p&gt;
&lt;p&gt;Not all peaks are of equal hight, and when you are on a peak, you are
usually surrounded by valleys. There might be a higher peak (i.e. better
configuration) available, but it’s not clear how to get there, since
moving there might mean moving through valleys.&lt;/p&gt;
&lt;p&gt;The idea behind stimulus is to provide the impetus, a kick if you will,
to make this transition to a higher peak.&lt;/p&gt;
&lt;h3&gt;Technical Solution&lt;/h3&gt;
&lt;p&gt;Laniers solution on a technical level is to use a network with
bidirectional links, instead of unidirectional links as we currently
have with the web. The architecture of this network is inspired by
&lt;a href=&quot;https://en.wikipedia.org/wiki/Project_Xanadu&quot;&gt;Project Xanadu&lt;/a&gt; already
founded by Ted Nelson in 1960.&lt;/p&gt;
&lt;p&gt;Whenever someone publishes something on the web they would be informed
if someone else links to their work, due to the bidirectionality of the
links. This would supposedly put a stop to copyright infringement and
also allow content creators to correctly identify and bill the consumers
of their media.&lt;/p&gt;
&lt;p&gt;Of course, this would only work if there were no anonymity on the web.&lt;/p&gt;
&lt;p&gt;Lanier further proposes a single, public, digitally networked
marketplace where every participant is tied to his personal real-life
identity, and where anything anyone creates online has to be paid for.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;My Criticism&lt;/h2&gt;
&lt;p&gt;I thoroughly enjoyed reading Lanier’s analyses, and his descriptions of
the mechanisms behind &lt;em&gt;Siren Servers&lt;/em&gt; in particular. This was for me the
best part of the book.&lt;/p&gt;
&lt;p&gt;However, he often hand-waves obvious counter arguments or advances his
own arguments in a non-rigorous way, often relying on personal
anecdotes.&lt;/p&gt;
&lt;h3&gt;Digital networks’ supposed role in hollowing out of the middle class&lt;/h3&gt;
&lt;p&gt;Considering his central thesis, that digital networking is hollowing out
the middle class in developed societies, I’m not sure how much blame
for that can be assigned to digital networking. Other plausible factors
include &lt;a href=&quot;http://charlesbiderman.com/2014/12/22/demographics-likely-the-trigger-event-that-began-the-great-recession-and-the-reason-it-wont-end-anytime-soon/&quot;&gt;demographic change&lt;/a&gt;,
&lt;a href=&quot;http://insight.kellogg.northwestern.edu/article/what_really_spurred_the_great_recession/&quot;&gt;globalisation&lt;/a&gt;
and the money printing policies of Central Banks which are fueling asset
price bubbles while real wages remain stagnant, thereby making
wage-earners poorer.&lt;/p&gt;
&lt;p&gt;My expectation is that no particular factor can be singled out, and that
the causes are multiple, varied and intertwined in complex and difficult
to understand ways, precisely because the economy is a complex, chaotic
system (in a &lt;a href=&quot;https://en.wikipedia.org/wiki/Chaos_theory&quot;&gt;mathematical&lt;/a&gt;
sense).&lt;/p&gt;
&lt;h3&gt;Lanier fails to meaningfully address Free and Open Source software&lt;/h3&gt;
&lt;p&gt;Lanier only very superficially addresses the role of free and open
source software (FOSS) and doesn’t even mention (let alone extensively
cover or deconstruct) the ideology of &lt;a href=&quot;https://www.gnu.org/philosophy/free-sw.html&quot;&gt;Free Software&lt;/a&gt; at all.&lt;/p&gt;
&lt;p&gt;As a quick recap to people who don’t know the difference between “Free Software” and “Open Source software”:&lt;/p&gt;
&lt;p&gt;Both groups concern themselves with creating software where the source
code is visible, as opposed to software where you cannot inspect the
source code, and are therefore unable to modify or know what it is
really doing.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 18em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 336px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/15c554ee4018939492f863cb8a207ad7/d99f2/Gnulinux.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 114.22222222222223%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAYAAAALHW+jAAAACXBIWXMAAAsTAAALEwEAmpwYAAAE70lEQVR42nVUa0wUZxSdBVSW3eVh0iitbSFNf7Q+qNCapmlLU7RN/dOkFDWxhiaVxrawVWprsCh2sVJ/FAPxgYgERFhcQI1EHoq4vBeQEB5SMC7vLSi4Aos6y87M6f0+wWKEm2xm5u695zvn3DsjCBQAVOyal5e3orq6+lhpaenYtWvXUFxc/KSysvJMenr6aqpx6+zsXHrz5k2PpKQkv9ra2liq6b169erDGzdulNbV1X0szAdLSEjwpmQjA6Ki1rKysmiz2ayn3J8nT55cP1vrzq6HDx/2b2xsPNLS0mKgOgPV2+knlZSUfPasqL+/X0/skJub20E5X2E2KL+9qampkoAv5ufnB5OK3+i5uqenJ2qOTENDwyf0H27dumVhgB4sabPZcug0nD179uAcGBUeYYWxsbHy3r17ceXKlcckW05OTpZPnz6N+vr6v+eYZ2Rk9FRVVeEZ4L17986TFzAajansmbyLzcnJQWJioouaJWpwtbe3K5OTkzL55zIYDNK5c+dAzLcRhld2dvaIxWKBwExmAENDQ4fKy8uRkpLy8Pr16+aCggKR5GJqakqpqanB9PQ0RkZGlLt376K1tRXj4+MKycaJEycmTCZTW2pqKoh9DxuGGwOk0wK7urpGMzMzER8fr5BPEp2sTExMYGxsDHQI2trawIIpYc8UnDmrZ4dQz/dzk+aglAitra3rCQ4Ogb//K/KWLVvR3NwMl8vF/MLAwAAHHBwcZJvAbpX79+8z2b137tzZJcyP0NBQLl2lUjGj4e7uLqkEFUJCQuB0OjkQk01sFXbf3d39L+1pMimwEeOs+cR4RERE8PUJClp/+cOPwrA26H1p27Yd8FSrwXxj0dHRwdhgeHgYDodD/IeChvE5yfdhS/8cQ5PpKWBY2BfGlD++RtK+DVL879FYufJl0BITSxHMz9HRUTx48ICzJLnOoqKi915gxwEjBA648R1N2tAlNeTbaqnwiBd0Gi+UlJRxhlarFYqiQKIQRRG0WhcXBJvPcFPYp0UVOd+gKmOj1FpTiDVrgxAeHs4B7XY7HwwxlGhtQO98/GKAc4ntp9LSMOUQlYHBES4r0ZAI1pObm8en2tfXB9pdkby8XFhY+Prsd8BtIbBAP7/lY11dt3mjyzUDUXyMiooK+Pj4Qqfzpj1s54f09vbaIyMjAxYCY+E+e9XHxOj5srIBSJILMzMil7p/fxxnSf9LtPzs7bgw26N6wTv2xVi1SlDrtLrmRksD65enpx2Q5f8Bs7OzOGBgYICyZ89u7NwZZYuLiwtdjCGfxeq33sTQkI1LcjimOKDT+YQDGvNNCi081GrvEb1ev+nAgQObCPClBVnW/OX3Wnu67mh9mifSjhtkcUbBDAFJkhMzLmbAAHKOviuT1Qjf6GsFBA1XtpBc/gE1atvkah3QopWPxQiI2PrtU7BZdqPWajQdX6Kk/rAUwxc1EM3Lv+KApmfePx/jl7UdsGjxxOzjtJe7IdWwWZ5+DC794eQjHPo1UunLWwJYvGU06fDIrJ2yZvmu46AJwov+daZ72ezFWjgrdQrq1ag7FYCoqF2Iif4JAW+8jXWvChi7pFFcZi0GL2isvee9dnSahKXCYmH60Wulcbf6y8J9nscK4paN/7LZvZ4NydND+EAQPDaErvGOzvp5mav44DLzme80K55uxiL+CYLwH5jjwYbCb6JWAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The GNU and Linux mascots. The GNU represents Free Software&quot;
        title=&quot;&quot;
        src=&quot;/static/15c554ee4018939492f863cb8a207ad7/d99f2/Gnulinux.png&quot;
        srcset=&quot;/static/15c554ee4018939492f863cb8a207ad7/3684f/Gnulinux.png 225w,
/static/15c554ee4018939492f863cb8a207ad7/d99f2/Gnulinux.png 336w&quot;
        sizes=&quot;(max-width: 336px) 100vw, 336px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;“Free Software” (as in freedom, not price) however stresses a moral
and ethical dimension of software development and usage. It basically
boils down to the fact that non-free software creates a dangerous and
immoral power imbalance, slanted in favor of the creator of the non-free
software and against the user of that software.&lt;sup id=&quot;fnref-2&quot;&gt;&lt;a href=&quot;#fn-2&quot; class=&quot;footnote-ref&quot;&gt;2&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Open Source software on the other hand ignores the moral dimension
completely and takes a much more expedient approach. It simply asserts
that developing software in the “open”, in other words, with the
source exposed, is a superior form of software development which will
result in better code.&lt;/p&gt;
&lt;p&gt;In the index of this book, there is no entry for “Free Software” or
“Open Source Software”. There is one entry “open source
applications”.&lt;/p&gt;
&lt;p&gt;Lanier doesn’t even attempt to address the viewpoint of the Free
Software movement, which has been warning about these issues (structural
power imbalance, &lt;em&gt;Siren Servers&lt;/em&gt;, ubiquitous online surveillance) for
decades. This is in my opinion a glaring omission from the book.&lt;/p&gt;
&lt;p&gt;Lanier might have coined the catchy phrase &lt;em&gt;Siren Servers&lt;/em&gt;, but his
analysis of their role and negative effects on users and society might
have well come from someone from the Free Software movement. See for
example the article &lt;a href=&quot;https://www.gnu.org/philosophy/who-does-that-server-really-serve.html&quot;&gt;Who does that server really serve?&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As the saying goes, ”&lt;em&gt;There is no cloud, only other people’s computers&lt;/em&gt;”&lt;sup id=&quot;fnref-3&quot;&gt;&lt;a href=&quot;#fn-3&quot; class=&quot;footnote-ref&quot;&gt;3&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Lanier of course, comes to a completely different conclusion on what
needs to be done to resolve the situation, and appears to hold
proponents of Free and Open Source Software (dimissively calling them
“racals”, “openness crusaders” and Pirate Party types), not only in
contempt, but partly responsible for the emergence of &lt;em&gt;Siren Servers&lt;/em&gt;
and rise of surveillance as business model.&lt;/p&gt;
&lt;p&gt;It is clear that if Lanier were to meaningfully address all ideological
opponents of his vision for the future, then he would have had to
address the ideas behind Free Software in a methodical and rigorous
manner and not with dismissive hand-waving.&lt;/p&gt;
&lt;p&gt;The fact of the matter is that Free Software &lt;em&gt;does&lt;/em&gt; provide an
alternative solution to the current mess of online surveillance,
increasing risk and fragilization, extreme power imbalances and
centralization into &lt;em&gt;Siren Servers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The solution is to ensure that the software you use is &lt;em&gt;free&lt;/em&gt;. If
software being used by a service is free and issued under a
license that ensures its freeness](&lt;a href=&quot;https://www.gnu.org/licenses/why-affero-gpl.html&quot;&gt;https://www.gnu.org/licenses/why-affero-gpl.html&lt;/a&gt;),
then that server will not have the ability to eventually become a &lt;em&gt;Siren Server&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;The reason for this is that users will know exactly what the software
does with their data and will have the ability to switch to a different
provider (while taking all their data with them), or to host it
themselves, at a moment’s notice.&lt;/p&gt;
&lt;p&gt;This means that the power balance is no longer slanted in favor of the
service provider, and users are much more in control of their data and
content.&lt;/p&gt;
&lt;h3&gt;Lanier’s hypocrisy&lt;/h3&gt;
&lt;p&gt;Throughout the book, Lanier criticises in particular Google and Facebook
for their creepy surveillance business models and their usage of &lt;em&gt;Siren
Servers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Lanier himself works for Microsoft, a company that is feverishly
competing with Google and Facebook in surveilling users and in
establishing their own &lt;em&gt;Siren Servers&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;However, Lanier of course does not at all address this conflict of
interest or that fact that his employer is just as complicit as the
companies he calls out. This apparent hypocrisy severely detracts from
the integrity of his book.&lt;/p&gt;
&lt;h3&gt;Lanier’s superficial and misconstrued criticisms of “openness”&lt;/h3&gt;
&lt;p&gt;Lanier’s refusal to meaningfully engage with the different ideas and
philosophies behind what he calls “openness” is for me one of the most
disappointing aspects of the book.&lt;/p&gt;
&lt;h4&gt;Wikipedia&lt;/h4&gt;
&lt;p&gt;He deceptively equates Wikipedia and Facebook, saying that both are a
culmination of the “information should be free” meme and that both
contribute to the devaluation of user created content. In a previous
book, he even calls Wikipedia “Digital Maoism”.&lt;/p&gt;
&lt;p&gt;Wikipedia is concerned with creating a digital
&lt;a href=&quot;https://en.wikipedia.org/wiki/Commons&quot;&gt;Commons&lt;/a&gt;. By voluntarily
contributing to the commons (as Wikipedia contributors do), you are not
devaluing your work, you are making it priceless, in both the literal
and figurative senses of the word.&lt;/p&gt;
&lt;p&gt;Conversely, the information on Facebook is not free and is not part of a
commons.&lt;/p&gt;
&lt;p&gt;I find it good to know that there are some things in this world on which
one cannot put a price tag, despite the efforts of people like Lanier.&lt;/p&gt;
&lt;p&gt;As the saying goes. ”&lt;em&gt;A cynic is someone who knows the price of
everything and the value of nothing.&lt;/em&gt;”&lt;/p&gt;
&lt;h4&gt;Wikileaks&lt;/h4&gt;
&lt;p&gt;Lanier incorrectly claims that Wikileaks is concerned with abolishing
all privacy. Anyone who has made even a half-arsed effort to understand
what Wikileaks is about would know that they stand for transparency of
the powerful and their institutions, in order to keep them
democratically accountable, and that they don’t advocate the
elimination of all personal privacy.&lt;/p&gt;
&lt;p&gt;Of course, this is a common mischaracterization of this organization,
often done to intentionally discredit them. Either Lanier is also trying
to discredit them or he couldn’t be bothered to properly research their
stated goals.&lt;/p&gt;
&lt;h4&gt;Linux&lt;/h4&gt;
&lt;p&gt;Lanier claims: ”&lt;em&gt;A linux always begets a Google&lt;/em&gt;” as if it’s is
somehow responsible for the emergence of &lt;em&gt;Siren Servers&lt;/em&gt;. This doesn’t
explain &lt;em&gt;Siren Servers&lt;/em&gt; built upon proprietary software, such as
StackOverflow which uses Microsoft.&lt;/p&gt;
&lt;p&gt;Inasmuch as one could argue that &lt;em&gt;Siren Servers&lt;/em&gt; are the result of &lt;em&gt;open
source&lt;/em&gt; software (note the distinction) it is exactly due to open
source’s gutting of the moral aspect out of &lt;em&gt;free software&lt;/em&gt;.&lt;/p&gt;
&lt;h2&gt;Lanier wants to remove anonymity on the web&lt;/h2&gt;
&lt;p&gt;Lanier criticises tech companies for their creepy surveillance business
models, and yet his proposal for “fixing” the internet would eradicate
all privacy online and have all human interactions facilitated via a
single, public market place. It would be a surveillance and privacy
nightmare.&lt;/p&gt;
&lt;p&gt;Concerning anonymity on the web, Lanier says this is the result of the
“pot-smoking liberals” and “paranoid conservatives” who originally
built the system and who thought anonymity was “cool”. Such a perfect
example of his dismissive, non-rigorous and arbitrary reductionism which
completely fails to meaningfully confront the potential benefits or
dangers of anonymity on the web.&lt;/p&gt;
&lt;p&gt;Lanier completely fails to address the fact that anonymity is often the
only defence people may have against corrupt and malevolent state power.
Whether this applies to activists during revolutions or to conscientous
whistleblowers, doing away with privacy would be throwing away one of
the few ways of ensuring free speech online.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 680px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/f61a70f5f6922fc5dad8179610ca601b/7bf67/Tahrir_Square_on_November_27_2012.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 52.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAALABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAv/aAAwDAQACEAMQAAABzrEpxTQkH//EABgQAQADAQAAAAAAAAAAAAAAAAEAAgMQ/9oACAEBAAEFAitWOMc6HVn/xAAVEQEBAAAAAAAAAAAAAAAAAAAAEf/aAAgBAwEBPwFX/8QAFhEBAQEAAAAAAAAAAAAAAAAAABEB/9oACAECAQE/AZqP/8QAGRAAAQUAAAAAAAAAAAAAAAAAARAgITGR/9oACAEBAAY/AoOpbP/EABkQAAMBAQEAAAAAAAAAAAAAAAABEUExUf/aAAgBAQABPyH34TVsHsb3RDbWjL0//9oADAMBAAIAAwAAABDE3//EABgRAAMBAQAAAAAAAAAAAAAAAAABETFR/9oACAEDAQE/EE1MI4f/xAAYEQEBAAMAAAAAAAAAAAAAAAABABEhUf/aAAgBAgEBPxByaYXb/8QAHBABAAICAwEAAAAAAAAAAAAAAQARIUExcYGR/9oACAEBAAE/ED2wGkC9QCVXKWNGvZTdJgIgxo40ysBfZZ5T/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Tahrir Square protests in 2012.&quot;
        title=&quot;&quot;
        src=&quot;/static/f61a70f5f6922fc5dad8179610ca601b/7bf67/Tahrir_Square_on_November_27_2012.jpg&quot;
        srcset=&quot;/static/f61a70f5f6922fc5dad8179610ca601b/863e1/Tahrir_Square_on_November_27_2012.jpg 225w,
/static/f61a70f5f6922fc5dad8179610ca601b/20e5d/Tahrir_Square_on_November_27_2012.jpg 450w,
/static/f61a70f5f6922fc5dad8179610ca601b/7bf67/Tahrir_Square_on_November_27_2012.jpg 680w&quot;
        sizes=&quot;(max-width: 680px) 100vw, 680px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;h2&gt;Monetizing all human interactions debases them&lt;/h2&gt;
&lt;p&gt;By wanting to turn the web into a giant marketplace where everyone
operates with an exposed identity and every digital creation, no matter
how trivial, needs to be paid for, Lanier wants to further the already
ongoing monetization of the public commons. As Charles Eisenstein writes
&lt;a href=&quot;http://sacred-economics.com&quot;&gt;sacred economics&lt;/a&gt;, monetizing all human
interactions actually debases them.&lt;/p&gt;
&lt;p&gt;Lanier calls his approach “humanitarian”; it is anything but. Instead,
by monetizing and thereby commodifying every online human interaction,
whether it’s a joke, a compliment or a statement of support, these
interactions are stripped of their inherent sacred quality of humanity.&lt;/p&gt;
&lt;p&gt;If you know that someone who sends you a message of support or love will
receive a micropayment for that message, could the original intent of
the message not be called into doubt?&lt;/p&gt;
&lt;h1&gt;My proposed solutions&lt;/h1&gt;
&lt;h2&gt;It’s about freedom, not cost&lt;/h2&gt;
&lt;p&gt;Lanier’s proposed solution ultimately has to do with costs and trying
to find a way to get people paid for anything they write and then
publish online, no matter how trivial.&lt;/p&gt;
&lt;p&gt;However, in so doing he comes up with a proposed solution that does away
with all privacy and anonymity.&lt;/p&gt;
&lt;p&gt;His proposal of using a network with bidirectional links might threaten
the &lt;em&gt;Siren Server&lt;/em&gt; status of services such as Facebook and Google.
However, it’s not clear how such a network will solve the problem of
Uber or AirBNB becoming &lt;em&gt;Siren Servers&lt;/em&gt;, thereby pushing out the middle
class jobs of taxi drivers and guest house operators.&lt;/p&gt;
&lt;p&gt;It’s not only about the network architecture, as Lanier suggests.
What’s more important is Software and Computing Freedom.&lt;/p&gt;
&lt;p&gt;If you don’t have the freedom to study, use and modify the software
that you use, then you will be systematically exploited and preyed upon,
no matter what the network architecture looks like.&lt;/p&gt;
&lt;p&gt;Free software specifically, is defined by these four freedoms:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;The freedom to run the program as you wish, for any purpose&lt;/li&gt;
&lt;li&gt;The freedom to read the source code and to modify it as you wish.&lt;/li&gt;
&lt;li&gt;The freedom to redistribute original copies so you can help your
neighbor.&lt;/li&gt;
&lt;li&gt;The freedom to distribute your own modified copies to others.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Being able to read the source code is essential for software to be free.
An organisation is however only compelled to share their source code if
they intend to distribute compiled copies as well. If the software is
used privately, i.e. in-house, then they are under no such obligation.&lt;/p&gt;
&lt;p&gt;Open Source on the other hand, also gives the right to read the source
code, but many open source licenses do not ensure the last two freedoms,
and therefore offer weaker protection.&lt;/p&gt;
&lt;p&gt;There is however a large overlap between the two groups. Most open
source software is also free software, and vice versa.&lt;/p&gt;
&lt;p&gt;Free software coupled with free and open protocols means that users are
not beholden to specific service providers. It’s exactly this aspect of
it which is why the dominant tech companies avoid free software like the
plague and instead embrace the watered down notion of “open source”.
Their goal is to maintain strict vendor lock-in, making it difficult for
users to switch to other service providers by holding their data and
online personas ransom. Something which they could not do if their
software respected the above four freedoms.&lt;/p&gt;
&lt;h4&gt;Who pays for fee software?&lt;/h4&gt;
&lt;p&gt;When discussing free software, the question often arises how one should
make money with software if you cannot enforce artificial scarcity,
vendor lock-in, holding user’s data ransom or spying on them.&lt;/p&gt;
&lt;p&gt;This is perhaps a topic for another blog post. In short, it definitely
is possible to make money writing freedom respecting software and the
more people insist on using only free software, the more economic
opportunities will arise.&lt;/p&gt;
&lt;p&gt;Software is better seen as a living, changing and evolving ecosystem,
than as a static object. It needs constant care and attention, to keep
it relevant, accurate, applicable and functioning. This care and
attention is a service which can and should be paid for.&lt;/p&gt;
&lt;p&gt;Who pays for this service? The users do. Whether they are governments,
universities, corporations or private individuals.&lt;/p&gt;
&lt;p&gt;How do they pay for it? Organisations sign service and support
contracts. They also commission the writing of new features or entirely
new applications.&lt;/p&gt;
&lt;p&gt;Private individuals can pay for free software through crowdfunding,
bounties, and donations.&lt;sup id=&quot;fnref-4&quot;&gt;&lt;a href=&quot;#fn-4&quot; class=&quot;footnote-ref&quot;&gt;4&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;
&lt;p&gt;Public institutions and foundations can issue grants or fund the
development of free software for usage in government and publically
owned enterprises.&lt;/p&gt;
&lt;p&gt;If all governments decided to only fund and use free software, it would
create a massive amount of investment in the sector. Additionally, money
spent on developing free software can be invested in a country’s own
programmer workforce, instead of it being sent overseas to oversized
foreign corporations.&lt;/p&gt;
&lt;p&gt;However, those companies that currently spy on us, hold our data ransom
and restrict our digital freedoms, won’t change by themselves. It’s up
to the users to take matters into their own hands, to demand freedom and
to support those companies, organizations and people who develop free
software.&lt;/p&gt;
&lt;h2&gt;Decentralization&lt;/h2&gt;
&lt;p&gt;The problems Lanier identify are largely caused by data-assymetry (who
has data on whom) and the resulting siren servers.&lt;/p&gt;
&lt;p&gt;An architectural approach to solving this problem, which complements
free software, is decentralization.&lt;/p&gt;
&lt;p&gt;Decentralization refers to a network structure (called topology) where
each node in the network can connect directly with any other node,
without the intervention of a middle man (such as Facebook or Google).&lt;/p&gt;
&lt;p&gt;In the network topologies pictured here, the &lt;em&gt;fully connected&lt;/em&gt; topology
is the most decentralized, while the star network is the most
centralized.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 508px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/593f9f2619cda97e66b180c9f59b51a4/2fd48/NetworkTopologies.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 48.888888888888886%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAKCAIAAAA7N+mxAAAACXBIWXMAAAsTAAALEwEAmpwYAAAB80lEQVR42k1Ra0/aYBTuT1/mF+KSxSUuEhAHU6RouAyxgOBakIsUu4FcKojBygbFUoptkdL2bXdKv+zkzZvnXJ5zxSzLQrZl2ZZt28p6VRk2K8PWSJiACi57K5KmGqYJAG2DtwABBQMUoBKBQuy8fmUYxkEqHCMJmm1pxsZEpmbo0lrxX8eGs/EGGZDucyr06cyfa1WBiFEPTLpBAcLLmZv+L+9VdDF9bbIdIIBxwHP+3Hm0eBnMxyv935lmxePdw0PhD6Evwvsb9jgenVAXz+IkWIhP5zNN01aqWmZuQ4X4ZavMS/NS985H4JEyAbmYx44nuO/DQ1+Tx5q+cdpOVPNH6Wj+vuZOZSHUHbCV9l3pviGpMtmhm2w736rphqEqqi+Ne5PhXL3otA3BuqEvRBEGdjcExWc8zyviStd4WVyu1QfuSVCW4JJlefWmqJIs8oJpmtj/W3UFIQR/tJq9oMlIiSB7jcgNUWQZMLLTUaFXL/YZasDQTx1s+a5wC34s8uPFDN4f6fWvJLiHOaFSBE2FyRTVod28xC0ZSEe/Z2OHabzHDTGyS3+MeXcTgZ2zA0/icDf1bT97CsVNy6l/TP742a67zJk0Pyom43QhTl+f1jLOzM7Nt12/PHPaWnPQVnVn4SdTWIeruhZRmL9wHAAToX/EnAYa4G/5iQAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Network Topologies&quot;
        title=&quot;&quot;
        src=&quot;/static/593f9f2619cda97e66b180c9f59b51a4/2fd48/NetworkTopologies.png&quot;
        srcset=&quot;/static/593f9f2619cda97e66b180c9f59b51a4/3684f/NetworkTopologies.png 225w,
/static/593f9f2619cda97e66b180c9f59b51a4/fc2a6/NetworkTopologies.png 450w,
/static/593f9f2619cda97e66b180c9f59b51a4/2fd48/NetworkTopologies.png 508w&quot;
        sizes=&quot;(max-width: 508px) 100vw, 508px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Creating large decentralized networks is more difficult than creating
centralized ones, which is why the web has come to rely on centralized
&lt;em&gt;Siren Servers&lt;/em&gt; to such a large degree.&lt;/p&gt;
&lt;p&gt;However, much exciting work is being done on decentralizing the web and
putting people back in control.&lt;/p&gt;
&lt;p&gt;Consider Finance, and Lanier’s assertion that &lt;em&gt;Siren Servers&lt;/em&gt;
contributed to the financial crisis preceding the &lt;em&gt;Great Recession&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;It’s more difficult to have a financial &lt;em&gt;Siren Server&lt;/em&gt; when financial
data is decentralized and therefore effectively available to everyone.&lt;/p&gt;
&lt;p&gt;This is already the case with decentralized cryptocurrencies such as
Bitcoin. The bitcoin protocol is an open and free protocol, the original
bitcoin wallet is free software and the transaction information
contained in the blockchain is available to all.&lt;/p&gt;
&lt;p&gt;An improvement upon Bitcoin would be to allow truly anonymous
transactions, and this &lt;a href=&quot;http://zerocoin.org&quot;&gt;appears to be on the horizon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Bitcoin and cryptocurrencies are however only one application which can
be built on top of the revolutionary distributed consensus blockchain
technology upon which it rests.&lt;/p&gt;
&lt;p&gt;There’s already work on &lt;a href=&quot;https://www.stackmonkey.com/&quot;&gt;distributed cloud hosting&lt;/a&gt;,
&lt;a href=&quot;http://twister.net.co&quot;&gt;distributed microblogging&lt;/a&gt; and a myriad of other services
running in a decentralized (non-&lt;em&gt;Siren Server&lt;/em&gt;) manner.&lt;/p&gt;
&lt;h3&gt;Federation&lt;/h3&gt;
&lt;p&gt;An older idea than blockchain-based decentralization is federation.
Think of the way in which you can send an email from a Gmail account to
someone with a Yahoo account, or to someone who hosts their own mail
server.&lt;/p&gt;
&lt;p&gt;Why can we send email to people with different service providers, but we
cannot send chat messages from a Google account to an iMessage account,
or between Whatsapp and Yahoo messenger?&lt;/p&gt;
&lt;p&gt;This ability of email is the result of something called federation. The
ability of servers from different providers and with different
implementations, to communicate and relay messages between one another.&lt;/p&gt;
&lt;p&gt;Email is federated but facebook messages are not, because you cannot
send a facebook message to someone outside of facebook.&lt;/p&gt;
&lt;p&gt;There is no technical reason why instant messaging cannot be federated.
In fact, XMPP, the protocol on which many of the messaging services are
originally based, allows federation.&lt;/p&gt;
&lt;p&gt;The reason we don’t have federation in messaging is because it’s not
in the interest of &lt;em&gt;Siren Servers&lt;/em&gt;. It would actively undermine their
dominance.&lt;/p&gt;
&lt;p&gt;If any of the big email providers, Google, Yahoo, Microsoft or Apple,
could get away with only allowing emails within their own system, they
would have done it by now. The proof is in the fact that they actively
prevent federation in their messaging apps. The reason they cannot do it
with email is because federated email achieved critical mass before any
single company could kill it off.&lt;/p&gt;
&lt;p&gt;Unfortunately, this was not the case with instant messaging. Therefore,
if you actively want to work against &lt;em&gt;Siren Servers&lt;/em&gt;, you should only
use &lt;a href=&quot;https://xmpp.net/directory.php&quot;&gt;instant messaging servers&lt;/a&gt; which
support federation, such as XMPP.&lt;/p&gt;
&lt;p&gt;You can sign up for a free XMPP chat account &lt;a href=&quot;https://conversejs.org&quot;&gt;here&lt;/a&gt;.
And if you’d like to chat with me, add me as a contact:&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;As you can see, I believe in a completely different remedy than the one
which Lanier suggests. One that’s based on a methodology, legal
framework and software which is already being used instead of something
which Wired magazine in 1995 called the
&lt;a href=&quot;http://archive.wired.com/wired/archive/3.06/xanadu.html&quot;&gt;longest-running vaporware project in the history of computing&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I thoroughly enjoyed Lanier’s analyses and his unique perspective on
things which I think made the book worth reading.&lt;/p&gt;
&lt;p&gt;However, his non-rigorous approach, his dismissiveness or ignorance of
alternative narratives and approaches to resolving the issues he
mentions, as well as his hypocritical omission of his own employer’s
complicity, left me disappointed and uninspired.&lt;/p&gt;
&lt;h2&gt;Footnotes:&lt;/h2&gt;
&lt;p&gt;&lt;video controls=&quot;controls&quot;
 poster=&quot;//static.fsf.org/nosvn/rms-photos/20140407-geneva-01.png&quot;
 style=&quot;width:512px&quot;
 src=&quot;http://audio-video.gnu.org/video/TEDxGE2014_Stallman05_LQ.webm&quot;
 type=&quot;video/webm&quot;&gt;
&lt;/video&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Introduction to Free Software and the Liberation of Cyberspace&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;footnotes&quot;&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id=&quot;fn-1&quot;&gt;Bruce Sterling calls them “The Stacks”, vertically integrated
social media. See &lt;a href=&quot;http://www.huffingtonpost.com/2012/03/13/bruce-sterling-sxsw-2012_n_1343353.html&quot;&gt;Bruce Sterling At SXSW 2013: The Best
Quotes&lt;/a&gt;.&lt;a href=&quot;#fnref-1&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-2&quot;&gt;If you’re interested in more detail about Free Software, watch
this presentation by Richard Stallman:&lt;a href=&quot;#fnref-2&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-3&quot;&gt;The earliest reference to this that I could find, is &lt;a href=&quot;http://www.secmeme.com/2014/04/there-is-no-cloud-just-other-peoples.html&quot;&gt;this article&lt;/a&gt;&lt;a href=&quot;#fnref-3&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;li id=&quot;fn-4&quot;&gt;See &lt;a href=&quot;https://www.kickstarter.com&quot;&gt;Kickstarter&lt;/a&gt;,
&lt;a href=&quot;https://www.indiegogo.com/&quot;&gt;IndieGogo&lt;/a&gt;,
&lt;a href=&quot;https://www.startjoin.com&quot;&gt;Startjoin&lt;/a&gt;,
&lt;a href=&quot;http://www.patreon.com&quot;&gt;Patreon&lt;/a&gt;,
&lt;a href=&quot;https://www.bountysource.com&quot;&gt;Bountysource&lt;/a&gt;,
&lt;a href=&quot;https://gratipay.com&quot;&gt;Gratipay&lt;/a&gt; and
&lt;a href=&quot;https://snowdrift.coop/&quot;&gt;Snowdrift&lt;/a&gt;.&lt;a href=&quot;#fnref-4&quot; class=&quot;footnote-backref&quot;&gt;↩&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Book review: Zen and the art of motorcycle maintenance]]></title><description><![CDATA[This book, a best-seller written in 1974, is regarded as a classic and one of the most important and
influential books of the last century…]]></description><link>https://opkode.com/blog/review-zen-and-the-art-of-motorcycle-maintenance/</link><guid isPermaLink="false">https://opkode.com/blog/review-zen-and-the-art-of-motorcycle-maintenance/</guid><pubDate>Sat, 03 Jan 2015 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 303px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d9dfec60cbbe6b8cd1fb258b106b4784/c8fe0/zen_and_the_art_of_motorcycle_maintenance.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 164.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAhABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAQCAwH/xAAXAQEAAwAAAAAAAAAAAAAAAAABAAID/9oADAMBAAIQAxAAAAG/nqTTa4LLNRitamS9gvok/8QAGxAAAgIDAQAAAAAAAAAAAAAAAQIAEQMQEiL/2gAIAQEAAQUCqAC4zchMlGZGixH6Dp64MRKXf//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BX//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BX//EAB8QAAEDAwUAAAAAAAAAAAAAAAABESECECAiMTJRgf/aAAgBAQAGPwK8mp5stLeiQsHRFLnE2bD/xAAeEAEAAgIBBQAAAAAAAAAAAAABABEhMRAgQVGB8f/aAAgBAQABPyHSohZ4K63qUClXh2iSRWx3dzIMMtyM3cfvgBkvF9H/2gAMAwEAAgADAAAAEHfCg/AP/8QAGBEAAwEBAAAAAAAAAAAAAAAAARARADH/2gAIAQMBAT8QoHUbcK//xAAZEQACAwEAAAAAAAAAAAAAAAABEAARITH/2gAIAQIBAT8QPUbmv//EACAQAQACAgEEAwAAAAAAAAAAAAEAESExURBBYXEggbH/2gAIAQEAAT8QSmyUdoYDxw7gAUQJcFqFJWwo73j8eizlaC61GFh7MI8+qgKQhql8RY+wq59VFhg8mPFwYUN5KxW/r4f/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Book cover: Zen and the art of motorcycle maintenance&quot;
        title=&quot;&quot;
        src=&quot;/static/d9dfec60cbbe6b8cd1fb258b106b4784/c8fe0/zen_and_the_art_of_motorcycle_maintenance.jpg&quot;
        srcset=&quot;/static/d9dfec60cbbe6b8cd1fb258b106b4784/863e1/zen_and_the_art_of_motorcycle_maintenance.jpg 225w,
/static/d9dfec60cbbe6b8cd1fb258b106b4784/c8fe0/zen_and_the_art_of_motorcycle_maintenance.jpg 303w&quot;
        sizes=&quot;(max-width: 303px) 100vw, 303px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;This book, a best-seller written in 1974, is regarded as a classic and one of the most important and
influential books of the last century.&lt;/p&gt;
&lt;p&gt;Superficially, it’s about the protagonist and his troubled son who go on a motorcycle trip across
America.&lt;/p&gt;
&lt;p&gt;During their rides he expounds philosophically on the two different ways in which people subjectively
perceive technology and then attempts to describe a way to reconcile this dualism.&lt;/p&gt;
&lt;p&gt;These two approaches to technology the author calls &lt;em&gt;classic&lt;/em&gt; and &lt;em&gt;romantic&lt;/em&gt; modes of thought.
The &lt;em&gt;classic&lt;/em&gt; approach is technical and analytic. It is concerned with underlying form and purpose.&lt;/p&gt;
&lt;p&gt;In the language of the 1960s and ’70s, the &lt;em&gt;classic&lt;/em&gt; approach is “square”.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;romantic&lt;/em&gt; approach is intuitive, idealistic and symbolic. It is therefore “groovy” instead of “square”.&lt;/p&gt;
&lt;p&gt;The book is in some way, an attempt to reconcile the schism that appeared in American society in the 1960s with
the emergence of the &lt;em&gt;romantic&lt;/em&gt; hippie movement, which rejected the dominant &lt;em&gt;classic&lt;/em&gt; mainstream narrative.&lt;/p&gt;
&lt;p&gt;However, this dichotomy extends further than the social and political milieu of 1960s and 1970s America and the author
traces its origins all the way back to ancient Greece and the analytical approaches of Socrates, Plato and Aristotle.
One can also see this dichotomy in software development; between the &lt;em&gt;classic&lt;/em&gt;,
analytical developers or engineers and the &lt;em&gt;romantic&lt;/em&gt; designers.&lt;/p&gt;
&lt;h2&gt;Differing approaches to esthetics and beauty&lt;/h2&gt;
&lt;p&gt;The author mentions a perceived &lt;em&gt;death force&lt;/em&gt;, apparently inherent in
technology, but which is actually something which emerges when one
approaches technology from a strictly &lt;em&gt;romantic&lt;/em&gt; viewpoint without any
appreciation for the &lt;em&gt;classic&lt;/em&gt; understanding of underlying form and
function. Out of a &lt;em&gt;classic&lt;/em&gt; understanding of technology, a different
esthetic value arises, one that appreciates the beauty of the optimal
combination of form and function.&lt;/p&gt;
&lt;p&gt;Programmers talk about code that is &lt;a href=&quot;http://programmers.stackexchange.com/questions/97912/how-do-you-define-elegant-code&quot;&gt;elegant&lt;/a&gt;.
Not elegant in a visual or artistic sense, but elegant in the sense that
is it is clear, succinct and functional to a degree that it cannot be
improved upon. This is the &lt;em&gt;classical&lt;/em&gt; esthetic ideal.&lt;/p&gt;
&lt;p&gt;To a &lt;em&gt;romantic&lt;/em&gt; person, a complex schematic might look complicated and
unappealing, while to the &lt;em&gt;classic&lt;/em&gt;, analytical minded person it might
be a thing of beauty.&lt;/p&gt;
&lt;p&gt;The author reconciles the &lt;em&gt;romantic&lt;/em&gt; and &lt;em&gt;classic&lt;/em&gt; modes of thought by
pointing towards unanalyzed, non-dualistic and “ultimate” reality.&lt;/p&gt;
&lt;p&gt;The author asserts that non-dualistic direct experience is the source of
&lt;em&gt;Quality&lt;/em&gt; in thoughts, acts and creations. Quality which encompasses
both the &lt;em&gt;romantic&lt;/em&gt; and &lt;em&gt;classic&lt;/em&gt; approaches.&lt;/p&gt;
&lt;p&gt;The book ultimately reveals that the protagonist himself has a dualistic
split within his own mind, which he needs to reconcile.&lt;/p&gt;
&lt;h2&gt;Another layer to the story&lt;/h2&gt;
&lt;p&gt;Besides the superficial story of the motorcycle trip, the book is also
about a man who experienced non-dualistic, cosmic consciousness;
pessimistically interpreted by his society as a pathology (i.e. mental
illness or insanity), and therefore in need of “correction”.&lt;/p&gt;
&lt;p&gt;This alterered state of consciousness, considered an illness by
psychiatrists, is triggered by an analytical, philosophical exploration
of the nature of &lt;em&gt;Quality&lt;/em&gt;, during which this man, through analysis,
scales the heights of abstraction which his mind can attain, all the way
up to non-dualistic experience.&lt;/p&gt;
&lt;p&gt;Through this, he realises that non-dualistic experience, that which we
experience immediately before the rational mind starts analyzing and
categorizing, cannot be defined. And yet, Western analytical thought is
not able to meaningfully deal with something which cannot be defined.&lt;/p&gt;
&lt;h2&gt;Practical lessons on quality&lt;/h2&gt;
&lt;p&gt;Ultimately the author reasons that &lt;em&gt;Quality&lt;/em&gt;, in word and deed arises
out of a state of being in contact with direct, immediate experience
while being completely immersed in what you are doing or working on.&lt;/p&gt;
&lt;p&gt;This is the Zen of motorcycle maintenance.&lt;/p&gt;
&lt;p&gt;People also talk about being “in the zone”, and in Psychology there is
the notion of ”&lt;a href=&quot;https://en.wikipedia.org/wiki/Flow_(psychology)&quot;&gt;flow&lt;/a&gt;“.&lt;/p&gt;
&lt;p&gt;In short, one should strive to experience and maintain &lt;em&gt;inner peace&lt;/em&gt;
while doing the work. The end result and end goal should also be &lt;em&gt;inner
peace&lt;/em&gt;. In so doing, the experience of doing the work will have quality
and the work itself will have quality.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;I loved this book. Since reading it, I have a completely new notion of
quality, a new appreciation for the limits of analytics and reason and
for the ultimately ineffable nature of direct experience.&lt;/p&gt;
&lt;p&gt;The book itself is a work of quality, and the author states in an
afterword that his motivation for writing the book was because he deemed
it a higher quality endeavor than not writing it.&lt;/p&gt;
&lt;p&gt;I thank him for that, and because of it, I am now inspired to maintain
inner peace while I work, to strive towards inner peace as my ultimate
goal, and to thereby achieve quality in what I do.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Antifragile Software Ecosystems]]></title><description><![CDATA[I recently finished reading the book Antifragile, by Nassim N. Taleb,
in which he discusses the idea of antifragility, the property that…]]></description><link>https://opkode.com/blog/antifragile-software-ecosystems/</link><guid isPermaLink="false">https://opkode.com/blog/antifragile-software-ecosystems/</guid><pubDate>Tue, 14 Jan 2014 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;right&quot; style=&quot;width: 14em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 184px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/42c7903899a17b989fda8ecb99955f19/4c9e9/antifragile.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 154.34782608695653%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAfABQDASIAAhEBAxEB/8QAGQAAAgMBAAAAAAAAAAAAAAAAAAQCAwUB/8QAFgEBAQEAAAAAAAAAAAAAAAAAAgAD/9oADAMBAAIQAxAAAAHti7J1pFSWlKKjqTSJ/wD/xAAdEAACAQUBAQAAAAAAAAAAAAABAwIABBESEyIx/9oACAEBAAEFAoN85UalAZENjcJAjrVv8VPqDkFp4qW32633n//EABoRAQADAAMAAAAAAAAAAAAAAAEAAgMREhP/2gAIAQMBAT8BrrW0884ZCPUgY8T/xAAeEQACAQMFAAAAAAAAAAAAAAAAAQMCEhMhMVJhof/aAAgBAgEBPwFwql6F0nLwbW5l6P/EAB0QAAIDAAIDAAAAAAAAAAAAAAABAhEhEiIxQeH/2gAIAQEABj8C2rNo6yVFURa9YfBzl4RKMisIwEzknR//xAAdEAADAQACAwEAAAAAAAAAAAAAAREhMWFBUaFx/9oACAEBAAE/IURWHn2UvJ3H0NfUE2OigZA/b+ilMgPnq9Q7LQ10JRKt8iFI8Kelyf/aAAwDAQACAAMAAAAQixXz/8QAHhEAAgEDBQAAAAAAAAAAAAAAAAERITFBYXGh4fD/2gAIAQMBAT8QrtibHPY6KGPajyNwnsf/xAAdEQACAgEFAAAAAAAAAAAAAAABEQAhMUFhkaHR/9oACAECAQE/EBTA7QgodnkSJN6XClNyZ//EAB8QAQACAgIDAQEAAAAAAAAAAAERIQAxQVFxkbGh4f/aAAgBAQABPxCT9YVsvFV9xSR24S9pMIL0cyvLvFRIRHrCDAn44wrYvR9BysyhBzF4gNsI0fxjJdTRDlkZW899/uLoZ3cyO694CBCIDb3n/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Book cover for Antifagile&quot;
        title=&quot;&quot;
        src=&quot;/static/42c7903899a17b989fda8ecb99955f19/4c9e9/antifragile.jpg&quot;
        srcset=&quot;/static/42c7903899a17b989fda8ecb99955f19/4c9e9/antifragile.jpg 184w&quot;
        sizes=&quot;(max-width: 184px) 100vw, 184px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I recently finished reading the book Antifragile, by &lt;a href=&quot;https://twitter.com/nntaleb&quot;&gt;Nassim N. Taleb&lt;/a&gt;,
in which he discusses the idea of &lt;q&gt;antifragility&lt;/q&gt;, the property that allows something to ultimately
improve and grow stronger when subjected to volatility and stressors.&lt;/p&gt;
&lt;p&gt;I highly recommend Taleb’s books, they have a tendency to throw
conventional wisdom on its head and make you think differently of our
world, in which randomness, volatility, opacity and non-linearity takes
precedence.&lt;/p&gt;
&lt;p&gt;As a software developer, I kept wondering how the insights gained from
this book apply to the world of software. Especially given the fact that
software is very fragile. The answer lies in the communities or
ecosystems that form around software. Many of them are fragile, but some
are antifragile.&lt;/p&gt;
&lt;p&gt;If you’re also a software developer, you’ll want to be in the second
category.&lt;/p&gt;
&lt;h2&gt;What is antifragile?&lt;/h2&gt;
&lt;p&gt;Taleb splits everything into three categories, fragile, robust and
antifragile.&lt;/p&gt;
&lt;p&gt;The initial chapters explain in detail why robust is not the opposite of
fragile, and why the neologism “antifragile” is needed to describe the
opposite of fragility.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container left&quot; style=&quot;width: 20em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 241px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/fcadcc11001905b498ce2a6effa821f9/4d3ab/Medusa.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 99.55555555555554%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQADAAAAAAAAAAAAAAAAAAEDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAAB5rIl1lEBQf/EABoQAAEFAQAAAAAAAAAAAAAAAAECAxAREgD/2gAIAQEAAQUCAsrTmGyNu1qR3//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EABoQAAICAwAAAAAAAAAAAAAAAAABECERIDH/2gAIAQEABj8CLUXweNf/xAAaEAEAAwEBAQAAAAAAAAAAAAABABExECFB/9oACAEBAAE/IcQtijB5UG3kaIUfL6sxP//aAAwDAQACAAMAAAAQxA9D/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPxAf/8QAFREBAQAAAAAAAAAAAAAAAAAAIEH/2gAIAQIBAT8Qo//EABoQAQEBAQEBAQAAAAAAAAAAAAERACFhMUH/2gAIAQEAAT8QWKI8D9w6yejgzK/RNkucAEOlgTS/C69yLVV9cpn/2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Medusa, courtesy of Wikimedia.org&quot;
        title=&quot;&quot;
        src=&quot;/static/fcadcc11001905b498ce2a6effa821f9/4d3ab/Medusa.jpg&quot;
        srcset=&quot;/static/fcadcc11001905b498ce2a6effa821f9/863e1/Medusa.jpg 225w,
/static/fcadcc11001905b498ce2a6effa821f9/4d3ab/Medusa.jpg 241w&quot;
        sizes=&quot;(max-width: 241px) 100vw, 241px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;If fragile systems are sensitive to stress and volatility, and need to
be kept “safe” from harm, lest they suffer or break down, then
antifragile systems are ones which ultimately benefit from randomness
and stress.&lt;/p&gt;
&lt;p&gt;In Greek mythological terms, one can think of Medusa, which grows
another two snakes on her head for each one that’s cut off. That’s
antifragile.&lt;/p&gt;
&lt;p&gt;So fragile and antifragile can be considered opposites, e.g. positive
and negative, while robust is simply neutral. It suffers little harm
from volatility but also gets little to no benefit.&lt;/p&gt;
&lt;h2&gt;Evolution is antifragile&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 248px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/7351b2649bcd7aee2271d1d81b8def97/2edd3/ostrich.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 128.88888888888889%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAaABQDASIAAhEBAxEB/8QAGQABAAIDAAAAAAAAAAAAAAAAAAEDAgQF/8QAFwEBAQEBAAAAAAAAAAAAAAAAAQIAA//aAAwDAQACEAMQAAAB7MUU8q20iiWDEP8A/8QAHRABAAIBBQEAAAAAAAAAAAAAAQACMQMREhMgIf/aAAgBAQABBQKODF9Xi9lmHwtXeVAPH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABURAQEAAAAAAAAAAAAAAAAAABEg/9oACAECAQE/ASP/xAAbEAACAQUAAAAAAAAAAAAAAAAAEBEBEiAhQf/aAAgBAQAGPwJ29IoQtY//xAAbEAEAAgMBAQAAAAAAAAAAAAABACEQEVExYf/aAAgBAQABPyHRKJlg/Iagp2NstPNQaOCBVJQAZcf/2gAMAwEAAgADAAAAEJ8Sj//EABYRAQEBAAAAAAAAAAAAAAAAABABEf/aAAgBAwEBPxDSH//EABcRAAMBAAAAAAAAAAAAAAAAAAABEBH/2gAIAQIBAT8Q0O//xAAbEAEAAwEBAQEAAAAAAAAAAAABABExIUEQkf/aAAgBAQABPxBqx/YQAtBTsItSobPZYbo7iAg3MBsE5sAuJAUda2jlwZmU0djPfj1n/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Ostriches have evolved from dinosaurs&quot;
        title=&quot;&quot;
        src=&quot;/static/7351b2649bcd7aee2271d1d81b8def97/2edd3/ostrich.jpg&quot;
        srcset=&quot;/static/7351b2649bcd7aee2271d1d81b8def97/863e1/ostrich.jpg 225w,
/static/7351b2649bcd7aee2271d1d81b8def97/2edd3/ostrich.jpg 248w&quot;
        sizes=&quot;(max-width: 248px) 100vw, 248px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Some good examples of antifragile systems are found in nature and
ecology. For evolution to work (i.e. for a species to adapt to its
randomly changing environments), random mutations are required between
individuals in that species.&lt;/p&gt;
&lt;p&gt;A random mutation in a member of a species holds the possibility of
making that member better adapted to its environment. By virtue of it
being better adapted, that member will on average live longer and
produce more offspring, which will be likely to have inherited the same
advantageous mutation. The process continues, propagating the beneficial
mutation throughout the species, in so doing, the species evolves and
becomes more fit and adapted to its environment.&lt;/p&gt;
&lt;p&gt;Nature is able to discard less well-adapted specimens and keep the
better-adapted ones. An ability which Taleb refers to as &lt;em&gt;optionality&lt;/em&gt;.
It has the &lt;em&gt;option&lt;/em&gt; to keep the “good” specimens and discard the
“bad” ones.&lt;/p&gt;
&lt;p&gt;The opposite of an &lt;em&gt;option&lt;/em&gt; is an &lt;em&gt;obligation&lt;/em&gt;. Nature is under no
obligation to keep the poorly adapted members of a species, and if it
were, it wouldn’t be antifragile anymore.&lt;/p&gt;
&lt;p&gt;So, although individual members within a collection (like a species) are
fragile to certain stressors, the overall effect on the collective level
is antifragility.&lt;/p&gt;
&lt;h2&gt;Software is fragile&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;max-width: 30em; width: 100%; height: auto&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 692px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/d105ccc5353d3e662fcd03592ef4a609/0c96c/fragile.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 66.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIFA//EABUBAQEAAAAAAAAAAAAAAAAAAAID/9oADAMBAAIQAxAAAAHVJqzdQnDH/8QAGRAAAwEBAQAAAAAAAAAAAAAAAQIDABEh/9oACAEBAAEFAklPD0N1StWwo4Aduf/EABYRAQEBAAAAAAAAAAAAAAAAAAARE//aAAgBAwEBPwGxo//EABYRAQEBAAAAAAAAAAAAAAAAAAARE//aAAgBAgEBPwGVk//EABwQAAEDBQAAAAAAAAAAAAAAAAABETESIUFCof/aAAgBAQAGPwLVS0DKYGqJ4f/EABoQAQEBAQEBAQAAAAAAAAAAAAERACExYXH/2gAIAQEAAT8hcX6PNdCC8ykC6REXPZoipze0H9z/2gAMAwEAAgADAAAAEOPf/8QAFxEBAQEBAAAAAAAAAAAAAAAAAQARIf/aAAgBAwEBPxDHUkv/xAAYEQEBAAMAAAAAAAAAAAAAAAABABEhMf/aAAgBAgEBPxBWkLHb/8QAHBABAAICAwEAAAAAAAAAAAAAAQARITFBUaFx/9oACAEBAAE/EGlqbTJ9Zz3q+MfI1ohsbjs6FBCeyr+0BsDqICt2Cz//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image courtesy of Wikimedia.org&quot;
        title=&quot;&quot;
        src=&quot;/static/d105ccc5353d3e662fcd03592ef4a609/0c96c/fragile.jpg&quot;
        srcset=&quot;/static/d105ccc5353d3e662fcd03592ef4a609/863e1/fragile.jpg 225w,
/static/d105ccc5353d3e662fcd03592ef4a609/20e5d/fragile.jpg 450w,
/static/d105ccc5353d3e662fcd03592ef4a609/0c96c/fragile.jpg 692w&quot;
        sizes=&quot;(max-width: 692px) 100vw, 692px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Unmaintained and unsupported software degrades when exposed to the
stressors of time and use.&lt;/p&gt;
&lt;p&gt;The more software you install on your computer, the higher the chance
that your machine will eventually become slow and prone to crashes and
bugs.&lt;/p&gt;
&lt;p&gt;The word “bitrot” is sometimes used to refer to the gradual
degradation of a software program over time and is related to the idea
of &lt;a href=&quot;http://stackoverflow.com/questions/510412/what-is-the-computer-science-definition-of-entropy&quot;&gt;entropy&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Large software systems that are composed of multiple interacting
subsystems, are especially vulnerable to bitrot, due to the fact that a
given subsystem cannot anticipate all the bugs or changes that might be
introduced to other subsystems over time.&lt;/p&gt;
&lt;p&gt;The more a piece of software is used, the more variance there is in how
it’s being used. For example in the order, type and amount of inputs it
receives as well as in the hardware its being installed on.&lt;/p&gt;
&lt;p&gt;Lets assume that a very specific interaction with the software, which
the programmer never foresaw, will cause the software program to crash
and become permanently degraded.&lt;/p&gt;
&lt;p&gt;Given enough time, someone will eventually interact with the software in
this specific way, thereby permanently degrading the functionality of
the software program (for example due to data corruption).&lt;/p&gt;
&lt;h2&gt;Are software businesses also fragile?&lt;/h2&gt;
&lt;p&gt;Businesses are generally fragile. They require a certain level of
stability to operate and are sensitive to volatility (like regulatory
changes, lawsuites or changing consumer tastes).&lt;/p&gt;
&lt;p&gt;An antifragile software business however would be one that does well
whenever some metric related to the software experiences increased
volatility.&lt;/p&gt;
&lt;p&gt;Remember:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Something that’s antifragile wants more volatility, because the benefit from increased volatility outweighs the harm.&lt;/li&gt;
&lt;li&gt;Similarly, you are fragile to a specific source of volatility when the potential downsides outweigh any upsides.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, let’s take “number of security flaws” as the metric.&lt;/p&gt;
&lt;p&gt;The fortunes of a company that does security audits would improve every
time there is a publicised security flaw in the software itself, or the
software is compromized by an attacker.&lt;/p&gt;
&lt;p&gt;They would therefore be antifragile to the “bad news” of exposed security flaws.&lt;/p&gt;
&lt;p&gt;Perhaps with an upper bound. If there are too many security flaws, the
reputation of the software itself might suffer irrevocably, and with it
that of the company.&lt;/p&gt;
&lt;p&gt;This illustrates the point that antifragile systems can handle
volatility and stressors up to a point. Given enough volatility and
stress, the entire planet can die out.&lt;/p&gt;
&lt;p&gt;Conversely, a company whose business model depends on the software being
stable, and on attacks not happening, would be fragile to the software
having security flaws.&lt;/p&gt;
&lt;h2&gt;A community of fragile members can itself be antifragile&lt;/h2&gt;
&lt;p&gt;So, as mentioned earlier, an ecosystem can be antifragile, even if the
individual units that make up that system are fragile.&lt;/p&gt;
&lt;p&gt;It is however important that the units themselves are relatively
redundant and that the fragility is not systemic inside the entire
ecosystem.&lt;/p&gt;
&lt;p&gt;To put it in more technical terms, units inside the system need to be
“hot-swappable” and their interactions with one another should be
“loosely coupled”. This is necessary to prevent complex and hard
dependencies within the system, which in the case of breakdown of one
unit would cause cascading failures and damage rippling through the
entire system.&lt;/p&gt;
&lt;h2&gt;Antifragile software ecosystems&lt;/h2&gt;
&lt;p&gt;So, we now get to the crux of this article.&lt;/p&gt;
&lt;p&gt;Software itself might be fragile, as well as businesses built around
that software, but the larger ecosystem that encompasses the software
and businesses, can be antifragile.&lt;/p&gt;
&lt;p&gt;A software ecosystem that is distributed over many small and relatively
self-contained businesses, each providing services around a common
shared resource of Free and Open Source software (FOSS), coupled with a
low barrier to entry for new businesses, is antifragile.&lt;/p&gt;
&lt;p&gt;Conversely, a software ecosystem that is centralized around one large
provider (often playing the role of gatekeeper or rent-seeker),
artificially restricting access to the software, attempting to stifle
any competition with its own services, is fragile and sensitive to large
negative Black Swans (difficult to predict but extreme events).&lt;/p&gt;
&lt;p&gt;I’ll elaborate on why this is by identifying the requirements for an
antifragile software ecosystem.&lt;/p&gt;
&lt;h2&gt;Requirements for an antifragile software ecosystem&lt;/h2&gt;
&lt;p&gt;&lt;strong&gt;Distributization&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Centralized systems provide a large single point of failure that
can cause the collapse of the entire ecosystem. Distributed
systems can take shocks much better and are able to route around
failures and breakdowns.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Redundancy&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;When one unit breaks down, others need to be able to pick up the
slack. For that to happen, they need to collectively be able to
perform the functions of the defunct one. For example, if a
software community relied solely on one unit in that community
for supplying hosting services, then the entire community would
break down if that one unit collapsed.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Optionality&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The individual members in an antifragile ecosystem need to be
able to modify and adapt.&lt;/p&gt;
&lt;p&gt;For a software ecosystem, this means the ability to modify and
adapt the software itself. Only through being able to modify the
software in a distributed, bottom-up way, can the ecosystem
withstand stressors in an antifragile way, by making use of
&lt;em&gt;optionality&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Optionality&lt;/em&gt; refers to having the &lt;em&gt;option&lt;/em&gt; to take (or do)
something or not. As mentioned earlier, it’s how evolution is
able to “design” extremely sophisticated organisms, by keeping
the “good” ones and discarding the bad ones, and it applies to
software ecosystems as well.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right img--transparent&quot; style=&quot;width: 18em&quot;&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 215px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/3622638edeb2be5a0d1780375ad92413/2eb24/plone-logo-56.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 26.046511627906977%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAFCAYAAABFA8wzAAAACXBIWXMAAAsTAAALEwEAmpwYAAABOklEQVR42lWQO0sDQRSFjwbBQi2sFDQQfCCCjYKCGGz8D9GAjRDFIiCI2CiTndld3YAxLD5QLEQtQgqxVPeZrKz+C3+Knt0IwQuHYWbuPfe7F9DdRUjvCdK/gu5ZkO46khDBAKSzBeVtQrXGYbiz6EQP/kf33vzJAMqvUQWa3kF8DdHYht4ahRlPwoxsqGADRvueKmH7pg8yLOI0yjJvARWnAPHdD81fYs08hDMNVD9rqbsR5qF5j6jGZVjxKglHWPRM7UNz99iwiApppX9IAAkjOmOzI9ZJTnXJ6RpQbzkSeud/hNewXgZ5XnQJ23UI0cucCejBMc9dqkzTE94PYH3kSWtDc+r02IGIh7mrZIf+A3XLRzMdI90hP2U419lNM0OaFVKPpaTidQbyfYojZrnfHJssQzlrSe4vEimKlXylgXQAAAAASUVORK5CYII=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Plone Logo&quot;
        title=&quot;&quot;
        src=&quot;/static/3622638edeb2be5a0d1780375ad92413/2eb24/plone-logo-56.png&quot;
        srcset=&quot;/static/3622638edeb2be5a0d1780375ad92413/2eb24/plone-logo-56.png 215w&quot;
        sizes=&quot;(max-width: 215px) 100vw, 215px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;For example, in the &lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt; CMS (content
management sytem) community, add-on modules are developed in a
redundant and distributed way. There are multiple blog add-ons,
commenting add-ons, newsletter add-ons and so on. Through a
process of optionality and selection, the good ones rise to the
top while the weaker ones are eventually discarded.&lt;/p&gt;
&lt;h2&gt;Why the requirement for Free and Open Source software?&lt;/h2&gt;
&lt;p&gt;FOSS facilitates all three of the above requirements. Communities and
ecosystems that develop around FOSS are by nature distributed, redundant
and provide optionality.&lt;/p&gt;
&lt;p&gt;Distributization and redundancy come from the lack of gatekeepers,
“rights-holders” and rent-seekers. Anyone can start using FOSS and
selling services around it from anywhere in the world. No license,
special qualification or permission required.&lt;/p&gt;
&lt;p&gt;Optionality comes from the fact that anyone can do trial-and-error
tinkering with the software and keep their improvements. They can also
choose the best or most appropriate changes and modifications made by
other people.&lt;/p&gt;
&lt;p&gt;Without optionality a software ecosystem will not be antifragile, and
without FOSS, a software ecosystem will not have optionality.&lt;/p&gt;
&lt;p&gt;Additionally, software that is
&lt;a href=&quot;https://www.gnu.org/philosophy/free-sw.en.html&quot;&gt;Free&lt;/a&gt; (as in Libre)
displays qualities much more akin to information than non-Free software,
which due to it’s source opacity functions more as a black-box
application. As Taleb explains in his book, information is antifragile.
You can’t easily kill it, and by trying to suppress it you have to
acknowledge its existence and refer to it.&lt;/p&gt;
&lt;p&gt;Lastly, the lower barrier to entry fosters competition.&lt;/p&gt;
&lt;p&gt;In order to differentiate themselves, individual developers or
businesses need to compete on quality and/or price. It’s survival of
the fittest, as opposed to the rent-seeking, vendor lock-in and monopoly
so often seen in proprietary software ecosystems.&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
&lt;p&gt;In the book, Taleb alludes to Silicon Valley’s &lt;q&gt;fail fast, be foolish&lt;/q&gt;
model as being antifragile as opposed to a more centralized
environment with inherent systemic risks, such as the New York banking
system (his example).&lt;/p&gt;
&lt;p&gt;Silicon Valley might provide an antifragile method for producing
businesses, but the software produced by these businesses don’t
necessarily result in antifragile ecosystems.&lt;/p&gt;
&lt;p&gt;Look at the software businesses that have arisen out of Sillicon Valley.
Facebook and Google are both large and centralized. Increasing
centralization and size results in increasing fragility of the web.&lt;/p&gt;
&lt;p&gt;If Google’s servers were to go down (or be compromized or blocked by a
government), a very large part of the web would cease to function. The
chance of Google’s servers going down are of course very small, it’s a
negative Black Swan event. Something which society nevertheless needs to
shield itself against.&lt;/p&gt;
&lt;/div&gt;
&lt;h2&gt;Antifragile against what?&lt;/h2&gt;
&lt;p&gt;Having mapped out the requirements for an antifragile software
ecosystem, it makes sense to consider the kinds of stressors such an
ecosystem will be antifragile against.&lt;/p&gt;
&lt;p&gt;This section is a bit more speculative, mostly because we cannot know
the exact nature and extend of the stressors a system will be exposed
to. Luckily we don’t need to know the stressors to be able to make use
of antifragility.&lt;/p&gt;
&lt;p&gt;It’s also important to know that stressors are information. In fact,
stressors often appear through the disclosure of “negative”
information. When negative information is revealed, it can cause shocks
to software ecosystems. The fragile ones will suffer and might even
break down, while the antifragile ones will ultimately benefit.&lt;/p&gt;
&lt;p&gt;Here are some examples of stressors a software ecosystem can be antifragile against:&lt;/p&gt;
&lt;h3&gt;Malicious Hacking (Cracking)&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 9em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 180px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 116.1111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAXABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAMEBf/EABYBAQEBAAAAAAAAAAAAAAAAAAECAP/aAAwDAQACEAMQAAAB1S1YJekkqdMB1Bj/xAAdEAACAgEFAAAAAAAAAAAAAAAAAgMRAQQSISIz/9oACAEBAAEFApWZDe9ryr4kvuaa8wjpZF5//8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAwEBPwEf/8QAFBEBAAAAAAAAAAAAAAAAAAAAIP/aAAgBAgEBPwEf/8QAHhAAAgEEAwEAAAAAAAAAAAAAAAERAhIhMRBBgbH/2gAIAQEABj8CxV5Bn4JisiO5Kr7tCnhtbEf/xAAdEAEAAwABBQAAAAAAAAAAAAABABEhEDFBUWGB/9oACAEBAAE/IahMvDvQPevMP3E2E/RGlgmwywp4ykudWFN9n//aAAwDAQACAAMAAAAQO/8AAf/EABgRAQEAAwAAAAAAAAAAAAAAAAEAEBEx/9oACAEDAQE/EBNYGe3/xAAXEQEBAQEAAAAAAAAAAAAAAAABABEx/9oACAECAQE/EEdiY5f/xAAdEAEBAAMAAgMAAAAAAAAAAAABEQAhMUFRYXGR/9oACAEBAAE/EGHHdUv4cGDyMWoBfruK50XGjslBR6TGiLhOgeP7iWhVlOF5hTJtDJ4kyoCiuvNz/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Surveillance Camera: Image courtesy of Wikimedia.org&quot;
        title=&quot;&quot;
        src=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg&quot;
        srcset=&quot;/static/63ae02b331fbf7729057cde1cfe04e8c/4ec73/Surveillance_cameras.jpg 180w&quot;
        sizes=&quot;(max-width: 180px) 100vw, 180px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;FOSS is more resistant to cracking than closed source software.
Additionally, distributed systems are much harder to target and
infect.&lt;/p&gt;
&lt;p&gt;Increased awareness and fear of cracking, makes FOSS, its
ecosystems and communities more attractive to software users
(individuals, companies, governments etc.) and therefore
antifragile to the “bad” news.&lt;/p&gt;
&lt;h3&gt;Surveillance&lt;/h3&gt;
&lt;p&gt;A big part of surveillance is actually also cracking, so the same
rules apply here.&lt;/p&gt;
&lt;p&gt;It’s much more difficult for eavesdroppers to embed backdoors in
software with freely available and visible source code.&lt;/p&gt;
&lt;p&gt;Encryption software is especially vulnerable and &lt;a href=&quot;http://www.theguardian.com/world/2013/jul/11/microsoft-nsa-collaboration-user-data&quot;&gt;can’t be trusted if its closed source&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;News of security flaws spread quickly throughout the community and
fixes are generally pushed out almost immediately. You won’t
easily have the problem of a FOSS community member privately
&lt;a href=&quot;http://gigaom.com/2013/06/14/microsoft-and-other-u-s-firms-disclose-security-flaws-to-spies-before-customers-report-claims&quot;&gt;disclosing security flaws to an intelligence agency&lt;/a&gt;
(so they might use if for surveillance) while hiding it from the
users.&lt;/p&gt;
&lt;p&gt;Again as surveillance and privacy fears increase, FOSS becomes
more attractive, making the communities and ecosystems around it more antifragile.&lt;/p&gt;
&lt;h3&gt;Negative economic circumstances&lt;/h3&gt;
&lt;p&gt;Many governments are experiencing budgetary constraints and
employing austerity. Governments are able to make &lt;a href=&quot;http://linux.slashdot.org/story/12/11/23/1732222/limux-project-has-saved-munich-10m-so-far&quot;&gt;significant savings&lt;/a&gt;
when they switch to FOSS ecosytems. Not mentioning the increased
autonomy and control of their software and resulting digital
formats.&lt;/p&gt;
&lt;h3&gt;Other stressors&lt;/h3&gt;
&lt;p&gt;There are of course many more stressors that might ultimately benefit
distributed FOSS ecosystems, for example &lt;em&gt;censorship&lt;/em&gt; and &lt;em&gt;economic
boicot&lt;/em&gt;, but for the sake of brevity I won’t go into detail for each one.&lt;/p&gt;
&lt;h2&gt;Conclusion&lt;/h2&gt;
&lt;p&gt;&lt;span class=&quot;right img-container img--transparent&quot; style=&quot;width: 6em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 80px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8f85cbf4403abd9c07f0f4e464a03b2c/81690/Bitcoin.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 98.75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAARlAAAEZQAGA43XUAAAFHElEQVR42o1VaUxUVxS+2sSW1LRVY7SNS2LaH5rWaH8YFevWKI1IpSK2IC2IgICsM1KHXakUoYKILGUTVCggDLsoy4CYQYYdYVgckH0chmEAGZDlLV+vk5hotElvcl7ueXn3O+ed833nEvL2WvLqYb6TrAyzNzib7rehJP/KZs2D69tRGrODywvZPJwgXJ0p+ol+so4YvHnmP9c150/OFl/drFaVHQPkjjwGfIHBAKBXBHS642W9Dd+dcxi3vL9QuB8lpq/OAG+DvnaWJXutSR8sMgaeunMY8WPRL2JeyGx5zUMLqCrMMVlzhue6RAz6grjFlnO8NH4H/M0/uPoeLELSfNdlTUotgeEAhuk8z4+UWaI+5SCqE75HedROSFOM0HDnKJ5XOEDXJALbf4XD1HVGXmiCAIslcW9lmuS5+sJo1S+AMoiZaXZFXfJ+lIZtRab/Jgw3haEwxhgD9SGoTjXDSIU90B2I2W5/sHMJAHuTqb65GwJj4qQHEx4gG6VphzXQxoJRXOQbbx7Eg4idaLhrBUmyKbRdMWi5L4C2JwEN+Y5oLTyNCQrI9VNQBa3vfDI3138B8YJVI0e2kLUk1Xu9z5QiEHiZwaoee6Et3RT1/5zERE8iuIkC8NpczA7ewqSC+pMFWFBloanYCeoGF7ByAV4q/IAXoWxdxgF4GhMhKYneVYnpBLDPY1lFvjV6C6zxNM8KJZF7MVj/JzCRD3H4XlTEGKJBbANMFWK8Jwkt2ceBDiF0Dc6AOpjVyE4j2GZZOXl0x0gFJg0zz0L5oZIzUJY547nEFe3ZllA2hYIfz0Ne5AE0ZRxBY561PkBvzSW0UJ9rc8ek9AzYHh9+vvUcbritUhFZ9o+L4NKge3oJGokDtDWemHr8OxRFtlA2hwH0N8c6ovXG0j2mi/Ew7RRqEvdCU2WD4XsWWGzzAif3RKxgLUtqM4wWoIvDdLsP1BJ7vKgTYkEeCHWtAKNtEfqManLsIEk9CVmuA2YHUmmQIjTm/AZ5uhH6Cn7GQrtIX89YjzUcqUowVEIdigVFAD/X6EbV4EOVEQJNs0gPyI3loPDGIXQWnEJxxG48eSAAFivRVe2L6mhDdOeYgevw4WfrnBDh+JmGFPy1pRR93sBQMDvT6ArmyXka0Qc9lW4Y74oGxnMhzbRGe7EDusppV5XplBGlqMn6FdWxu9BfeIImcZ4dumdKCb60msR7fOqpqrSgWQWxM60CzMicMCRxgm7gtj47biybNkYMlu6hzcN0Xwqkd09DfPlryOINMVFlBbR5sOXXt8L1KAkgbgfJmvuR34zMy4WY7bjATdQ60i7boiXnFKXLfqjlN1CVbg1VexTKkk8gK2gbiq9sQ0X4t+jJMaEDRMiPSawQZvfxhOUeskmvlshzyx3l2YfBKvzYGdqxaUpaZZkNpEk/UC4GozTJDH21f+ARlV5zqgla080xUE751xsCtjuIEV/+Ci7GxIe8KehYj5V/D5SaAapwBsooTtceiOEqF3Tk21CjNcyzhaLEBZqWYMxpxQBkPObymQpKH8ExIiYkcOk7Iyfi7PJrzbm0yPP5POaLOEymMVAncryKKmmU0kVH36OGAeq4aWUiJw7fDtcjJHPfvo0fvTO+Xmfqf5yYpF7c0tlWYIUZuTfPKym51THUErA4HAV1iy9flXIIwdYGarvviCP5P+tLQj70MCLHwhwMbscJP3+WJNq4GO+1no1wXjHqe3Jpkd0+Yr9nA1nxvivgX7FK0IpGEC8aAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;The Bitcoin logo&quot;
        title=&quot;&quot;
        src=&quot;/static/8f85cbf4403abd9c07f0f4e464a03b2c/81690/Bitcoin.png&quot;
        srcset=&quot;/static/8f85cbf4403abd9c07f0f4e464a03b2c/81690/Bitcoin.png 80w&quot;
        sizes=&quot;(max-width: 80px) 100vw, 80px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I’ve mapped out the requirements for a software ecosystem (and
community) to be antifragile, and have alluded to Plone as an example of
such an ecosystem.&lt;/p&gt;
&lt;p&gt;The Plone software, like other Free software (Drupal, Wordpress, Apache,
Firefox, Libre Office, GNU/Linux etc.), is a technological commons. It
belongs to humanity as a whole.&lt;/p&gt;
&lt;p&gt;Everything I wrote also applies to the ecosystems around
cryptocurrencies, like &lt;a href=&quot;http://www.bitcoin.org&quot;&gt;Bitcoin&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;There are usually vibrant communities of developers, packagers,
integrators, evangelists and users around these pieces of Free software,
and they usually conform to the requirements mentioned above. Members
are distributed all over the world, there is redundancy in development
skills and support offerings and the source code is Free (as in beer and
in speech).&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Converse.js 0.7 released: Now supports Off-the-record encryption]]></title><description><![CDATA[I’m happy to announce that the 0.7 release of
Converse.js now supports Off-the-record (OTR)
encrypted messaging. The OTR protocol not only…]]></description><link>https://opkode.com/blog/converse.js-otr-support/</link><guid isPermaLink="false">https://opkode.com/blog/converse.js-otr-support/</guid><pubDate>Sun, 10 Nov 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;I’m happy to announce that the 0.7 release of
&lt;a href=&quot;http://conversejs.org&quot;&gt;Converse.js&lt;/a&gt; now supports &lt;a href=&quot;https://otr.cypherpunks.ca/&quot;&gt;Off-the-record (OTR)&lt;/a&gt;
encrypted messaging.&lt;/p&gt;
&lt;p&gt;The OTR protocol not only &lt;strong&gt;encrypts your messages&lt;/strong&gt;, it provides ways
to &lt;strong&gt;verify the identity&lt;/strong&gt; of the person you are talking to, &lt;strong&gt;plausible
deniability&lt;/strong&gt; and &lt;strong&gt;perfect forward secrecy&lt;/strong&gt; by generating new
encryption keys for each conversation.&lt;/p&gt;
&lt;p&gt;How this works is actually fascinating. The encryption keys are
generated via a &lt;strong&gt;Diffie-Helman exchange&lt;/strong&gt;. On youtube there is a
&lt;a href=&quot;https://www.youtube.com/watch?v=YEBfamv-_dovb&quot;&gt;video with a very simple and intuitive explanation&lt;/a&gt;
on how the Diffie-Helman key exchange works. For more details, you can also read
the OTR &lt;a href=&quot;https://otr.cypherpunks.ca/Protocol-v3-4.0.0.html&quot;&gt;version 3 protocol spec&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I was able to add OTR support for converse.js by using
&lt;a href=&quot;https://twitter.com/arlolra&quot;&gt;Arlo Breault&lt;/a&gt;’s excellent
&lt;a href=&quot;https://github.com/arlolra/otr&quot;&gt;otr.js&lt;/a&gt; library, which is also used in
&lt;a href=&quot;https://crypto.cat/&quot;&gt;Cryptocat&lt;/a&gt; and
&lt;a href=&quot;https://joindiaspora.com/&quot;&gt;Diaspora&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Many thanks go out to him for this.&lt;/p&gt;
&lt;div class=&quot;chat&quot;&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;Arlo cautions that the otr.js library has not yet been properly vetted
by security researchers and shouldn’t be used in life or death situations.&lt;/p&gt;
&lt;p&gt;This word of caution applies doubly so to its integration into converse.js!&lt;/p&gt;
&lt;p&gt;I’m not a professional cryptographer and this should be seen as an experimental feature.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Caveat emptor!&lt;/em&gt;&lt;/p&gt;
&lt;/div&gt;
&lt;h3&gt;Screencast&lt;/h3&gt;
&lt;p&gt;&lt;em&gt;Note: For detailed fullscreen, make sure that video quality is set to
HD, by clicking the gear icon on the video player.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/O2THwIhloHI&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt; &lt;/iframe&gt; &lt;/div&gt;
&lt;h3&gt;On Javascript Cryptography&lt;/h3&gt;
&lt;p&gt;Implementing Cryptography in Javascript is relatively controversial and
in 2011 Matasano security wrote a scathing criticism called
&lt;a href=&quot;http://www.matasano.com/articles/javascript-cryptography/&quot;&gt;Javascript Cryptography Considered Harmful&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I read that article before I started working on OTR support for
converse.js and I’d like to go through some of its criticisms step by
step to explain how they might apply to converse.js and what I’ve done
to mitigate them.&lt;/p&gt;
&lt;p&gt;If you’re going to read on, it would make sense to go read that article
first.&lt;/p&gt;
&lt;h4&gt;Secure delivery of Javascript to browsers being a chicken-egg problem&lt;/h4&gt;
&lt;p&gt;Their criticism appears to apply to the case where developers use
Javascript cryptography to implement secure communications with a server
&lt;em&gt;instead&lt;/em&gt; of relying on a standard protocol such as SSL/TLS.&lt;/p&gt;
&lt;p&gt;The OTR crypto is not trying to compete with or replace SSL/TLS.&lt;/p&gt;
&lt;p&gt;Sending data in the clear with normal HTTP is not secure and should be
avoided. Therefore, if you are going to use OTR with converse.js, always
make sure that the site users HTTPS (i.e. SSL/TLS).&lt;/p&gt;
&lt;p&gt;Ideally you would also want a mechanism to sign the Javascript and then
verify it’s authenticity once it’s been downloaded.&lt;/p&gt;
&lt;p&gt;This can be done with code that runs in browser extensions (like
Cryptocat does), but (AFAIK) unfortunately not with browser-agnostic
javascript (like converse.js).&lt;/p&gt;
&lt;p&gt;This looks to me like the achilles heel for browser javascript crypto.&lt;/p&gt;
&lt;p&gt;Besides the webserver serving the Javascript, it’s also important that
the BOSH service you use employs SSL/TLS, as well as the XMPP server the
BOSH service connects to.&lt;/p&gt;
&lt;p&gt;The XMPP community is on a drive to secure all the major public XMPP
servers. See the &lt;a href=&quot;https://github.com/stpeter/manifesto/blob/master/manifesto.txt&quot;&gt;Manifesto&lt;/a&gt;
created by &lt;a href=&quot;https://twitter.com/stpeter&quot;&gt;Peter Saint-Andre&lt;/a&gt; and signed
by many in the XMPP community.&lt;/p&gt;
&lt;p&gt;On &lt;a href=&quot;http://xmpp.net&quot;&gt;xmpp.net&lt;/a&gt; they let you test the security of servers on the Jabber/XMPP network.&lt;/p&gt;
&lt;p&gt;Besides using javascript served via TLS, you can also download the
converse.js tarball to your computer, unpack the files and access them
directly. The &lt;strong&gt;index.html&lt;/strong&gt; page will open up a page identical to the
one on &lt;a href=&quot;http://conversejs.org&quot;&gt;conversejs.org&lt;/a&gt;.&lt;/p&gt;
&lt;h4&gt;Browser Javascript being hostile to cryptography&lt;/h4&gt;
&lt;h5&gt;The prevalence of content-controlled code.&lt;/h5&gt;
&lt;p&gt;If the website fetches javascript from thirdparty websites (for example
to serve advertisements), then you not only have to trust the server to
serve non-malicious code, but also all those 3rd party servers.&lt;/p&gt;
&lt;p&gt;The solution is to not use such a site for secure communications. Clear
your cache regularly, Use hosts you trust, or as I’ve mentioned above,
bypass the webserver entirely by using converse.js from your own
filesystem.&lt;/p&gt;
&lt;h5&gt;The malleability of the Javascript runtime.&lt;/h5&gt;
&lt;p&gt;Javascript is indeed very malleable. Methods and attributes on objects
can be replaced during run-time (see &lt;a href=&quot;https://en.wikipedia.org/wiki/Duck_typing&quot;&gt;Duck
Typing&lt;/a&gt; and &lt;a href=&quot;https://en.wikipedia.org/wiki/Monkey_patch&quot;&gt;Monkey
Patching&lt;/a&gt;),&lt;/p&gt;
&lt;p&gt;This makes it easy to inject malicious code into Javascript.&lt;/p&gt;
&lt;p&gt;However, in order to do this, the attacker’s code needs access to those
Javascript objects, and fortunately Javascript provides a way of hiding
sensitive objects inside
&lt;a href=&quot;http://stackoverflow.com/questions/111102/how-do-javascript-closures-work&quot;&gt;closures&lt;/a&gt;,
thereby preventing an attacker from accessing and manipulating them.&lt;/p&gt;
&lt;p&gt;Simply put, a closure defines a limited scope for objects, variables and
functions which when used correctly, cannot be accessed from any other
Javascript code.&lt;/p&gt;
&lt;p&gt;Any variables, objects or functions defined locally inside another
(parent) function (with the &lt;code class=&quot;language-text&quot;&gt;var&lt;/code&gt;) keyword, are not accessible outside
of that parent function.&lt;/p&gt;
&lt;p&gt;If the parent functions is anonoymous (is not referenced anywhere) or
the child function’s runtime outlives the parent’s, you have a
private, enclosed scope with data that cannot be accessed from outside
that scope.&lt;/p&gt;
&lt;p&gt;All the data in converse.js is encapsulated inside such closure.&lt;/p&gt;
&lt;h5&gt;The lack of systems programming primitives needed to implement crypto.&lt;/h5&gt;
&lt;p&gt;Matasano claims that &lt;strong&gt;Javascript lacks a secure random number generator RNG&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;Without having authoritative knowledge on whether their claim is valid,
I’ll refer you to this &lt;a href=&quot;http://log.nadim.cc/?p=33&quot;&gt;blog post by Nadim Kobeissi&lt;/a&gt;
(author of Cryptocat), where he claims:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;This is in fact not the case.&lt;/em&gt; &lt;code class=&quot;language-text&quot;&gt;window.crypto.getRandomValues()&lt;/code&gt; &lt;em&gt;is
a secure random number generator available in JavaScript, and
supported by major web browsers.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;His blog post is well worth reading, and he also addresses some other
criticisms for which I didn’t have anything to add.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;OTR encryption in converse.js provides increased security and privacy
for your chats. Messages are encrypted and not logged or cached&lt;/p&gt;
&lt;p&gt;Any Jabber/XMPP services that snoop on your communications by logging
your messages (like for example Facebook does) will only have access to
the encrypted ciphertext, making it useless for surveillance or
exploitation.&lt;/p&gt;
&lt;h4&gt;Features coming future releases&lt;/h4&gt;
&lt;p&gt;The current implementation of OTR doesn’t have any encryption policy
support. With that, I mean the ability to set a policy such as &lt;em&gt;Always
encrypt messages&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Currently you need to always manually enable encryption.&lt;/p&gt;
&lt;h4&gt;Distributed services and self-hosting&lt;/h4&gt;
&lt;p&gt;There are more and more Free and Open Source (FOSS) self-hosted
web-applications becoming available as alternatives to so-called
centralized “cloud” solutions.&lt;/p&gt;
&lt;p&gt;See for example &lt;a href=&quot;http://www.roundcube.net&quot;&gt;roundcube&lt;/a&gt;,
&lt;a href=&quot;http://kolab.org&quot;&gt;kolab&lt;/a&gt;, &lt;a href=&quot;https://www.owncloud.org&quot;&gt;ownCloud&lt;/a&gt;,
&lt;a href=&quot;http://mailpile.is&quot;&gt;MailPile&lt;/a&gt;, &lt;a href=&quot;www.friendica.com&quot;&gt;friendica&lt;/a&gt; and
&lt;a href=&quot;http://www.buddycloud.com&quot;&gt;buddycloud&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Converse.js can be integrated into any of these applications, and since
you should ideally host them yourself, you’ll have more control on what
Javascript is actually being served.&lt;/p&gt;
&lt;h4&gt;Feedback, patches, donations&lt;/h4&gt;
&lt;p&gt;All of the work I did on OTR integration was in my free time and free of
charge. A gift and my personal contribution towards the movement for
providing free communication solutions that are not founded upon
surveillance and commercial exploitation of personal data.&lt;/p&gt;
&lt;p&gt;All the code is open source and contributions are always welcome, be it
in audits, features, bugfixes, documentation, words of encouragement or
tips.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Converse.js: XMPP instant messaging with Javascript]]></title><description><![CDATA[It is now possible to use converse.js, the Javascript from
collective.xmpp.chat, in a standalone way, to communicate with any
public Jabber…]]></description><link>https://opkode.com/blog/converse.js-xmpp-instant-messaging-with-javascript/</link><guid isPermaLink="false">https://opkode.com/blog/converse.js-xmpp-instant-messaging-with-javascript/</guid><pubDate>Sat, 02 Mar 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;It is now possible to use converse.js, the Javascript from
collective.xmpp.chat, in a standalone way, to communicate with any
public Jabber account.&lt;/p&gt;
&lt;p&gt;Lately I’ve been spending time refactoring
&lt;a href=&quot;http://conversejs.org&quot;&gt;converse.js&lt;/a&gt; the Javascript library used by
&lt;a href=&quot;https://pypi.python.org/pypi/collective.xmpp.chat&quot;&gt;collective.xmpp.chat&lt;/a&gt;
the instant messaging add-on for the &lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt; CMS. My
goal is to make it usable on it’s own, requiring nothing else except an
&lt;a href=&quot;http://xmpp.org&quot;&gt;XMPP&lt;/a&gt; server to communicate with.&lt;/p&gt;
&lt;p&gt;This would enable any website owner to add instant messaging
functionality to their website, and due to the federated nature of XMPP,
users could chat to any other public XMPP account (once they have been
accepted as a contact).&lt;/p&gt;
&lt;p&gt;One thing that previously prevented you from using converse.js on its
own, was the fact that it made XHR calls to the Plone backend to fetch
user data. To fix this, I added vCard support, to converse.js but also
to Plone by adding it to
&lt;a href=&quot;https://pypi.python.org/pypi/collective.xmpp.core&quot;&gt;collective.xmpp.core&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Last week I reached a significant milestone on the path to this goal,
and I’d like to take a moment and share with you.&lt;/p&gt;
&lt;p&gt;It is now possible to use converse.js (in a static HTML page) to
communicate with Jabber accounts on any public server.&lt;/p&gt;
&lt;p&gt;In the demo below, I illustrate this by chatting to a Google user and to
a Jabber.org user. In the converse.js page, I’m authenticated with a
&lt;a href=&quot;http://jappix.com&quot;&gt;Jappix.com&lt;/a&gt; account and I also use their &lt;a href=&quot;http://metajack.im/2008/09/08/which-bosh-server-do-you-need/&quot;&gt;connection
manager&lt;/a&gt;
to connect to their XMPP server. If you’re doing XMPP via HTTP (i.e in
the browser), you’ll need a connection manager as a bridge to your
intended XMPP server. Thanks a lot to the Jappix guys for making their
connection manager public!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Note: For detailed fullscreen, make sure that video quality is set to
HD, by clicking the gear icon on the video player.&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/kJr9vwRdvFY&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt; &lt;/iframe&gt; &lt;/div&gt;
&lt;p&gt;If you are interested in the project, please contribute by forking the &lt;a href=&quot;https://github.com/jcbrand/converse.js&quot;&gt;code on github&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Thanks a lot to &lt;a href=&quot;https://github.com/alecghica&quot;&gt;Alec Ghica&lt;/a&gt; and &lt;a href=&quot;https://github.com/ichim-david&quot;&gt;David Ichim&lt;/a&gt; from &lt;a href=&quot;http://www.eaudeweb.ro&quot;&gt;Eau de Web&lt;/a&gt;
who’ve made various improvements to both collective.xmpp.chat and converse.js over the past months.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Report on the Beer and Wine Sprint in Cape Town]]></title><description><![CDATA[The Beer and Wine sprint wrapped
up on Sunday and it’s now a good time to report on what was South
Africa’s first ever core Plone sprint…]]></description><link>https://opkode.com/blog/report-on-the-cape-town-leg-of-the-beer-wine-sprint/</link><guid isPermaLink="false">https://opkode.com/blog/report-on-the-cape-town-leg-of-the-beer-wine-sprint/</guid><pubDate>Tue, 29 Jan 2013 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The &lt;a href=&quot;http://plone.org/events/community/beer-and-wine-sprint&quot;&gt;Beer and Wine sprint&lt;/a&gt; wrapped
up on Sunday and it’s now a good time to report on what was South
Africa’s first ever core Plone sprint. This was a joint sprint between
Cape Town and Munich, which in hindsight, was a very good idea. The two
groups of sprinters had daily meetings via Google hangouts, and the
structure and support we received from Munich helped a lot. Connecting
with the sprinters on another continent brought home the point that we
are a global community and that no core Plone work is done in
isolation. The daily hangouts also motivated us to get cracking so that
we could have something to report on!&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 15em&quot;&gt; &lt;img src=&quot;/da87f86c5e8fe6b3ccc750d1045d5c2e/209_4385.jpg&quot; alt=&quot;image&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;South Africa is geographically isolated from the places where most Plone
development takes place (notably Europe and North America) , which
results in the local Plone community not getting as much exposure to
sprints and community events as would have been possible otherwise. The
goal of this sprint was to help change that, and to provide an
opportunity for us to contribute back to the Plone community from which
we’ve received so much.&lt;/p&gt;
&lt;p&gt;Most of the people who attended the sprint were first-timers, and it was
a joy to see the enthusiasm with which people started working. Eric
Steele and David Glick flew down to join us here at the tip of Africa,
and provided much needed experience and support.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/171b47cd4024809258206fca0eeddb36/209_4389.jpg&quot; alt=&quot;image&quot;&gt;&lt;/p&gt;
&lt;p&gt;About 14 people met at sprint venue on Thursday morning and after
introductions and a quick hello to the Europeans via the wormhole, we
formed groups and started sprinting.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 15em&quot;&gt; &lt;img src=&quot;/dffd62c969a76520ff4ebdb068bb1cfc/209_4380.jpg&quot; alt=&quot;image&quot;&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Mike Metcalfe and Campbell Mckellar-Bassset (rockfruit) started working
on porting CMFPlone tests from Products.PloneTestCase to
plone.app.testing. They kept at it with dogged determination for the
next four days of the sprint and made good progress. Izak Burger and
Jurgen Blignaut tackled some TinyMCE bugs, while Rudi Ackhurst, Witek,
Johan Beyers and myself started working on &lt;a href=&quot;https://dev.plone.org/ticket/13260&quot;&gt;Plip #13260&lt;/a&gt;. We did this via Dojo
sessions, which we held for most of the sprint. Other people did
tutorials and proofreading of documentation.&lt;/p&gt;
&lt;p&gt;It appears as if the sprinting bug has bitten at least some of the
people who attended, and there’s already been talk of doing this again
some time. I personally had an amazing experience and learned a lot
while organising this event.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;left img-container&quot; style=&quot;width: 25em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 400px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/68dd2bb458ed295a4766e3fea9f81f8a/066f9/8415489149_4d6343914c.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwAAAwEAAAAAAAAAAAAAAAAAAAIEA//EABYBAQEBAAAAAAAAAAAAAAAAAAEAAv/aAAwDAQACEAMQAAABbFZ8tow3/8QAGRABAQEAAwAAAAAAAAAAAAAAAgEEAxEj/9oACAEBAAEFApSSXDRqPRRsQ88sd4f/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/AT//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/AT//xAAgEAACAAQHAAAAAAAAAAAAAAAAAQIDESESMUFRYXKR/9oACAEBAAY/AoOpV67F5Pglhy5HEWVT/8QAHBAAAgIDAQEAAAAAAAAAAAAAAREAITFRYYHR/9oACAEBAAE/IcSXp2HoWATKn2EXTBFY0PUGlZCH2CFZ7U//2gAMAwEAAgADAAAAENvP/8QAFxEAAwEAAAAAAAAAAAAAAAAAAAEhMf/aAAgBAwEBPxBTUQ//xAAXEQADAQAAAAAAAAAAAAAAAAAAASEx/9oACAECAQE/ENcZT//EABsQAQEBAQADAQAAAAAAAAAAAAERIQAxQWGh/9oACAEBAAE/ELUQ4MNbL0AbNoALQ/eFqRgqic7Rs7rU7DdfzpDW4MAlU98xCbBmPGd//9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;image&quot;
        title=&quot;&quot;
        src=&quot;/static/68dd2bb458ed295a4766e3fea9f81f8a/066f9/8415489149_4d6343914c.jpg&quot;
        srcset=&quot;/static/68dd2bb458ed295a4766e3fea9f81f8a/863e1/8415489149_4d6343914c.jpg 225w,
/static/68dd2bb458ed295a4766e3fea9f81f8a/066f9/8415489149_4d6343914c.jpg 400w&quot;
        sizes=&quot;(max-width: 400px) 100vw, 400px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;To the &lt;em&gt;bittereinders&lt;/em&gt; who sprinted every single day (Thursday to
Sunday), thanks for your energy and support! This would have not been
possible without you. We laid a solid foundation for future core Plone
contributions from our local group.&lt;/p&gt;
&lt;p&gt;Lastly, thanks a million to everyone involved in making this sprint a
reality, Eric, David and all the people who attended, our sponsors the
Praekelt and Plone Foundations, the guys in Munich and all those who
helped with support and advice. And thanks to Liz Leddy who planted the
initial seed in my head that this was not only possible, but a actually
great idea!&lt;/p&gt;
&lt;p&gt;&lt;em&gt;P.S Credit for 3 of the photos goes to&lt;/em&gt; &lt;a href=&quot;http://www.flickr.com/photos/davisagli/&quot;&gt;David Glick&lt;/a&gt;&lt;/p&gt;
&lt;br/&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/82da67cd65015087b559d3b7a64c4660/6aca1/8416589378_ffb70c74dc_c.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 67.11111111111111%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAANABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAAAAf/aAAwDAQACEAMQAAABdoSibIuR/8QAHRAAAgIBBQAAAAAAAAAAAAAAAQIDBAAREhMUIv/aAAgBAQABBQI2Du7TKIbHIkj+1YHIRpH/AP/EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAMAAwEAAAAAAAAAAAAAAAABEQISIjH/2gAIAQEABj8CyXkLCwfJNRH/xAAZEAEBAQEBAQAAAAAAAAAAAAABEQAhQWH/2gAIAQEAAT8h5gYeQfe6k47MAqGujzL7cJzf/9oADAMBAAIAAwAAABAT/wD/xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAdEAEBAAIDAAMAAAAAAAAAAAABEQAhMUFRYcHw/9oACAEBAAE/ENGhhzV1efm5QGC9v1nGDegt/XG8ZXfmC0CiOl8waoRdKbuf/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;8416589378 ffb70c74dc c&quot;
        title=&quot;&quot;
        src=&quot;/static/82da67cd65015087b559d3b7a64c4660/6aca1/8416589378_ffb70c74dc_c.jpg&quot;
        srcset=&quot;/static/82da67cd65015087b559d3b7a64c4660/863e1/8416589378_ffb70c74dc_c.jpg 225w,
/static/82da67cd65015087b559d3b7a64c4660/20e5d/8416589378_ffb70c74dc_c.jpg 450w,
/static/82da67cd65015087b559d3b7a64c4660/6aca1/8416589378_ffb70c74dc_c.jpg 650w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Slides and Video for my talk on XMPP+Plone at Plone Conf 2012]]></title><description><![CDATA[The video of the talk I gave at in Arnhem at the 2012 Plone Conf has
been uploaded to Youtube. Check it out if you are interested in…]]></description><link>https://opkode.com/blog/slides-and-video-for-my-talk-on-xmpp-plone-at-plone-conf-2012/</link><guid isPermaLink="false">https://opkode.com/blog/slides-and-video-for-my-talk-on-xmpp-plone-at-plone-conf-2012/</guid><pubDate>Fri, 02 Nov 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The video of the talk I gave at in Arnhem at the 2012 Plone Conf has
been uploaded to Youtube. Check it out if you are interested in
integrating XMPP with Plone.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Thanks a lot to the person who uploaded this video!&lt;/strong&gt; After seeing
Cillian de Roiste spending much of his free time uploading the
&lt;a href=&quot;http://www.youtube.com/results?search_query=Plone+Konferenz+M%C3%BCnchen+2012&amp;#x26;oq=Plone+Konferenz+M%C3%BCnchen+2012&amp;#x26;gs_l=youtube.3..33i21.3549.6563.0.6845.7.7.0.0.0.0.692.1224.2j2j1j5-1.6.0...0.0...1ac.1.uWw0vLyeGX4&quot;&gt;videos of the Munich Plone Konf&lt;/a&gt;,
I realise how much effort this is!&lt;/p&gt;
&lt;h2&gt;Follow-up info on XMPP-stuff after the conf&lt;/h2&gt;
&lt;p&gt;In the talk, I mention collaborative editing and showed demos of it
(with TinyMCE). Unfortunately soon afterwards I came upon a significant
flaw in the current approach. If you are interested in the collaborative
editing possibilities for Plone, please read &lt;a href=&quot;../problems-with-collaborative-editing-of-html.html&quot;&gt;Collaborative editing of
HTML with TinyMCE not going to happen
soon&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Also since this talk, I’ve been quite busy improving
&lt;a href=&quot;http://github.com/collective/collective.xmpp.chat&quot;&gt;collective.xmpp.chat&lt;/a&gt;
to get it production ready. I’ve made an &lt;a href=&quot;http://pypi.python.org/pypi/collective.xmpp.chat/0.1&quot;&gt;initial release to
Pypi&lt;/a&gt;, which was
actually supposed to be a 0.1 &lt;strong&gt;alpha&lt;/strong&gt; release (but which I messed up
somehow). Please consider collective.xmpp.chat to still be alpha
software and not yet production ready! The most notable issue at the
moment is poor support for having multiple tabs open. I’m aware of this
and will work on a solution soon. &lt;strong&gt;Update&lt;/strong&gt;: Fixed in the latest
release: &lt;a href=&quot;http://plone.org/products/collective.xmpp.chat/releases/0.2a2&quot;&gt;&lt;a href=&quot;http://plone.org/products/collective.xmpp.chat/releases/0.2a2&quot;&gt;http://plone.org/products/collective.xmpp.chat/releases/0.2a2&lt;/a&gt;&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I’m also in the process of extracting the Javascript files from
collective.xmpp.chat and putting them in their own repository, called
&lt;a href=&quot;http://github.com/jcbrand/converse.js&quot;&gt;converse.js&lt;/a&gt;. The idea behind
this is to completely decouple the JS from Plone and in doing so allow
one to implement/deploy something like collective.xmpp.chat for other
non-Plone backends.&lt;/p&gt;
&lt;p&gt;That’s it for now. Thanks for the support and encouragement from
everyone in the Plone community. You guys rock!&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;https://www.slideshare.net/jcbrand/realtime-collaborative-applications-in-plone&quot;&gt;Real-time, collaborative applications in Plone&lt;/a&gt; by &lt;a href=&quot;http://www.slideshare.net/jcbrand&quot;&gt;jcbrand&lt;/a&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 81.5126050420168%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;//www.slideshare.net/slideshow/embed_code/key/NUGD58O1NXIo4E&quot; frameborder=&quot;0&quot; marginwidth=&quot;0&quot; marginheight=&quot;0&quot; scrolling=&quot;no&quot; style=&quot;border:1px solid #CCC; border-width:1px; margin-bottom:5px; max-width: 100%; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot; allowfullscreen=&quot;&quot;&gt; &lt;/iframe&gt; &lt;div style=&quot;margin-bottom:5px&quot;&gt; &lt;strong&gt;&lt;a href=&quot;//www.slideshare.net/jcbrand/realtime-collaborative-applications-in-plone&quot; title=&quot;Real-time, collaborative applications in Plone&quot; target=&quot;_blank&quot;&gt;Real-time, collaborative applications in Plone&lt;/a&gt; &lt;/strong&gt; from &lt;strong&gt;&lt;a href=&quot;https://www.slideshare.net/jcbrand&quot; target=&quot;_blank&quot;&gt;jcbrand&lt;/a&gt;&lt;/strong&gt; &lt;/div&gt; &lt;/div&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/7m7qP\_mSQXc&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt; &lt;/iframe&gt; &lt;/div&gt;</content:encoded></item><item><title><![CDATA[Collaborative editing of HTML with TinyMCE not going to happen soon]]></title><description><![CDATA[TL:DR: Collaborative editing doesn’t work well with XML/HTML. Right
now, the solution seems to be to use Markdown instead. During my talk on…]]></description><link>https://opkode.com/blog/problems-with-collaborative-editing-of-html/</link><guid isPermaLink="false">https://opkode.com/blog/problems-with-collaborative-editing-of-html/</guid><pubDate>Mon, 22 Oct 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;em&gt;TL:DR: Collaborative editing doesn’t work well with XML/HTML. Right
now, the solution seems to be to use Markdown instead.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;During &lt;a href=&quot;http://www.ploneconf.org/the-event/talks/conference-talks/instant-messaging-in-plone&quot;&gt;my talk on XMPP applications in Plone&lt;/a&gt;,
someone asked whether I was aware of any issues with regards to
collaborative editing in TinyMCE.&lt;/p&gt;
&lt;p&gt;I don’t exactly remember my reply, but it came down to “no”, I
wasn’t aware of any problems with it. Just the next day however, at the
sprints, I encountered a fundamental problem with regards to
collaborative editing of Rich Text through TinyMCE.&lt;/p&gt;
&lt;p&gt;The problem lies in the fact that the
&lt;a href=&quot;http://code.google.com/p/google-diff-match-patch/&quot;&gt;Diff-Match-Patch&lt;/a&gt; is
meant for &lt;strong&gt;plain text only&lt;/strong&gt;. It has no concept of structured content
such as the a DOM-tree and can therefore create problems when one tries
to patch HTML content. It seems that mainly two things can happen.
Firstly, because your HTML nodes are not atomic, they can be broken by
the patching algorithm inserting text inside them. Secondly, the
patching can result in HTML nodes appearing in the wrong order. (See
what the author of Diff-Match-Patch had to say about it on the &lt;a href=&quot;http://code.google.com/p/google-diff-match-patch/wiki/Plaintext&quot;&gt;project
page&lt;/a&gt;
and his excellent &lt;a href=&quot;http://stackoverflow.com/questions/2430083/can-i-use-a-plaintext-diff-algorithm-for-tracking-xml-changes&quot;&gt;explanation on
stackoverflow&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Ideally one should use a patching algorithm that is tree-based and which
will maintain the integrity of the DOM-tree. When using the plain text
algorithm, there are however two approaches to try and mitigate the
above issues.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Strip all HTML tags, diff-match-patch the resulting plain text and
re-insert the original tags.&lt;/li&gt;
&lt;li&gt;Replace all tags with Unicode chars outside of the used range
(thereby making them atomic), apply diff-match-patch and then
restore all tags.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The problem with the first approach is that your markup is now
immutable. So any markup changes a collaborator makes (e.g bold,
italics, heading or other formatting) will be discarded. I think this is
a dealbreaker and rules out this approach.&lt;/p&gt;
&lt;p&gt;The problem with the second approach is that even though your HTML nodes
are now atomic, they might still appear in the wrong order.&lt;/p&gt;
&lt;p&gt;Because of this, I think trying to do collaborative editing via an
HTML-based Wysiwyg editor is not the way to go. Instead, a
&lt;a href=&quot;http://en.wikipedia.org/wiki/Markdown&quot;&gt;Markdown&lt;/a&gt; editor (such as &lt;a href=&quot;http://epiceditor.com/&quot;&gt;Epic
Editor&lt;/a&gt;) seems to be the way to go. Markdown is
plain text, and therefore doesn’t suffer from the problems mentioned above.&lt;/p&gt;
&lt;p&gt;I think I have created the impression at the Plone conf that
production-ready collaborative editing via TinyMCE will soon be a
reality, and for that I would like to apologize.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Instant Messaging for Plone with javascript and XMPP]]></title><description><![CDATA[Late last year Yiorgis Gozadinos who at the time
was still working for Jarn, released a video showing his work in
integrating XMPP (eXtended…]]></description><link>https://opkode.com/blog/instant-messaging-for-plone-with-javascript-and-xmpp/</link><guid isPermaLink="false">https://opkode.com/blog/instant-messaging-for-plone-with-javascript-and-xmpp/</guid><pubDate>Mon, 30 Jul 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Late last year &lt;a href=&quot;http://ggozad.com/&quot;&gt;Yiorgis Gozadinos&lt;/a&gt; who at the time
was still working for Jarn, released a video showing his work in
integrating &lt;a href=&quot;http://xmpp.org&quot;&gt;XMPP&lt;/a&gt; (eXtended Messaging and Presence
Protocol) into Zope/Plone.&lt;/p&gt;
&lt;p&gt;I had some experience in creating a &lt;a href=&quot;http://plone.org/products/babble.client&quot;&gt;chat client for
Plone&lt;/a&gt; before and was inspired
by the possibility of porting it to XMPP. In the end it wasn’t so much
of a port but rather a complete rewrite.&lt;/p&gt;
&lt;p&gt;Today, I’m relieved and happy that it’s finally in a state where I can
show it to you. I’ve been spending most of my free time the last two
months
writing &lt;a href=&quot;https://github.com/collective/collective.xmpp.chat&quot;&gt;collective.xmpp.chat&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;It’s been both frustrating and fun (mostly fun) and a very
valuable learning experience. Like that one week where I rewrote the
entire codebase to make use of &lt;a href=&quot;http://backbonejs.org&quot;&gt;backbone.js&lt;/a&gt;.
Aaah, fun times.&lt;/p&gt;
&lt;h2&gt;Some features already implemented:&lt;/h2&gt;
&lt;p&gt;Single user chat Roster support (adding/removing contacts)
(&lt;a href=&quot;http://xmpp.org/extensions/xep-0144.html&quot;&gt;XEP-0144&lt;/a&gt;) Setting presence
status (online, offline, away, busy) Custom status messages Multi-user
chatrooms (&lt;a href=&quot;http://xmpp.org/extensions/xep-0045.html/&quot;&gt;XEP-0045&lt;/a&gt;) Chat
windows stay open upon page reload Offline storage of messages using
HTML5 localstorage (still needs to be secured) Message actions (/me)
Setting the topic of a chatroom (/topic)  &lt;/p&gt;
&lt;p&gt;Because almost all the code is written in Javascript
(&lt;a href=&quot;https://github.com/jcbrand/converse.js&quot;&gt;converse.js&lt;/a&gt; is about
1500 LOC), you can even stop the Zope server and still continue to
chat. Unfortunately I forgot to show this in the screencast.&lt;/p&gt;
&lt;p&gt;If anyone has any questions about the code, how to install, configure
and use it, please don’t hesitate to contact me. The add-on includes a
&lt;a href=&quot;https://github.com/collective/collective.xmpp.chat/blob/master/buildout.cfg&quot;&gt;buildout.cfg&lt;/a&gt;
file that will set up Zope/Plone, Nginx and ejabberd for you. But please
beware, the code is still in a pre-alpha state.&lt;/p&gt;
&lt;p&gt;And then lastly, I plan to give a talk at the upcoming &lt;a href=&quot;http://www.ploneconf.org/&quot;&gt;Plone Conference in Arnhem&lt;/a&gt;. This talk will focus on
collective.xmpp.chat, the underlying technologies and how to write
XMPP-enabled add-ons.&lt;/p&gt;
&lt;p&gt;If you consider this an interesting topic, please go and &lt;a href=&quot;http://www.ploneconf.org/the-event/talks/conference-talks/instant-messaging-in-plone&quot;&gt;vote for this talk&lt;/a&gt;
to ensure that it gets accepted.&lt;/p&gt;
&lt;h2&gt;Screencast&lt;/h2&gt;
&lt;div class=&quot;gatsby-resp-iframe-wrapper&quot; style=&quot;padding-bottom: 56.25%; position: relative; height: 0; overflow: hidden; margin-bottom: 1.0725rem&quot; &gt; &lt;iframe src=&quot;https://www.youtube-nocookie.com/embed/xMTOXjAoTlc&quot; frameborder=&quot;0&quot; allow=&quot;accelerometer; autoplay; encrypted-media; gyroscope; picture-in-picture&quot; allowfullscreen=&quot;&quot; style=&quot; position: absolute; top: 0; left: 0; width: 100%; height: 100%; &quot;&gt; &lt;/iframe&gt; &lt;/div&gt;
&lt;div class=&quot;note&quot;&gt;
Note: If you have trouble reading the text, click on the gear icon and set the video to High Definition.
&lt;/div&gt;</content:encoded></item><item><title><![CDATA[Plone and Dexterity: Enable behaviors per content type instance]]></title><description><![CDATA[plone.behaviors are great, but because they are stored in the FTI, they
are enabled for all instances of a content type. This blogpost will…]]></description><link>https://opkode.com/blog/plone-and-dexterity-enable-behaviors-per-content-type-instance/</link><guid isPermaLink="false">https://opkode.com/blog/plone-and-dexterity-enable-behaviors-per-content-type-instance/</guid><pubDate>Tue, 03 Jan 2012 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;plone.behaviors are great, but because they are stored in the FTI, they
are enabled for all instances of a content type. This blogpost will show
how you can enable a plone.behavior for a specific instance.&lt;/p&gt;
&lt;div class=&quot;note&quot;&gt;
Note: This blogpost assumes that you are already familiar with a lot of the
Zope/Plone programming technologies and concepts. Every time I mention a
specific add-on or technology, I&apos;ve added a link to documentation.
&lt;/div&gt;
&lt;div class=&quot;note&quot;&gt;
UPDATE: There is now a add-on for Plone based upon the approach taken in
this blog post, please see:
[collective.instancebehavior](https://pypi.python.org/pypi/collective.instancebehavior).
&lt;/div&gt;
&lt;p&gt;Behaviors, provided by the plone.behavior package, provide a very useful
way of extending the functionality of a Dexterity content type.
Unfortunately, the fact that a content type’s behaviors are stored in
its factory contents information (FTI) inside the portal_types tool,
means that they are class (or type) specific, and not instance specific.
This means that behaviors can only be enabled globally, in other words
only for all the instances of a specific type.&lt;/p&gt;
&lt;p&gt;So what can we do when we want to enable behaviors only for a specific
instance of a content type? At Syslab we for example had a client who
wanted a basic folderish Workspace content type, that can be extended
into a more featureful custom Project type.&lt;/p&gt;
&lt;p&gt;To enable per instance behaviors, we would need a way to store those
behaviors on the instance. I decided to use annotations for this
purpose. Additionally we must create our own IBehaviorAssignable adapter
that overrides the default one to not only look for an object’s FTI
registered annotations, but also look for the behaviors stored in the
current instance’s annotations.&lt;/p&gt;
&lt;p&gt;I created this adapter in a module named behavior.py:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; myproject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;config &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; INSTANCE_BEHAVIORS_KEY &lt;span class=&quot;token keyword&quot;&gt;as&lt;/span&gt; KEY
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; myproject&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;types&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;workspace &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IWorkspace
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behavior&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interfaces &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IBehavior &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt;
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; zope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;annotation &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IAnnotations
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; zope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;component &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; adapts&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; queryUtility plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dexterity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behavior
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; DexterityBehaviorAssignable


&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;DexterityInstanceBehaviorAssignable&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DexterityBehaviorAssignable&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
     &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot; Support per instance specification of plone.behavior behaviors &quot;&quot;&quot;&lt;/span&gt;
     adapts&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IWorkspace&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token builtin&quot;&gt;super&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;DexterityInstanceBehaviorAssignable&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;__init__&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        annotations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; IAnnotations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instance_behaviors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; annotations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;KEY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;enumerateBehaviors&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behaviors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;fti&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behaviors &lt;span class=&quot;token operator&quot;&gt;+&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;instance_behaviors
        &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; name &lt;span class=&quot;token keyword&quot;&gt;in&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behaviors&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
            behavior &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; queryUtility&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IBehavior&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
            &lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; behavior &lt;span class=&quot;token keyword&quot;&gt;is&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
                &lt;span class=&quot;token keyword&quot;&gt;yield&lt;/span&gt; behavior&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now register this adapter via ZCML in configure.zcml:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;adapter&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;factory&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.behavior.DexterityInstanceBehaviorAssignable&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We know what we want to use as a storing mechanism (Annotations) for per
instance behaviors, and we have a custom adapter that knows to look for
them, but we still need a way to save new behaviors to a specific
instance’s annotations.&lt;/p&gt;
&lt;p&gt;In my case, I wanted to extend the Workspace content type with a Project
behavior that provides additional fields. Refer to my blogpost on
schema-extending a dexterity type for an explanation on how to create
such a custom behavior. This was however only my specific use-case, and
any behavior can be applied in this way.&lt;/p&gt;
&lt;p&gt;To provide a mechanism for saving new per instance behaviors, I created
a browser view @@enable_project, which can be called on any Workspace
instance. When it gets called, my custom behavior (with full path
myproduct.types.project.IProject) gets saved in the annotations of the
specific Workspace.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;EnableProject&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;View&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IWorkspace&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt; grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;enable_project&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;require&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;cmf.ModifyPortalContent&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;render&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; aq_inner&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        annotations &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; IAnnotations&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        instance_behaviors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; annotations&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;get&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;KEY&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        instance_behaviors &lt;span class=&quot;token operator&quot;&gt;+=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;myprodcouct.types.project.IProject&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        annotations&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;KEY&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; instance_behaviors

        IStatusMessage&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;add&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            _&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&quot;This Workpace has now been turned into a Project.&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;u&quot;info&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;request&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;RESPONSE&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;redirect&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;/&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;join&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;context&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getPhysicalPath&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You may want to provide a UI mechanism for enabling per instance
behaviors. I decided to do this by adding a new object_buttons action
in the actions.xml Generic Setup file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;portal_actions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;meta_type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Plone Actions Tool&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;xmlns:&lt;/span&gt;i18n&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&amp;lt;http://xml.zope.org/namespaces/i18n&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;object_buttons&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;meta_type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;CMF Action Category&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;enable_project&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;meta_type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;CMF Action&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;i18n:&lt;/span&gt;domain&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;plone&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;title&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;i18n:&lt;/span&gt;translate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;Enable project&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;description&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;&lt;span class=&quot;token namespace&quot;&gt;i18n:&lt;/span&gt;translate&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;url_expr&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;string:\$&amp;lt;object_url/@@enable_project&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;available_expr&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;python:context.portal_type == &apos;myproject.types.workspace&apos; and not context.is_project() or False&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;permissions&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Modify portal content&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
                &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;visible&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;True&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
            &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;This provides a convenient way (via the actions dropdown) for the end user to turn a Workspace into a Project.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[The difference between BrowserSkins and BrowserLayers]]></title><description><![CDATA[In this blogpost I’d like to shed some light on two concepts that sound
similar and can be quite ambiguous and confusing when first…]]></description><link>https://opkode.com/blog/the-difference-between-browserlayers-and-skinlayers/</link><guid isPermaLink="false">https://opkode.com/blog/the-difference-between-browserlayers-and-skinlayers/</guid><pubDate>Fri, 08 Jul 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In this blogpost I’d like to shed some light on two concepts that sound
similar and can be quite ambiguous and confusing when first encountered.&lt;/p&gt;
&lt;p&gt;When we register certain Zope Components (via ZCML or Grok), we can
specify a &lt;em&gt;layer&lt;/em&gt; attribute for which we would provide an &lt;em&gt;Interface&lt;/em&gt;.
This will restrict these components to be available only when that
&lt;em&gt;Interface&lt;/em&gt; is provided by the &lt;em&gt;Request&lt;/em&gt; object.&lt;/p&gt;
&lt;p&gt;In ZCML it looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;browser:&lt;/span&gt;page&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;foo&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;*&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;template&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my-template.pt&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;permission&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zope.Public&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.interfaces.IMyLayer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And with Five.Grok:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;Foo&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;BrowserView&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot; &quot;&quot;&quot;&lt;/span&gt;
    grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;template&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;my-template&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;name&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;foo&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    grok&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;layer&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;interfaces&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;IMyLayer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;How would the &lt;em&gt;Request&lt;/em&gt; provide an interface? Well, with the &lt;a href=&quot;http://www.muthukadan.net/docs/zca.html&quot;&gt;Zope
Component Architecture&lt;/a&gt;, you
can make any object provide any interface, by using
the &lt;strong&gt;alsoProvides&lt;/strong&gt; method. In this way we can use interfaces as
markers, to mark or identify certain objects.&lt;/p&gt;
&lt;p&gt;In Plone this is very handy, because it allows us to only enable or
disable certain functionality, by registering it against a specific
&lt;em&gt;Interface&lt;/em&gt; and then marking the &lt;em&gt;Request&lt;/em&gt; or not. This “marking” of
the request is done when your Plone add-on product is installed or
uninstalled in the configuration panel.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;How&lt;/em&gt; this is done, depends on two different implementations, one
in &lt;a href=&quot;http://pypi.python.org/pypi/plone.theme&quot;&gt;plone.theme&lt;/a&gt; (called
&lt;em&gt;BrowserSkins)&lt;/em&gt;, and one
in &lt;a href=&quot;http://pypi.python.org/pypi/plone.browserlayer&quot;&gt;plone.browserlayer&lt;/a&gt;
(called &lt;em&gt;BrowserLayers&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Both approaches do the same thing, they mark the &lt;em&gt;Request&lt;/em&gt; with an
&lt;em&gt;Interface&lt;/em&gt;, but they way they do it differs, and that can be
bewildering to the uninitiated.
 &lt;/p&gt;
&lt;h1&gt;BrowserSkins&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;plone.theme&lt;/em&gt; provides a way mark the request with an interface when
it’s associated with a &lt;em&gt;skin&lt;/em&gt; installed in the &lt;em&gt;portal_skins&lt;/em&gt; tool.
Plone 4 comes with two &lt;em&gt;skins&lt;/em&gt;, the &lt;em&gt;Classic&lt;/em&gt; skin and the newer
&lt;em&gt;Sunburst&lt;/em&gt;. In other frameworks or environments, a &lt;em&gt;skin&lt;/em&gt; could be
called a &lt;em&gt;theme.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Lets pretend we were creating a &lt;em&gt;skin&lt;/em&gt; with a new egg product called
&lt;em&gt;collective.kickasstheme&lt;/em&gt;. If you’ve ever generated a Plone theme
package with &lt;a href=&quot;http://pypi.python.org/pypi/PasteScript&quot;&gt;PasteScript&lt;/a&gt; and
&lt;a href=&quot;http://pypi.python.org/pypi/ZopeSkel&quot;&gt;ZopeSkel&lt;/a&gt;, then you’ve now doubt
seen the following.&lt;/p&gt;
&lt;p&gt;In &lt;em&gt;collective.kickasstheme.browser.interfaces.py&lt;/em&gt; we have this
interface declared:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;theme&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interfaces &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IDefaultPloneLayer

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IThemeSpecific&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IDefaultPloneLayer&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Marker interface that defines a Zope 3 browser layer.
       If you need to register a viewlet only for the &quot;Custom Theme&quot;
       theme, this interface must be its layer (in
       kickasstheme/viewlets/configure.zcml).
    &quot;&quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Registered with this ZCML:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;interface&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.interfaces.IThemeSpecific&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;type&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zope.publisher.interfaces.browser.IBrowserSkinType&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Kickass Theme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;And then with browser resources registered against it, for example:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;browser:&lt;/span&gt;resourceDirectory&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;collective.kickasstheme.images&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;directory&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;images&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.interfaces.IThemeSpecific&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;

  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;browser:&lt;/span&gt;viewlet&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;collective.someviewlet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;manager&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;plone.app.layout.viewlets.interfaces.IPortalFooter&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;class&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.viewlets.MyViewlet&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;layer&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.interfaces.IThemeSpecific&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
      &lt;span class=&quot;token attr-name&quot;&gt;permission&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;zope2.View&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The &lt;em&gt;skin&lt;/em&gt; is installed with
&lt;a href=&quot;http://packages.python.org/Products.GenericSetup/&quot;&gt;GenericSetup&lt;/a&gt;, so we
need to inform it about it in
&lt;em&gt;collective/kickasstheme/profiles/default/skins.xml&lt;/em&gt;&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;object&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;portal_skins&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;allow_any&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;False&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;cookie_persistence&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;False&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;default_skin&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Kickass Theme&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
  &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;--&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;Here&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;comes&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;a&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;list&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;of&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;registered&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;folders&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;that&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;are&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;registered&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;in&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;portal_skins&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;--&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;&lt;em&gt;plone.theme&lt;/em&gt; registers an event subscriber (also known as an &lt;em&gt;event
listener&lt;/em&gt;) for the &lt;em&gt;IBeforeTraverseEvent&lt;/em&gt;. In this subscriber, it
queries for the &lt;em&gt;BrowserSkin&lt;/em&gt; that is installed with the current &lt;em&gt;Skin&lt;/em&gt;
in &lt;em&gt;portal_skins&lt;/em&gt; and then uses &lt;strong&gt;directlyProvides&lt;/strong&gt;, to mark
the &lt;em&gt;Request&lt;/em&gt; object with this &lt;em&gt;BrowserSkin.&lt;/em&gt; If our skin/theme
product is installed, then the &lt;em&gt;IThemeSpecific&lt;/em&gt; interface declared in
our egg &lt;em&gt;collective.kickasstheme&lt;/em&gt; will be the &lt;em&gt;BrowserLayer&lt;/em&gt; and will
mark the &lt;em&gt;Request&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;You can see the code for yourself in &lt;em&gt;plone/theme/layer.py&lt;/em&gt;
and &lt;em&gt;plone/theme/configure.zcml&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;This means that all components (such as &lt;em&gt;BrowserViews&lt;/em&gt;,
&lt;em&gt;ResourceDirectories&lt;/em&gt;, &lt;em&gt;viewlets&lt;/em&gt;, etc.) registered against our
&lt;em&gt;BrowserSkin&lt;/em&gt; will now appear. As soon as we uninstall our theme egg,
they will again disappear, because the &lt;em&gt;BrowserSkin&lt;/em&gt; is again removed.&lt;/p&gt;
&lt;h2&gt; 
&lt;strong&gt;Drawbacks&lt;/strong&gt;&lt;/h2&gt;
&lt;p&gt;&lt;em&gt;BrowserSkins&lt;/em&gt; have two major drawbacks.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;You can only have one of them active at any time. If you need more
than one &lt;em&gt;BrowserSkin&lt;/em&gt; (which is just an &lt;em&gt;Interface&lt;/em&gt;) on the
&lt;em&gt;request&lt;/em&gt; (i.e to render portlets registered against another one)
you will have to subclass that other &lt;em&gt;BrowserSkin&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;You also need to create a theme product (with a &lt;em&gt;skin&lt;/em&gt; registered in
&lt;em&gt;portal_skins&lt;/em&gt;) every time you want to create your own
&lt;em&gt;BrowserSkin&lt;/em&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, what do we do if we for example want to create a new viewlet or
portlet in a non-theme product, but don’t want it to render unless the
product is installed?
 &lt;/p&gt;
&lt;h1&gt;BrowserLayers&lt;/h1&gt;
&lt;p&gt;&lt;em&gt;plone.browserlayer&lt;/em&gt; was developed to solve this problem.&lt;/p&gt;
&lt;p&gt;So, now we can create any egg, it doesn’t have to be a theme egg, and
the declare inside it our &lt;em&gt;BrowserLayer.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;We start off by creating the marker &lt;em&gt;Interface&lt;/em&gt; that will be given to
the &lt;em&gt;layer&lt;/em&gt; attribute:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; zope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interface &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; Interface

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IMyProductLayer&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;Interface&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot;Browser layer for this particular product &quot;&quot;&quot;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Then add a &lt;em&gt;browserlayer.xml&lt;/em&gt; file to the &lt;em&gt;GenericSetup&lt;/em&gt; profile
directory, with the following:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token prolog&quot;&gt;&amp;lt;?xml version=&quot;1.0&quot;?&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;layers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
        &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;layer&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my.product&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;interface&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;my.product.interfaces.IMyProductLayer&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;layers&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;When we now install our egg in Plone’s control panel, our
&lt;em&gt;BrowserLayer&lt;/em&gt; will also added to &lt;em&gt;plone.browserlayer’s&lt;/em&gt; persistent
registry of “installed” layers and applied to the &lt;em&gt;Request&lt;/em&gt; object
during runtime.&lt;/p&gt;
&lt;p&gt;All components and resources registered against this &lt;em&gt;BrowserLayer&lt;/em&gt; will
be activated and visible. Once we uninstall our egg, they will disappear
again.&lt;/p&gt;
&lt;p&gt;  &lt;strong&gt;Benefits:&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;The benefits of using &lt;em&gt;BrowserLayers&lt;/em&gt; are basically the inverse of the
drawbacks of using &lt;em&gt;BrowserSkins&lt;/em&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;Any egg can have a dependency on &lt;em&gt;plone.browserlayers&lt;/em&gt; and create
&lt;em&gt;BrowserLayers&lt;/em&gt;, not just theme eggs.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;You can have multiple &lt;em&gt;BrowserLayers&lt;/em&gt; currently on the &lt;em&gt;Request.&lt;/em&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1&gt;Conclusion&lt;/h1&gt;
&lt;p&gt;Both &lt;em&gt;BrowserSkins&lt;/em&gt; and &lt;em&gt;BrowserLayers&lt;/em&gt; allow you to mark and unmark the
&lt;em&gt;Request&lt;/em&gt; object and thereby switch components on or off. They also
allow you to override existing components, by simply registering your
custom components against a specific &lt;em&gt;layer.&lt;/em&gt; Previously, you had to
override them in &lt;em&gt;overrides.zcml&lt;/em&gt; and this could only be done once.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;BrowserSkins&lt;/em&gt; had some drawbacks and &lt;em&gt;BrowserLayers&lt;/em&gt; where developed to
address these. That said, both are still around and both are still in
use.&lt;/p&gt;
&lt;p&gt;Lastly, please use them! It’s bad practice to register components for
Plone sites that are not tied to a &lt;em&gt;layer&lt;/em&gt;. If you do. they will be
active in the Plone site, regardless of the egg being installed or not,
potentially causing havoc when serving multiple Plone sites.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Schema-extending Dexterity content types with five.grok and plone.behavior]]></title><description><![CDATA[This is a quick blog post about using
plone.behavior to change
the schema of Plone’s
Dexterity content types.
Hopefully it’ll help people…]]></description><link>https://opkode.com/blog/schema-extending-dexterity-content-types-with-five.grok-and-plone.behavior/</link><guid isPermaLink="false">https://opkode.com/blog/schema-extending-dexterity-content-types-with-five.grok-and-plone.behavior/</guid><pubDate>Mon, 13 Jun 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a quick blog post about using
&lt;a href=&quot;http://pypi.python.org/pypi/plone.behavior&quot;&gt;plone.behavior&lt;/a&gt; to change
the schema of &lt;a href=&quot;http://plone.org&quot;&gt;Plone’s&lt;/a&gt;
&lt;a href=&quot;http://plone.org/products/dexterity&quot;&gt;Dexterity&lt;/a&gt; content types.
Hopefully it’ll help people familiar the
&lt;a href=&quot;http://plone.org/products/archetypes&quot;&gt;Archetypes&lt;/a&gt;’
&lt;a href=&quot;http://pypi.python.org/pypi/archetypes.schemaextender&quot;&gt;schema-extending&lt;/a&gt;
paradigm, to achieve the same effect with Dexterity types.&lt;/p&gt;
&lt;p&gt;Of course, Dexterity is not Archetypes, and plone.behaviors are not
schema-extenders (&lt;em&gt;well, not only&lt;/em&gt;), but sometimes you want to do the
same thing, whether you’re using Archetypes or Dexterity, and that is
extend the
&lt;a href=&quot;http://plone.org/products/dexterity/documentation/manual/developer-manual/schema-driven-types/the-schema&quot;&gt;schema&lt;/a&gt;
of an existing content type created in a different product (that you
don’t want to &lt;em&gt;or cannot&lt;/em&gt; edit) in your own product.&lt;/p&gt;
&lt;p&gt;Martin Aspeli has provided much more thorough and complete documentation
on behaviors
&lt;a href=&quot;http://plone.org/products/dexterity/documentation/manual/behaviors/referencemanual-all-pages&quot;&gt;here&lt;/a&gt;.
In short, behaviors can be seen as conditional adapters. The condition
being that the behavior must be listed in the &lt;em&gt;behaviors&lt;/em&gt; property of
the type’s FTI (&lt;em&gt;Factory Type information&lt;/em&gt;).&lt;/p&gt;
&lt;p&gt;Schema-extending in Archetypes also happened through adapters, but they
were not checked against the type’s FTI, and were thus not conditional.&lt;/p&gt;
&lt;h1&gt;Example:&lt;/h1&gt;
&lt;p&gt;Suppose we have a &lt;em&gt;Sector&lt;/em&gt; type in another package,  and that we want to
add another field &lt;em&gt;statistics_level.&lt;/em&gt; We don’t want to modify this
other package, so we’ll use &lt;em&gt;plone.behavior&lt;/em&gt; to “extend its schema”.&lt;/p&gt;
&lt;p&gt;In our own package, we create &lt;em&gt;sector.py&lt;/em&gt; and add the following code:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; zope &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; schema
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;directives &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; dexterity
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;directives &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; form
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;autoform&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interfaces &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IFormFieldProvider
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dexterity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behaviors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; MetadataBase
&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; plone&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;app&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;dexterity&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;behaviors&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;metadata
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; DCFieldProperty

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;IExtendedSector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;form&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Schema&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    &lt;span class=&quot;token triple-quoted-string string&quot;&gt;&quot;&quot;&quot; &quot;&quot;&quot;&lt;/span&gt;
    statistics_level &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; schema&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Choice&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
        title &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&quot;label_statistics_level&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&quot;Statistics Level&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        description &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; _&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;
            &lt;span class=&quot;token string&quot;&gt;&quot;help_statistics_level&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&quot;Level 1: Basic statistics. Level 2: More detailed statistics.&quot;&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        required&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token boolean&quot;&gt;True&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        vocabulary &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; SimpleVocabulary&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
            SimpleTerm&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; title&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&quot;1&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
            SimpleTerm&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;2&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; title&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&quot;2&quot;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        &lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
        default&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token number&quot;&gt;1&lt;/span&gt;
    &lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The interface &lt;em&gt;IExtendedSector&lt;/em&gt; defines the new field statistics_level
that we want to add.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;alsoProvides&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IExtendedSector&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; IFormFieldProvider&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We then mark &lt;em&gt;IExtendedSector&lt;/em&gt; with &lt;em&gt;IFormFieldProvider&lt;/em&gt; to signal that
it should be processed for form fields.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;ExtendedSector&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;MetadataBase&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    statistics_level &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; DCFieldProperty&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IExtendedSector&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;statistics_level&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next we need a class that implements the &lt;em&gt;MetadataBase&lt;/em&gt; behavior adapter
and which will act as the adapter factory.&lt;/p&gt;
&lt;p&gt;Now we need to wire this adapter in with ZCML:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;plone:&lt;/span&gt;behavior&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;title&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Extended Sector&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;description&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;Provide additional statistics_level field&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;provides&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.sector.IExtendedSector&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;factory&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.sector.ExtendedSector&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token attr-name&quot;&gt;for&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;plone.dexterity.interfaces.IDexterityContent&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly we need the &lt;em&gt;portal_types&lt;/em&gt; FTI (Factory Type Information) to be
updated with our behavior. Go the the ZMI, then &lt;em&gt;portal_types&lt;/em&gt; and then
click on the Dexterity type you want to extend. You will see that there
is a lines field called &lt;em&gt;Behaviors.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Add the interface of your new extender here, i.e
&lt;em&gt;collective.myproduct.sector.IExtendedSector&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;That’s basically it!&lt;/p&gt;
&lt;p&gt;You probably want to add the behavior interface to a
&lt;a href=&quot;http://plone.org/documentation/kb/genericsetup&quot;&gt;GenericSetup&lt;/a&gt; XML file
that defines the type you are extending, to avoid having to manually add
it to &lt;em&gt;portal_types&lt;/em&gt; every time you create a new site (it’s also very
easy to forget about this step).&lt;/p&gt;
&lt;p&gt;Something like this in your type’s GS-XML file:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;&amp;lt;!-- List of enabled behaviors --&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;property&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;name&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;behaviors&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;plone.app.content.interfaces.INameFromTitle&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
    &lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;element&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;value&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;collective.myproduct.sector.IExtendedSector&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;/&lt;/span&gt;property&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Oh, and lastly… you’re going to need
&lt;a href=&quot;http://pypi.python.org/pypi/five.grok&quot;&gt;five.grok&lt;/a&gt; for this. Your
package needs to be grokked, otherwise the &lt;em&gt;plone.directives.form&lt;/em&gt; form
hints won’t be activated.&lt;/p&gt;
&lt;p&gt;In your &lt;em&gt;configure.zcml&lt;/em&gt;:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;xml&quot;&gt;&lt;pre class=&quot;language-xml&quot;&gt;&lt;code class=&quot;language-xml&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token tag&quot;&gt;&lt;span class=&quot;token punctuation&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;token namespace&quot;&gt;grok:&lt;/span&gt;grok&lt;/span&gt; &lt;span class=&quot;token attr-name&quot;&gt;package&lt;/span&gt;&lt;span class=&quot;token attr-value&quot;&gt;&lt;span class=&quot;token punctuation attr-equals&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;.&lt;span class=&quot;token punctuation&quot;&gt;&quot;&lt;/span&gt;&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;/&gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You can do a lot more than just the above with&lt;em&gt;Dexterity&lt;/em&gt;and
&lt;em&gt;plone.behavior&lt;/em&gt;, take a look at Martin’s
&lt;a href=&quot;http://plone.org/products/dexterity/documentation/manual/behaviors/referencemanual-all-pages&quot;&gt;documentation&lt;/a&gt;
for more info.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[New spelling and grammar checker for TinyMCE]]></title><description><![CDATA[The spellchecker “After the deadline” is now available as an add-on
for TinyMCE in Plone. It’s multilingual, open-source, platform agnostic…]]></description><link>https://opkode.com/blog/new-spelling-and-grammar-checker-for-tinymce/</link><guid isPermaLink="false">https://opkode.com/blog/new-spelling-and-grammar-checker-for-tinymce/</guid><pubDate>Fri, 25 Mar 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;The spellchecker “After the deadline” is now available as an add-on
for TinyMCE in Plone. It’s multilingual, open-source, platform agnostic
and even does grammar checking.&lt;/p&gt;
&lt;p&gt;I’ve actually already added this add-on two months ago but didn’t get
around to mentioning it.  &lt;a href=&quot;http://afterthedeadline.com&quot;&gt;After the deadline&lt;/a&gt;
is an open-source spelling and grammar checker that can be integrated with web based WYSIWYG editors,
such as our beloved &lt;a href=&quot;http://tinymce.moxiecode.com/&quot;&gt;TinyMCE&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This new spelling checker provides some advantages over the existing
(and still default) &lt;a href=&quot;http://www.iespell.com/&quot;&gt;IESpell&lt;/a&gt;. Firstly, IESpell
only works on Microsoft Windows. Secondly, IESpell is only free for
non-commercial purposes. &lt;em&gt;After the deadline&lt;/em&gt; however is open-source
(GPL license, see &lt;a href=&quot;http://open.afterthedeadline.com/&quot;&gt;here&lt;/a&gt;) and
platform agnostic. Oh, and it’s multilingual as well! To top it off…
the killer feature, for us at least, is that it has a &lt;em&gt;grammar checker.&lt;/em&gt;
Pretty impressive IMHO.&lt;/p&gt;
&lt;p&gt;The actual thing doing the spellchecking, is a Java server app, which
you should &lt;a href=&quot;http://open.afterthedeadline.com/how-to/get-started/&quot;&gt;download and install&lt;/a&gt;
on your own server. There is a public default option for testing and
demonstration purposes, but it comes with no guarantees.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;After the deadline&lt;/em&gt; is included with all &lt;a href=&quot;http://pypi.python.org/pypi/Products.TinyMCE/1.2.4&quot;&gt;Products.TinyMCE&lt;/a&gt;
releases since 1.2.1, but it’s not the default spell checker. To enable
it is at least straightforward.&lt;/p&gt;
&lt;h2&gt;Enabling AtD in TinyMCE for Plone:&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;Go to the Plone control panel and click on “TinyMCE Visual Editor”&lt;/li&gt;
&lt;li&gt;Click on ‘Toolbar’ (middle left)&lt;/li&gt;
&lt;li&gt;Make sure that ‘spellchecker’ is checked.&lt;/li&gt;
&lt;li&gt;Click on ‘Libraries’ (top right)&lt;/li&gt;
&lt;li&gt;Under &lt;strong&gt;Spellchecker plugin to use&lt;/strong&gt;, choose &lt;strong&gt;After the deadline&lt;/strong&gt;&lt;/li&gt;
&lt;li&gt;Under AtD Service URL, choose your ATD server’s URL. (The default is their - public service)&lt;/li&gt;
&lt;li&gt;It’s however recommended that you install your own AtD spellchecker service&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://open.afterthedeadline.com/how-to/get-started&quot;&gt;See here&lt;/a&gt; for more details.&lt;/li&gt;
&lt;li&gt;You should now have &lt;em&gt;After the deadline&lt;/em&gt; enabled and have a spellcheck button in your TinyMCE editor.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;  If you’d like a demonstration of ATD, &lt;a href=&quot;http://www.polishmywriting.com/&quot;&gt;click here&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Plone 4 compatible release of Quills]]></title><description><![CDATA[Since I’ve started this site, I’ve been using
Quills for blogging functionality in
Plone. So far, it’s been perfectly fine for my
relatively…]]></description><link>https://opkode.com/blog/plone-4-compatible-release-of-quills/</link><guid isPermaLink="false">https://opkode.com/blog/plone-4-compatible-release-of-quills/</guid><pubDate>Thu, 10 Mar 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;right images-container&quot; style=&quot;width: 9em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 125px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/c5d632bd43f3f4e599702142238a2194/fac75/quills.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 40%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAICAYAAAD5nd/tAAAACXBIWXMAAAsTAAALEwEAmpwYAAAA+UlEQVR42oWSz0tCQRDH9y09DUICLxISYkGv/JGKeUjrUAlFdStE8RIevfmndPOvfc/PxNdY5IkLH2Z33sx8Z3eec1pZlpXSNC1qH8keQWx+sy5YFiNq8AXn/x9JuMHRgQ8rHCSV4RkezMoXyx7DI3RhDdO/htic2UFBlryAawn04UWJTzCEijofqNgPzODXYqzIhTlV0BLfUVph32ACr/AN9/jn2ASqcCf/WMKf4ZUtcAk9qMMIruAW2tBQx5fQNFGJjVSsBX77Tl5XSFTQuz2LbyfqaKZ3t+cqhIN0uwdNzgfWb/8CTdTnCEV56v5Ad6c22SA2yovfAP9+XjHCWt7wAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;image&quot;
        title=&quot;&quot;
        src=&quot;/static/c5d632bd43f3f4e599702142238a2194/fac75/quills.png&quot;
        srcset=&quot;/static/c5d632bd43f3f4e599702142238a2194/fac75/quills.png 125w&quot;
        sizes=&quot;(max-width: 125px) 100vw, 125px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Since I’ve started this site, I’ve been using
&lt;a href=&quot;http://plone.org/products/quills&quot;&gt;Quills&lt;/a&gt; for blogging functionality in
&lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt;. So far, it’s been perfectly fine for my
relatively simple needs and I haven’t found a reason to change.
Unfortunately, except for some work to port Quills to Plone 4,
development and bugfixes on Quills has completely dried up. No new
releases were made for more than a year and the mailing list was almost
dead. I only realised this when I fixed some bugs while porting my site
to Plone 4 and couldn’t find anybody to help making a new Plone 4
compatible release.&lt;/p&gt;
&lt;p&gt;Eventually I got hold of Tim Hicks, one of the original maintainers of
Quills, and I offered to help out with maintaining Quills and to make
the new releases.&lt;/p&gt;
&lt;p&gt;So, I’m happy to announce that new Plone 4 compatible releases of the
Quills packages have been made. Notably
&lt;a href=&quot;http://pypi.python.org/pypi/Products.Quills/1.8a1&quot;&gt;Products.Quills&lt;/a&gt;,
&lt;a href=&quot;http://pypi.python.org/pypi/Products.QuillsEnabled/1.8a1&quot;&gt;Products.QuillsEnabled&lt;/a&gt;
and &lt;a href=&quot;http://pypi.python.org/pypi/quills.app/1.8a1&quot;&gt;quills.app&lt;/a&gt; (all now
at version &lt;strong&gt;1.8a1&lt;/strong&gt;). This new release is labeled &lt;em&gt;alpha&lt;/em&gt;, as I’m
still very new to the Quills codebase, but I’m already using it on this
blog without any major problems.&lt;/p&gt;
&lt;p&gt;If there is anyone who is still using Quills on a legacy Plone site and
would like to migrate to Plone 4, just pin your Products.Quills (and
Products.QuillsEnabled) version to 1.8a1 in your versions.cfg or
bulidout.cfg.&lt;/p&gt;
&lt;p&gt;Hopefully everything goes well (did I mention it’s &lt;em&gt;alpha&lt;/em&gt; ;) but if
not, feel free to let me know and I’ll try to help out.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[New beta of Babble Client (and related packages) released]]></title><description><![CDATA[After spending a few months acclimatising to a new life and continent,
I’m happy to be productive again. I’ve released a new beta version of…]]></description><link>https://opkode.com/blog/new-beta-of-babble-client-and-related-packages-released/</link><guid isPermaLink="false">https://opkode.com/blog/new-beta-of-babble-client-and-related-packages-released/</guid><pubDate>Wed, 19 Jan 2011 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;After spending a few months acclimatising to a new life and continent,
I’m happy to be productive again. I’ve released a new beta version of
Babble.Client and other packages.&lt;/p&gt;
&lt;p&gt;In the last 6 months, my girlfriend and I went backpacking in &lt;a href=&quot;http://opkode.net/blog/category/south-america&quot;&gt;South
America&lt;/a&gt; and then we
moved continents to go live in South Africa after having stayed in
Germany for a while. To be honest, we completely underestimated the
amount of effort involved in adapting and integrating into our new
environment and the amount of admin that was waiting for us after having
lived without any significant responsibilities for 4 and a half months
while backpacking.&lt;/p&gt;
&lt;p&gt;We had virtually no worldly possessions except for our backpacks (and
some boxes in storage), and needed to get a place to stay and some
office space for me.&lt;/p&gt;
&lt;p&gt;Needless to say, it took us a while to get back on our feet and for me
to get into a good working rhythm again.&lt;/p&gt;
&lt;h2&gt;New packages released:&lt;/h2&gt;
&lt;p&gt;So, I’m happy to finally be back in the swing of things and to be
releasing new updates to some of the packages I help maintain.&lt;/p&gt;
&lt;p&gt;I’ve released new versions of the packages in the &lt;strong&gt;Babble&lt;/strong&gt; suite,
specifically worth mentioning is the new beta version
of &lt;a href=&quot;http://plone.org/products/babble.client&quot;&gt;babble.client&lt;/a&gt; (&lt;strong&gt;1.4b1&lt;/strong&gt;)
which provides support for email usernames (available in &lt;a href=&quot;http://plone.org/products/plone/features&quot;&gt;Plone
4&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;Together with the client release, I had to release new versions of the
messaging
server: &lt;a href=&quot;http://plone.org/products/babble.server&quot;&gt;babble.server&lt;/a&gt;
(&lt;strong&gt;0.3.1&lt;/strong&gt;),
&lt;a href=&quot;http://plone.org/products/actionbar.babble&quot;&gt;actionbar.babble&lt;/a&gt;
(&lt;strong&gt;0.1b1&lt;/strong&gt;), a package which provides Babble integration for
the &lt;a href=&quot;http://plone.org/products/actionbar.panel&quot;&gt;actionbar.panel&lt;/a&gt;, and
also a new version
of &lt;a href=&quot;http://plone.org/products/collective.js.blackbird&quot;&gt;collective.js.blackbird&lt;/a&gt;
(which I use for Javascript logging). You can use
&lt;a href=&quot;http://plone.org/products/babble.demo%22%3Eabble.demo%3C/a%3E&quot;&gt;babble.demo&lt;/a&gt;
(&lt;strong&gt;0.2&lt;/strong&gt;) to quickly set up a prototype environment in which to test Babble.&lt;/p&gt;
&lt;h2&gt;Improvements and new features:&lt;/h2&gt;
&lt;p&gt;I’ve gotten a few requests for new Babble client features the last
months, for example the ability to broadcast chat messages and to
restrict contacts to certain groups. Some of the smaller requests, I’ve
implemented in my spare time (such as better URL handling in messages,
and making the portlet header configurable), but others would simply
take up too much of my valuable free time to implement. I would however
be happy to assist anyone considering implementing these features
themselves.&lt;/p&gt;
&lt;p&gt;Some improvements I would like to eventually implement myself are better
Javascript testing (for which I need to remove all DTML statements) and
the ability to push messages to the client via something like
&lt;a href=&quot;http://en.wikipedia.org/wiki/Comet_(programming)&quot;&gt;comet&lt;/a&gt; (instead of
polling).&lt;/p&gt;
&lt;p&gt;There are going to be some
&lt;a href=&quot;http://groups.google.com/group/plonesa&quot;&gt;PloneSA&lt;/a&gt; sprints coming up in
the Cape Town area here in South Africa where I would hopefully be able
to work on some of these areas.&lt;/p&gt;
&lt;p&gt;As always, contributions are very welcome, thanks to &lt;strong&gt;Cleber J.
Santos&lt;/strong&gt; for fixing some Plone 3 compatibility bugs!&lt;/p&gt;
&lt;p&gt;Feel free to contact me with questions or suggestions!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[South American travel diary, Part 4. September 2010]]></title><description><![CDATA[3 September, Starting our hike to Choquequirao Choquequirao is a lesser known ruined Inca city located on the Salkantay
mountains. It can…]]></description><link>https://opkode.com/blog/south-american-travel-diary-part-4/</link><guid isPermaLink="false">https://opkode.com/blog/south-american-travel-diary-part-4/</guid><pubDate>Mon, 11 Oct 2010 00:00:00 GMT</pubDate><content:encoded>&lt;h2&gt;3 September, Starting our hike to Choquequirao&lt;/h2&gt;
&lt;p&gt;Choquequirao is a lesser known ruined Inca city located on the Salkantay
mountains. It can only be visited after a strenuous two day hike, down
into the Apurímac valley and then up again on the other side of the
mountain. This makes it much less visited and also more mysterious than
the famous Inca ruins at Machu Picchu. So far only about 30-40% of the
site has been excavated.&lt;/p&gt;
&lt;p&gt;The tour we booked consisted of four days of hiking, two days to
Choquequirao and two days back for a total of about 70 km of steep,
mountaneous terrain.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a4e98101ccc657a2cc641789b9f9d8dd/IMGP7493.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We got up early in the morning and headed by bus to the small town of
Cachora, less than 200km removed from Cusco but still about 4 hours of
driving on the endlessly curving and car-sickness inducing mountain
road.&lt;/p&gt;
&lt;p&gt;Cachora is a quaint and very rural town, with just about every building
we could identify built out of mud. We waited at the back of a small
shop, watching the chickens, pigs and mules in the backyard, as Jesús,
our guide and cook, prepared lunch. Inside a dark room to the left was a
colony of guinea pigs, most of whom inevitably will end up on someone’s
dinner plate someday. I considered eating guinea pig in Arequipa, a
local delicacy, but after seeing a photo of a skinned guinea pig spread
out on a plate, I decided to pass.&lt;/p&gt;
&lt;p&gt;We were supposed to be a group of four people, but at the last minute,
the other couple canceled because of food sickness. That meant it was
only Manuela and I, Jesús our guide and Milano, the horse-guy, which
suited us just fine. Additionally, we had a horse and a mule with us.
They carried our luggage, food and the tent, as we headed off to the
wild for the next four days. The English speaking guide we were
promised, was of course nowhere to be found. Luckily our Spanish skills
were by now good enough to understand the important bits and on occasion
even make some smalltalk with Jesus, who turned out to be not just a
nice guy but also fitter than a marathon runner.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0ab9c4ea24d3ddbf8177476d88feb79a/IMGP7495.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We started our trek at about 12 in the afternoon, heading towards the
snow-capped mountains in the distance. The trail went slowly upwards for
about 10 kilometers (although this would turn out to be the most level
part of the hike), before we descended on the other side of the mountain
for another 9 km towards our campsite Chiquiska, near the Apurímac
river. On the way we passed small farms and little huts with corn on
plastic sheets lying next to them in the sun. The corn will be fermented
to create Chicha, the local beer that dates back from Incan times. We
stopped at one of the huts and bought a whole jug of the grainy, fizzy
and little bit sour beer, for only 1 sol (about €0,30).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/317db33dd36746ace032e88136d8f7ce/IMGP7510.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Jesús told me that they also have a stronger variant made out of
fermented sugar cane. As luck would have it, we met a local farmer with
his mule and his wife coming up the mountain. He happened to have some
sugar cane chicha and generously offered it to us. We drank some of the
stronger chicha, made a bit of small talk and then went our separate
ways, them continuing up the mountain and us going down towards the
river.&lt;/p&gt;
&lt;p&gt;We arrived at our campsite just before dark, to discover that we would
be the only people sleeping there. We were camping at an oasis near the
river, surrounded by banana and papaya trees. Facilities were basic open
outdoor showers (also known as hose pipes) and a hole in the ground as a
toilet. We had a fresh papaya straight from the tree, before we unpacked
our stuff and sat down to dinner. We were amazed at Jesús’ ability to
prepare a hearty and tasty three-course dinner in the wilderness with
his limited supplies and no electricity.&lt;/p&gt;
&lt;p&gt;That night, Jesús and Milano slept out in the open on wooden benches as
Manuela and I went to bed in the relative luxury of our sleeping bags in
a small domed tent.&lt;/p&gt;
&lt;h1&gt;4 September, Choquequirao&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/c25be80c2f81831bd55d6eb78d2e84ea/IMGP7658.jpg&quot; alt=&quot;This is a
toilet.&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the second day, we had to cross the Apúrimac river and hike back up
the mountain on the other side. This turned out to be the toughest day
of the hike, and Manuela got very angry at me for all the time
anticipating the end around the corner only to find another steep
zig-zag going further up the mountain.&lt;/p&gt;
&lt;p&gt;At about noon, after 5 or 6 hours of hiking upwards, we reached a
relatively level clearing with a small village of less than a 50
inhabitants. The houses were made of mud and there was no electricity or
running water except for a mountain stream from which the locals
channeled water using hose pipes.&lt;/p&gt;
&lt;p&gt;We ate lunch under a roof next to one of these houses and then tried to
rest for a while before we would have to continue trekking another 2
hours to the lost city of Choquequirao.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7e465b2e124b8287a62901d8eed71b37/IMGP7585.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Choquequirao is situated in an absolutely stunning area and its clear
that the Incas had an eye for choosing spectacular locations to build
some of their cities. The beauty of these locations convinced them of
their sacredness, and on a small hill next to the city they made a flat
and round clearing (like a heli-pad) where they held their rituals.
Standing in this clearing, with a 360° view of the mountains on all
sides and the river cutting through the middle, was a very special
experience that made the tough hiking all the more worth it.&lt;/p&gt;
&lt;p&gt;Jesús and I then walked down towards the terraces on the other side of
the mountain to look at the llama pictures made in the rock walls. The
original way down was a long series of stone steps that would have to be
hell to walk back up again. Luckily there is now also a  hiking path
going back up.&lt;/p&gt;
&lt;p&gt;As mentioned before, Choquequirao is only partly excavated, and it was
possible to go into the bushes next to the excavated buildings and see
more walls, houses and other structures hidden between the thick
vegetation. There were only 4 other tourists at the site that afternoon
and we could roam the whole area undisturbed and entranced by the
magical surroundings.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/4ea88b2788ce94e26b0234b68d0eb75a/IMGP7598.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We stayed as long as we could and then started hiking back to the
previous village were we would overnight. The hike lasted well past
sunset and into the night and Manuela remarked on how we started the
days hike before sunrise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b6aab2cf0c032f8be5a991aac2904455/IMGP7538.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;That night, Jesús prepared a delicious soup that he claims is a family
tradition and we lay on the grass to look at the stars as we did the
previous night down by the river. They were more vivid than I’ve ever
seen before, and that includes star-gazing in the desert in Namibia and
near the observatory in Sutherland, South Africa.&lt;/p&gt;
&lt;h1&gt;5 September, Choquequirao&lt;/h1&gt;
&lt;p&gt;On the third day, we had to hike back down the mountain, up the other
side past our old camping site to another site further up. On the way,
we stopped at a small mud house and shop were Jesús and I drank two
vases of locally brewed Chicha beer before continuing onwards.&lt;/p&gt;
&lt;p&gt;That night we camped next to a small two room mud house, were a local
woman and her husband lived. We had dinner inside the bigger room, which
functioned as a living-room, bedroom and kitchen in one, as the wife
tended to an open fire and heated up some left-overs for the just
returning husband. We were humbled by the simple and secluded lives that
these people live, up in the mountains and far away from the trappings
of modern society.&lt;/p&gt;
&lt;p&gt;That night we had a special show held for us by the fireflies flickering
neon green in the darkness and spread out all over the mountain.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3274f8cce1f41201da426573cba01b0c/IMGP7619.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;6 September, Choquequirao&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/5069c0defea9b9608c60e127adacdc9f/IMGP7760.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We had half a day of trekking left before we reached the town of
Cachorra again. We left early and hiked up the mountain in thick mist
that prevented us from seeing more than a few meters ahead. It was about
6 difficult kilometers up the steep mountainside, before we reached the
top and hiked another 10 level kilometers to town.&lt;/p&gt;
&lt;p&gt;The last four days’ hike was tough but definitely worth the effort. We
visited a lost city located in a spectacular location which left us
amazed and inspired. In the process we learned a lot about ourselves,
about rural Peru and the difficult yet simple life up in the mountains.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ef5189100a889aa8adee24ca822296ca/IMGP7481.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;10 September, Traveling to Machu Picchu&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/d1ec8f57370874254e294ff45a608537/IMGP7952.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;After spending a few days resting in Cusco again, we prepared to leave
to the famous Inca ruins of Machu Picchu. For many travelers, Machu
Picchu might well be the main attraction of their South American trip. I
remember being filled with wonder at the prospect of a continent filled
with spectacular and mysterious ruins left by enigmatic empires such as
the Incas, Aztecs and Mayans.&lt;/p&gt;
&lt;p&gt;Machu Picchu itself was every bit as magical as I imagined it to be, but
the profiteering, bad service and lies peddled to us by the agency we
trusted to get us there, left quite a few fantasies shattered. Reality
however sometimes has the effect of tempering a wild imagination.&lt;/p&gt;
&lt;p&gt;Not that it would have necessarily have been better going with another
agency. Cusco is filled to the brim with tour operators. Any idiot can
set up a table with pictures of Machu Picchu and other attractions and
start selling tours. And many do. The tours they sell are of course
passed along to other operators, and in the process all accountability
goes out the window.&lt;/p&gt;
&lt;p&gt;Add to this the fact that the only sanctioned way of getting to Machu
Picchu (with the exception of hiking for 2 to 3 days) is paying about
US$100 for a one way train trip of little more than 100km, and we
almost considered leaving the whole thing as it felt a bit too much like
a rip-off.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d2ccd51f07486a16ed457cc5dc997a1f/IMGP7841.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Instead, we thought we found a way to beat the system. A small operator
(one of these desk jobbies as mentioned earlier) offered two-day trips
to Machu Picchu via bus for about US$115, whereas a normal tour would
cost about US$180,&lt;/p&gt;
&lt;p&gt;We left the morning very early, 4:30am to be exact, in a small tour bus
excited to be on our way to the famous site. The first 3 hours driving
turned out to be uneventful, until we reached the top of a mountain pass
outside of Cusco. Turns out that we were bundled together with another
group who booked a more adventurous tour and that they would now cycle
down the mountain while we slowly follow 50m behind in the tour bus. For
the next 2 and a half hours, we crawled down the mountain at about 20km
per hour with the group of 20 or so cyclists ahead of us. Of course, our
“tour agency” completely neglected to impart this little piece of
information to us.&lt;/p&gt;
&lt;p&gt;After coming down the mountain (with its comparatively good road), the
day got progressively worse. Due to delays caused by the cyclists, bad
planning and numerous roadworks on the horribly uneven and narrow gravel
road through the valley, we reached the town of Santa Thereza for lunch
at about 16:00pm with not a single apology or explanation made.&lt;/p&gt;
&lt;p&gt;Eventually, after getting into a smaller bus and then afterwards also a
train ride, we reached &lt;em&gt;Aguas Calientes&lt;/em&gt;, the small tourist town close
to Machu Picchu. It must be the most fake and kitsch town we have
encountered on this whole trip. Perhaps ever. Everywhere are plastic
Incas, kitsch paintings of muscled Incas (abvious rip-offs of 1980s
fantasy art such as by &lt;a href=&quot;http://www.google.com/images?q=boris+vallejo&amp;#x26;um=1&amp;#x26;ie=UTF-8&amp;#x26;source=og&amp;#x26;sa=N&amp;#x26;hl=en&amp;#x26;tab=wi&amp;#x26;biw=1024&amp;#x26;bih=487&quot;&gt;Boris
Vallejo&lt;/a&gt;),
and of course someone trying to get you into their (overpriced)
restaurant or hotel. Our tour guide on the other hand, couldn’t be
bothered to even remove his headphones to properly talk to us.&lt;/p&gt;
&lt;p&gt;As mentioned, we left the morning at 4:30am, and arrived in Aguas
Calientes at about 8:00pm. Keep in mind that Aguas Calientes and Cusco
are only about 112km (in a straight line) apart.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/40086e78a541fa8fc82d443a5d9b9e3a/IMGP7809.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;10 September, Machu Picchu&lt;/h1&gt;
&lt;p&gt;We got up at 3am that morning in order to be among the 400 people who
would be allowed to climb Huayna Picchu, the hill next to the lost city.&lt;/p&gt;
&lt;p&gt;Walking around the ruins of Machu Picchu made all the effort in getting
there worthwhile. The ruins and their location are simply spectacular
and not even our half-useless guide could spoil the occasion.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b6c0f42635f93d9a12d78972846986d0/IMGP7944.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the way back, even though we were squeezed into a small minibus, the
driver decided to make some more cash on the side and drove around Santa
Thereza offering a trip to Cusco. Eventually three more locals entered
the minibus as well and we continued to Cusco. The drive back was even
more horrible than before. Our driver drove carelessly and very
dangerously along the mountain passes, so much that we repeatedly had to
ask him to drive more carefully. He didn’t give a rat’s ass of course,
and continued to speed and cut corners.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7cf84cf826d565dc0a00bdaea487dcd4/IMGP7947.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;After about 8 hours of driving, when we got closer to Cusco, he suddenly
veered off the tarmac and started driving on a rough and uneven dirt
road. Turns out that there was some kind of roadblock ahead which he was
trying to avoid. Why the hell would he take a big detour on a rough
gravel road to avoid a roadblock? Of course he declined to tell us, so
we could only guess.&lt;/p&gt;
&lt;p&gt;Long story short, Manuela and I were so relieved to be back at our
hostel after a frightening and claustrophobic journey of about 9 hours,
that we went to the supermarket and bought a whole lot of comfort food.
Crisps, chocolate and red-wine. We celebrated still being alive. Moral
of the story, don’t take the “bus” to Machu Picchu!&lt;/p&gt;
&lt;h1&gt;11 September&lt;/h1&gt;
&lt;p&gt;We went for a massage. Like everything in Peru (and even more so in
Bolivia) even though the masseuses really try hard and I can only
respect their work ethic, they somehow just lack those finishing touches
of professionalism. The CD player doesn’t work, they need to move the
tables when a new client comes in and the one girl burnt Manuela with a
hot stone. All in all, it was only €6, so still good value for money.&lt;/p&gt;
&lt;p&gt;Manuela also received coca cream for her face. This reminded me of an
earlier prediction I made to her and which I’ll mention here as well. I
predict that within 5 to 10 years, a coca craze or fashion will enter
the Western market for especially cosmetics and toilettries. Expect coca
toothpaste, facial creams, shampoos and the like. Watch this space ;)
Similar to the herbal toothpaste craze of a few years back…&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/9fc8340d03a117a4ca469fc5030c6ddf/IMGP7768.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;13 September, Leaving to Manu National Park&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/2bc575fc0c9c51dc8eb70272a5019b50/IMGP8016.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We had already resigned ourselves with the idea of not going to the
Amazon during this trip, when Manuela spotted a flyer in Cusco
advertising a work and travel opportunity in the Amazon basin in Manu
National Park. Originally we considered going to Belém in Brazil, or
Iquitos in Peru, but both turned out to be very expensive and the
stories of unscrupulous and non-ecofriendly tour operators didn’t
impress us much either. This opportunity, presented by an agency called
ManuPeruAmazon, seemed to be different however, and after chatting with
them at their Cusco office, we signed up for a week of camping in the
jungle to help out with volunteering work while also taking part in
hikes and boatrides.&lt;/p&gt;
&lt;p&gt;Manu National Park is an area which is so difficult to reach that the
Spaniards actually never invaded it. They attempted at different times
resulting in the loss of many men forcing them to eventually give up.
Uncontacted tribes still roam the vast and unreachable interior.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://www.manuperuamazon.com/&quot;&gt;ManuPeruAmazon&lt;/a&gt; is the project of
Oliver Innocente, an Italian expat, and his Peruvian wife Carolina.
Oliver has been living in Peru for about 20 years, most of them spent in
the jungle.&lt;/p&gt;
&lt;p&gt;After taking a 7 hour bus-ride from Cusco into Manu National park, we
arrived at a small town where Oliver was waiting for us. His right hand
was bandaged after been stung or bitten by something, most probably a
spider. His right thumb, where the bite took place, was completely red
and swollen up to more than twice it’s normal size, while his fingers
and wrist were also still red and swollen. On the spot where the bite
took place, was a large gash with raw flesh peeling out. And this was
already 8 days after it happened. This being the jungle, Oliver didn’t
have access to medication, not that he wanted any really, and he made
exclusive usage of local medicinal plants.&lt;/p&gt;
&lt;p&gt;We drove for another half an hour to a small river port town and Oliver
showed us the biggest pea I’ve ever seen. The pips are covered in a
white fluff, which was quite tasty.&lt;/p&gt;
&lt;p&gt;From the port we took a motorized wooden boat on the &lt;em&gt;Madre del Dios&lt;/em&gt;,
an important tributary of the Amazon river, downstream into the jungle
and towards our camping place. It was an amazing experience.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3ca17066db7ff70327d071671602f4da/IMGP7991.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The campsite itself was literally 4 small domed tents and two reed and
grass structures to provide shade. For the next 5 days we would have to
wash in the river and digg a small hole every time we needed a toilet.
This was exactly the experience I was hoping for, something more basic
and away from the other tourists and tour guides who treat them like
wallet owning cattle.&lt;/p&gt;
&lt;p&gt;Oliver was given this particular plot of land (more than a 100 hectares)
by the Peruvian government only two months ago, to facilitate its
rehabilitation after being damaged earlier by a large landslide. He
already had grand plans for reintroducing different plant species,
creating a botanical center and also facilities for students and
scientists to come and study the jungle. About 60 meters up, there was
another campsite, with a thatched roof where Carolina would prepare
food. We were convinced relatively early that Oliver was genuinely
concerned with protecting the local environment and that he cared deeply
for the jungle. He spoke with great respect of the local natives who
still live in the Amazon and about their beliefs and knowledge of the
environment.&lt;/p&gt;
&lt;p&gt;This first nigth at the campsite we saw little glowing green eyes,
moving between the plants and the darkness. These irridescent green dots
were on the backs of so-called &lt;em&gt;click beetles&lt;/em&gt;, named after the clicking
sound they make when you capture them. This, coupled with the
everpresent symphony of the jungle, countless other beetles, crickets,
critters, bugs and birds, created a truly magical first night in the
Amazon.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0b96c9aa76905d4b621fd14ed86fe6ed/IMGP7974.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;14 September, Working and hiking in the Amazon&lt;/h1&gt;
&lt;p&gt;On this day we got up at about 5 in the morning and went to the clay
walls where blue headed parrots licked clay to ingest minerals in order
to counter the toxins of some of the unripe fruits they eat.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/95480581469e17f3a42984e534b4634e/IMGP8009.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Our campsite was right next to the river and there were still pools of
water near the tents. Numerous butterflies of many different shapes,
colours and sizes asssembled near these pools. Some were very large and
yellow, others were adorned with intricate patterns of a beautiful dark
blue, while another kind was a kind of unearthly neon green. They
contributed a whole bouquet of different colours to the jungles’s
palette of infinite shades of green.&lt;/p&gt;
&lt;p&gt;The path towards the topmost campsite was steep and at certain spots
difficult to climb. One of the first things that needed to be done, was
to build steps on these steep parts and Tony and I volunteered to start
working on this. At the upper campsite, there was also a small nursery,
made out of halved bamboo reeds, where Manuela and Sofia helped to clean
the reeds and plant new seeds.&lt;/p&gt;
&lt;p&gt;Using shovels in the damp sand, we relatively quickly created the
initial steps, but in the jungle humidity and hot sun we sweated like
never before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ab654232d46cea94ed8341535ba87d6a/IMGP8102.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;After doing volunteer work in the morning, we ate lunch, relaxed for a
whlie and then took the boat downriver to start a four hour hike
starting on the other riverbank. We hiked for about an hour and a half,
through swamps, under gigantic leaves (called &lt;em&gt;Elephant ears&lt;/em&gt;) and under
very tall trees where we saw some squirrel monkeys. Eventually we
reached a small lake bordered by an imposing wall of thick impenetrable
jungle up to 40 meters high. We took a so-called “catamaran”
(basically just a wooden barge) on the river and for the first time, we
were so quiet, slowly floating on the still water, that we could really
appreciate the countless birds on the lake, undisturbed by our presence.
On the one side of the river, a
&lt;a href=&quot;http://en.wikipedia.org/wiki/Capybara&quot;&gt;Capybara&lt;/a&gt; was relaxing and
everywhere where the Huatzin (German “Schopfhuhn”) and other birds.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e2b4113ff2a8749e715fbd063df210d9/IMGP8031.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We arrived back at the campsite when it was already dark and becoming
clear that a thunderstorm would soon be breaking out. For the last half
an hour we saw impressive displays of lightning interspersed with loud
ominous thunder, betraying the massive size of the clouds moving above
us. The wind was so strong, that first Tony’s and Sofia’s and then our
tent collapsed and we hastily had to pack our stuff and hike away from
the river bank to the upper campsite to avoid the danger of a rising
river during the night.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/51803f5e13b30c5b323d08b72cc89b10/IMGP8069.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As we reached the upper campsite, the wind picked up in strength and it
started to rain. The strong wind teared holes into the sides of the
large tent housing our dining area. The winds were by now so strong that
we were at risk of falling trees and more than once we had to run
outside and stand in the relative safety of a clearing. The branches of
some trees were now breaking off, and once I had a narrow escape as a
large sharped edged branch came flying past me as I came out of the
tent. Eventually the wind started to quiet down, while the rain
continued through the night and into the next morning.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0bd2f7ed34057008524a061d77c255d6/IMGP8092.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;15 September, Tabacco ceremony&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/a0af2e3a5069aa84ede887dbcc6a02be/IMGP8085.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It is quite interesting to experience the rich, lush and fertile jungle,
while simultaneously also it’s hostility. Sandflies and mosquitos are
an everpresent nuisance, biting the skin and causing itches and sores.
One tree’s bark causes irritation on the skin while many others are
covered in dangerous thorns. All the worms we encountered are covered in
large hairy spikes that are not to be touched, while poisenous plants
and fruits abound. Yet, we drank water from a local stream, without the
need of even a purifier, while the tap water of most of South America is
off limits.&lt;/p&gt;
&lt;p&gt;Previously Thomas, a polish volunteer who was already at the campsite
when we arrived on the first day, went out to pick some wild jungle
tobacco and let it dry out in the sun. The local people use the tobacco
in a ceremony as a medicinal plant, during which the participants drink
boiled tobacco water, together with about 5 litres of water, until they
throw up, thereby cleaning and purifying their stomachs. Thomas offered
to prepare the tobacco for us and all four of us decided to take part in
such a ceremony. It was an interesting experience and each of us threw
up in the end. I felt weak and tired directly after the ceremony, but a
little while later I regained my strenght and headed down to continue
working on the steps.&lt;/p&gt;
&lt;p&gt;Coming down the steps, I saw a big Tayra otter, directly in front of me.
It snatched what seemed to be a banana left there by someone and then
disappeared into the bushes. It was amazing, every time leaving the
camp, you could discover animals, birds or insects of which you never
had an idea before,&lt;/p&gt;
&lt;h1&gt;16 September&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/dac26332009484723d7aa586d69a79a7/IMGP8104.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The following night, we moved our tent for the third time in three days.
This time, next to a very tall tree near the edge of the campsite.
Coming down this tree was a long path of &lt;em&gt;leaf-cutter ants&lt;/em&gt;, each one
carrying cutling of leaf in its pincers. The path extended down onto the
ground and then away into the jungle for about 15 meters before it
disappeared into the dense undergrowth and I couldn’t follow it
anymore. This was a very nice surprise for me, having grown up playing
with (torturing) the large red ants on my grandfathers farm and since
developing a fascination for these industrious little creatures. The
Amazon jungle seems to be an ant lovers paradise.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/cfac704d005fe21e94f3d6115f0df829/IMGP8180.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;During our hike two days ago, Victor, our Peruvian guide, showed us a
specific tree filled with very aggressive &lt;em&gt;fire ants&lt;/em&gt;. These ants live
in symbiosis with this tree and actively protect it from any invaders,
for example such as the leaf-cutter ants. The other trees in the jungle
are fair game for all kinds of insects, ants and mammals, but this
specific tree is left unscathed.&lt;/p&gt;
&lt;p&gt;Then there are the large (2 to 3 centimeters!) black solitary ants. They
do not belong to any colony and are quite dangerous, with a bite that
causes a nasty fever. In addition there were even larger reddish ants,
whose backsides the natives cook in oil, and all kinds of flying ants.&lt;/p&gt;
&lt;h1&gt;17 September, Leaving to Cuzco&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/f4c62d72eb452b9e8f157f500d48a37a/DSC_1681.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;Our last morning in the jungle was spent carrying stones to cover the
steps we built. Afterwards we all went for a fun and refreshing swim in
the the river, letting the current take us to another riverbank
downstream. Five minutes out of the river and we were again drenched in
sweat as we packed our bags for the long trip back to Cuzco.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/687ad088965a61bf389b35df1a8c3a26/IMGP8109.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The bus smelled like sweat and coca leaves, and after arriving at the
first roadblock, we understood why. There was a woman in in traditional
clothes carrying a large bag, and when the police officer entered the
bus she stuffed it under the large jumper she was wearing. As he passed
her, she pulled it out and threw it across two rows to a friend on
another seat, who hid it under his seat. The police officer took a quick
look and left without any arrests, but more drama was to come as we
entered Cusco.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0afefd6ee40b1eb94fa88def15b6bd4f/DSC_1627.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The second roadblock, about 4 o’clock in the morning, contained many
more police officers and they were also quite a bit more aggressive.
Four officers entered the bus and started searching through people’s
bags. The woman who previously managed to hide her bag from the police
wasn’t so lucky this time. Three officers stood over her and demanded
to see the bag she was trying to hide. She just flatly refused however,
and when one officer tried to take the bag, a pulling match broke out
between her and the police. For what seemed like 20 seconds, the police
officer tried to pulll the bag away from her as she clung to it for dear
life. Ultimately, it was an quite entertaining if futile effort on her
part to prevent them searching through her bag, and eventually she was
arrested.&lt;/p&gt;
&lt;p&gt;When we eventually left the bus at the bus station, about 5 o’clock in
the morning, I noticed that the whole floor was covered in coca leaves.
Apparantly, Peruvians are allowed to transport a certain quote of coca
leaves on them, but the problem on the bus was that the people from the
jungle were trying to transport coca above this quota.&lt;/p&gt;
&lt;h1&gt;18 September, Reggae party in Cusco&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/2321b39a29e3e818957851067af97ef2/IMGP7448.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As this was our last night together with Tony and Sofia, we decided to
celebrate and go out. We partied the whole night through in a club where
a Reggae band played all the classics and time flew by.&lt;/p&gt;
&lt;p&gt;We were definitely sad to have to split up with our new friends again as
the four of us got along very well which can be rare while traveling.&lt;/p&gt;
&lt;p&gt;Something for other travelers to take note of in Cuzco is a small
vegetarian restaurant in Calle Ruinas named &lt;em&gt;La Encuentro&lt;/em&gt; in Cusco.
They offer the best lunch deal in town between the many tourist rip-offs
(salad buffet and 2 courses of food plus a drink made, all made of
organic ingredients for 6 Soles).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a8e72765faab939364b7c133b9170308/IMGP7749.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;20 September, Leaving to Chile&lt;/h1&gt;
&lt;p&gt;For our trip to Tacna, on the border with Chile, we finally managed to
book a &lt;em&gt;Cruz del Sur&lt;/em&gt; bus, recognised as the best bus service in Peru.
Not only that, but we also managed to get the mythical &lt;em&gt;full cama&lt;/em&gt; bus
with fully reclining seats. We’ve almost given up hope of capturing one
of these elusive buses in South America, despite persistent rumours that
they do actually exist.&lt;/p&gt;
&lt;p&gt;During our stay in Copacabana, we went to a bus agency with large
&lt;em&gt;TurPeru&lt;/em&gt; (another good bus company) posters outside and booked what we
thought was a &lt;em&gt;full cama&lt;/em&gt;, &lt;em&gt;TurPeru&lt;/em&gt; bus from Copacabana to Arequipa. We
got however a crappy local bus with semi-reclining seats and a terrible
driver schooled in the proud Peruvian tradition of bad bus drivers.&lt;/p&gt;
&lt;p&gt;This time, things were different however. We arrived at the terminal,
and there it was. An actual &lt;em&gt;Cruz del Sur&lt;/em&gt; full-cama bus waiting for us.
This was the most luxurious bus we took so far, with plasma screen
televisions and large spacious leather seats, pillows, blankets, food,
drinks and a clean bathroom. The bus is even monitored via GPS to
prevent speeding, which is a welcome restriction to your average
Peruvian driver’s natural impulse.&lt;/p&gt;
&lt;h1&gt;21 September, Tacna Peru to Arica in Chile&lt;/h1&gt;
&lt;p&gt;We drove 9 hours to Arequipa and then switched to another, less
luxurious bus to Tacna. The landscape outside of Tacna is completely
barren. This must be the place where they shot the Martian landscape
scenes in movies like &lt;em&gt;Total Recall&lt;/em&gt;. There is absolutely nothing
growing in this part of the Atacama desert and it was quite a contrast
to the lust Amazonian jungle in Manu national park. The air that finally
manages to cross the high Andes is by then completely depleted of water.
This results in the Atacama desert, the driest desert in the world.&lt;/p&gt;
&lt;p&gt;Arriving in Tacna, we took the local bus to Arica for 10 Soles per
person. Half the price that the Taxi drivers (apparantly &lt;em&gt;Collectivo&lt;/em&gt;)
at the bus station wanted. The bus was fine and crossing the border to
Chile without incident as well.&lt;/p&gt;
&lt;p&gt;Coming into Arica, we were stunned by the amount of Chilean flags we
saw. Almost every single house and many cars had a Chilean flag
(sometimes two) hanging on a mast. We weren’t sure what to make of this
spectacle.&lt;/p&gt;
&lt;p&gt;Arica has a pedestrian precinct on Avenue &lt;em&gt;21 de Mayo&lt;/em&gt; and it was
interesting to see all the fashionable clothes shops, department stores
and other consumerist havens which people in many countries take for
granted but were quite scarce in Peru and basically non-existent in
Bolivia. Almost all the shops were decorated with Chilean colours and
flags and it was here that we finally realised that Chile was busy
celebrating their 200 year independence anniversary.&lt;/p&gt;
&lt;h1&gt;21 September, Tacna Peru to Arica in Chile&lt;/h1&gt;
&lt;p&gt;Just outside our hotel is a mural with four graves, one whose cross
throws the shadow of a swastika. One of the graves bears the inscription
&lt;em&gt;Augusto Pinochet, 1915-2006. Fuck&lt;/em&gt;, a reference to Chile’s brutal
former right-wing dictator, whose regime was responsible for the deaths
and dissapearances of tens of thousands of dissident Chileans. Shortly
after coming to power after a military coup in 1979, he rounded up all
the leftists and dissidents he could find and killed and tortured them
in the local Santiago football stadium.&lt;/p&gt;
&lt;p&gt;Incidentally, during the 1980s, he also had narrow relations with Israel
and the Apartheid South African government. Chile is still coming to
grips with the pain caused by his regime, and it was interesting to see
this already on our first day here.&lt;/p&gt;
&lt;h1&gt;23 September, Arriving in San Pedro de Atacama, Chile&lt;/h1&gt;
&lt;p&gt;We were quite disappointed with &lt;em&gt;San Pedro de Atacama&lt;/em&gt;. The town itself
looks quite nice, with desert adobe style buildings and a bit of an
alternative vibe, but this was all spoiled by the aggressive tour
operators, accommodation, restaurant and bar promoters and sky high
prices. The moment we got out of the bus, we were surrounded by 5 or 6
different people trying to sell us their accommodation. For the rest of
our stay in the town, we would not be able to go outside without having
to fight off various different sellers and promotors. Definitely not our
idea of a nice time. The Lonely Planet mentions that San Pedro de
Atacama is a town in which the tourism industry developed too rapidly
(with all the negative aspects that this brings), and that is exactly
how it appeared to us as well.&lt;/p&gt;
&lt;p&gt;It was sad and a bit strange to see almost no authenticity in the town.
We encountered almost no locals who weren’t trying to cash in on
tourism. There were for example no school children walking home, or any
other activity by the locals that might represent some kind of normalcy
unaffected by tourism, except the sunday church service.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1aba2377e31349bbe9ea596c8fb62aff/IMGP8237.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;25 September, Bicycle ride to the valley of the moon&lt;/h1&gt;
&lt;p&gt;After an aborted attempt at cycling the 12km out of town towards the
&lt;em&gt;Valle de la Luna&lt;/em&gt; (valley of the moon) the previous day (we left too
late to catch the sunset), we decided to try again one more time. To
make matters worse the previous day, my bicycle broke and we had to walk
back to town. So, instead of going to KMZ, were we were before, we went
to another and even cheaper shop, where we rented the bikes for half a
day at C$3000 (€4,50).&lt;/p&gt;
&lt;p&gt;We biked out of town for about 5 kilometers, until the entrance to the
valley of the moon, from where it was another 7 kilometers on a
relatively flat gravel road that curves to the right and then ends after
a ramp up and into the canyons. We weren’t the only ones going there,
but just about the only ones going by bike. Quite a lot of buses and
cars passed us by as we huffed and puffed cycling against a strong
headwind.&lt;/p&gt;
&lt;p&gt;We eventually reached the lookout point and watched the sunset, still
being relatively stressed after a negative hostel experience earlier in
the day. The landscape is quite pretty and we felt that renting a pair
of bikes to get there was probably our best option. San Pedro de Atacama
offers quite a few scenic places to which the many tour agencies would
be quite happy to drive you, but the tours (as with most things in the
town) are all overpriced in our opinion.&lt;/p&gt;
&lt;p&gt;Concerning our negative experience earlier in the day, suffice to say
that we would NOT recommend staying at &lt;em&gt;Corvatsch&lt;/em&gt; hostel. The staff
were all rude and unfriendly and there was a dark cloud of negativity
hanging over the place from the moment we arrived. The guy who runs the
place is hands down the biggest asshole we met in Chile (people in
general actually being quite friendly and nice) who even physically
threatened a fellow roommate of ours after he objected to his female
friend being shouted at. Eventually, our whole dorm of 6 people demanded
our money back, packed our stuff and left for another hostel.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0f38328718ea470c63727918aa75132a/IMGP8280.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;26 September, Back to Bolivia and Salar de Uyuni&lt;/h1&gt;
&lt;p&gt;During our last stay in Bolivia, we were prevented from going to the
famous &lt;em&gt;Salar de Uyuni&lt;/em&gt;, the largest salt flat in the world, by
discontented miners and other Bolivians from the Potosi district. They
had blockaded the roads outside of Potosi as well as the small town of
Uyuni with stones and dynamite, effectively imprisoning the whole town
populations and preventing anyone else from getting in. The story made
international headlines because a group of about a hundred tourists were
stranded at the Uyuni airport while the food stores of the town ran low.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/5fad7b78a3b53faaa37c92d98bd985df/IMGP8365.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We waited a few days extra at Sucre, hoping that the dispute might be
resolved soon, but eventually realised the gravity of the situation and
went to La Paz instead. You might expect that as the situation worsened,
the tourists in Bolivia might be dissuaded from trying to get into
Uyuni, but for some of them, it did exactly the opposite. People paid
outrageous sums of money for private jeep transfers all the way from La
Paz, to try and circumvent the roadblocks, just about the same time as
the stranded Uyuni tours tried to escape via small chartered flights. At
least one time they were unsuccessful, with protesters laying rocks and
dynamite on the airport runway.&lt;/p&gt;
&lt;p&gt;So, here we were about a month later and things seemed to be back to
normal in Uyuni. This time we would enter from the Chilean border (close
to San Pedro de Atacama), and drive through the Bolivian Altiplano (high
plateau) desert with it’s harsh cold weather towards the salt flat
itself.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1df5d437b9b03d4f69fbabf6ed9dbbcc/IMGP8394.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7ca4736c579cc455e4b1d9eb3c603e6a/IMGP8439.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the first day, we drove with the &lt;em&gt;Licancabur&lt;/em&gt; volcano in the
background, towards sulfur spewing geysers and hotsprings where we took
a dip in the 35° water. We then continued past green and turquise
coloured lakes towards the spectacular &lt;em&gt;Laguna Colorada&lt;/em&gt; (red lake),
where we would overnight at a house nearby.&lt;/p&gt;
&lt;p&gt;For the whole day the wind was blowing with incredible force, blasting
sand into your face and eyes, while temperatures hovered just above
freezing point. Nevertheless, Manuela and I decided to take a walk
towards a lookout point near the red lake. The wind was behind our backs
making things a bit easier as we walked through the small tough
gold-coloured bushes (basically the only vegetation in the area) past a
herd of Vicunyas (cousins of the Llama) on the one side and pink
flamingoes on the other side.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/dd93638c25f0abe0850f96b70b7730c7/IMGP8343.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Walking back towards our lodgings was a different story however. The
wind was blowing against us with full force, freezing our exposed skin
and hurting our eyes. From time to time we would turn around and walk
backwards for a while, before we would get tired of the slow pace and
make another attempt at trudging against the wind. This might have been
more frustrating, if not for the fact that we were enchanted by the
harsh but beautiful landscape around us. Parts of &lt;em&gt;Laguna Colorada&lt;/em&gt;’s
waters were a truly blood-coloured red, creating an impressive contrast
to the gold coloured wind-swept hills.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1b3ffacb626d6926e4e00f632e548e47/IMGP8376.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;27 September, Salar de Uyuni&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/5768022a5853492fbba83a95aa2c06f5/IMGP8433.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;All the tour operators in Salar de Uyuni make use of Toyota Land
Cruisers, as they are the only vehicles able to handle the rough terrain
coupled with the extreme height above sea-level (well above 3500m up to
more than 5000m).&lt;/p&gt;
&lt;p&gt;On the second day our old Land Cruiser shook and bumped its way past
more coloured lakes, vicunyas and pink flamingos. We had a flat tire
just after lunch, and then another one near the end of the day, which
left us stranded and hoping that another tour group would soon pass and
help us out.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/00a0ebdf66a99f3555d9e42873c85d40/IMGP8444.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In the end, we were very lucky and only had to wait about 15 minutes
before another Land Cruiser arrived from whom we could get a spare
wheel. We slept the night in a salt hotel, a bit of a gimmick, but still
kinda cool.&lt;/p&gt;
&lt;p&gt;Flavio, our excellent guide and driver, spent most of the evening
patching and fixing the two burst tires. Before we embarked on the Uyuni
tour we were a bit concerned, having heard numerous stories of drunk and
sometimes abusive drivers. Luckily this didn’t turn out to be a problem
for us and we were very impressed with the one that we had.&lt;/p&gt;
&lt;p&gt;We booked the tour through a Chilean tour company called Tierra Mistica,
and could recommend them to other travelers.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7ce36cd8fd56e41b39248469969e51a2/IMGP8411.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;28 September, Salar de Uyuni&lt;/h1&gt;
&lt;p&gt;On the final day of the Salar de Uyuni tour we finally reached the
actual salt flat. The salar is actually the remnant of an ancient
prehistoric inland sea and is almost completely flat. In fact, it’s
probably the best driving surface (if not actually a road) in all of
Bolivia!&lt;/p&gt;
&lt;p&gt;In the middle of the salar lies Incahuasi (meaning house of the
Inca’s), an outcropping refered to as the “island”. The island is
covered in large cacti, and still has the remains of the ancient coral
reefs that grew there when the whole place was under water. It must have
been an awesome place for scuba diving.&lt;/p&gt;
&lt;p&gt;You can easily lose your perspective in the Salar, making it possible to
take all kinds of silly photos. I broke off a piece of salt from the
ground and put it in my mouth. It was salty, but not as extreme as a
clump of table salt would have been.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e3b8d148744dc49c9276884f4d519d4d/IMGP8400.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;29 September Tupiza, Bolivia&lt;/h1&gt;
&lt;p&gt;We arrived in Tupiza, the previous night after hitching a ride with a
driver from Tupiza tours who also just finished a Salar de Uyuni tour.
He dropped us off at &lt;em&gt;Hostal Horizon Colorado&lt;/em&gt; and after some
unsuccessful haggling we settled on a private room with three beds, a
television, private bathroom with mirror and a waste basket (almost
always lacking) for less than half the price we paid for the shitty 6
bed dorm in San Pedro de Atacama (about €7,40).&lt;/p&gt;
&lt;p&gt;Next to our hostel is a &lt;em&gt;salon de belezza&lt;/em&gt; (beauty salon) and, in
typical Bolivian fashion, with a nameboard that looks like it was
&lt;em&gt;designed&lt;/em&gt; (I use the word quite liberally) using Microsoft paint and
some standard fonts together with a few images of women collected from
the web. One of the “women” actually being a picture of a Barbie doll.
Whatever happened to subtlety?&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1ddb9f6846a802d7e9b1488ccea02b05/IMGP9977.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;From the getgo we felt quite happy and at home in Tupiza and despite our
earlier reservations, we were enjoying it to be in Bolivia again. So far
we’ve managed to avoid any buses and the people even seem a bit
friendlier than before. Either because our Spanish skills are improving
or perhaps because Tupiza is just a friendlier town. It’s a pleasure
walking around town again, visiting the local markets with their wide
variety of fresh produce, cheap clothes from China, offerings to
Pachamama and almost anything else that the townsfolk might need.&lt;/p&gt;
&lt;p&gt;It’s also one of the more authentic towns we’ve come across so far.
Especially compared to San Pedro de Atacama, where it feels as if every
single inhabitant is greedily contemplating how to make (more) money out
of tourism. In Tupiza, the locals go about their daily routines (like
selling llama fetuses for example), largely oblivious (or at least
tolerating) the odd gringo to come across their path. So far we’ve
spotted about 12 other gringos after criscrossing the entire town. Gone
are the kitsh tourist shops, restaurant and bar promoters pestering you
to enter their establishments and of course the swarm of tourists who
would otherwise with their presence enable all these things to happen.
It’s like a breath of fresh air.&lt;/p&gt;
&lt;h1&gt;30 September Horseback riding in Tupiza, Bolivia&lt;/h1&gt;
&lt;p&gt;Tupiza really has some amazing surroundings, perfect for donning a
cowboy hat and heading out on a horse. We rented two Argentinian horses
and set off with our guide on a 7 hour ride out into the area.&lt;/p&gt;
&lt;p&gt;Turns out, our “guide” was a thirteen year old boy. Perhaps this was
not strictly legal, and it would be unthinkable in Germany, but he
seemed to know the area and how to ride a horse and in Bolivia that
already counts for a lot.
 &lt;/p&gt;
&lt;h1&gt;1 October, Leaving for Córdoba, Argentina&lt;/h1&gt;
&lt;p&gt;After our horseback-riding adventure of the previous day we were ready
to leave to Córdoba in Argentina. This would mean 3 hours in a local bus
until the Bolivian-Argentinian border, and then another 18 hours in an
Argentinian bus until Córdoba.&lt;/p&gt;
&lt;p&gt;We went to the bus station two days before to find the bus schedule and
perhaps so long book a bus to the border, but when we arrived there we
saw an agency for a bus company called &lt;em&gt;Balut&lt;/em&gt;, whith large photos of a
big gold bus with the letters &lt;em&gt;Cama Gold&lt;/em&gt; written across it. The other
bus agencies had paintings of buses if anything at all. Not exactly
something that instills confidence.&lt;/p&gt;
&lt;p&gt;We entered the little &lt;em&gt;Balut&lt;/em&gt; office and asked the lady some questions.
“Yes the bus is full-cama (meaning luxurious and fully reclining) and
looks like the gold one on the picture”, “Yes, lunch and dinner will
be served on the bus.”, “The bus will leave from the border at 19:00
and will take you through border controls”, and so on. Wow, this seems
great!&lt;/p&gt;
&lt;p&gt;Well, aftrer taking another dilapedated old local Bolivian bus to the
Villazon, we were still optimistic and looking forward to the gold
coloured luxury &lt;em&gt;full-cama&lt;/em&gt; bus that will be taking us from there to
Córdoba.&lt;/p&gt;
&lt;p&gt;We enter the &lt;em&gt;Balut&lt;/em&gt; office in Villazon, see more pictures of gold Balut
buses crossing Argentina and ask for our tickets. Turns out however that
just about everything we were promised before was bullshit. The bus
isn’t full-cama, isn’t gold and looks nothing like on the pictures. It
will leave later than originally told and there won’t be any meals
served on the bus. And lastly, it doesn’t take us through border
controls, we have to walk there (or take a taxi) ourselves. Ah, good old
Bolivia, that was again, what people warned us of before!&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1&gt;October, Cordoba in Argentina&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/e04ebb19639d89d3eb8f56bbf734fa24/IMGP0086.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s alread October by now and we have since left Bolivia for Cordoba
and Buenos Aires in Argentina.&lt;/p&gt;
&lt;p&gt;Cordoba is a fascinating and culturally rich city with seven (7!)
universities. We spent a lot of time just walking through the city
center, checking out the bakeries, coffee shops, malls and other
amenities that we’ve since learned to appreciate.&lt;/p&gt;
&lt;p&gt;Roberto Allende and the guys from Menttes invited me out for dinner and
I was served the largest steak I’ve ever seen. Covered with two fried
eggs for good measure.&lt;/p&gt;
&lt;p&gt;Roberto’s lovely wife and their 2 month old son also accompanied us,
giving Manuela the chance to hold and play with the baby, while we
discussed frameworks.&lt;/p&gt;
&lt;p&gt;The next night we met up with the Javier Mansilla (whom I met earlier at
the Budapest Plone conference) and his colleagues at Machinalis and
enjoyed some Picadas with Argentinian beer and more wine.&lt;/p&gt;
&lt;p&gt;We agreed that the Plone ties between Argentina and South Africa need to
be strengthened and I intend to return home with just that message!
Thanks for the friendly hospitality from all the Plonistas in Cordoba!&lt;/p&gt;
&lt;h1&gt;October, Buenos Aires Argentina and then off to Cape Town!&lt;/h1&gt;
&lt;p&gt;&lt;img src=&quot;/e16940d5d68d19eadc062d4cd7c359f2/IMGP0125.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We had high hopes for Buenos Aires after hearing so many good stories
from friends and travelers and I’m glad to say that we weren’t
disappointed in the least. Tango in the streets, more good steak,
friendly people, good infrastructure, great nightlife, and an old and
interesting city center; Buenos Aires really has a lot to offer.&lt;/p&gt;
&lt;p&gt;The Argentinians close all the shops around lunch until about 16:00 to
allow for a fiesta, which took a bit getting used to as we tended to
start going out to town at around lunch each day. Because of this, the
Argentinians also go out much later. We would arrive at a restaurant at
21:30 and be the only customers there. Then, at about 22:30 the locals
arrive and at 23:00 it’s full! In Germany many restaurants would have
by then already closed the kitchen.&lt;/p&gt;
&lt;p&gt;We have three days left in Argentina before flying to Cape Town and
starting a new chapter of our lives in South Africa. I am still enjoying
Buenos Aires, its culture of Gauchos (Cowboys), Tango and late night
dining, but also filled with excitement at the prospect of going home
for the first time in two years and at seeing old friends and family
again.&lt;/p&gt;
&lt;p&gt;From myself and Manuela, who had contributed lots of insights,
corrections and stories to this blog, I would like to say, thanks for
reading and “Adiós Chicos!”&lt;/p&gt;</content:encoded></item><item><title><![CDATA[South American travel diary, Part 3. Aug 2010]]></title><description><![CDATA[In August, we continued traveling through Bolivia and onwards to Peru.
Along the way we saw dinosaur tracks, a military parade celebrating…]]></description><link>https://opkode.com/blog/south-american-travel-diary-part-3/</link><guid isPermaLink="false">https://opkode.com/blog/south-american-travel-diary-part-3/</guid><pubDate>Sun, 08 Aug 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;In August, we continued traveling through Bolivia and onwards to Peru.
Along the way we saw dinosaur tracks, a military parade celebrating
Bolivia’s independence, had some really good food in Sucre, mountain
biked down the world’s most dangerous road in La Paz and visited Inca
ruins at the Island of the Sun.&lt;/p&gt;
&lt;h2&gt;1 August, Traveling from Samaipata to Sucre&lt;/h2&gt;
&lt;p&gt;We began the month traveling by night bus from the lovely small town of
Samaipata to Sucre, the constitutional capital of Bolivia.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/c97acdfb6fc21d366c588946fd1479db/IMGP6522.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We stopped in the middle of the night next to a church in a small
unknown town, and everybody streamed out of the bus. Obviously this was
a restroom break, but in Bolivia that implies something else than it
would in most other countries.&lt;/p&gt;
&lt;p&gt;Most passengers didn’t even walk five meters before unfastening and
pissing right there in the street between the bus and the church. A
proper restroom was or even a kios was nowhere to be found.&lt;/p&gt;
&lt;p&gt;About 30 meters away, a family or group of friends were sitting around a
table in a little restaurant. For them, it must have been a sight to
behold; an entire bus full of people (men and woman) appearing in their
field of view, pissing in and around the street.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0dba893df5fba856c1b88ee9fcd57725/IMGP6444.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;With an area of 30 meters around the bus covered in dozens of streams of
urine, everyone promptly returned to their seats and the bus continued
to Sucre as if nothing funny ever happened.&lt;/p&gt;
&lt;p&gt;In hindsight, we were lucky that the bus stopped at all. We have been
warned that the busses travel for hours and hours without stopping for
breaks and one traveler even told us that she suspected people of
urinating in their seats.&lt;/p&gt;
&lt;p&gt;Little did we know that urine (and urinating) would become a recurring
theme in Bolivia. Men and boys (and sometimes woman) would piss at the
side of a traffic filled street in the middle of town and in broad
daylight. That awful smell is omnipresent and a not so gentle reminder
that everything outdoors is fair game to be used as a lavatory, and not
just by the roaming packs of dogs.&lt;/p&gt;
&lt;h2&gt;2 August, Sucre: Exploring Cólon&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/c6e2a308d29f956d527c7ca5b0aa86f0/IMGP6448.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Manuela, our friends &lt;a href=&quot;http://southernhemisnuggets.blogspot.com/2010/08/capital-of-bolivia-sucre-no-la-paz-no.html&quot;&gt;Tony and Sofia&lt;/a&gt;and
myself arrived early the next morning in Sucre and took a taxi to our
hostel.&lt;/p&gt;
&lt;p&gt;We headed off to the nearby &lt;em&gt;Christobal Colón&lt;/em&gt; street, to find a cheap
place for lunch. There were a few &lt;em&gt;Plato Familiar&lt;/em&gt; restaurants in the
area, with not much separating them concerning outward aesthetics, so we
decided with our empty guts and chose one at random. The eatery was
family owned and the children were also involved, either taking orders
or carrying plates of food. The menu is set. Everyone eats the same
lunch, with the advantage being that it is incredibly cheap. Lunch
consisted of a soup (described by Sofia as reminiscent of Minstroné), a
main dish consisting of grilled meat with rice and a small salad, and an
orange for desert. All for 9 Bolivianos per person, about €1.&lt;/p&gt;
&lt;h2&gt;3 August, Sucre’s markets&lt;/h2&gt;
&lt;p&gt;The city center of Sucre is actually quite pretty, with white colonial
buildings backdropped by large mountains in the distance.&lt;/p&gt;
&lt;p&gt;What is really remarkable and noticable about Sucre, is the everpresent
juxtaposition of cultures and generations. The old and the new clash on
almost every street. I would walk down the street passing an old woman
in traditional clothes selling nuts, and then a few meters later pass an
internet shop filled with young kids playing World of Warcraft.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0ece561bc8c0647f1d97c70853ca7f7a/IMGP6738.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Travelers looking for something more authentic than a South American
varitation of western consumerism, will inevitably enjoy Bolivia. The
woman in particular all wear traditional outfits consisting of Bowler
hats, braided hair down to their hips decorated with tassles at the ends
and colourfully weaved ponchos, scarves and bags. Parts of the outfit,
the hat in particular, can be attributed to Spanish influences, but the
end effect is unquestionably and endearingly native.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7e5d136e5b8c9e582762ec873c336b17/IMGP6527.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Going shopping in Sucre (and Bolivia in general) is an experience in and
of itself. Supermarkets are few and far between, and Bolivians instead
buy and sell almost anything you might need at the local market or on
the street. The main market in Sucre is quite big and well ordered. The
woman selling cosmetics, soap and beauty products are all clumped
together in one area.&lt;/p&gt;
&lt;p&gt;Another area is reserved for stalls with food products (pasta, rice,
canned food, sauces etc.), yet another section contains meat sellers,
then fruit sellers, cakes, sweets, toys and on and on. The whole area
bustles with activity and shopping seems to be a much more social
experience, with the inevitable small talk and bartering as one moves
from stall to stall to buy the day’s or week’s essentials. You cannot
walk through the market without people calling you over to try and sell
their warres. Their sales call is usually a three times repetition of
the particular item they want to sell. Such as &lt;em&gt;Mandarina!, Mandarina!,
Mandarina!&lt;/em&gt; when selling fruit, or even &lt;em&gt;La Paz!, La Paz!, La Paz!&lt;/em&gt;,
when selling tickets at the bus station.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1c545f3c97314c31a62f06bf56e9cd50/IMGP6470.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7deddaf4f87cd3ca812f28d9ad7d5ca4/IMGP6469.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The walls of the one courtyard inside the market building are lined up
with small fruit stalls, with women behind them selling smoothies and
fruit salads. I ate the best tasting fruit salad of my life at one of
these stalls (for about € 0.50). We’ve seen similar fruit salad stalls
in La Paz, but they weren’t as good. Highly recommended for anyone
visiting Sucre.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a2f8b622f680aa0acd010692ed5993d8/IMGP6556.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt; 
&lt;img src=&quot;/edc037e72a5b499fb16414278c89a689/IMGP6495.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In addition to the local market, there are also &lt;em&gt;turistico&lt;/em&gt; markets,
selling bags, clothes, jewelry and mementos to the tourists. One of the
travelers favourites, is the &lt;em&gt;chompa&lt;/em&gt;, the Bolivian equivalent of a
jersey or jumper (from where the local name comes), complete with llama
patters and often being associated and worn by the Bolivian president
Evo Morales, much in the same way that Nelson Mandela wore his colourful
shirts. Other loved items are colorful bags and handbags, leather
wallets, caps and Incan/Peruvian beanies. Almost every backpacker will
buy at least one traditional clothes item, which the older people all
still wear, while many youngsters try their best to look urban and
“western”.&lt;/p&gt;
&lt;p&gt;Another oddity in Sucre (at least for Bolivia), is the businessman
wearing the western style suit and tie. This is quite a contrast to the
countryside, where the people live a life of subsistance farming with
their donkeys, chickens and cows.&lt;/p&gt;
&lt;h2&gt;4 August, Sucre’s dinosaur tracks&lt;/h2&gt;
&lt;p&gt;We made a visit to the dinosaur tracks outside of Sucre, home of the
largest collection of dinosaur footprints in the world. The footprints
were discovered in 1994 by the workers at the cement quarry operating in
the area. Up to 5000 prints from about 250 different dinosaurs are
embedded in a gigantic, near-vertical slab of limestone rock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/cb56b25e28b91df8145bb183fa1ff63a/IMGP6518.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Unfortunately the visit was a major disappointment, even for a former
dinosaur nut like me. It seems that the company owning the quarry
prevented the construction of a proper dinosaur park or museum. The
limestone rock containing the footprints is seperated from the actual
museum by a large part of the quarry, including a road carrying its
trucks, and this section is off limits to any visitors. The small
dinosaur museum is located on a hill about 50 meters away, from where
you can squint to try and see the footprints.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/bf899f564041b79fd5060512efc594d3/IMGP6516.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I couldn’t help but wonder whether this was not the result of bribing
and corruption which enabled a big business (the cement company) to
prevent the establishment of a proper museum (next to the actual
footprints) of what is obviously a national archeological treasure. The
museum itself looked nice from the outside and it seems as if is was
created or funded by people with good intentions, who wanted to create a
center for education and the preservation of the prints, but the fact
that it was so far removed from the actual site was just depressing. In
the end, after hearing from another disappointed Spanish tourist, that
the museum itself was not worth the entrance fee, and also out of
principle, we decided not to enter.&lt;/p&gt;
&lt;p&gt;Tony and I tried to sneak down the hill and closer to the footprints to
get a closer view or at least a nicer picture, but we were quickly
spotted by the guards and told to leave. Closer to the tracks, we found
a small brick building and a sign welcoming visitors to the Dinosaur
museum, confirming our suspicions that the original musuem was planned
to be closer to the actual prints. Too bad.&lt;/p&gt;
&lt;h2&gt;5 August, Sucre: My birthday, the mirador and the best steak in a very long time&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/98eb632cd39d5fb385e95c2b9f72aca2/IMGP6641.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;One of the advantages of Sucre, is the high number of good and yet very
affordable restuarants in the area. Today was my birthday, and Manuela
and I went with Tony and Sofia to a café up a hill where one could have
a view of the whole city. Tony and I bought some coca leaves at the
market the previous day, and we were munching on balls of leaves pressed
into our cheeks as we walked up the hill. After about an hour of having
the leaves in your mouth, you should add a catalyst (either plant ash or
bicarbonate soda) and then put the ball back into your mouth. The end
effect is a mild stimulant, like a strong cup of coffee, but not much
more.&lt;/p&gt;
&lt;p&gt;Afterwards we went to a French restaurant near the city center. We drank
a bottle of Aranjuez red wine and decided to eat potatoes with caviar
and the steak with red wine and mushroom sauce. This turned out to be
the absolute culinary highlight of our time in Bolivia, and the best
steak in ages, all for less than €5 per person.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a895ec30998d72235748b3f71536c5c1/IMGP6626.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Bolivia’s anniversary of independence is on the 6th of August (circa
1825), and on the night of the 5th, there was a large military parade
right under the balcony from where we were sitting. It was a very nice
coincidence (&lt;em&gt;Glücksfall&lt;/em&gt;), and we felt fortunate to be able to witness
it from above, since the streets were incredibly crowded. The parade was
quite militaristic, something which none of us has ever really
witnessed. An impressive variety of military units with different
outfits and weapons marched past our balcony, including a group of
paramilitaries who rode on jeeps wearing full camouflage, while pointing
semi-automatic machine guns at the spectators. Quite a spectacle from
above.&lt;/p&gt;
&lt;h2&gt;7 August, Sucre: Going out to Florin&lt;/h2&gt;
&lt;p&gt;After having had a fun night of food and drink 3 nights before at
Florin, a dutch owned bar and restaurant, we decided to go back for
seconds. Coincidentally a pop band from La Paz named &lt;em&gt;Dr. Jet&lt;/em&gt; was
playing that night and we were entertained with covers of Spanish pop
songs as well as Lady Gaga, Shaquira, Robbie Williams and others.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ff1ad354d6a1826de1c2232057ddde0c/IMGP6549.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was interesting to see that not a single person there was wearing any
traditional peace of clothing or even jewelry. Everyone was dressed
completely western, with one guy making sure that his Hilfiger jersey
was draped over his shoulder exactly right to allow one to see the
label. Just as the preppies do in the business school in Mannheim
Germany and probably all over the world.&lt;/p&gt;
&lt;p&gt;Sucre in general was a culinary pleasure especially considerung the
prices. It’s also the chocolate capital of Bolivia and we more than
once went to a local cafe where we drank hot chocolate and ate chocolate
covered fruit, for about € 2,50 in total. In the end, we stayed much
longer in the city than we expected, as we were hoping for the road to
Potosi to clear. It was being barricaded and blocked for weeks by
unhappy protestors, trapping panicky tourists inside the city of Potosi
and preventing anyone else from going in. In the end the situation took
too long to normalise and we decided to continue onwards to La Paz.&lt;/p&gt;
&lt;h2&gt;10 August Arriving in La Paz&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/b0d840f69b6832c6dc7065b7eded1ecf/IMGP6728.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The overnight bus ride to La Paz was quite terrible and nerve-racking.
Just the day before we read news of 72 people that died (and 196
injured!) only in the month of February 2010 in bus accidents in
Bolivia, and now we were sitting in such a bus, speeding along the side
of a mountain, with a steep drop off at the one side. Loud
Peruvian/Bolivian music blared through the shitty bus speakers, creating
more distortion than anything melodic, while we tried to enjoy the
cultural experience and not imagine rolling down to our deaths in the
valley below.&lt;/p&gt;
&lt;p&gt;The bus trip was again overnight and upon arriving in La Paz and
checking into our hostel, we decided to make use of the rest of the day
by walking to the nearest lookout point &lt;em&gt;Mirador Killi Killi&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;La Paz is really high, the highest capital (administrative) city in the
world, and we quickly ran out of breath every time we walked up a hill.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/399406d70203657f6f8bbf4adace4504/IMGP6718.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;11 August, La Paz’s witches market&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/0cb3070444ec0ea1f278cf416f4cc3ce/IMGP6731.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We went to the &lt;em&gt;Plaza de Armas&lt;/em&gt; in the city center on our way to the
famous &lt;em&gt;Witches’ market&lt;/em&gt;. The main square is again quite pretty,
surrounded by colonial buildings and well policed. One of the buildings
still contains bullet holes from a gun fight between the police and army
some years ago. The square is full of pidgeons and local women sell
seeds to feed them, which was popular among both the locals and the
gringos.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/travel-images/IMGP6763.JPG&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We continued further, past a few more markets before eventually reaching
the wiches’ market. This is probably the most touristic area of La Paz,
but still fascinating. In between the numerous &lt;em&gt;touristicos&lt;/em&gt; stalls,
there were &lt;em&gt;witches’&lt;/em&gt; stalls, selling all kinds of plants, potions,
offerings, totems and even dried up baby llamas or llama fetuses, dried
frogs and dead Armadillos.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3ab2dc826850bc4e1570ef0265110fdc/IMGP6780.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Referring to these people as &lt;em&gt;witches&lt;/em&gt; is in my opinion quite misleading
and also unfortunate, because aside from the “magic potions” which are
all bullshit and imported from the east anyway, these people were just
selling the traditional gifts (such as the baby llamas) to be offered to
&lt;em&gt;Pachamama&lt;/em&gt;, the earth goddess. To refer to them as witches is to impose
(often negative) western stereotypes onto their traditional customs and
practices. Many native Americans in Bolivia and Peru still adhere to
their traditional and native customs and practices, which include making
burnt offerings to Pachamama.&lt;/p&gt;
&lt;h2&gt;13 August, Mountain biking on the death road&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/64c34743704ddaba61bec335e44e7709/IMGP6820.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Mountain biking on the death road, outside of La Paz, is one of the main
tourist attractions in the area. It’s called the “death road”, or
“the worlds most dangerous road” because of the alarming amount of
fatal car accidents that have occured there over the years, and not
because of the amount of mountain biking accidents, although some
tourists have also died. The road is dangerous, because it is only wide
enough for one vehicle at a time, slopes downwards from a height of
4700m to 1200m and is flanked by the side of a mountain one the one
side, and a steep drop into the canyon below on the other side.&lt;/p&gt;
&lt;p&gt;What few people seem to mention however, is that the death road is also
beautiful. It is inside a cloud forest and the surrounding landscape and
vegetation is simply stunning.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3f40389d4b557e7e0a017867c2f41e8b/IMGP6840.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The cloudforest seems to be one of nature’s most psychedelic places.
White mists from the clouds fill the air, as if from a giant smoke
machine, while new fractal shaped fern leaves uncoil and unfold
according to a genetic blueprint that is hundreds of millions of years
old. Now and then you find colourful flowers; pink, purple, orange and
red, some big and shaped like a Jester’s hat and others small, hanging
like brightly coloured clocks. Between them fly colourful butterflies.
Bright spots in a canopy of a million different shades of green. All the
rocks and fallen branches are covered in moss and vines twist and turn
around the trees and bushes. Streams flow in the cracks and ravines,
sometimes falling dozens of meters over the edge of a cliff, down to a
pool below. The whole place seems to breathe; alive, vibrant and blessed
with the abundance of water.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/64a4e0498e8eaf5a28506501a503fb11/IMGP6834.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Biking the death road was an incredible thrill and well worth the price.
We started early the morning at the top of the mountain &lt;em&gt;La Cumbre&lt;/em&gt; at
4700m. So high, that it was icy cold and actually snowing. The first
part was on a tarred road, still being used by cars and trucks (as
opposed to the actual death road which has a newer tarred replacement).
After a while we reached the actual death road (a gravel road) and the
beginning of the cloud forest. From here on, it was still another 63km
and 3500m down to the vally below. An unforgettable combination of
adrenalin sport and nature.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6d2740a8936d83681c7a6384f2fe6d55/IMGP6898.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;15 August, Last day in La Paz and traveling to Copacabana&lt;/h2&gt;
&lt;p&gt;After a few days in La Paz, we left for our final Bolivian destination.
The town of Copacabana on the coast of Lake Titicaca.&lt;/p&gt;
&lt;p&gt;On our final day in La Paz, we shared some impressions of this
fascinating city and we remarked on how amateur things in Bolivia
sometimes appear. In some areas of La Paz, the billboards are actually
the prettiest things in view. Sometimes, we would go to a restaurant,
and it would feel as if you were the first customers they have ever had.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/8886c1c685b2cc75896250dbf6dfac05/IMGP6939.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Upon our arrival in Copacabana, we went to such a restaurant. We wanted
to leave, feeling that it might be a mistake to eat at this particular
restaurant, seeing that they had no other customers yet, horrible
decoration, a dirty table cloth, and a strange menu, but the whole
family of about three generations were looking at us excitedly (at least
by Bolivian standards, which is with almost no expression at all), so
that we felt compelled to stay and stimulate the local economy. Big
mistake. We ordered a bottle of Kohlberg red wine, which by had now
secured its place as the best value for money in Bolivia, but this time
for more than double the retail price. Ten seconds later the mom and her
small daughter ran out of the restaurant and Manuela makes a bet with me
that they are going out to buy the Kohlberg. Sure as hell, a while later
she returns with a bottle shaped object hidden beneath her poncho.&lt;/p&gt;
&lt;p&gt;We also ordered two trouts, one with butter and one with tomato, known
to be one of the local specialities. After a while the trouts arrive,
both looking identical. Fried in fat, lying on a handful of chips, with
a bit of dry rice on the side. The only difference is that my trout is
completely covered in Ketchup while Manuela has some butter (or perhaps
margerine) smeared over hers. Depressed at being fleeced with our shitty
trouts and (expensive) cheap bottle of wine, we ate without much
conversation, although we occasionally made jokes and laughed at the
situation.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/33c3d0ce67c1f88e39cc4d26447d1b1f/IMGP6959.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It’s remarkable how many Bolivians try to use tourism as a means for
creating better lives for themselves and how hard they sometimes have to
work for it. Once we were in a restaurant, run by a married couple who
worked from the morning to the night, while their small child played
behind the counter. The mother makes all the food and the father takes
the orders. Later, we would go to a restaurant run entirely by a single
woman. She would take the orders, cook the food and serve it, for seven
tables! We were glad to support these hardworking local people, and were
therefore also prepared to sometimes lower our standards a little.&lt;/p&gt;
&lt;h2&gt;16 Copacabana&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/c4e279f037cf077eaa9666765b679fe6/IMGP6978.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In Copacabana we visited the local cathedral with its famous &lt;em&gt;Virginita
of Copacabana&lt;/em&gt;, a statue (almost doll) of the holy mother Mary, created
by a relative of the famous Inca king Atahualpa. The Incas worshipped
mother earth through the goddess &lt;em&gt;Pachamama&lt;/em&gt;, and this practice was
later synthesised with the Catholic veneration of Maria, as introduced
by the Spanish.&lt;/p&gt;
&lt;p&gt;Copacabana is surrounded by three hills, and we wanted to climb up one
of them to see the nice view. As it happened, this hill was also a type
of pilgrimage, with a place for burnt offerings at the top. Along the
path to the top, there were stone monuments, with scenes from Jesus’
capture, lashings and crucifixion, culminating in the final scenes of
his death and resurrection at the top of the hill. Midway up towards the
top of the hill, a shaman was holding a ceremony for a young couple,
burning their offerings of candy, fake money and other paraphernelia on
an altar.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0642221fe209c30dfee4438512127177/IMGP6989.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We took a breather and went to the edge to look out at the sun over lake
Titicaca ahead of us. Just then, an old man walks past us, pulls out his
wiener and pisses right in front of Manuela and I. We took the (not so)
subtle hint, and left the area to continue upwards.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/694fd22021f5fb1fc8e7a2086d5c97de/IMGP7003.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Walking up the hill, I remarked that this must be the dirtyist, most
littered hill I have ever climbed. Paper, plastic, beer bottles and
everything in between was scattered along the whole way, making the
experience much less pleasant.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d941b91d888d72bc54fc653045aa8582/IMGP6998.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At the top of the hill, more people where making offerings to smaller
representations of the Virginita (basically a doll in a glass case), who
represents the mother Mary, but also &lt;em&gt;Pachamama&lt;/em&gt;. The locals believe
that (among other things) you must offer something representative of
that which you want to receive. So many people would burn fake money, in
the hopes of receiving real money.&lt;/p&gt;
&lt;p&gt;The craziest of all however, was the stalls at the top selling small
houses, cars and other offerings such as confetti and sweets.
Presumably, if you want a new car of a new house, you buy such a small
representation, and burn it as an offering to the Virginita.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/de936d578d1eb02ba441fed3e9d7f505/IMGP6995.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Another strange practice, that we also in a catacomb beneath the church,
was the custom of buying candles, burning them and then using the wax to
create the outline of the object that you want. As mentioned, at the top
of the hill were stone monuments with paintings of Jesus’s crucifixion
and resurrection behind dirty glass cases. These stone monuments were
completely covered in these wax figures, making them very oily and
dirty.&lt;/p&gt;
&lt;p&gt;It’s relatively well known (or should be) that Catholicism is a
synthesis of early christian sects and some pagan European practices,
which makes the fact that there is an ongoing synthesis of Catholicism
with the indigenous American/Incan beliefs as found in Bolivia, ever
more fascinating.&lt;/p&gt;
&lt;h2&gt;17 August, Isla del Sol&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/fda2d5000fca916d23ab67d8aadf43d6/IMGP7031.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Apparantly, according to the Incas, lake Titicaca was the navel of the
world, the place where the first Incas were created and also where the
sun and the moon came from.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/793c163d6768b3c03de24720ca6d9ae9/IMGP7040.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We took the 8:30 ferry to &lt;em&gt;Isla del Sol&lt;/em&gt; (Island of the sun) where
according to Incan legend, the Incan god Viracocha, the first Incan
Manco Capac and his sister (Incan royalty married their sisters) met and
where the reign of the Incas began. Nearby is also the smaller &lt;em&gt;Isla del
la Luna&lt;/em&gt; (Island of the moon), where the ruins of a pre-hispanic Incan
monastery that housed virgins to be sacrificed on the sun island, can
still be seen. It is said that the sun and the moon came out of lake
Titicaca, and that the sun, being jealous of the moon’s bright light,
threw dust into its face, thereby covering its light and causing its
grey white colour.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d8d70f1f7f136c9d1e5e41c49ffe0a81/IMGP7053.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We stopped at the north end of the island, and after a quick stop at a
small museum where you could see Incan and pre-Incan artifacts recovered
from the depths of Titicaca, we headed off to the ruins at the north end
of the Island. We walked to the &lt;em&gt;Piedra Sagrada&lt;/em&gt; (holy rock), before
continuing to a rock outcropping containing the face of the Incan god
&lt;em&gt;Virococha&lt;/em&gt;. The Incan’s (and perhaps even pre-Incas) recognised an
elongated angry looking face in the rock, considered it to be from a
deity and built an altar in front of it on a piece of rock that is so
perfectly situated in front of the face that it’s almost eery. We were
introduced to a local &lt;em&gt;Curandero&lt;/em&gt; Shaman, who still conducts ceremonies
at the altar, asking for good harvests or other favours. He explained to
us that virgins were sacrificed there in pre-hispanic times, later to be
replaced by llamas, and also that there is an energy in the name
&lt;em&gt;Virococha&lt;/em&gt; and in the names of other deities.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d5b5429f4c0d158bd3e8c5081c7f1c50/IMGP6965.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;In what is such an incredible coincidence (and blind luck) that it’s
almost uncanny, the image of the first conquistador to meet the Incas in
the area, Francisco Pizzarro, reminded the Incas of their deity
&lt;em&gt;Virococha&lt;/em&gt;. An elongated, angry face with a beard. The Incan ruler,
&lt;em&gt;Atahualpa&lt;/em&gt; killed his half-brother (and heir to the Incan empire) a
while before, and the Incas were already tense and scared of what they
considered a taboo act by &lt;em&gt;Atahualpa&lt;/em&gt;. So when Pizzarro (deemed
representative or incarnation of &lt;em&gt;Virococha&lt;/em&gt;) arrived, his Incan army of
40 000 men were so terrified of their deity’s wrath, that they fled
before the 140 men strong conquistadorean army. This provided Pizarro
with a victory that would otherwise have been much less likely.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a1f78b7eb03fad3be134f127130958dd/IMGP7048.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The effect that the Inca’s prophesies and mythologies had in their own
downfall and subjugation towards the Spanish, gave me food for thought
concerning the ever popular Christian apocalyptic prophesies and their
power in actualising some of the events they “prophesize” simply by
the power of enough people believing in them (as the Incas believed in
their own mythology).&lt;/p&gt;
&lt;p&gt;Apocalyptic musings aside, we visited the Incan palace nearby, where
&lt;em&gt;Atahualpa&lt;/em&gt; first met &lt;em&gt;Pizarro&lt;/em&gt; and offered some of his gold in turn for
his life. &lt;em&gt;Pizarro&lt;/em&gt; instead decided that he wanted all of the gold and
then killed &lt;em&gt;Atahualpa&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;After visiting the ruins, we started walking along the ridge of the
Island towards the south side which took us the whole day, ending at a
restaurant with a spectacular view of the sunset over lake Titicaca.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7543ba0922fae0340afbd4c35c64a77e/IMGP7089.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;19 August, Traveling to Arequipa, Peru&lt;/h2&gt;
&lt;p&gt;We took the early morning bus to Arequipa in Peru, a 9 hour journey.
Along the way we saw impressive hilled landscapes with herds of llamas
and a lake with pink flamingoes. Unfortunately the bus driver drove like
a maniac, speeding, honking incessantly and making the whole bus sway
from side to side, causing Manuela and I to become car sick. The
unpleasant bus journey was however lightened up a bit by a guy who sang
while playing a peruvian flute and a Jukelele.&lt;/p&gt;
&lt;p&gt;So far Peru seems very much like Bolivia. As in Bolivia, many people
paint the walls of their houses with political advertisements for their
preferred candidate for the local governor. Sometimes a large rock in an
outcropping in the middle of nowhere would be painted with a political
party’s emblen, name and slogan on a white background. I am much more
aware of the local politics in Bolivia and Peru than during our time in
Argentina and Brazil.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/f0ab3b18f23f65ab2aef38393a6f1aac/IMGP7159.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;21 August, Arequipa&lt;/h2&gt;
&lt;p&gt;After staying in our third so-called “party hostel”, which are very
popular among backpackers, we’re quite disappointed with the level of
sophistication and maturity of many of the backpackers we encounter. A
lot of them treat the experience the same way teenage adolescents would
treat a school trip, flirting and jockeying for attention or popularity,
drinking every night before throwing up and then bragging about it the
next day, and generally acting as if they are still somewhere in Europe,
Australia or North America. One highlight was a drunk couple coming back
to our 6-bed dorm after partying until about 3:30 am, and then
proceeding to have very noisy sex, in the process waking everybody up
and all without even the slightest appology.&lt;/p&gt;
&lt;p&gt;This is of course a gross generalisation, and we have met many
open-minded, knowledge hungry and genuinely interesting travelers along
the way, but usually not in “party hostels”.&lt;/p&gt;
&lt;h2&gt;22 August, Arequipa&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/a94cfcdaf8e10de63b520d32e506f0a7/IMGP7157.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Coming in to Arequipa, we saw a lot of poor neighbourhoods with dirty
unkempt buildings. The city center is quite the opposite however, with
lots of renovations being done in the streets around the main square.
Arequipa is surrounded by three big volcanoes, and the colonial
buildings in and around the square have been built with the white
“sillar” volcanic rock, lending it it’s reputation as the “white
city”.&lt;/p&gt;
&lt;p&gt;In the afternoon we went to the local “Santuary” museum, where the
frozen remains of “Juanita”, a twelve year old Incan ritual sacrifice
victim is on display. The Incas sacrificed children, seen as pure and
unspoilt, to win the gods’ favour whenever they fell on hard times. In
the 1400s, the Incan empire was plagued by an erupting Volcano (near
Arequipa) followed up by a drought. Juanita was the daughter of a family
of very high social standing, who was taken from Cusco, all the way up
to a very high Volcanic mountain to be sacrificed. The Incas believed
the mountains were the realms of the gods and the weather patterns and
tribulations they faced going up there, were the gods response to their
presence.&lt;/p&gt;
&lt;p&gt;After her death, Juanita was wrapped in fine cloth and buried with a
collection of symbolic and sacred objects. For the next 500 odd years,
she remained frozen in the -20°c temperature, untill she was discovered
in the thinning ice of yet another volcanic eruption in 1995.&lt;/p&gt;
&lt;p&gt;The musuem and the staff were very professional and well worth a visit.
A far cry from what we had become accustomed to during our time in
Bolivia.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6b1adbea0da682db34c9cf9347087620/IMGP7170.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;23 August, Mountain biking at Volcano Misti&lt;/h2&gt;
&lt;p&gt;After having so much fun mountain biking down the death road in La Paz,
we decided to have another mountain biking adventure at the Misti
Volcano. We got picked up early in the morning and drove out to the foot
of the Volcano, getting nice views of Arequipa as we left the city
limits. The outskirts are not so soft on the eye (to put it
euphemistically) as the city center. Peruvians stream into the city
looking for a better life and construct shabby looking brick buildings
on the outskirts. Often the walls are left unrendered and unplastered,
leaving the houses looking ugly and unfinished.&lt;/p&gt;
&lt;p&gt;New communities made up of these buildings appear quite quickly at the
edges of the city, where there is no water, sewage or electricity
infrastructure. After some time the new residents start to demand basic
services and eventually the government provides them, together with
property rights. In this way, the city grows in a haphazard and
disorganized way and making the outskirts very unattractive. It must be
said however, that these people at least build brick structures, so
it’s still a few steps ahead of squatters and shanty towns of which we
have seen surprisingly little in South America.&lt;/p&gt;
&lt;p&gt;A little bit up at the foot of the Misti, we got stopped and geared up
to bike down to the bottom. It was quite a bit more difficult and
technical than in La Paz, but still an incredible amount of fun! We then
drove to another small rural town and mountain biked there as well,
before returning to town for lunch at Mistica café in Calle San
Francisco. Secret tip: The best lunch we had in town and for only 8
soles each.&lt;/p&gt;
&lt;h2&gt;24 August, Trekking the Colca canyon&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/8a78eb0218442b581e14a4e89003cc3d/IMGP7269.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The Colca Canyon, outside of Arequipa, is reportedly the deepest canyon
in the world, twice as deep as the Grand Canyon and averages a depth of
3400 meters for a length of 100 km.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a3c807b261cff0a332c71e53295113aa/IMGP7307.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We booked a tour for two days and left at 3:00 am the first day to the
town of Cabanaconde to start hiking down the canyon. A while before we
stopped at a well known Condor lookout point for breakfast and another
opportunity to spot some of these majestic birds. What awaited us there
completely surpassed our expectations. Condors were floating on the
rising thermals right in front of the viewpoint and sometimes less than
5 meters away! About 8 condors seemed to be in the area, seemingly
unperturbed by the dozens of tourists snapping away with their cameras.&lt;/p&gt;
&lt;p&gt;The hike down to the canyon took the rest of the day, about 7 hours in
total and 14 km in length. We spent the night at the so called (and well
deserved) “Oasis”, with a pristine rock pool of fresh 22° mountain
water. The accommodation consisted of huts with thatched roofs and mud
walls and floors. Basic but part of the fun and atmosphere.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/fc47fe185fd6cfca8ea26d52f1542f02/IMGP7298.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;25 August, Trekking the Colca canyon&lt;/h2&gt;
&lt;p&gt;On the last day of the Colca canyon treĸ, we woke up at about 4am to
hike back up and out of the canyon. It took us about 2 hours and 45
minutes (3 hours being the average) to complete the 6km long and 1km
high hike out of the canyon.  It was quite a challenge because it was so
steep, but also good training for the hike to
&lt;a href=&quot;http://en.wikipedia.org/wiki/Choquequirao&quot;&gt;Choquequirao&lt;/a&gt;that we would
later attempt. Part of the hiking trail up and out of the canyon can be
seen in the photo below:&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ffd75fad33eb78ec991baad56ac9dc69/IMGP7374.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The rest of the day was mostly spent driving in the bus and watching the
scenery, including a majestic view of a nearby valley covered in
terraces (seen below) some perhaps dating from the Incan times, before
visiting some hot springs where we could relax our aching muscles.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6e766ff373cf4ac1a4a04988ca99ccc7/IMGP7426.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;27 August, Leaving to Cusco&lt;/h2&gt;
&lt;p&gt;At the end of the month, we left for the famous city of Cusco, were
we’ll be visiting two lost Incan cities. Machu Picchu and the lesser
known Chocequirao.&lt;/p&gt;
&lt;p&gt;That we will leave for next month however, and for the next blog entry. :)&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;P.S. Think twice before using Escandinavia tour agency in Arequipa,
Peru&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;We booked the mountain biking and Colca Canyon activities through a
local tour company (Escandinavia) located in the main square (Placa de
Armas) in Arequipa. The agency is run by a Peruvian named Edgar, who
speaks good English. We were quite happy with the tours he booked for
us, but unfortunately things changed for the worse later when he made an
erronous bus booking for us, for which he lost an entire day. Afterwards
we caught him lying to us about having someone to pick us up in Cuzco,
and he also didn´t pay (as promised) the deposit of a booking we had to
cancel because of his mistake. The fact that he made a mistake in
booking our bus could be overlooked, but after he lied to us and also
neglected to fulfill his promises, we feel it’s necessary to warn
others. The staff at the Point hostel in Arequipa also later informed us
that - after some disappointments - they do not make use of his services
anymore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/9e94b4316e9640880e1dc628b33ab12b/IMGP7444.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[South American travel diary, Part 2. July 2010]]></title><description><![CDATA[We continue on our travels through South America, including visting the
Pantanal in Brazil, Iguacu falls in Argentina, Ciudad del Este in…]]></description><link>https://opkode.com/blog/south-american-travel-diary-part-2/</link><guid isPermaLink="false">https://opkode.com/blog/south-american-travel-diary-part-2/</guid><pubDate>Sat, 07 Aug 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;We continue on our travels through South America, including visting the
Pantanal in Brazil, Iguacu falls in Argentina, Ciudad del Este in
Paraguay and then off to Samaipata in Bolivia.&lt;/p&gt;
&lt;h2&gt;4 July, Canoa Quebrada&lt;/h2&gt;
&lt;p&gt;We got a room without breakfast included, so we decided to use the
opportunity to sleep late instead of being woken by an alarm clock. At
about 12 am we went down to the local (very basic) bar/restaurant for
some Churrascuro (grilled meat and side dishes) at R$ 10 per person
(about €4.50). It’s been 6 weeks without any stomach problems or
diarrhea. This includes eating from street stalls, bus stations and from
makeshift “home” restaurants (sometimes in people’s living rooms).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ca9a9bd5163926a553ade28362841f56/IMGP5190.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/47ee7614818c5696dd7abd46b817af5c/IMGP5206.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We then went to the main beach, quickly saw that it was too crowded for
us, turned left and started walking to a collection of electric
windmills off in the distance. Canoa’s beach is quite long, a local
estimated about 20 km in total, with the main beach occupying only about
150m, so we had a long stretch of deserted beach to explore.&lt;/p&gt;
&lt;p&gt;I expressed my desire to to go and stand under one of the windturbines
so we continued walking along the coast into their direction. After
about almost two hours of walking in the midday sun we concluded that
these things were still deceptively far away, and that we must get some
rest soon. To make matters worse, we only had 500ml of water with us. I
eventually found a new target to make all the walking worthwhile and we
headed off to a sanddune nearby to look for some shade.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/919de75ca894b12a4e598123bf24b93e/IMGP5204.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Canoa Quebrada is very reminiscent of Swakopmund in Namibia. It’s very
hot and dry with a long stretch of coast flanked with white sanddunes.
Very pretty in it’s own way. We were unfortunately quite sad to see
plastic litter across the entire stretch of beach that we walked. To
make matters worse, we found several dead fishes and puddles of brown
and clearly polluted water. One of the big touristic selling points in
Canoa is the buggy rides to the sanddunes. Every 15 minutes a buggy with
smiling people would pass us by as we walked along the coast and
practically the entire stretch of beach was turned into a buggy highway
covered in tire tracks. As a result we were a bit disappointed with
Canoa Quebrada. It seems the residents still need to develop a sense of
responsibility for conserving the beaches fragile ecosystem and for
keeping it clean.&lt;/p&gt;
&lt;h1&gt;6 July Overnighting at Fortaleza airport&lt;/h1&gt;
&lt;p&gt;Our plane from Fortaleza to Campo Grande left at 6:00 in the morning, so
we made the decision to stay the night at the airport.&lt;/p&gt;
&lt;p&gt;At about 12:00 at night, we made a little campsite under the stairs of
the viewing hall and got ready to tuck in. Manuela successfully slept
there for about an hour, but about half an hour after I joined, a
security guard came and politely asked us to leave. That was pretty much
our only chance for sleeping that night, so for the remainder we sat on
some (probably purposefully) uncomfortable chairs listening to music and
trying to catch some minutes of sleep before being woken up by the
inevitable pins and needles in the butt cheek and leg that bore the
brunt of the body’s weight.&lt;/p&gt;
&lt;h1&gt;7 July, Campo Grande&lt;/h1&gt;
&lt;p&gt;We arrived in Campo Grande at about 12 in the afternoon. Hungry and
exhausted. We met a Danish couple and the four of us were quickly roped
in by a smooth talking Pantanal tour salesman named Gil.&lt;/p&gt;
&lt;p&gt;Gil fired off his sales pitch at our fragile, sleep deprived minds. We
were all wary of being ripped off and trying to be intelligent,
discerning tourists, but eventually the prospect of going downtown alone
with our backpacks to look for a better deal looked less and less
appealing. Gil continued, showing us pictures of a Pantanal lodge with
reclining beach chairs, swimming pool, dormitories and private rooms and
then when our defenses finally broke, went ahead and sold us a package
that excluded all of the above. Without explicitly telling us of course.&lt;/p&gt;
&lt;h1&gt;9 July, Santa Clara lodge, Pantanal&lt;/h1&gt;
&lt;p&gt;The first morning of our stay in the Pantanal, we had to be ready at 4
o’clock to go on an early morning game drive.&lt;/p&gt;
&lt;p&gt;The Pantanal is 90% private owned, so we had to restrict ourselves
mostly to the big public gravel road that moves between the farms, which
felt less immersive in the wild than the game drives I’ve been on in
South Africa. This was one of a few times that the thought occurred that
it’s quite a shame that there is no big national park in the Pantanal,
such as Etosha in Namibia or Kruger Park in South Africa.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/def547064ce302a64af8f975202a5794/IMGP5305.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a20d93aabf652c940a59f1b256705967/IMGP5316.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For brevity, I’ll refrain from overly describing this amazing place,
and instead the inquisitive reader to the &lt;a href=&quot;http://en.wikipedia.org/wiki/Pantanal&quot;&gt;wikipedia
page&lt;/a&gt;. Some interesting facts
that I can’t help mentioning though, are that the entire Pantanal
covers an area the size of France and contains about 35 million caimans
(alligators) and a stunning collection of birds and other wildlife.
&lt;em&gt;Pantanal&lt;/em&gt; means swamp, and during the rainy (summer) season, almost the
entire place gets covered in water. During the dry months, only a
limited amount of swamps remain though, with lots of dry bushveld in
between.&lt;/p&gt;
&lt;p&gt;Our guide for the early morning trip was exceptional. In the dim light
of dawn he spotted birds in trees and even small spiders in the road.
Sometimes it took me half a minute to spot a bird that he recognised
minutes before in a moving vehicle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ad557c796226889e7f06df249ea91f41/IMGP5282.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Overall we spent about 6 hours in the bush, which included watching a
spectacular sunrise over a lake, followed up by a hike for about 2
hours.&lt;/p&gt;
&lt;p&gt;We saw quite a few animals, a local raccoon, small bush deer, large
deer, some more caimans, black howler monkeys, a large and scary
tarantula like spider and a variety of birds.&lt;/p&gt;
&lt;p&gt;The afternoon was spent horse-riding. What could be said about that?
Well, it was great, I could get used to a lifestyle of regular
horse-riding and I felt a special kinship with my specific horse, even
though it was a bit of a tourist whore. It made some strange grunting
and burping noises during the ride, which prompted various theories from
our group as to their origin, randing from the mundane, to sexual to
esoteric.&lt;/p&gt;
&lt;h1&gt;10 July, Santa Clara lodge, Pantanal&lt;/h1&gt;
&lt;p&gt;The nights we slept in hammocks in the open air (surrounded with
mosquito nets), and were woken up that morning by the sounds of the
wild. Loudest of all was the call of a bird called the
&lt;em&gt;Chacochachalaka&lt;/em&gt;, whose name is an onomatopedic attempt to recreate
this creature’s cacophonic call but which ultimately fails. The noise
is usually created by at least two birds in tandem. The one starts
making a more high pitched call, then immediately followed by a lower
pitched reply. The aural effect is a bit similar to a recording of a
chicken being grabbed by the neck and swung around a few times, with the
pitch lowered a few octaves.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/70aee5a88dfee77f5e9ca824933560cc/IMGP5333.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For the morning activity, we went on a boat ride on the local river, a
tributary of the Paraguay river. We got a chance to see even more
Caimans, some Capivaras and another large variety of birds.&lt;/p&gt;
&lt;p&gt;The afternoon was spent piranha fishing with little peaces of beef, a
surprisingly easy and fun activity. Manuela had one of the biggest
catches of the day, I caught about 5 piranhas, with 3 being let go for
being too small to do anything useful with.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e8a0f578e611aa6c8eb68062c384c790/IMGP5461.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Later, while we were cleaning the fish, our guide cut out the tiny heart
of a dead piranha. To my amazement, it was still beating! Our guide
remarked that perhaps that’s why the piranhas are such nasty fish, they
have very small hearts. I held the beating heart in my palm for a few
minutes, considering wether I should eat it, but eventually threw it
away. The piranhas have very sharp teeth, capabale of biting off a
finger, even after they’re dead (due to convulsions), but the concept
of people being attacked and killed by piranhas is a myth. We swam in
the caiman and piranha infested waters and lived to tell the tale.
Piranhas will only attack if you are bleeding and caimans eat only fish.
So even though both animals are still dangerous and can definitely
injure a person badly, it’s still quite safe to swim in the river if
you maintain a distance and avoid any bleeding.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ea06cdecd4b0b00303cb8b7b621e6af1/P7100696.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;11 July, Santa Clara lodge, Pantanal&lt;/h1&gt;
&lt;p&gt;Early that morning, in addition to the now familiar cry of the
&lt;em&gt;Chacochachalakas&lt;/em&gt;, we were woken up by the ominous ruckus made by a
troupe of Black Howler Monkeys. It was however a pleasure to lie in a
hammock in the early morning ours listening to the sounds of nature, and
even the less musical animal cries are a huge improvement over the
sounds of construction workers and city traffic.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b3b46824c7e444647020c74aa105599a/IMGP5275.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;12 July, Santa Clara lodge, Pantanal&lt;/h1&gt;
&lt;p&gt;We spent the morning taking on a two and a half hour hike, during which
our guide explained many of the medicinal properties of the local
vegetation. Examples included the Yellow Trumpet Tree, whose bitter sap
is a remedy for inflöamation. A water lily from which a hallucinogenic
tea could be made, the Acori Palm, from whose seeds you could press
drops of water to use as eyedrops. The Acori Palm was quite abundand in
the area and seemed to be an important part of the local ecosystem. The
leaves are fed on by the cattle during the raining season, when the
grass is covered in water. The coconuts are eaten by armadillos to file
their teeth and eaten by the Macaws, who can crack them open with their
powerful beaks. From the hard shell covered fruit you can make a
drinking cup, a plate or a horn with which to make a Jaguar call. Inside
the hard shell of the fruit is a yellow flour (in addition to some
worms) which is eaten by the natives. We were also introduced to Tuco, a
bamboo used for making bows, and Caraguata, a bromeliad whose leaves are
used for fiber. At this point I stopped taking notes and decided to
concentrate on enjoying the hike instead.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/travel-images/IMGP5434.JPG&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Overall, the Pantanal was an enriching but not entirely stressfree and
relaxing experience. Firstly, there was an unpleasant run-in with a very
rude and unprofessional guide on the first day. Then, the huge amount of
acquired mosquito bites coupled with steep temperature changes between
searing hot in the afternoon and chillingly cold at night in addition to
the everpresent and all-covering dust, meant that I was quite relieved
to be leaving. On this trip so far, we have been happiest when we were
doing our own thing on our own time. Taking part in a packaged tour of
the Pantanal was just the opposite of that. The activities were fun and
worth the effort and money, but there were just a few too many
unpleasantries, none the least the way we were treated by some of the
lodge staff, that make me remember the experience with mixed feelings.&lt;/p&gt;
&lt;h1&gt;13 July, Bonito&lt;/h1&gt;
&lt;p&gt;We arrived in Bonito (meaning beautiful) the night before, after a long
and very bumpy ride on what was probably the most half-hearted attempt
at creating a temporary gravel road in order to facilitate repairs on
the main road. In other words, this gravel road was awful, and I had
visions of our poor little minibus breaking down with us having to spend
the night at the side of the road in the middle of nowhere.&lt;/p&gt;
&lt;p&gt;Instead, all went well and we were now in the popular town of Bonito,
renowned for it’s offering of beautiful caves and rivers and a whole
range of activities associated with them. There was just one problem,
the hostel where we stayed and all the activities it included, were
terribly expensive.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b8b8e54bbfc8d66890fb669d897bc5d8/IMGP5522.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We therefore opted for the poor man’s alternative, rented bicycles and
rode 7km to &lt;em&gt;Banleário Municipal&lt;/em&gt;, where we could snorkel in the river.
The bicycle trip out of town was a pleasure, providing another chance to
take in and appreciate the landscape. &lt;em&gt;Banleário Municipal&lt;/em&gt; was a
pleasant surprise, next with a very beautiful and clear turqoise
coloured river, swarming with fishes. We snorkeled for about two hours
until it started raining, when we huddled under a shelter with two
Brazillian caretakers discussing (in broken Portuegese) Brazillian
weather/festivals/beer/people/etc. compared to their German equivalents.
We were again struck by the friendliness of most of the Brazillians we
encountered.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/34aaf08892c6c39ddde638e3617ff0c9/IMGP5527.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Bonito is definitely one of the richest most developed towns we’ve
encountered so far, with quite a few very stylish and modern houses
around town. Perhaps that’s why the activities were so expensive. It
could also however just be an indicator of the wealth gap between the
poorer North and richer South of Brazil.&lt;/p&gt;
&lt;h1&gt;14 July&lt;/h1&gt;
&lt;p&gt;After one day in Bonito, we left deviated from our original plan and
decided to leave for &lt;em&gt;Foz do Iguacu&lt;/em&gt;, a Brazilian border town near the
Iguacu waterfalls. As we headed more and more south, the landscape and
the climate continued to change, getting greener and colder. Some areas
even reminded us of the south of Germany, with neatly kept green fields
dotted with patches of forest vegetation (rainforest as compared to
Germany’s temperate forest).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/894994b56443c4770735efbddadec14d/IMGP5542.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We had to change buses twice and waited about two hours in the middle of
the night for one of the later ones, which meant that I was again very
tired upon arrival.&lt;/p&gt;
&lt;p&gt;We decided to take it slow, had lunch with a nice older Danish couple
who (very patiently) were waiting with us the previous night for their
own (even more delayed) bus. We swapped some travel stories and they
told us about their adventures in Peru. Afterwards, we left for the
Argentinian border town of Puerto Iguazu, to find some accommodation for
the night.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/97c843b3e33b32b4e235312cdd7faccc/IMGP5588.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Upon arriving in Argentina, we quickly detected a different vibe,
culture and look than we were getting used to in Brazil. The shops
seemed to be better stocked and with more specialties.&lt;/p&gt;
&lt;h1&gt;15, 16 July, Iguacu Waterfalls&lt;/h1&gt;
&lt;p&gt;We spent two days visiting the &lt;em&gt;Parque Nacional Iguazu&lt;/em&gt;, in which the
spectacular Iguazu waterfalls can be found. The largest of which, is the
&lt;em&gt;Garganta el Diablo&lt;/em&gt;, or “Devil’s throat”.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/86c52e43bf1883cfecfffb536af4767a/IMGP5626.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d82c87d7f5c52d041454a0f714a3aa13/IMGP5670.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The magnificence of the this waterfall is beyond description. Enormous
amounts of water continuously flowing over the edge and into a white
abyss. The white mist making it difficult if not impossible to see the
water below. When the eye looks on to the water pouring over the edge,
it tries in vain to find something in the ever changing sceneto focus
on, giving rise to a mesmerizing effect. I felt as if I could have
stared at the falling water for hours.&lt;/p&gt;
&lt;p&gt;There are 269 other waterfalls, extending to both sides of this monster,
creating a wide vista so impressive and beautiful that no picture or
photo could ever do it any justice. We know, not just because we tried
to capture it with our small 100€ camera, but also because we could not
find any postcard, poster or picture elsewhere that captured their
splendour. Simply put, they are much too big to adequately fit in any
picture while still maintaining a perspective of their true size.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/9459b6c27d642450dffd4e6313f26f56/IMGP5762.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the second day, it was very cold and raining, which dampened our
enthusiasm a bit, but after seeing a blind person visiting the park the
previous day, things were placed in perspective and I was grateful for
having the good health and fortune to see these impressive waterfals.&lt;/p&gt;
&lt;h1&gt;18 July, Tres fronteiras park&lt;/h1&gt;
&lt;p&gt;After our rainy excursion to the waterfalls, I fell ill for about two
days in which we stayed inside at the hostel. The small ten person
dormitory was particularly suffocating for Manuela who didn’t like the
hostel to begin with.&lt;/p&gt;
&lt;p&gt;On the second (and our last) day, I however started to feel better and
we decided to walk to the “Tres Fronteiras” park, were you could see
Brazil, Paraguay and Argentina all in one view. The park itself was free
and our spirits were lifted after getting out of the hostel for a
change.&lt;/p&gt;
&lt;h1&gt;19 July, Ciudad del Este&lt;/h1&gt;
&lt;p&gt;Ciudad del Este is a chaotic Paraguayan frontier town on the border with
Brazil and Argentina and the second biggest city in Paraguay. Its entire
economy seemingly depends on its large markets of (mostly cheap Asian)
consumer goods which are bought by Brazillians looking to save money by
avoiding customs and sneaking the goods back through the border. Often
the goods are then resold on the Brasillian side.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3219097e6ebfeea114fe76107ebed7ba/IMGP5797.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Many people who visit Ciudad del Este for a day don’t even bother to
get their passports stamped and the buses and taxis who cross the border
from Brazil wont stop at the passport controls unless you specifically
ask them. Upon nearing the border, we however decided not to tempt fate,
and asked our bus driver to let us out to get our passports stamped.&lt;/p&gt;
&lt;p&gt;Upon entering the city via the “Friendship bridge”, we immediately saw
the large markets covering all available sidewalk space. Many of the
buildings between the sidewalks are also filled to the brim with small
markets and shops. We didn’t experience the Paraguayans as being too
aggressive salespeople however and usually didn’t feel badgered to buy
crap we didn’t want.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7ecfafd0c1352223de937fc7b372c4ec/IMGP5821.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was raining during our excursion, and this only highlighted the
neglect and disrepair of the city itself. Large potholes were filled
with brown water, and some buildings seem to never have been painted. By
chance, we passed a mall (more like a narrow 5 story department store
than a mall) called “Mona Lisa” which we recognised from large
billboards in Brazil, urging shoppers to go to Ciudad del Este and shop
there. We decided to take a look.&lt;/p&gt;
&lt;p&gt;Inside we were quite surprised. Fancy and expensive cologne and
fragrants, new Ipads and Iphones, imported Swiss chocolate, Sushi and a
whole assortment of other luxury items. The mall itself could be located
in any big city in the world, but the contrast with the disheveled,
dirty and poor spectacle going on outside its walls was striking.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/83533119993aef1f88b12c30693cbb8a/IMGP5808.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At the end of the day we took a minibus taxi back across the bridge to
Brazil. The one guy sitting next to Manuela looked quite nervous as we
neared the Brazillian border but as the taxi driver made a point of
speeding around the border gates he relaxed visibly and made a Catholic
cross with his right hand. Everyone&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/02f718ad20098dce5cf8e94165bd9ed3/IMGP5838.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;was therefore a bit surprised when the two gringos in the back asked to
be let out to go and stamp their passports again. The driver pulled over&lt;/p&gt;
&lt;p&gt;right there at the side of the road, ignoring the hooting from the
irritated drivers behind us and let us out, before speeding away again.&lt;/p&gt;
&lt;p&gt;On the same day we took a long distance bus back up to Corumba on the
border with Bolivia.&lt;/p&gt;
&lt;h1&gt;21 July, Puerto Quijarro&lt;/h1&gt;
&lt;p&gt;We spent a day in Puerto Quijarro, a small dusty Bolivian frontier town
on the border with Brazil. After having spent almost all my cash in
obtaining a visa I wasn’t aware I needed, I had to find a place to
withdraw some more Bolivianos. Neither of the two cash machines in the
town accepted my card however. Again the problem seemed to be that I had
a Mastercard. In fact, I had two, which feels like having two left feet
at a dancing contest. In South America, Visa is accepted almost
everywhere, Mastercard however is a different story. In the end we had
to take a taxi to the nearby town of Puerto Suarez, to use their ATM,
which did accept my card.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/57b6773da7f41bb0cf9769077225adea/IMGP5865.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As a result of this, we didn’t have a chance to buy train tickets to
Santa Cruz for the day (you can only buy tickets in person and for the
same day), and ended up being the only two guests staying in one of the
nicest, most spacious hostels we’ve ever been to, Tamengo. It used to
be the local public swimming pool, before the current owner bought it
and turned it into a hostel. The town of Quijarro was so poor that it
seemed unlikely that the municipal would have had the funds left to
maintain a public swimming pool.&lt;/p&gt;
&lt;h1&gt;22 July, Train from Puerto Quijarro to Santa Cruz&lt;/h1&gt;
&lt;p&gt;We woke up early and made sure to get tickets for the train later in the
day. We would be traveling on what is known as the “death train”,
apparently because it was used to transport yellow fever victims in the
past.&lt;/p&gt;
&lt;p&gt;The train shaked and dipped along at a snails pace. On a small
television at the front of the compartment, Spanish songs from the 1970s
were playing, sung, among others, by an overly zealous woman with
kitsch, bright make-up and a priest with a guitar. Early in the day I
heard an old 90s techno song blaring from some car’s speaker in a dusty
road populated with chickens, pigs and countless stray dogs. So far,
being in Bolivia has presented its strange moments.&lt;/p&gt;
&lt;h1&gt;23 July, Traveling from Santa Cruz to Samaipata&lt;/h1&gt;
&lt;p&gt;We arrived in Santa Cruz, after a harrowing 17 hour train ride. The
compartment bumped, stuttered and shaked, and occasionally there would
be very loud bangs coming from below as we not only swayed in a sideways
motion, but also vertically, with the bottom of our carriage banging on
the tracks below. On occasion the train swayed so much that I would
instinctively prepare for the inevitable tipping over of our carriage.
In the end, the inevitable seemed to be avoided, or perhaps just delayed
for a later time.&lt;/p&gt;
&lt;p&gt;One of the first things noticable about Santa Cruz, as we zipped away
from the bus station in a taxi, was that there were no high rise
buildings, and everywhere seemed desperately poor, although we went past
a car dealership selling luxury 4x4s, including a Porsche Cayenne.
Nevertheless, Bolivia is one of the poorest places I have ever visited,
outside of some pockets in Southern Africa. Coming into Santa Cruz with
the train, we saw an unplanned sprawl of shoddy structures, bisected
with dirt roads. Rubbish is strewn everywhere, and in between chickens,
pigs, cattle and people roam listlessly looking for something to do or
eat. The children seem happy though, having fun playing in the dirt.
Bolivias population is mostly indigenous, and for some reason their
babies are incredibly cute, with dark elf-like eyes.&lt;/p&gt;
&lt;p&gt;We spent about 3 hours in Santa Cruz and then took a minibus taxi to
Samaipata (30 Bolivianos each), but after 20 minutes of alternating
acceleration, then braking, then snaking through traffic, our driver
sped over a speedbump and the car broke down. We had to all get out at
the side of the road and wait for a replacement minibus to arrive.&lt;/p&gt;
&lt;p&gt;The new driver was older with big, very thick glasses. I wasn’t sure
whether this should instill confidence or fear in his ability to
see objects in the road. Every now and then he would unceremoniously
stop the car and jump out to take a piss at the side of the road in
full view of the occupants. Later we were all almost killed when he
narrowly avoided being driven over by a large oncoming truck. All the
time without any communication from his side or the slightest apology.
When we arrived in Samaipata, he simply drove past and we had to tell
him to stop and insist that he turn back and drop us off. Now suddenly
he was very chatty with the other occupants, no doubt complaining about
the gringos in the back.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/5f22a4a2890d539bb1371b9845b31ad2/IMGP5889.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;As he sped away, we were however more relieved than anything else, and
looking forward to a new week of adventures.&lt;/p&gt;
&lt;p&gt;A cliché in many people’s minds is that indigenous populations live
closer to the land, more in harmony with nature and have more respect
for the earth than the greedy, exploitative westerners. Sadly, this is
not the picture we were presented with in Santa Cruz and on the way to
Samaipata. Many people seem to lack any sense of responsibility for
caring for their environment, painfully evident by the fact that the
whole countryside seems to be covered in rubbish. Plastic bottles,
wrappers and the like are simply thrown on the ground, with no regards
for the terrible visual and environmental pollution it causes.&lt;/p&gt;
&lt;h1&gt;24 July, Samaipata&lt;/h1&gt;
&lt;p&gt;Samaipata, a town of 3000 inhabitants in an “ellbow of the Andes” with
no bank branch, ATM, supermarket or dedicated internet connection, is
the provincial capital of the province Florida and even boasts a court
with 2 apparently unbribable judges. Unless you pay them in cash.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/2a89621804ecf0655b07a50b1a0774d4/IMGP5922.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/1ba86d83b54955dd34a184dac3907f25/IMGP5921.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;There is however a wonderful fresh food and meat market that more than
makes up for the lack of a supermarket. The apples and pears in
particular were delicious. There’s also a small European expat
community (particularly Germans and Austrians) who provide tours, good
restaurants, cafés and even a very good French bakery. Not to be
outdone, there was also a very good local restaurant that we would often
frequent during our stay.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/3c1f8f645b46c830156a4013522b66ec/IMGP5968.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Samaipata is located in a valley, with the rainforests of Amboro
National park on the one side and a much dryer semi-arid climate on the
other, which of course makes for a lot of diversity and interesting
scenery.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/06044ecf8e281d0c763f6b8590abb3d1/IMGP5924.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b366d2c0a2587693ad2bcfee5f9ece58/IMGP6190.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;On that morning, we met up with &lt;a href=&quot;http://southernhemisnuggets.blogspot.com/2010/08/santa-cruz-and-samaipata-one-big-fat.html&quot;&gt;Tony and
Sofia&lt;/a&gt;,
whom we first met in Rio de Janeiro and stayed in contact with since
then, and together decided to take a hike to a lookout point on one of
the hills nearby. Long story short, we took a wrong turn and instead
ended up at the local “Zoo”. More an animal refuge run by an expat
Swiss wonman, with a selection of touchy howler monkeys, spider monkeys,
a three legged wild cat, some dogs, wild pigs, tortoises, macaws,
parrots and a selection of other critters. Our visit more than made up
for not finding our lookout point and we were glad to contribute in a
small way towards protecting the abandoned and traumatised animals.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/693cdef90db16cf6646515ec14cde42c/IMGP6068.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/6139ec3e4d7d58c8266f929044f6bb7d/IMGP5959.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;26 July, Horse-riding&lt;/h1&gt;
&lt;p&gt;We returned to the zoo to rent some horses and rode up a nearby hill
with a lookout point called “Mirador El Paradiso”. One of the dogs of
the zoo went with us and he was later joined by another dog from a
nearby farm. They accompanied us all the way up to the top of the hill,
with the one dog making sure that any and all wildlife were thoroughly
chased away before our arrival, by running out ahead and barking loudly.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/travel-images/IMGP6020.JPG&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/travel-images/IMGP5982.JPG&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The lookout point provided a very nice vista of the surrounding hills
and valleys and the horses could even graze a bit at the top. The whole
trip took two and a half hours at about €13. Money well spent.&lt;/p&gt;
&lt;h1&gt;27 July, Bella Vista&lt;/h1&gt;
&lt;p&gt;One of the oldest tour agencies in town (they might actually be the
oldest) is called &lt;a href=&quot;http://www.the-roadrunners.info/&quot;&gt;RoadRunners&lt;/a&gt;,
started by a loud but very friendly Austrian named Olaf about 15 years
ago. I was initially attracted to their shop when I saw that they had a
book exchange with a broad selection, and in the end Olaf was nice
enough to lend me a thick biography on Che Guevara. Che’s last guerilla
mission was in Bolivia, and before he was eventually captured and killed
somewhere in the area, his men went down to Samaipata to rob a bank and
retrieve some asthma medication for Che. One local guard was killed and
in the excitement the guerillas fled from the scene and the shocked
villagers without remembering to get any medication. Che was condemned
to suffer from acute asthma for the rest of the campaign.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/bc53eedb8f9dfc40e1041f2f924b605f/IMGP6106.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We decided to take a tour called “Bella Vista” (Pretty view) with
RoadRunners and it turned out to be one of the highlights of our lengthy
stay in Samaipata. We drove out of town for about an hour and then
proceeded to hike up a high mountain (dubbed the “cathedral” by
RoadRunners) with a flat top from which we would have a spectacular 360°
view of the surroundings. The hike was not too taxing, but no picnic
either and we sometimes had to walk in single file on a ridge too thin
for two people to stand side by side, flanked by steep drops on either
side. Not a good idea for people with a fear of heights.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/c31356e4bce0117172f5ecf88a24d1f9/IMGP6144.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We were blessed with good weather and the views were spectacular,
getting better and better as we hiked to the top. From above you could
see in all directions, up to the furthestmost edges of the Bolivian
Andes, about 80 km away. We hiked down on the opposite side of the
mountain we hiked up upon, eventually ending in a ravine covered in a
forest with ferns, bromeliads, orchids and even two impressive tree
ferns.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;h1&gt;29 July, Condor Hike&lt;/h1&gt;
&lt;p&gt;The majestic (but truly ugly) Condor, with a wingspan of up to 3 meters,
is the national symbol of Bolivia. It can cover a distance of hundreds
of kilometers in a day, conserving its energy by gliding on air
currents. Near Samaipata is a cliff with a small inaccessible pool and
waterfall, which attracts Condors from as far as Argentina and Peru, due
to it’s secludedness and the fact that Condors cannot ascend straight
from the ground up, but instead from the side of a cliff where the air
currents can hold them up.&lt;/p&gt;
&lt;p&gt;We hooked up with local guide Saúl, (a trained Biologist and owner of
Tucandera tours) who accompanied Tony, Sofia, Manuela and I on a 16 km
trek over the mountains to a lookout point where we could view the
condors swooping down to the waterfall to bathe and drink.&lt;/p&gt;
&lt;p&gt;We first took a taxi to a waterfall, called “La Pajcha”, and then to a
point nearby were we started hiking up a mountain. Sometimes we would
arrive, sweating and out of breath at a certain area, to find it
littered with cow dung. This was something we already noticed on our
Bella Vista hike and we were continuously amazed at the mountain
climbing skills of the local cattle.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d3c870e879d21c6195a1f11d86ab1afa/IMGP6195.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Saúl showed us some local fauna, including some aromatic flowers “Vira
Vira” to make tea from (he was nice enough to pick some for us and we
continued to make tea for the following two weeks) and a plant with
which the local indigenous woman induce abortions (and risk their own
lives or nervous systems). We saw condors quite early on, including one
very rare (for the area) tropical condor, but we could not have known
the spectacle that awaited us when we reached the cliff. There were
about 6 condors visible at the top of the waterfall, and we made turns
using Saúl’s binoculars to get a better view. Every few minutes, a
solitary or pair of condors would appear on the horizon, to swoop down
into the canyon and land on the cliff on top of the waterfall. It was an
amazing site to behold, and, for lack of an expensive camera, we had to
be content with taking it all in being in the moment. We saw about 25
condors in total and the day turned out to be one of the highlights of
our entire South American trip.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;../images/travel-images/IMGP6228-1.JPG&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We were warned beforehand that too many tourists might disturb the
birds, and we made sure not to get too close, even declining to go to
another lookout when our guide offered. In the end, we stayed a good
distance, saw two dozen condors and had the time of our lives staring
out into the expanse of the large condor filled canyon in front of us.&lt;/p&gt;
&lt;h1&gt;30 July, El Fuerte&lt;/h1&gt;
&lt;p&gt;The original Samaipata, a pre-Incan settlement, was located next to a
large slab of sandrock. The sandrock was carved out at the top and at
the sides, in what appears to be for ritualistic purposes. The Incas
later arrived and continued to carve out symbolic shapes with Jaguars
and Condors, and three twenty four meter long channels with symbolic
snake carvings, used for liquid sacrifices. In the middle is a round
circle with alternating seats for high priests and spirits. At the sides
are niches that were covered in gold and contained urns with the
mummified remains of important people.&lt;/p&gt;
&lt;p&gt;Today, Samaipata is located in a valley, and this original settlement is
now only known as “El Fuerte” (the fort). El Fuerte was the eastern
most fronteir town of the Incan empire and therefore of particular
importance to them, (much more important than Machu Picchu apparently)
as can be seen by the length of the snake canal, which is much longer
than a similar one in Cusco. Theories abound as to the significance of
the site. Some years ago, an Austrian scientist studied the site, and
found water rising out of holes in the rock (though to be used for
sticking in poles for building structures). The theory arose that the
sandrock might in fact contain limerock, that acts as a sponge and
collects rainwater through the sandrock, only to release it again at a
later stage. Upon witnessing this phenonemon, the original inhabitants
considered the site sacred, and built a temple to pray and sacrifice to
the spirits to provide them with water from the rock.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/89644f902711b9cbae5319e2c47d496d/IMGP6268.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We again took the tour with Olaf from Roadrunners, who told us lots of
amazing stories about the Incas, the Spanish conquistadores and an
incredible coincidence that made an army of 40 000 warriors flee from
160 conquistadores headed by Pisarro.&lt;/p&gt;
&lt;p&gt;Unfortunately the sandrock of El Fuerte is very soft and subject to a
lot of erosion. So far the authorities have not done anything to combat
this, and if left unchecked, some of the carved out features might be
already be gone in 15 to 20 years.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/03a79f147d5ff6f153a04b0b85e3585a/IMGP6293.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;31 July, Cloud forest in Amboro National Park&lt;/h1&gt;
&lt;p&gt;Samaipata is located close to the Amboro National Park, an area of about
100km by 120km with a large section in the middle completely off limits
to visitors. Located inside Amboro at the top of a mountain range is a
cold rainforest, the so-called cloud forest. The name arising from the
fact that it’s so high that it’s mostly covered in clouds.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b087e79fd43b590ea30cc8aba2543289/IMGP6377b.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;This was our last activity in Samaipata, and we went out one last time
with Olaf to go and hike up to the cloud forest. Three weeks earlier,
there was heavy snow in the area (for the first time in 50 years) and
the cloud forest suffered a lot as a result, with many branches
breaking, trees falling down and the big tree ferns losing their leaves.
The hiking path was also partly destroyed and we would have to do some
machete work here and there to clear a path.&lt;/p&gt;
&lt;p&gt;It was however still an amazing experience walking through a forest
covered in clouds, seeing trees covered in ferns, moss and lycans and
smelling the mist in the air.&lt;/p&gt;
&lt;p&gt;We can definitely recomend &lt;a href=&quot;http://the-roadrunners.info&quot;&gt;RoadRunners&lt;/a&gt; to
anyone intending to visit Samaipata. Olaf and the gang were very
helpful, friendly and honest and after three outings with Olaf we were
all a bit sad to say goodbye.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b19443e16b6b8aa5ca1e40e895a13631/IMGP6356.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/8a4ec2096da78f38cd91682e17878526/IMGP6298.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e100304a98852e1d490d7670d064f98a/IMGP6421.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h1&gt;1 August, Finishing Che Guevara&lt;/h1&gt;
&lt;p&gt;This was our last day in Samaipata before leaving for Sucre and I spent
most of the day finishing reading the biography of Che Guevara that Olaf
lent me. I was finished with about two hours to spare before our bus
arrived and was glad to have received some insights into the man whose
famous image adorns Cuban money, posters, flags and the t-shirts of
clueless teenagers and students everywhere in the western world.&lt;/p&gt;
&lt;p&gt;Che definitely had some admirable qualities, but he was also a fanatic
Marxist and a cold-blooded killer and guerilla fighter. I find it the
hight of irony that his image adorns the t-shirts of youths from the
very same capitalist countries he so despised. Just as I have once
before realised with regards to the selling of religious relics, I was
again aware how almost nothing is sacred or taboo when it comes to
selling on the open market of capitalism, even if it is the image of a
man who died fighting against that very same idea.&lt;/p&gt;
&lt;p&gt; &lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/bfc5d39abee8f86a2431a4a098b6f5a8/IMGP6367.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[South American travel diary, Part 1. June 2010]]></title><description><![CDATA[This is a roundup of the first month of my shared travels through Brazil
and South America, in the form of a journal or diary. I tried to…]]></description><link>https://opkode.com/blog/south-american-travel-diary-part-1/</link><guid isPermaLink="false">https://opkode.com/blog/south-american-travel-diary-part-1/</guid><pubDate>Tue, 06 Jul 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This is a roundup of the first month of my shared travels through Brazil
and South America, in the form of a journal or diary. I tried to write
down the highlights of almost each day, as a means of remembering
special events and to share with the people who care. This post turned
out to be quite long, with the personally more interesting and intuitive
bits appearing near the end, as I became more relaxed and immersed in
the traveling experience. Feel free to skip boring parts or to just look
at the pictures ;)&lt;/p&gt;
&lt;h2&gt;30/31 May, Sao Paulo&lt;/h2&gt;
&lt;p&gt;The people at Olah! hostel were very helpful and accommodating. They
picked us up at the airport and had to wait about two hours for us, due
to a delayed flight. Then they even offered to take us to the
supermarket at 12 o’ clock at night.&lt;/p&gt;
&lt;p&gt;In general Brazillians seem friendly and eager to help. We felt as
though we stood out as travelers but during our first day walking in Sao
Paulo, three different people approached us asking questions (probably
for directions) in Portuguese, so perhaps we blended in better than
imagined.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/f960121cb069c4fa4a7e2c50549b46ed/IMGP3892.jpg&quot; alt=&quot;Downtown Sao Paulo&quot;&gt;&lt;/p&gt;
&lt;h2&gt;1 June&lt;/h2&gt;
&lt;p&gt;We went to &lt;a href=&quot;http://www.virtualtourist.com/travel/South_America/Brazil/Estado_de_Sao_Paulo/Sao_Paulo-1500790/Things_To_Do-Sao_Paulo-Museu_de_Arte_de_SPaulo_MASP-BR-1.html&quot;&gt;Museu de Arte de S.Paulo
(&lt;em&gt;MASP&lt;/em&gt;)&lt;/a&gt;,
which provided free entrance on Tuesdays. They had an exhibition of
collages from the German artist &lt;a href=&quot;http://en.wikipedia.org/wiki/Max_Ernst&quot;&gt;Max
Ernst&lt;/a&gt; with a well written
breakdown of his life and interpretations of the different pieces. We
made our own interpretations of his work, which largely consisted of
critiques of the abuse of power by the elite (represented by the French
bourgoise), but also of men over woman.&lt;/p&gt;
&lt;p&gt;We left the museum inspired by Ernst’s creativity, his well-traveled
and bohemian lifestyle indicating that creative lifestyle design is
nothing new. Some people have been traveling the world and making a
living doing what they love for a long time already.&lt;/p&gt;
&lt;h2&gt;2 June&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/a8379673d92b0981797b89d971b03891/IMGP3953.jpg&quot; alt=&quot;Manuela in Sao Paulo&quot;&gt;&lt;/p&gt;
&lt;p&gt;The sight of vagrants and destitutes lying on the dirty sidewalk and
public spaces in the center of Sao Paulo was quite jarring, and
something I was not used to seeing anymore since spending a year and
half in Germany. They were in all likelyhood just sleeping, but one
couldn’t be sure. One might have been lying there dead with people just
passing by unaware.&lt;/p&gt;
&lt;p&gt;We went to the famous &lt;a href=&quot;http://www.galeriadorock.org.br&quot;&gt;Galeria do
Rock&lt;/a&gt;, a 6 story mall dedicated to Hard
Rock and Heavy Metal culture, where we met Aggnes, who works with
Sepultura and is a volunteer for the Sea Sheperd organisation.&lt;/p&gt;
&lt;p&gt;Up at the top of the Banespa building, one gets an impression of how big
this city really is. Buildings and skyskrapers dot the landscape
extending as far as the eye can see.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b3336f2a3229fa40bde0282b3978a06d/IMGP3974.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;June&lt;/h2&gt;
&lt;p&gt;On Thursday we met my friend Witek (who coincidentally happens to be in
Sao Paulo) and his Brazilian friend Selena. We went together to Parque
&lt;a href=&quot;http://en.wikipedia.org/wiki/Ibirapuera&quot;&gt;Ibirapuera&lt;/a&gt;, the biggest park
in Sao Paulo. It was a day of relaxing in the park and drinking coconut
water while Witek and I discussed some of the parallels between South
Africa and Brazil. Later Selena took us in her car for a trip around the
city, explaining the sites, presenting it to us in a completely
different light.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/64237dd63d3d3749cccc11d393058ad1/IMGP3986.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;4 June, Rio de Janeiro&lt;/h2&gt;
&lt;p&gt;We take the bus, Expresso do Sul, to Rio de Janeiro. We opt for
Executivo, the mid range option and are pleasantly surprised with a very
modern and comfortable interior.&lt;/p&gt;
&lt;p&gt;Upon arrival in Rio, we are a bit surprised with how poor and unkempt
the neighbourhoods look. We drive past favela after favela and
everywhere are scribbles and grafiti. A lot of the grafiti in Sao Paulo
were really very impressive murals, but our first impression of Rio is
that it’s mostly gang signs and scribbles. Every inch seems to be
tagged. Sometimes places that are seemingly impossible to reach are
marked, such as the 3rd stories of buildings and on the sides of
bridges.&lt;/p&gt;
&lt;p&gt;Later at the hostel we had Caipirinha night, lots of fun and a good time
to meet other travelers. I spent some time with an American traveler of
(North-)Korean descent, discussing the expressiveness of the German
language. He was suitably impressed ;)&lt;/p&gt;
&lt;h2&gt;5 June&lt;/h2&gt;
&lt;p&gt;We took a walk to Botafogo and Flamengo beach with Niall, an Irishman we
met the night before. The weather is pretty crap, windy and rainy, but
we’re all in a comparatively good mood and it’s fun to explore Rio for
the first time.&lt;/p&gt;
&lt;p&gt;On Botafogo beach, Brazillians are playing American football (which was
a surprise) and an old guy is doing amazing tricks with a soccerball.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/5fe9f7c70ddea6d5a45e4c53b58f0d0a/IMGP4206.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We again drink coconut water, agua de coco, this time with a straw
straight out of a cooled coconut.&lt;/p&gt;
&lt;p&gt;Our backpackers was nice at first glance, but we soon realize that we
are two of almost 40 people squeezed into the place.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e58072d3fde0df6744fd99c2a16dc112/IMGP4119.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;6 June&lt;/h2&gt;
&lt;p&gt;Today is Sunday and we plan to go to the Hippie market in Ipanema. First
we walk to Copacabana beach. It’s still a bit windy but it’s nice and
warm and there are lots of people on the beach.&lt;/p&gt;
&lt;p&gt;So far Rio seemed quite poor and unkempt, but in Copacabana beach it’s
like a world apart and we can see why it’s so famous. The official
uniform for Brazillian men seems to be boardshorts and nothing else. The
women wear hotpants with small tops or small dresses.&lt;/p&gt;
&lt;p&gt;The Hippie market was a very nice surprise. There were lots of beatiful
handmade leatherware, such as deocrated world maps, bowls, belts and
armbands. Also jewellery and dresses. We saw very little kitsch tourist
trinkets, and the market seemed to live up to its Hippie name.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/707a8dce61054b066a3dbaebf49ae1d6/IMGP4251.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;7 June&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/a3bce1346c3eba338b9d07586e6f2060/IMGP4128.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/086522d1dc2b9f6120326655512017d0/IMGP4311.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We want to walk to &lt;a href=&quot;http://en.wikipedia.org/wiki/Tijuca&quot;&gt;Tijuca&lt;/a&gt;forest,
but don’t reach it and instead go to the Botanic gardens. The botanic
gardens were 5 Reais to enter, which in our opinion didn’t make it
worthwhile, as it was relatively boring. The whole of the not very big
park was filled with workers cleaning up and building paths, to the
point of absurdity. We felt that the park already had too many paths and
that it was just like any other park, and not what we expected from
botanical gardens.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/0653951caa0513972343232bfbb8e6f3/IMGP4307.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7c7a303f76244dc7d3b890e6161ceaa3/IMGP4344.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/412d7691f115d267e94e4a9653d1dce7/IMGP4332.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;That night we bought what we thought was red wine. Upon drinking it, we
realised though that it was very sweet and must have been some mix. It
tasted like a mix of red wine and Fanta grape. Weird…&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e996819c9b13411018b1d4ac55ead13a/IMGP4318.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;8 June&lt;/h2&gt;
&lt;p&gt;We took a one day Rio tour, and although it was nice and sunny the whole
day, the Christ Redeemer statue was engulfed in a big fluffy cloud. We
went up regardless but the view were not nearly as spectacular as they
would be on a clear day.&lt;/p&gt;
&lt;p&gt;We also went to the charming old neighbourhood of Santa Theresa and
later to Lapa, were we met the artist who covered a whole flight of
stairs in tiles collected from all over the world. Lots from Germany and
a few from South Africa as well, unfortunately all of them quite kitsch.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/11783155b20c905a5bb592a90c1abb4f/IMGP4147.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;9 June, Itacaré&lt;/h2&gt;
&lt;p&gt;We leave to Itacaré on Sao Geraldo busline. I made an effort to stay
awake and take in the landscape. Deforestation was evident everywhere
and for me quite sad. Nonetheless, the landscape was striking and
pretty.&lt;/p&gt;
&lt;h2&gt;10 June&lt;/h2&gt;
&lt;p&gt;We arrive in &lt;a href=&quot;http://www.itacare.com.br&quot;&gt;Itacaré&lt;/a&gt;after a 24 hour bus
trip. Itacaré is a small town on the coast of Bahia, with 14 beatiful,
pristine beaches popular among hippies and surfers. Each one has its own
character, with some only reachable after hiking through the forest,
revealing a secluded tropical paradise, filled with trees coconuts and
cute white crabs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/e0dd8f6ad07afb9a03dcd2cc1e33a770/IMGP4427.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The houses are small and modest, but gone are the scribbles and grafiti
which were so commonplace in Rio. Everywhere locals are working,
digging, mixing sement in the street and painting the sidewalk stones
red white and blue. Lines with confetti and Brazillian flags span the
narrow cobblestone streets and a festive atmosphere is in the air. In
June the inhabitants of Itacaré have a month long &lt;a href=&quot;http://www.visionofbrazil.com/Destination/BA-Salvador/Event/Sao-Joao-Festival.aspx&quot;&gt;Sao
Joao&lt;/a&gt;
religious festival, not to mention the World cup getting underway.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/66435e10a9d930985b0341c4f3296226/IMGP4423.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/c086ceed0966ea2fcb270803f05e84ee/IMGP4595.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Children are everywhere, playing in the streets and whenever there is a
patch of grass free, they will be playing football. The neighbourhood
were we stay is a bit more rough than the touristy main street, but we
feel safe and there is a definite community spirit in the air. The
people seem to live outdoors and with one another, not closed off in
their own houses as people in suburbs tend to do.&lt;/p&gt;
&lt;p&gt;As a South African, it was very noticable how mixed Brazil is and how
easily and comfortably the different people and races interact with one
another. Mixed race couples are common and I hope that South Africans
could one day take a leaf out of Brazils book and also learn to live so
relaxed and comfortably with one another.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/a38da03741c05987f53505b1ed6accce/IMGP4727.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;12 June&lt;/h2&gt;
&lt;p&gt;I watched a Brazilian dating show tonight, and it was quite a funny
experience. The contestants start kissing within 5 minutes of meeting
each other, and every now and then, everyone is rounded up and made to
show off their dancing skills, with especially the men going over the
top, showing their abs and striking rediculous poses.&lt;/p&gt;
&lt;p&gt;One thing that was remarkable tongight, was that although Brazil is such
a ethnically diverse culture, when watching television you would think
that it is mostly white with some brown sprinkled here and there.
Television presenters are on average much more paler than the faces seen
in the streets and towns.&lt;/p&gt;
&lt;h2&gt;13 June&lt;/h2&gt;
&lt;p&gt;Everyone in the hostel, about 8 people, started partying with a few
beers at the hostel and we then went out to town for a jol. The Itacaré
nightlife was great, with the alternative/Hippie vibe and influence
omnipresent. We ended up at a place on the beach where a Reggae band
played all the classics. Capirinhas were everywhere and it was a great
atmosphere and ambiance for Manuela and I discuss our trip and how it
was going so far. I felt a sense of euphoria, and again realised that
life can be as exiting or boring as you want it to be, and that the
possibilities for excitement and fulfillment are endless.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/65dc68e0305f7926684dddd2bfffe0f0/IMGP4669.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;14 June&lt;/h2&gt;
&lt;p&gt;Today we got up early to walk to the end of town and then hiked for some
50 minutes through Atlantic rainforest to get to Prainha (little beach),
one of the prettiest beaches in the area.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/390e58775cdd4efb41043f6c14b4cf07/IMGP4491.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;On the way we passed a small waterfall and a smaller rocky beach with a
beatiful view.&lt;/p&gt;
&lt;p&gt;Prainha was practically deserted except for two other couples and some
surfers, including a Brazillian couple we met two nights before.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7957348885089c3ef177abf21416939a/IMGP4504.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;It was a lovely way to spend the day in the Bahian nature and at a
pristine beach, and best of all, it did’t cost us a cent to get there.&lt;/p&gt;
&lt;p&gt;That night, we suggested that we have a barbeque at the hostel, and
Marialena, the cleaning lady at the hostel, sent a young boy to buy some
fresh fish for us. She showed me how to clean and prepare them and then
I grilled them with some meat, potatoes and aubergine all together on
the fire.&lt;/p&gt;
&lt;p&gt;Afterwards we chatted the night away about life, traveling and Brazil.
We received a lot of insight from Niels, a Portuguese speaking Dutchman,
about the politics, laws, police and culture in Brasil.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/4031e5ddcf0d5cd792b2fb3c59cd698f/IMGP4762.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;16 June&lt;/h2&gt;
&lt;p&gt;This night we went to Jungle bar to watch the local
&lt;a href=&quot;http://en.wikipedia.org/wiki/Capoeira&quot;&gt;Capoeira&lt;/a&gt; school showing off
their moves. It was an unforgettable experience. Everybody was in peak
physical condition, and some of the older guys were quick as hell. The
teacher is a guy called Jamaika, apparently in the late 40s, but still
looking very fit.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/bfc064650386746d4ac3fab1044572cf/IMGP4653.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;I couldn’t help but think of the slaves who in their meagre spare time
created and practiced the art of Capoeira. The slave masters were wary
of anything that might have made the slaves a threat, so Capeoiera was
disguised to on the face of it appear as a dance, perpetually
accompanied with distinctly African singing and music, with the more
dangerous moves only practiced when they were alone. Often I was
reminded of breakdancing, although this martial art is much much older.&lt;/p&gt;
&lt;p&gt;Today, the descendents of those original slaves still practice their
martial art, and the descendents and relatives of the slave masters are
honoured to become their understudies.&lt;/p&gt;
&lt;h2&gt;17 June&lt;/h2&gt;
&lt;p&gt;We traveled today with Fausto, Niels and Helena to the more secluded
beaches of Havaizinho (little Hawai) and Engenhoca. You need to walk for
about half an hour through the forest to reach Havaizinho, and then
another 20 minutes to reach Engenhoca. Both beaches are beautiful with
Havaizinha being our favourite. Engenhoca was a pleasure to swim in,
with nice waves but very little undercurrent. We ended the day back at
Itacaré on a hill at La Choncha beach watching the sunset. Just another
day in paradise. :)&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/5152fee485c5fb40cb0666d8bc6913be/IMGP4705.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;19 June&lt;/h2&gt;
&lt;p&gt;We had an amazing time in Itacaré, spending 9 days in total. Steve at
&lt;a href=&quot;http://www.buddysitacare.com&quot;&gt;Buddys&lt;/a&gt; was an awesome host and the staff
(especially Daniel) were incredibly friendly, making us feel completely
at home. We will leave with heavy hearts but fond memories.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/001f1287c5ffc04e9d3d5bc7022377c2/IMGP4713.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;20 June, Morro de Sao Paulo&lt;/h2&gt;
&lt;p&gt;We woke up early to catch the bus from Itacaré to Valença. The bus
departs numerous times each day, but Brazil was playing in a World cup
match that day and we’ve heard stories of the whole country coming to a
standstill during football matches, so we decided to play it safe.&lt;/p&gt;
&lt;p&gt;From Valença we took the speedboat (pronounced “speegy boachy” by the
locals) ferry to the Island of Morro de Sao Paulo.&lt;/p&gt;
&lt;p&gt;The water was opaque with such smooth waves that they reminded me of the
simulated waves in a computer game. I’ve been reading about quantum
mechanics and the fact that certain physical attributes are left
undetermined (uncomputed?) until some observer chooses to observe them.
Lately the view of the universe as a quantum computer seems to make more
and more sense to me. Things are left uncomputed as quantum waves of
probability, until (and if) the first observer chooses to observe them.&lt;/p&gt;
&lt;p&gt;Upon arriving at Morro de Sao Paulo, we passed through a lovely arched
colonial gate. In the afternoon in winter the sun can be seen setting
through its opening.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d050b051ad6ce539cf8db9be526cc016/IMGP4836.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Morro de Sao Paulo has no cars (none that I’m aware of). That being
said, the first thing you are being greeted with upon entering through
the gate (aside from the official charging a R$10 land tax) is some guy
offering a taxi. The taxi it turns out, is a wheelbarrow, in which they
load your baggage and then push for you through the sandy streets,
stopping at the Pousadas while you haggle with the owners.&lt;/p&gt;
&lt;h2&gt;21 June&lt;/h2&gt;
&lt;p&gt;Morro de Sao Paulo is nice, the weather is perfect and it has it’s own
charm, but it’s quite a bit more touristy than Itacaré. Everyone wants
a piece of the pie, and you sometimes feel objectified as a walking
wallet.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/ce9874dcaccb2d03bfda2e4422df1400/IMGP4975.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/2f4288b4c7e52d4353f41bf074ebcbc2/IMGP4865.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;22 June&lt;/h2&gt;
&lt;p&gt;We took a trip today to another beach on the island, where we smeared
some magic mud on us. All information we got was “Remédico”
(pronounced: Hermaigico, ‘ai’ as in ‘fair’) and “Medinicional”, so
were still not sure what it’s good for. My skin did however feel quite
smooth afterwards.&lt;/p&gt;
&lt;p&gt;We then left to the pristine island of Ponta de Corraes, apparantly with
a 70km stretch of untouched coastline. Unfortunately the terrible
polluting effect of plastic was abundantly clear in the large amount of
bottles, caps and other garbage washed up on the shore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/f57c84b1e6b4ee0710c873dc90235af9/IMGP4948.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;23 June&lt;/h2&gt;
&lt;p&gt;&lt;img src=&quot;/e5aefc1c98550155933739a6e584c2eb/IMGP4956.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;We tried to hike to a fountain on the island, took a wrong turn and
ended up crossing the whole island, until we reached the beach on the
other side. We hiked a bit through the jungle, and upon reaching a small
village, the locals enthusiastically greeted us and even offered us some
of their food.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/d48fdd8f8ca157ccb58e992bd8e8f692/IMGP4981.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;At night there was a Sao João celebration, with a live reggae band and
groups in colourful dresses doing traditional dances.&lt;/p&gt;
&lt;p&gt;Earlier, during the day, Manuela found a ripe, intact coconut, which we
took home and placed in the fridge. That night we drank the chilled
coconut water and ate coconut flesh from a smalled “seco” (dry)
coconut.&lt;/p&gt;
&lt;h2&gt;24 June&lt;/h2&gt;
&lt;p&gt;We left before noon on a catamarán to Salvador. It’s almost impossible
to not get seasick while sitting inside, but if you go stand outside in
the front and stare out into the endless sea, then the nausea goes away
and the fun of sailing takes over. I tried to imagine the trials and
hardships the Rennaisance era European sailors had to overcome, crossing
the oceans in search of a traderoute to India.&lt;/p&gt;
&lt;p&gt;It was a holiday today, and Salvador’s city center was empty. We went
straight to the airport and spent 5 hours waiting for our flight to
Natal.&lt;/p&gt;
&lt;p&gt;We were hosted by a &lt;a href=&quot;http://couchsurfing.org&quot;&gt;couchsurfer&lt;/a&gt; named Cyrus,
who was even kind enough to pick us up at the airport.&lt;/p&gt;
&lt;h2&gt;Friday 25 June, Natal&lt;/h2&gt;
&lt;p&gt;We went walking in the area of Alecrím, Natal, and shown the town square
of the original Portuguese settlement. Cyrus told us that the Portuguese
generally created their settlements in the same fashion. A government
building, followed by a jail and then a church, all three surrounding a
town square. Converted Indians would then build their houses around the
town square and extending outwards.&lt;/p&gt;
&lt;p&gt;We spent the afternoon with a group of friends watching the Brazil,
Portugal game ending in a disappointing 0-0 draw. Afterwards we all sat
around the tree, with the group spontaneously breaking out into
percussion and song. For me it was culturally eye opening, to see a
completely racially mixed group of friends naturally erupting into a
distinctively African flavoured song. These people have completely
embraced the African heritage of the slaves and made it part of their
Brazillian culture. It is the complete opposite of South Africa, were
the different cultures were forcefully kept seperate, never developing a
common sense of culture or togetherness and where white people still
often reject anything perceived as “black” African, while patting
themselves on the back for being so “African” themselves. This is
however, slowly changing in SA, with people becoming more integrated.
Brazil is just decades (or centuries) ahead.&lt;/p&gt;
&lt;p&gt;We then went to the beach and Fortaleza dos Reis Magos (“Fort of the
three wise men”), which was the initial Porguese construction in Natal.
The fort was built in the 18th century, later captured by the Dutch, and
then recaptured by Portuguese and Native Indian soldiers.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/11d6ca6e99b208a88fa78d129536ded1/IMGP5027.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;That night, we went to a gathering organised by Cyros’ percussion
group. The party was inside a mostly bare building, with a bar in the
corner serving beer, water and cola. The drummers play on halved plastic
water and trash barrels. One guy was playing on an empty gas canister.
Everyone was dancing and a girl in oriental dress danced in the middle,
reminiscent of belly dancing. Many of the songs were religious songs of
the Afro-Brazillian religion
&lt;a href=&quot;http://en.wikipedia.org/wiki/Candombl%C3%A9&quot;&gt;Candomblé&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;After about 15 minutes, the whole procession of drummers and crowd
(about 30 to 40 people) went outside into the street (all the while
drumming and maintaining the rhythm). Some passers by joined the crowed,
some dancing and one took a large carton box over his body and made
strange animalistic dance moves. It was for us complete magic, being
included in a strange type of social ritual, with no idea of what will
happen next and with no understanding of the their language.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/17ed6bcd6995fbf9898f4d0e8d086dee/IMGP5064.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;Outside we were entertained by a clown performance, with passing busses
more than once slowing down and/or coming to a stop while the driver and
inhabitants stare at the show.&lt;/p&gt;
&lt;p&gt;Everyone went back inside the house/building and inside continued to
make music and dance. There were no pretensions, no designer clothes,
cars or any other methods for portraying exclusivity or arrogance and we
as two foreigners felt honoured but also welcome.&lt;/p&gt;
&lt;p&gt;Everyone danced with everyone else, and dance they could. Often the
dancing couples appeared quite intimate, with hips moving seamlessly to
the rhythm, only to rearrange into new couples for the next song. I
spent a lot of time entranced, just watching the people move. Manuela
made the observation that Brazillians seem to be so much more body
orientated than Europeans, who “live more in their minds” and I
completely agree. During the day they wear skimpy clothing, are very
active playing, competing, gesturing and generally moving their bodies
about, and afterwards they spend the night dancing and embracing.
Touches of the body are common; hugs, brushes, pats and often for single
women, grabs.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/8c8b8072b5123dca67032bbb0f62215d/IMGP5068.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Saturday 26 June&lt;/h2&gt;
&lt;p&gt;We take the bus to Pipa, a popular small coastal town about 40km south
of Natal.&lt;/p&gt;
&lt;h2&gt;Monday 28 June, Pipa&lt;/h2&gt;
&lt;h3&gt;Sanctuário Ecológico&lt;/h3&gt;
&lt;p&gt;This morning we left early to go to &lt;em&gt;Sanctuário Ecológico&lt;/em&gt;. A private
conservation area just outside Pipa. We met up with Cyro, two
Argentinian friends and a local couple and hiked the trails in the park.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/16f6cc15d809a9c62803ff643c610700/IMGP5090.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;The park was beautifully preserved and maintained, with lots of
signposts, markers and designated viewpoints with benches and rails.
There was even a small labyrinth in next to one of the trails. Cyro
informed us that the sanctuary is privately owned, by a Brit (named Dave
AFAIK), that he sponsored local turtle conservation projects and also
built an English school in the area. We were very impressed and inspired
with this person’s effort and contribution in helping to preserve some
of the local vegetation (instead of exploiting it or building a hotel
complex).&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/444530f7bb3164e7d6d76c614bfe387e/IMGP5078.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h3&gt;Brazil and the South African struggle&lt;/h3&gt;
&lt;p&gt;Before the Brazil vs Chile match, they showed some of the public viewing
areas in Brazil. Sao Paulo, Copacobana beach in Rio and also Salvador. I
was interested to see a big African National Congress flag being waved
in the Salvadorian crowd, although not completly surprised. I’ve
noticed streets named after Nelson Mandela, grafiti of him on the walls
and have heard a Portuguese Brazilian song (one of many apparantly)
about him being sung the other night during the live performance in
Natal.&lt;/p&gt;
&lt;p&gt;Brazillians strongly identified with the plight of oppressed non-white
South-Africans during Apartheid, and were enthusiastic supporters of
Bafana Bafana during their stint in the world cup. It’s fascinating to
witness how strongly the South African struggle still resonates with
these people. On a different continent, but with still with a lot in
common.&lt;/p&gt;
&lt;p&gt;Later a thought occurred to me. Although there seems to be similar
negative sentiment towards Israel’s occupation of the Palistinian
territories, (in many places in the world, not notably strong in Brazil
though), that for all the Palistinians’ tribulations, they lack a
Nelson Mandela figure.&lt;/p&gt;
&lt;h2&gt;Tuesday 29 June&lt;/h2&gt;
&lt;h3&gt;Praia dos Golfinhos&lt;/h3&gt;
&lt;p&gt;Initially the day did not seem very promising, with intermittent rain
for most of the morning. Later, however, the weather cleared and we went
to &lt;em&gt;Praia dos Golfinhos&lt;/em&gt; (Dolphin’s beach), to go for a swim and relax
in the sun.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/b2ae64b736a9c5b8958e985a0566af81/IMGP5112.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Praia dos Golfinhos&lt;/em&gt; is a well-known hang-out for dolphins and we were
hopeful to meet some of these fascinating creatures. The about 1 km
stretch of beach was mostly deserted with only about 8 other people
there, but in the sea motorboats carrying hopeful dolphin watching
tourists were regularly making the rounds coming into the bay. No
dolphins appeared though, and the tourists we’re distracted by the
opportunity to swim near the boat and by the the tour operators who took
some (no doubt facebook-profile) photos of them on the boat.&lt;/p&gt;
&lt;p&gt;I felt a bit irritated by the boats, imagining the loud motors to be
distracting or unnerving to the dolphins. Eventually the boats left, and
we decided to take a dip in the sea. The waves are very calm, and the
water warm, so much that we ventured deep enough to not be able to stand
anymore.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/7ca1e0bae9de5d20ecb58f043c3564d5/IMGP5096.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;p&gt;For a second I thought I saw someone swimming quite a bit more ahead.
Then, half a minute later, we saw two dolphins coming out of the water,
just about 12 meters ahead of us. It was a completely magical event, and
I felt a sense of joy and excitement unique to this type of experience.
We continued to stay in the water for about 15 more minutes and saw the
two dolphins appear about 8 more times. Later, when we walked home, they
appeared again, with a boat in the background, heading back to the
harbour, completely oblivious to their pr:esence.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/4fa03a00071683de852c63e9fdab765f/IMGP5100.jpg&quot; alt=&quot;&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Wednesday 30 June&lt;/h2&gt;
&lt;h3&gt;Projeito dos Criancas (The childrens’ project)&lt;/h3&gt;
&lt;p&gt;The previous night we met a fellow traveler, who after seeing me
practice &lt;a href=&quot;http://www.thewingrevolution.com&quot;&gt;WingRevolution&lt;/a&gt;martial arts
(which I learned during my stay in Germany) told me about open Capoeira
lessons being held the following morning. This was one of these very
fortunate coincidences that seem to appear so often during our travels.
I’ve been wanting to take some Capoeira lessons but was intimidated by
the language barrier and the amount of time it would take to learn
anything meaningful. This particular school was literally across our
Pousada, and I thought that this was an opportunity not to miss.&lt;/p&gt;
&lt;p&gt;So that morning, I got up early and went to the Capoeira school to see
what’s up. The place was completely empty, but I decided to go in
anyway to see if I could find someone. Inside I met Miguel, who was one
of the instructors, and as luck would have it, he spoke English. There
and then we had an hour of personal instruction. He showed me the main
moves, showed me how they play the main musical instrument and told me
some stories about Capoeira.&lt;/p&gt;
&lt;p&gt;That night was another hour and half group lesson, with the local
Capoeira master, some of the local kids, and a few really good fighters.
For the second half of the lesson, everyone gathered in a circle,
clapping hands on the beat of drums and instruments with the students
(and trainers) taking turns to show of their moves and play-fight
against one another. The better fighters were very popular oppononents
with everyone wanting to duel against them.&lt;/p&gt;
&lt;p&gt;After some time, I was called out to duel in the ring, with this being
my first day of learning Capoeira. It was already a very humbling
experience to first overcome my internal intertia, fears and doubts and
join the school, but now I was also expected to show of the moves that I
learned. The master was already in the ring, having dueled with a
previous student, and we took hands locked hands (a courtesy before
starting the duel) and then started to fight/dance. It was an intense,
exciting and eventually euphoric experience and afterwards I gained a
new appreciation for the benefits of opening yourself up to experiences
which might seem intimidating at first.&lt;/p&gt;
&lt;p&gt;The Capoeira (and on alternate days Hip-Hop) school, &lt;strong&gt;Projeto das
Criancas&lt;/strong&gt;, was started by a Norwegian woman named Helga as a means of
community education and upliftment by training the local children free
of charge.&lt;/p&gt;
&lt;p&gt;&lt;img src=&quot;/291fb5f8651f5a88c6290638aabac8eb/IMGP5159.jpg&quot; alt=&quot;Projeto das Criancas Capoeira school&quot;&gt;&lt;/p&gt;
&lt;h2&gt;Wrap up&lt;/h2&gt;
&lt;p&gt;That’s it for the first month of the trip. I’m typing this in a small
internet shop in Canoa Quebrada, near Fortaleza in Natal, where we are
currently staying. Wednesday the 7th we’re flying to Campo Grande and
the Pantanal area. I’ll post another blog entry for July sometime in
the beginning of August.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bom dia!&lt;/strong&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Backpacking through South America]]></title><description><![CDATA[On Sunday 30th May I’ll be flying to Sao Paulo, Brazil for a 4 month
adventure backpacking through South America. This trip been more than…]]></description><link>https://opkode.com/blog/backpacking-through-south-america/</link><guid isPermaLink="false">https://opkode.com/blog/backpacking-through-south-america/</guid><pubDate>Wed, 26 May 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;On Sunday 30th May I’ll be flying to Sao Paulo, Brazil for a 4 month
adventure backpacking through South America.&lt;/p&gt;
&lt;p&gt;This trip been more than 14 months in the making, involving &lt;em&gt;lots&lt;/em&gt; of
preparation, saving, buying gear, receiving inoculations, filling in
forms, doing research, selling furniture, dealing with bureaucracy and
other non-sexy admin that people don’t generally associate with
backpacking through exotic lands. The amount of effort involved has been
compounded by the fact that we are afterwards moving back to South
Africa.&lt;/p&gt;
&lt;p&gt;That being said, it’s all finally coming to a close and my girlfriend
and I are slowly realising that we are nearing the start of a great
adventure.&lt;/p&gt;
&lt;p&gt;Needless to say, I will during this time be taking a hiatus from working
on Plone and the packages that I maintain. I’m taking a netbook along
to check emails, so I won’t be completely unreachable, but I cannot
guarantee timely replies and/or updates.&lt;/p&gt;
&lt;p&gt;Most of the packages I authored were done for &lt;a href=&quot;http://syslab.com&quot;&gt;Syslab&lt;/a&gt;,
(usually under the ‘slc’ namespace), and the guys there would be able to
help with merging patches and the like.&lt;/p&gt;
&lt;p&gt;To Alex Pilz and the gang at Syslab, I would like to say, thanks for a
wonderful year and a half in Germany! I couldn’t have asked for nicer
and more competent people to work with and I am happy to have become
good friends with all of you.&lt;/p&gt;
&lt;p&gt;On Sunday begins a great new adventure.  Hopefully I’ll be able to have
a beer with some of the Plonistas, Pythonistas, Zopatistas and other
-istas in South America!&lt;/p&gt;
&lt;p&gt;Cheers!&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 638px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5c2b56a9d2d85bc200e985612b347cde/8608d/travel_route_south_america.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 100.44444444444444%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAGAABAQEBAQAAAAAAAAAAAAAAAAIDBAX/xAAVAQEBAAAAAAAAAAAAAAAAAAABAv/aAAwDAQACEAMQAAAB9SI1Z5xU75AyKP/EABwQAAEDBQAAAAAAAAAAAAAAAAABAhADERIhMf/aAAgBAQABBQJqaVkNMrRTF6f/xAAVEQEBAAAAAAAAAAAAAAAAAAAQQf/aAAgBAwEBPwEh/8QAFREBAQAAAAAAAAAAAAAAAAAAEEH/2gAIAQIBAT8BKf/EABcQAAMBAAAAAAAAAAAAAAAAAAABECH/2gAIAQEABj8CMrjv/8QAGhABAAIDAQAAAAAAAAAAAAAAAQARECFBYf/aAAgBAQABPyE3eo3GAq1r2KFjuDcO1j//2gAMAwEAAgADAAAAEDf/AH3/xAAWEQEBAQAAAAAAAAAAAAAAAAABECH/2gAIAQMBAT8QxIx//8QAFxEBAQEBAAAAAAAAAAAAAAAAARAhMf/aAAgBAgEBPxDRh1P/xAAcEAEBAAIDAQEAAAAAAAAAAAABEQAhEDFRQcH/2gAIAQEAAT8QAwl3ZhG67GvXFqqCon78zfQrC61ODq+BjC6Bgecf/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Our travel route through South America&quot;
        title=&quot;&quot;
        src=&quot;/static/5c2b56a9d2d85bc200e985612b347cde/8608d/travel_route_south_america.jpg&quot;
        srcset=&quot;/static/5c2b56a9d2d85bc200e985612b347cde/863e1/travel_route_south_america.jpg 225w,
/static/5c2b56a9d2d85bc200e985612b347cde/20e5d/travel_route_south_america.jpg 450w,
/static/5c2b56a9d2d85bc200e985612b347cde/8608d/travel_route_south_america.jpg 638w&quot;
        sizes=&quot;(max-width: 638px) 100vw, 638px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Babble: Instant messaging for Plone]]></title><description><![CDATA[babble.client is new a chat client for Plone, similar in style to Google
Chat and Facebook Chat. I’ve been having a lot of fun at Syslab…]]></description><link>https://opkode.com/blog/babble-instant-messaging-for-plone/</link><guid isPermaLink="false">https://opkode.com/blog/babble-instant-messaging-for-plone/</guid><pubDate>Thu, 29 Apr 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;babble.client is new a chat client for Plone, similar in style to Google
Chat and Facebook Chat.&lt;/p&gt;
&lt;p&gt;I’ve been having a lot of fun at &lt;a href=&quot;http://www.syslab.com&quot;&gt;Syslab&lt;/a&gt;
recently working on an &lt;em&gt;Instant Messaging&lt;/em&gt;
&lt;a href=&quot;http://plone.org/products/babble.client&quot;&gt;client&lt;/a&gt; and
&lt;a href=&quot;http://pypi.python.org/pypi/babble.server/0.1a1&quot;&gt;server&lt;/a&gt; combo for
&lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt;. The client app is a Plone add-on (for both
versions 3 and 4), which makes use of &lt;a href=&quot;http://jquery.com&quot;&gt;JQuery&lt;/a&gt;,
polling and Ajax techniques, to try and create a Facebook/Google like
chatting experience. Thanks to the excellent cross-browser support of
JQuery, I didn’t have to spend a lot of time getting it to work on
Internet Explorer.&lt;/p&gt;
&lt;p&gt;The messaging server is a pure &lt;a href=&quot;http://zope2.zope.org/&quot;&gt;Zope 2&lt;/a&gt;
application and was designed to be a standalone and independently usable
service, unaware of any client side solution. Its design is based on an
earlier version that I had worked on at &lt;a href=&quot;http://upfrontsystems.co.za&quot;&gt;Upfront
Systems&lt;/a&gt;, and for which &lt;a href=&quot;http://www.upfrontsystems.co.za/Members/roche/where-im-calling-from&quot;&gt;Roché
Compaan&lt;/a&gt;
deserves a lot of of the credit.  &lt;/p&gt;
&lt;h1&gt;Great, I would like to try out a DEMO!&lt;/h1&gt;
&lt;p&gt;For anyone curious to check it out, I’ve created a
&lt;a href=&quot;http://plone.org/products/babble.demo&quot;&gt;demo&lt;/a&gt; that automatically sets up
a working &lt;strong&gt;Babble&lt;/strong&gt; environment.&lt;/p&gt;
&lt;p&gt;Please take note that this demo is &lt;em&gt;not&lt;/em&gt; intended to be included in an
existing Plone environment. It’s a separate
&lt;a href=&quot;http://buildout.org&quot;&gt;buildout&lt;/a&gt; with a Zeo server and two clients
(running under Supervisord) and a policy egg that installs and
configures the &lt;em&gt;message server&lt;/em&gt; and &lt;em&gt;client.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;If you include the &lt;em&gt;babble.demo&lt;/em&gt; egg in another buildout, the Zeo setup
and instance ports will most likely be different, requiring you to set
up the &lt;em&gt;portal_chat&lt;/em&gt; tool by yourself, thereby defeating the purpose of
having a self-configuring demo.  &lt;/p&gt;
&lt;h1&gt;Cool, I love to read docs, where are they?&lt;/h1&gt;
&lt;p&gt;Good! I’ve created Sphinx
&lt;a href=&quot;http://opkode.net/babbledocs/index.html&quot;&gt;documentation&lt;/a&gt; that you may
peruse for your reading pleasure.&lt;/p&gt;
&lt;h1&gt;What’s in a name?&lt;/h1&gt;
&lt;p&gt;For lack (and want) of an awesome name, I googled for &lt;em&gt;Synonym + Chat&lt;/em&gt;
and relatively quickly settled on &lt;em&gt;Babble&lt;/em&gt;, only later realising that I
chose a name that specifically refers to meaningless babby chatter and
more generally functions as a less-than-complimentary description of
someone’s incoherent ramblings.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Babble:&lt;/strong&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;utter meaningless sounds, like a baby, or utter in an incoherent
way; “The old man is only babbling—don’t pay attention”&lt;/li&gt;
&lt;li&gt;to talk foolishly; “The two women babbled and crooned at the baby”&lt;/li&gt;
&lt;li&gt;ripple: flow in an irregular current with a bubbling noise;
“babbling brooks”&lt;/li&gt;
&lt;li&gt;spill the beans: divulge confidential information or secrets; “Be
careful—his secretary talks”&lt;/li&gt;
&lt;li&gt;gibberish resembling the sounds of a baby&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Babblebabblebabblebbable&lt;/h1&gt;
&lt;p&gt;That’s it. If you have encountered any problems or bugs while setting
up and using *Babble*, feel free to contact me. Suggestions are also
welcome.&lt;/p&gt;
&lt;p&gt;Thanks to Nikel Weiss, who helped me with some testing and provided
helpful suggestions and feedback. Thanks also to &lt;a href=&quot;http://blog.alexanderpilz.net/&quot;&gt;Alex
Pilz&lt;/a&gt; for not deciding to use a Freenode
solution ;)&lt;/p&gt;
&lt;h1&gt;Examples:&lt;/h1&gt;
&lt;p&gt;By itself, &lt;strong&gt;Babble&lt;/strong&gt; provides a special &lt;em&gt;Who’s online?&lt;/em&gt; portlet, to
show currently active users. When you click on a user, a chat window
will pop up at the bottom.&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 564px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/e8a2177596110b362bb3089d73ae8c4e/ba4d9/copy_of_Screenshot1.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 113.33333333333333%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAAAsTAAALEwEAmpwYAAACf0lEQVR42p2UzW7TQBDH/S5cShFCQrwDb8CVMwcCSIgH4I6QGirgzI0DN248AF9CaktTJymOv2LHsb1eZ7273i+XcRq1aZsmiNHfK+1qfjs7s7O2TjZZLSmhFaXtxyjJ3G+z1CUVq4WwjDEb4TTPiqLIshzjIp+MUBpnOeK1sBhjTdOsgYViCBcYY0JIWZa4bA2mQirLNI0218o0AHPb9Q+PR3v9P7YbBmnhJcidIMJqaw3ZwuZEap6gIppmRTmjvK6lUuZkHPrTOLQ2FgwizygrKQNMagMsLPrOYDzqX4BXJg85B9PcnaQgJ05STAoqBv1e7B3/Q2TNcVXNKgYqKziAgMXAPY684TmslIL7uApLDWeuClIBWbT3W8NiCLA7tJQ2p6qlgDYQSi5JSK25pO4kGcWJE0+CaZaVM0S5fXRwOeeVBpEpNAo3XMC1LuqSRmEWBQvYGD3O+l6y7yUHZ3KT/TCzg6x35P/oud9t/6c//Q0+4/xor/clCA6t050IQ68+Pnjx/l6nu9Xp3uy82X68s/V09/bLD/d3Pj18/u7uk91boE53G/Ts7Z1Hr298/tpdRIYNSNBHg1/Ut9PUm2RhlLhZEVUcJXk88IfOeBQkfhg744njhUPHt6H25zlP09weOAiTquK4KFGOKeWQo1J6qRNO26HNHFq37e1WBqotobbQ7tBDUgowuDzw0VpfrWIzRxawNmbl29wAq7lB1P+BESrgsSKEtVbznC4IfNbBdV0LKWG8zmkdfDapGCY0JxQta1bl8zpeNsgUxgUsJKCpaovMhOBzMag5wlFdc220Av8ltU8bYHgS8MfggmOScDFjdXkmmOblWEhx3bH/AhdIGnq+rVBCAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;image&quot;
        title=&quot;&quot;
        src=&quot;/static/e8a2177596110b362bb3089d73ae8c4e/ba4d9/copy_of_Screenshot1.png&quot;
        srcset=&quot;/static/e8a2177596110b362bb3089d73ae8c4e/3684f/copy_of_Screenshot1.png 225w,
/static/e8a2177596110b362bb3089d73ae8c4e/fc2a6/copy_of_Screenshot1.png 450w,
/static/e8a2177596110b362bb3089d73ae8c4e/ba4d9/copy_of_Screenshot1.png 564w&quot;
        sizes=&quot;(max-width: 564px) 100vw, 564px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Babble&lt;/strong&gt; is similar in looks to Facebook’s chat client. If you liked
the bottom panel that Facebook sported (until recently), then make sure
to also install
&lt;a href=&quot;http://plone.org/products/actionbar.babble&quot;&gt;actionbar.babble&lt;/a&gt;. This egg
provides Babble integration for the
&lt;a href=&quot;http://plone.org/products/actionbar.panel&quot;&gt;ActionBar&lt;/a&gt; panel.&lt;/p&gt;
&lt;p&gt;See the screenshot below for an example:&lt;/p&gt;
&lt;p&gt;&lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 650px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/8e04a05adb9043f026caa8798737392b/a6d36/Screenshot.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 58.22222222222222%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAMCAIAAADtbgqsAAAACXBIWXMAAAsTAAALEwEAmpwYAAABrUlEQVR42o1STW/UMBDNrwXBjSv8AS49grgg1AsXDiv1UC6AoGfUqtpCqzRlCWmy2cRfSRx/xTaMnZIKgSqeHGs8Gb+ZeeOkLK+5kFIpo/U0TT//G977hDKGMcHwEdx1nbUWKOxfcM794zKEuvh7ijDGKK00lKFVMGBXUkphjPbe+T+RMMYIIbBD2r7vQwYPtEAc9ruRYEKbFsF9SmkkwpvqIt+lVZtVKENd0bK8YZsd3TT0O+U95YIMHHVDP6oEShzGUUe1IK1U/PDj3v7q4fPVvZeHj958evrq7eNnq/svDh68fv/kaP356DT9cPL13cn5elMm0JEQQmvjowZQb48oLmuKmbXeAndLdD9aF3oABSAamr8RrCirjgsuDRdqEJKPUoN43rkozwRmIIQDlGVBTpB2VgvOiZAKXFFJN/tC9G+4AL/MZh7YHBAyNy3IRRFhCCGwW0xhKs5B/5MP4zML13L5ds51g3cIhO4iengr/ZBqkyqdSnXBx+1N1d4vT2WmC2Wfrc/OT48vvxzX9a6uqm1VFcW3oriKKyuvf2yjc1l5nl+m6VWWCSF+AU5dqTOKUiefAAAAAElFTkSuQmCC&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Babble with the ActionBar&quot;
        title=&quot;&quot;
        src=&quot;/static/8e04a05adb9043f026caa8798737392b/a6d36/Screenshot.png&quot;
        srcset=&quot;/static/8e04a05adb9043f026caa8798737392b/3684f/Screenshot.png 225w,
/static/8e04a05adb9043f026caa8798737392b/fc2a6/Screenshot.png 450w,
/static/8e04a05adb9043f026caa8798737392b/a6d36/Screenshot.png 650w&quot;
        sizes=&quot;(max-width: 650px) 100vw, 650px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt;&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using extract_messages in your Pylons/Python egg with a ./src directory layout]]></title><description><![CDATA[If you want to have your egg’s package contents inside a ‘src’
folder, you’ll need to tweak the configuration files a bit. Here’s
what I’ve…]]></description><link>https://opkode.com/blog/using-extract_messages-in-your-python-egg-with-a-src-directory/</link><guid isPermaLink="false">https://opkode.com/blog/using-extract_messages-in-your-python-egg-with-a-src-directory/</guid><pubDate>Wed, 24 Mar 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;If you want to have your egg’s package contents inside a ‘src’
folder, you’ll need to tweak the configuration files a bit. Here’s
what I’ve learned…&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;images-container right&quot; style=&quot;width: 15em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 200px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/5a0adce305e8361e5438b250d5e64321/e07e9/3149760367_dcd5169791.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAABQACA//EABcBAAMBAAAAAAAAAAAAAAAAAAABAgP/2gAMAwEAAhADEAAAAVOQec6dgZn/xAAaEAACAgMAAAAAAAAAAAAAAAAAAgERAxMU/9oACAEBAAEFArJcs6XJztJvc//EABYRAAMAAAAAAAAAAAAAAAAAAAABEf/aAAgBAwEBPwGoqP/EABYRAQEBAAAAAAAAAAAAAAAAAAARAf/aAAgBAgEBPwGaj//EABYQAAMAAAAAAAAAAAAAAAAAAAAgMf/aAAgBAQAGPwJaf//EABsQAAICAwEAAAAAAAAAAAAAAAABEXEQMUGR/9oACAEBAAE/IWqFLREr8OtFYn//2gAMAwEAAgADAAAAEIzP/8QAFBEBAAAAAAAAAAAAAAAAAAAAEP/aAAgBAwEBPxAD/8QAFhEBAQEAAAAAAAAAAAAAAAAAAAER/9oACAECAQE/EItv/8QAHBABAAIDAAMAAAAAAAAAAAAAAQARITFBUWGh/9oACAEBAAE/ECFWiMUh1y+y7LLsK78xj0D0qVb+J//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;iPylons&quot;
        title=&quot;&quot;
        src=&quot;/static/5a0adce305e8361e5438b250d5e64321/e07e9/3149760367_dcd5169791.jpg&quot;
        srcset=&quot;/static/5a0adce305e8361e5438b250d5e64321/e07e9/3149760367_dcd5169791.jpg 200w&quot;
        sizes=&quot;(max-width: 200px) 100vw, 200px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;I’ve been spending a lot of time trying to figure out something quite
simple, so I’ll write a blog post about it to hopefully save someone
else some time with this.&lt;/p&gt;
&lt;p&gt;I’m in the process of creating a Pylons egg. For illustration purposes,
I’ll call it MyEgg.&lt;/p&gt;
&lt;p&gt;The egg is created as follows:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;paster create &lt;span class=&quot;token parameter variable&quot;&gt;--template&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;pylons MyEgg&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The default egg directory looks like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;MyEgg 
  docs 
  myegg
    config
    controllers
    lib
    model
    public
    templates
    tests
MyEgg.egg-info&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;I prefer however to put the package contents &lt;strong&gt;myegg&lt;/strong&gt; inside a
&lt;strong&gt;./src&lt;/strong&gt; directory. That way, I can more easily use
&lt;a href=&quot;http://www.buildout.org/&quot;&gt;zc.buildout&lt;/a&gt; to manage &lt;strong&gt;MyEgg&lt;/strong&gt; and its
dependencies. I can then use buildout to manage and develop this egg’s
dependencies by also putting them in &lt;strong&gt;./src&lt;/strong&gt;.&lt;/p&gt;
&lt;p&gt;After almost 3 years of using buildout on a daily basis, this layout
just fits my brain better.&lt;/p&gt;
&lt;p&gt;The new folder structure would now look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;MyEgg 
  docs 
  src   
    myegg     
      config     
      controllers     
      lib     
      model     
      public     
      templates     
      tests 
MyEgg.egg-info&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Updating your setup.py script:&lt;/h2&gt;
&lt;p&gt;To make Distutils aware of the new directory layout, you also need to
add the following two lines to the setup method call in your setup.py
script:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;packages&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;find_packages&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; exclude&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;ez_setup&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
package_dir&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;h2&gt;Extracting translatable strings from your python files:&lt;/h2&gt;
&lt;p&gt;To generate a *.pot file that contains all the translateable strings in
your code, you run the following command:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;python setup.py extract_messages&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;To have the new directory structure (with ./src) and still be able to
use &lt;strong&gt;extract_messages&lt;/strong&gt; to internationalize your egg takes a bit more
tweaking.&lt;/p&gt;
&lt;p&gt;Firstly, in the setup.cfg file, you need to append &lt;strong&gt;src&lt;/strong&gt; to the paths
in the different sections. For example, in the&lt;strong&gt;extract_messages&lt;/strong&gt;
section, it would look like this:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;text&quot;&gt;&lt;pre class=&quot;language-text&quot;&gt;&lt;code class=&quot;language-text&quot;&gt;[extract_messages]
add_comments = TRANSLATORS:
output_file = src/myegg/i18n/myegg.pot
width = 80&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;NOTE: there are other commands (such as &lt;strong&gt;compile_catalog&lt;/strong&gt;) that also
need to be run later as part of enabling I18N support for your package.
For the purpose of this blog post, I’m concentrating on
&lt;strong&gt;extract_messages&lt;/strong&gt;, but the above change in the setup.cfg file
applies to the other sections as well. For more info on I18N in Pylons,
refer to the Pylons
&lt;a href=&quot;http://pylonsbook.com/en/1.1/internationalization-and-localization.html&quot;&gt;Book&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;And now for the problem I was struggling with ;)&lt;/h1&gt;
&lt;p&gt;&lt;span class=&quot;right img-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 200px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/61085e950fb9566e1f3a9ae08aee4c6d/e07e9/3210086353_87818a1be5.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 75%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAPABQDASIAAhEBAxEB/8QAGAAAAgMAAAAAAAAAAAAAAAAAAAQCAwX/xAAVAQEBAAAAAAAAAAAAAAAAAAADAP/aAAwDAQACEAMQAAABbRoiNpCIp//EABkQAAIDAQAAAAAAAAAAAAAAAAACAQMSEf/aAAgBAQABBQKbEY1x9UmyGhjh/8QAFREBAQAAAAAAAAAAAAAAAAAAABH/2gAIAQMBAT8BR//EABcRAQADAAAAAAAAAAAAAAAAAAABERL/2gAIAQIBAT8BuWn/xAAaEAABBQEAAAAAAAAAAAAAAAAAEBEhIjFB/9oACAEBAAY/AquWw1OkH//EAB0QAAMAAgIDAAAAAAAAAAAAAAABESExQVFhcfD/2gAIAQEAAT8ho0j8oTUy1cPihRq9uGdvoKFwR//aAAwDAQACAAMAAAAQBy//xAAWEQEBAQAAAAAAAAAAAAAAAAABABH/2gAIAQMBAT8QAzGRf//EABcRAAMBAAAAAAAAAAAAAAAAAAABESH/2gAIAQIBAT8Q1onh/8QAHBABAAICAwEAAAAAAAAAAAAAAQARITFBUWFx/9oACAEBAAE/EEMCdQHk3c3CMe/YLowl8KliNdF1EyxVipzDon//2Q==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Pylons&quot;
        title=&quot;&quot;
        src=&quot;/static/61085e950fb9566e1f3a9ae08aee4c6d/e07e9/3210086353_87818a1be5.jpg&quot;
        srcset=&quot;/static/61085e950fb9566e1f3a9ae08aee4c6d/e07e9/3210086353_87818a1be5.jpg 200w&quot;
        sizes=&quot;(max-width: 200px) 100vw, 200px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The problem I encountered with this layout was that the
&lt;strong&gt;extract_messages&lt;/strong&gt; command (courtesy of
&lt;a href=&quot;http://babel.edgewall.org/&quot;&gt;Babel&lt;/a&gt;) that is used to extract
translatable strings for I18N support, now didn’t find my python files
anymore.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;python setup.py extract_messagesrunning extract_messageswriting PO
template src/myegg/i18n/myegg.pot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you look at a Pylon project’s setup.py files (if you created it with
the &lt;em&gt;paster&lt;/em&gt;’s pylons template), you will see the following lines
commented out:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token comment&quot;&gt;##message_extractors = {&apos;myegg&apos;: [&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## (&apos;**.py&apos;, &apos;python&apos;, None),&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## (&apos;templates/**.mako&apos;, &apos;mako&apos;, None),&lt;/span&gt;
&lt;span class=&quot;token comment&quot;&gt;## (&apos;public/**&apos;, &apos;ignore&apos;, None)]},&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;The solution to this problem was to uncomment the
&lt;strong&gt;message_extractors&lt;/strong&gt; parameter in &lt;strong&gt;setup.py&lt;/strong&gt;, and to tell it to
look in the &lt;strong&gt;src&lt;/strong&gt; directory:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;message_extractors &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;src&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;
   &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;**.py&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;python&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;templates/**.mako&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;mako&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;
    &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;public/**&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;ignore&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token boolean&quot;&gt;None&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now the extract_messages command works and creates a &lt;strong&gt;myegg.pot&lt;/strong&gt; file
that contains all the translatable strings in my app.&lt;/p&gt;
&lt;p&gt;Here’s the output (shortened for brevity):&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;$ python setup.py extract_messages running extract_messages
extracting messages from src/__init__.py extracting messages from
src/myegg/__init__.py &lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;..&lt;/span&gt; extracting messages from
src/myegg/tests/functional/__init__.py writing PO template &lt;span class=&quot;token function&quot;&gt;file&lt;/span&gt; to
src/myegg/i18n/myegg.pot&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Hope this helps another Pylons, Distutils or I18N newbie to save some
time.&lt;/p&gt;
&lt;h2&gt;Further reading:&lt;/h2&gt;
&lt;p&gt;For more information on using zc.buildout with Pylons, read this
community &lt;a href=&quot;http://wiki.pylonshq.com/display/pylonscommunity/Howto+install+Pylons+with+buildout&quot;&gt;HowTo&lt;/a&gt;
and also this informative
&lt;a href=&quot;http://mg.pov.lt/blog/pylons-with-buildout.html&quot;&gt;blogpost&lt;/a&gt; by Marius Gedminas.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Why you should open source your code]]></title><description><![CDATA[This blog post is based upon my experience in developing add-ons for the
Plone open source content management system. It’s therefore mostly…]]></description><link>https://opkode.com/blog/why-you-should-open-source-your-code-your-python-eggs/</link><guid isPermaLink="false">https://opkode.com/blog/why-you-should-open-source-your-code-your-python-eggs/</guid><pubDate>Thu, 18 Mar 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;This blog post is based upon my experience in developing add-ons for the
Plone open source content management system. It’s therefore mostly
aimed at the Plone community, although some of the insights mentioned
might also apply to other communities and to web-development in general.&lt;/p&gt;
&lt;p&gt;In the last 15 months, I have released 15 &lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt;
add-on products as open-source python eggs, available for download on
&lt;a href=&quot;http://plone.org&quot;&gt;Plone.org&lt;/a&gt; and &lt;a href=&quot;http://pypi.python.org/pypi&quot;&gt;Pypi&lt;/a&gt;,
the python package repository. In the preceding 4 years of Plone
development, I released only a single product.&lt;/p&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 15em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 300px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/cc9dafa6bb799d845684ec7bdce7742a/f93b5/python_egg.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 90.66666666666666%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAASABQDASIAAhEBAxEB/8QAGAABAAMBAAAAAAAAAAAAAAAAAAMEBQH/xAAUAQEAAAAAAAAAAAAAAAAAAAAA/9oADAMBAAIQAxAAAAHsl/HNhQCIN8H/xAAaEAEBAQADAQAAAAAAAAAAAAACAwEAESIh/9oACAEBAAEFAomlyQBhtnUBkotehFM5vmX2vP/EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQMBAT8BH//EABQRAQAAAAAAAAAAAAAAAAAAACD/2gAIAQIBAT8BH//EAB8QAAEDAwUAAAAAAAAAAAAAAAEAAhEQITESEyJRkf/aAAgBAQAGPwKdyAtbnE9LllBvqg5FlNBN70//xAAdEAEAAwACAwEAAAAAAAAAAAABABEhQVEQYXGh/9oACAEBAAE/IXhBNPcDLFyv7H6UGvsciW7rmVV+x2SpcPcTkzGwpj4//9oADAMBAAIAAwAAABDDyDz/xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAEDAQE/EB//xAAUEQEAAAAAAAAAAAAAAAAAAAAg/9oACAECAQE/EB//xAAcEAEAAwEBAQEBAAAAAAAAAAABABExUSFxgdH/2gAIAQEAAT8QoyUqW3zJwCXIMQd3hHobHjB2HHkqDX8z8heR82gMpgMxGjFnZZvt9iV70A2ABQUE/9k=&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Image by MrTopf&quot;
        title=&quot;&quot;
        src=&quot;/static/cc9dafa6bb799d845684ec7bdce7742a/f93b5/python_egg.jpg&quot;
        srcset=&quot;/static/cc9dafa6bb799d845684ec7bdce7742a/863e1/python_egg.jpg 225w,
/static/cc9dafa6bb799d845684ec7bdce7742a/f93b5/python_egg.jpg 300w&quot;
        sizes=&quot;(max-width: 300px) 100vw, 300px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;In this process, I have witnessed a personal metamorphosis. I can draw a
relatively clear line between ‘Ye Olde Worlde’ web-developer who was
set in his ways and narrow minded in his methods, and the &lt;em&gt;new!&lt;/em&gt;
&lt;em&gt;improved!&lt;/em&gt; open source developer.&lt;/p&gt;
&lt;p&gt;I’ve seen the transformative power of (the act of) open sourcing and
although I’m sure that a lot of what I have learned is already old hat
to many developers, I would like to share the insights I have gained
from this experience. Many developers have been made aware of the
inherent advantages of collaborating in an open-source community, but to
take part in it yourself and to experience the inherent benefits first
hand, is the only way of developing a true conviction for the
appropriateness of open source collaboration.&lt;/p&gt;
&lt;p&gt;The fact is, that you have a lot to gain by engaging with the community,
through collaborating, sharing your ideas and making your code public.&lt;/p&gt;
&lt;h3&gt;Open source everything that might be useful to others&lt;/h3&gt;
&lt;p&gt;It’s relatively common practice in the Plone community to develop a
so-called ‘policy package’ for a new project. The policy package
should tie everything together, configure the Plone application to the
client’s needs, and install all the other add-ons.&lt;/p&gt;
&lt;p&gt;Additionally, a theme egg for implementing a custom theme is usually
also required. These two packages, together with a collection of
third-party and in-house developed packages (each responsible for a
specific feature set), on top of Plone itself, constitutes the software
product presented to the client.&lt;/p&gt;
&lt;p&gt;Before I was introduced to the idea of a policy egg by &lt;a href=&quot;http://www.packtpub.com/Professional-Plone-web-applications-CMS/book&quot;&gt;Martin Aspeli&lt;/a&gt;
and others who championed the idea, I would usually when given an
assignment, develop only one Plone add-on product for it. This add-on
then contained all the custom software code that I wrote for this
specific client and/or product, regardless of whether certain parts of
it would also be beneficial to other people or projects.&lt;/p&gt;
&lt;p&gt;This is of course not the proper way to develop a sustainable, reusable
and configurable solution for a client. Instead, every piece of
functionality that constitutes a logical grouping of features and that
could theoretically be reused somewhere else, should be packaged
separately in its own python egg.&lt;/p&gt;
&lt;p&gt;And here’s the catch: you should &lt;strong&gt;ideally&lt;/strong&gt; open-source everything
except the policy package. Even the theme egg should be considered for
open sourcing.&lt;/p&gt;
&lt;p&gt;The policy package serves as the puppetmaster, that ties these different
pieces together to make the integrated unit (or puppet show). It is the
proprietary configuration that contains the client specific
implementation details, the client’s copyrighted logo and images, the
site copy and everything else that makes the site unique to the client.
It’s the secret sauce or the kernel’s 11 herbs and spices, in a matter
of speaking.&lt;/p&gt;
&lt;p&gt;With regards to the rest of the custom developed eggs in your project,
release them as open source eggs on Pypi! You have a lot to gain by
doing so.&lt;/p&gt;
&lt;p&gt;Let me elaborate on why…&lt;/p&gt;
&lt;h2&gt;Advantages&lt;/h2&gt;
&lt;h3&gt;Open sourcing your code forces you to be a better programmer&lt;/h3&gt;
&lt;p&gt;The implicit mental adjustment coming from the knowledge that you are
writing source code which will be read and modified by others, is
already enough to considerably enhance the quality of the code that you
will write.&lt;/p&gt;
&lt;p&gt;Why? Because of the added social pressure.&lt;/p&gt;
&lt;p&gt;&lt;a href=&quot;http://en.wikipedia.org/wiki/Glossophobia&quot;&gt;Glossophobia&lt;/a&gt;, the fear of
public speaking, rumoured to be the most common fear in the minds of
people, is a consequence of the fear of public humiliation.&lt;/p&gt;
&lt;p&gt;Nobody wants to be humiliated publicly. Not for being a poor speaker and
not for writing bad source code. The fact is, that you will make more of
an effort to write clear and legible code that follows best practices
when you are writing for an audience (the community of developers) than
when you are writing for personal or ‘in-house’ consumption.&lt;/p&gt;
&lt;p&gt;Before I started writing code with the intention of open-sourcing it, I
would be much more inclined to include quick and dirty hacks to “save
time” or to “simplify” things. Ironically, quick hacks such as
hardcoding a value or overriding a template instead of putting it in a
viewlet will in the long run, waste time and overcomplicate things.&lt;/p&gt;
&lt;p&gt;A quick real world example: Your boss or client wants a
&lt;a href=&quot;http://www.sohtanaka.com/web-design/facebook-style-footer-admin-panel-part-1/&quot;&gt;facebook style action panel&lt;/a&gt;
on the bottom of a site.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;Do you:&lt;/em&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Decide not to open source this functionality, and instead add the
styles and templates to the theme egg while hardcoding the links on
the panel because it’s quick and easy?&lt;/li&gt;
&lt;li&gt;Decide from the getgo that you will open source this and therefore
create a separate &lt;a href=&quot;http://plone.org/products/actionbar.panel/&quot;&gt;egg&lt;/a&gt;
for this piece of functionality, that adheres to best practices to
make it reusable, extendable and configurable?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The second option might take longer initially, but its benefits pay off
in the long run, especially when the client requires technical support.&lt;/p&gt;
&lt;h3&gt;The community provides an additional level of quality control&lt;/h3&gt;
&lt;p&gt;I’m careful here to add the word ‘additional’ since you should not
solely rely on the community to test your code for you. On the contrary,
other people will be reluctant to try out your products if you don’t
put in the initial effort or write tests and doing quality control
yourself.&lt;/p&gt;
&lt;p&gt;That being said, granted that you have released a quality package, you
&lt;em&gt;will&lt;/em&gt; receive an additional layer of community powered quality control
by virtue of the fact that the developers and integrators using your
code will let you know when they run into bugs, and often even fix them
for you! “With many eyes, all bugs are shallow.”&lt;/p&gt;
&lt;h3&gt;The community provides new perspectives, ideas and enhancements.&lt;/h3&gt;
&lt;p&gt;This past year, various developers have contacted me with suggestions,
ideas and improvements to some of the packages that I have released.
Some have made a meaningful amount of effort to explain why a certain
solution might be better, and in the process have provided me with a
free education and broadened the scope of my Plone dev knowledge.&lt;/p&gt;
&lt;p&gt;Overall, the quality of the packages that I have released, has been
improved through the sustained contributions of other developers in the
Plone community. This is after all one of the main advantages of open
source, seen from a purely pragmatic point of view. To witness this
process in action and with code that you yourself have contributed, is
very satisfying.&lt;/p&gt;
&lt;h3&gt;Social currency (A social C.V or Résumé)&lt;/h3&gt;
&lt;p&gt;&lt;span class=&quot;img-container right&quot; style=&quot;width: 35em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 500px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/02823702ed9497a373b88bc7a679f2ed/41099/59031479_fc26e3c06b.jpg&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 60%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAMABQDASIAAhEBAxEB/8QAFgABAQEAAAAAAAAAAAAAAAAAAgQA/8QAFAEBAAAAAAAAAAAAAAAAAAAAAP/aAAwDAQACEAMQAAABBnZVpMf/xAAZEAADAAMAAAAAAAAAAAAAAAAAAQIQERL/2gAIAQEAAQUCdHdCtiZvH//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQMBAT8BP//EABQRAQAAAAAAAAAAAAAAAAAAABD/2gAIAQIBAT8BP//EABoQAAICAwAAAAAAAAAAAAAAAAABMpECECH/2gAIAQEABj8C43ZJ2Tyse//EAB0QAAICAgMBAAAAAAAAAAAAAAABESExcUFhodH/2gAIAQEAAT8hcuXuJH1EC5NyyiyZ4RPXp//aAAwDAQACAAMAAAAQwA//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAEDAQE/ED//xAAUEQEAAAAAAAAAAAAAAAAAAAAQ/9oACAECAQE/ED//xAAgEAACAQIHAQAAAAAAAAAAAAABEQAx0SFBYYGRofHw/9oACAEBAAE/EBZATI+s+D+4UKWb1ijVsVZsw1vC5acrz//Z&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;Photo by Superbez&quot;
        title=&quot;&quot;
        src=&quot;/static/02823702ed9497a373b88bc7a679f2ed/41099/59031479_fc26e3c06b.jpg&quot;
        srcset=&quot;/static/02823702ed9497a373b88bc7a679f2ed/863e1/59031479_fc26e3c06b.jpg 225w,
/static/02823702ed9497a373b88bc7a679f2ed/20e5d/59031479_fc26e3c06b.jpg 450w,
/static/02823702ed9497a373b88bc7a679f2ed/41099/59031479_fc26e3c06b.jpg 500w&quot;
        sizes=&quot;(max-width: 500px) 100vw, 500px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;Open source contributions, being easily searchable and in the public
domain, form an authorative record of the depth and quality of an
individual or company’s output.&lt;/p&gt;
&lt;p&gt;Compared to the sections traditionally contained in a Curriculum Vitae
(Résumé), your open source contributions form your &lt;em&gt;work experience&lt;/em&gt;
section, while their contributors and users serve as &lt;em&gt;references&lt;/em&gt;.
Sustained open source contributions coupled with helpful and courteous
interaction with the community, provides a more authoritive record of
ability and character than any CV ever could.&lt;/p&gt;
&lt;h2&gt;Suggestions:&lt;/h2&gt;
&lt;p&gt;I’d like to round up this post by making some suggestions which I
consider will better the chances of your product not only being used by
the community, but also receiving code improvements and bugfixes.  &lt;/p&gt;
&lt;h2&gt;Don’t host in-house:&lt;/h2&gt;
&lt;p&gt;Use the &lt;a href=&quot;http://svn.plone.org/svn/collective&quot;&gt;collective&lt;/a&gt; repository to
host your Plone source code. We’re lucky to have it, and that’s what
it’s there for. Alternatively, use Google’s &lt;a href=&quot;http://code.google.com/projecthosting/&quot;&gt;project hosting&lt;/a&gt;
or &lt;a href=&quot;http://www.github.com&quot;&gt;github&lt;/a&gt;. Although, in my opinion, it doesn’t
make much sense to call something collective.* if it’s not hosted on
the collective repo (I know others disagree with this).&lt;/p&gt;
&lt;p&gt;You want the barrier to entry for participation in your code to be as
low as possible. That means making it as easy as possible to quickly
provide improvements and bugfixes.&lt;/p&gt;
&lt;p&gt;If you host your open source products privately, you might gain users,
but you will have far fewer contributors willing to fix and enhance your
code, simply because they’re not willing to jump through hoops to be
able to do so. Private or walled off hosting discourages contributions
and promotes forking. Which would be a forking shame (sorry, I had to).&lt;/p&gt;
&lt;h3&gt;Start your project in the open:&lt;/h3&gt;
&lt;p&gt;Don’t develop your packages privately, waiting for them to be “good
enough” to be added the to a public repository.&lt;/p&gt;
&lt;p&gt;Start from the beginning on developing publicly on a repository such as
the collective. This will ensure that you stay aware of the fact that
you are writing code for others and not just for yourself. As mentioned
before, when you consider the fact that others will have to read and
digest your code, you will more carefully consider your method, class
and variable names. Do they make sense? Are they consistent? Is the code
explicit and readable? etc.&lt;/p&gt;
&lt;h3&gt;Release your Plone eggs on both Pypi and plone.org:&lt;/h3&gt;
&lt;p&gt;Some users prefer to search for Plone add-ons via plone.org, while
others use Pypi. Cater to both to maximise your visibility. Plone.org
goes a step further by among other things allowing you to upload a
screenshot and your company’s logo.&lt;/p&gt;
&lt;p&gt;Tools such as &lt;a href=&quot;http://pypi.python.org/pypi/zest.releaser&quot;&gt;zest.releaser&lt;/a&gt;
or &lt;a href=&quot;http://pypi.python.org/pypi/jarn.mkrelease/1.0.2&quot;&gt;jarn.mkrelease&lt;/a&gt;
make releasing eggs a breeze. Use them! :)&lt;/p&gt;
&lt;h2&gt;Conclusion:&lt;/h2&gt;
&lt;p&gt;When it comes to open sourcing your code, the fear might arise, that by
making your code available for others to use and adapt, you might in
some way lower your chances of monetizing the code. For people living
with a mindset of scarcity, in which ideas and creations must be guarded
closely to safeguard their success and to prevent others from
“stealing” or profiteering from them, it might be difficult to make
the paradigm shift necessary, towards a mindset of abundance,
opportunity, sharing and collaboration.&lt;/p&gt;
&lt;p&gt;The fact is, that you have a lot to gain by engaging with the community,
through collaborating, sharing your ideas and making your code public.
;)&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Archetypes: Schema extending an object only inside a specific folder]]></title><description><![CDATA[It’s possible to register schema-extenders (and modifiers) for only
certain subsections (folders) of your Plone site. It’s relatively
simple…]]></description><link>https://opkode.com/blog/schema-extending-an-object-only-inside-a-specific-folder/</link><guid isPermaLink="false">https://opkode.com/blog/schema-extending-an-object-only-inside-a-specific-folder/</guid><pubDate>Tue, 26 Jan 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;&lt;span class=&quot;right images-container&quot; style=&quot;width: 17em&quot;&gt; &lt;span
      class=&quot;gatsby-resp-image-wrapper&quot;
      style=&quot;position: relative; display: block; margin-left: auto; margin-right: auto; max-width: 160px; &quot;
    &gt;
      &lt;a
    class=&quot;gatsby-resp-image-link&quot;
    href=&quot;/static/b904de300b01cf55b67cf11579d487be/69538/plone.png&quot;
    style=&quot;display: block&quot;
    target=&quot;_blank&quot;
    rel=&quot;noopener&quot;
  &gt;
    &lt;span
    class=&quot;gatsby-resp-image-background-image&quot;
    style=&quot;padding-bottom: 114.375%; position: relative; bottom: 0; left: 0; background-image: url(&apos;data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAXCAIAAACEf/j0AAAACXBIWXMAAAsTAAALEwEAmpwYAAAC40lEQVR42pVUW1PTQBjtX/PZGX+Ejo+ODz44PumDDjCOI5eOwDigDko7BeyNWwCBYhUsoVBoKYS2tIGklzRN0qS5bRLcZtv0wsiMO5l099tzzn759nx13dwalgUfC/46EdOy7Ej/cN1itkCGaXGSUpNk3TAd0bvIaLfCieEoPh1cmw5gUwFs8vuKZ/1XrlS96U6mj4zOPCTyo7OBKJ4QJRGGDMPgeCESOxr4PI/hqe7UOuQW86Lg9gZrvADnxwV67TAtqxoCQIl334JY7Lib73IWjCCNeYPFCgPnOJF/Mu65/3wwmmiepukAvlleGJzxEyTtUDrkpd/xlZ09JJkvMY9ejzx8OUTZWhBgmM2ybeAnX5Y2O2SUAdyZ9K/mrzuqDVlpKAqciLJa5kVg17xYE4a94YYsI5gLQSVVH/aE6pKESupca0PVds8uZ7BILJmGSxUYI95wtcb1k997QnxdvGkzEVnVgW9j59XoRDx5CpeKDty+JZbj22QbBEzLvYBlyGsnbU6SGaGpVeX4AkUbdtoVQZpYWJbtz2mSHbRva88f+YMKRjLs+MrO0w9fU7kCsqdpY6In597lTRTpqTZVYQdmAnnbSfvE5YMXQ/ceP8NTZ/ZV6fAtyJrbFybpYs9VOYvoYfLtbKjENbPdjsW3YnHTbBlbVPWp0Hr0INFvkm7fR/DEm0/zGwcpiG6eCYxavbGXyox5Qz/xo7726GkM9CV0ueJZ/jE8GxifW/zoX52YW5zDtuky02fsW10FC9POEwAATc4Jddgbzq7V29gdsg4M5GFoJkfi7tEi64ZxnCXjRF5S1AxV1gCA/VSuCUi0wgmoveqyIkhyPxk6KZbOxs9zoqwQV8V6Q7m4Lp3mKVYQrypsnLg8J4uweLupzH46q2gacnGHDJmy0oyekRSUSBeoZI7kRYksVymGzVIlRdN/J4kcXQbtKnTuWQeg/fHAbgmVte0JofBBQSgK5f75B/hf4y8tTgWydOtDgwAAAABJRU5ErkJggg==&apos;); background-size: cover; display: block;&quot;
  &gt;&lt;/span&gt;
  &lt;img
        class=&quot;gatsby-resp-image-image&quot;
        alt=&quot;image&quot;
        title=&quot;&quot;
        src=&quot;/static/b904de300b01cf55b67cf11579d487be/69538/plone.png&quot;
        srcset=&quot;/static/b904de300b01cf55b67cf11579d487be/69538/plone.png 160w&quot;
        sizes=&quot;(max-width: 160px) 100vw, 160px&quot;
        style=&quot;width:100%;height:100%;margin:0;vertical-align:middle;position:absolute;top:0;left:0;&quot;
        loading=&quot;lazy&quot;
        decoding=&quot;async&quot;
      /&gt;
  &lt;/a&gt;
    &lt;/span&gt; &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;It’s possible to register schema-extenders (and modifiers) for only
certain subsections (folders) of your Plone site. It’s relatively
simple, and all you need is to do is add a local site-manager to the
folder and then register the adapters against it.&lt;/p&gt;
&lt;p&gt;This blogpost assumes that you are already familiar with Plone’s
Archetypes schema extensions and provides more advanced usage examples.
If you’ve got no idea what I’m talking about but want to learn more,
checkout the pypi page
&lt;a href=&quot;http://pypi.python.org/pypi/archetypes.schemaextender&quot;&gt;here&lt;/a&gt; first.&lt;/p&gt;
&lt;h2&gt;Introduction&lt;/h2&gt;
&lt;p&gt;By using simple adapters (known as schema-extenders), it’s possible to
extend or modify the schemas of your Archetypes objects without actually
getting your hands dirty. One advantage of using adapters to modify an
Archetype’s schema is that it allows multiple &lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt;
add-on products to modify the schema in an extendible and non-invasive
way, without using any subclassing. You don’t need to touch the
original code at all.&lt;/p&gt;
&lt;p&gt;The &lt;a href=&quot;http://wiki.zope.org/zope3/ComponentArchitectureOverview&quot;&gt;Zope Component
Architecture&lt;/a&gt;
(ZCA) provides the functionality that makes all this happen. Adapters
are registered (via
&lt;a href=&quot;http://plone.org/documentation/manual/theme-reference/buildingblocks/components/wiring&quot;&gt;ZCML&lt;/a&gt;
or python) and are then kept track of by a ZCA component known as a site
manager.&lt;/p&gt;
&lt;p&gt;A normal Plone site provides a global &lt;strong&gt;site manager&lt;/strong&gt; located at the
root of the site. This site manager keeps track of all the registered
adapters in the site. When you schema-extend an object, it’s the site
manager that is queried for the possible adapters (schema-extenders and
schema-modifiers) that apply to this object.&lt;/p&gt;
&lt;p&gt;You don’t however have to have only one site-manager. You can easily
create a local site-manager in a folder elsewhere in your site, and this
allows you to have a folder specific registry of ZCA adapters and
utilities. Concerning schema-extension, this means that you have
schema-extenders that apply only in certain subsections (folders) of
your site.&lt;/p&gt;
&lt;h2&gt;The nitty gritty&lt;/h2&gt;
&lt;p&gt;So, how do we do this? First we need to create the schemaextender that
we will be applying only on a local folder. The following code describes
this extender object. To keep it simple, it adds one extra field to the
existing object’s schema, namely the ExtensionStringField.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; zope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interface &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; Products&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;Archetypes
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; atapi &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; archetypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;schemaextender&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;field
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ExtensionField &lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; archetypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;schemaextender&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interfaces
&lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; ISchemaExtenderclass

ExtensionStringField&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ExtensionField&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; atapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StringField&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

&lt;span class=&quot;token keyword&quot;&gt;class&lt;/span&gt; &lt;span class=&quot;token class-name&quot;&gt;LocalExtender&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token builtin&quot;&gt;object&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;

    zope&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interface&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;implements&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;ISchemaExtender&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
    _fields &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;ExtensionStringField&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;&apos;MyLocalString&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; widget&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;atapi&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;StringWidget&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt;

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;__init__&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; context&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;context &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; context

    &lt;span class=&quot;token keyword&quot;&gt;def&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;getFields&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;self&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
        &lt;span class=&quot;token keyword&quot;&gt;return&lt;/span&gt; self&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;_fields&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lets assume that we have now have a folder in which we want objects of a
certain type to be extended by our extender above. To be able to do
this, we first need to create a local site-manager inside this folder.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; five&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;localsitemanager &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; make_objectmanager_site

&lt;span class=&quot;token keyword&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;not&lt;/span&gt; ISite&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;providedBy&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;folder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;:&lt;/span&gt;
    make_objectmanager_site&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;folder&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;So, as mentioned, the code above will create a local site-manager inside
your folder. How and when you call the above code is up to you. You can
for example put it in an &lt;a href=&quot;http://www.zope.org/Documentation/How-To/ExternalMethods&quot;&gt;External
Method&lt;/a&gt; and
call it once, or you could create a
&lt;a href=&quot;http://www.slideshare.net/wooda/rocky-burt-subtyping-unleashed&quot;&gt;subtype&lt;/a&gt;
and have a reproducible way of creating local site-managers through the
Plone UI.&lt;/p&gt;
&lt;p&gt;Next, we have to register our schema-extender for a specific object this
specific site-manager. Which kind of object it is, is determined by
it’s interface(s). So, assuming we wanted to extend all the Documents
in this folder, we would register our extender for the IATDocument
interface.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;python&quot;&gt;&lt;pre class=&quot;language-python&quot;&gt;&lt;code class=&quot;language-python&quot;&gt;&lt;span class=&quot;token keyword&quot;&gt;from&lt;/span&gt; Products&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;ATContentTypes&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;interface &lt;span class=&quot;token keyword&quot;&gt;import&lt;/span&gt; IATDocument
sm &lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt; folder&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;getSiteManager&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;
sm&lt;span class=&quot;token punctuation&quot;&gt;.&lt;/span&gt;registerAdapter&lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;LocalExtender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;IATDocument&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; ISchemaExtender&lt;span class=&quot;token punctuation&quot;&gt;,&lt;/span&gt; name&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token string&quot;&gt;u&apos;LocallyExtendedObject&apos;&lt;/span&gt;&lt;span class=&quot;token punctuation&quot;&gt;)&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;ul&gt;
&lt;li&gt;The first variable passed to registerAdapter, is our LocalExtender
class, also known as the adapter factory. The factory is used to
compute the adapter.&lt;/li&gt;
&lt;li&gt;The second variable is a tuple containing a sequence of interfaces
that the object must implement to make it a candidate for
adaptation.&lt;/li&gt;
&lt;li&gt;The third variable is the interface that the factory
(schema-extender) must implement in order to make it a valid adpater
in this context.&lt;/li&gt;
&lt;li&gt;Lastly, the name is useful since it can be used to override adapters
that applied to subtypes of an object.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;For more info on local site-managers and registering ZCA components for
them, see
&lt;a href=&quot;http://svn.zope.org/five.localsitemanager/tags/2.0.3/src/five/localsitemanager/localsitemanager.txt?rev=107574&amp;#x26;view=markup&quot;&gt;five.localsitemanager.localsitemaqnager.txt&lt;/a&gt;.&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Using the Gmail SMTP server to send emails from Plone]]></title><description><![CDATA[Need to test emails on a local test instance, or just too lazy to set up
your own mail server? Just use Google’s smtp server! It is possible…]]></description><link>https://opkode.com/blog/using-the-gmail-smtp-server-to-send-emails-from-plone/</link><guid isPermaLink="false">https://opkode.com/blog/using-the-gmail-smtp-server-to-send-emails-from-plone/</guid><pubDate>Mon, 04 Jan 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Need to test emails on a local test instance, or just too lazy to set up
your own mail server? Just use Google’s smtp server!&lt;/p&gt;
&lt;p&gt;It is possible to use Gmail’s smtp server to send emails from your
&lt;a href=&quot;http://plone.org&quot;&gt;Plone&lt;/a&gt; site. It’s very simple and I’ll show you how.&lt;/p&gt;
&lt;p&gt;You’ll of course need a Gmail account, get one &lt;a href=&quot;http://mail.google.com/mail/signup&quot;&gt;here&lt;/a&gt;.&lt;/p&gt;
&lt;h1&gt;Setup&lt;/h1&gt;
&lt;p&gt;In your Plone site, log in as the administrator, then go to ‘Site
Setup’ and then ‘Mail’.&lt;/p&gt;
&lt;p&gt;Now in the form, give the following values:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;strong&gt;SMTP server:&lt;/strong&gt; smtp.gmail.com&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;SMTP port:&lt;/strong&gt; 587&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESMTP username:&lt;/strong&gt; Here you give your gmail email address, i.e
&lt;a href=&quot;mailto:john@gmail.com&quot;&gt;john@gmail.com&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;ESMTP password:&lt;/strong&gt; Give your gmail account password.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Site ‘From’ name:&lt;/strong&gt; Use the default or whatever you prefer.&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;Site ‘From’ address:&lt;/strong&gt; This is the reply-to address on the
email. For users it would seem as if the email was sent from this
address. It’s important that this address belongs to a user in the
site, since it’s also the address to which emails will be sent when
users contact the administrator via the ‘contact’ form.&lt;/li&gt;
&lt;/ul&gt;
&lt;h1&gt;Troubleshooting:&lt;/h1&gt;
&lt;ul&gt;
&lt;li&gt;Make sure TLS is enabled. This dіdn’t work for me until I went to
the ZMI (Site Setup &gt; Zope Management interface), clicked on
MailHost and uncheck the ’&lt;strong&gt;Disable TLS&lt;/strong&gt;’ checkbox (the last
option).&lt;/li&gt;
&lt;li&gt;Also, make sure that your Python instance is compiled with SSL
support.&lt;/li&gt;
&lt;li&gt;Make sure that IMAP support is enabled for your Gmail account. When
in Gmail, click on the ‘settings’ link at the top right, then the
‘Forwarding and POP/IMAP’ link and enable IMAP access.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Now, in your Plone site, click on the ‘contact’ link in your site and
send yourself a congratulatory email!&lt;/p&gt;</content:encoded></item><item><title><![CDATA[Compiling Python with Readline support on Ubuntu Linux]]></title><description><![CDATA[Compiling Python on Ubuntu is often necessary for development purposes
and for specific versions. Here I’ll show you in a few easy steps how…]]></description><link>https://opkode.com/blog/compiling-python-with-readline-support-on-ubuntu-linux/</link><guid isPermaLink="false">https://opkode.com/blog/compiling-python-with-readline-support-on-ubuntu-linux/</guid><pubDate>Fri, 01 Jan 2010 00:00:00 GMT</pubDate><content:encoded>&lt;p&gt;Compiling Python on Ubuntu is often necessary for development purposes
and for specific versions. Here I’ll show you in a few easy steps how
to install your own Python instance into a folder in your home
directory.&lt;/p&gt;
&lt;p&gt;There are various advantages to compiling your own Python version,
instead of using the system’s installed version.&lt;/p&gt;
&lt;p&gt;Portability is one of them. By having a python instance in my home
folder, I can easily install different versions of Ubuntu and just copy
over the python files, thereby immediately and easily setting up my
previous python environment.&lt;/p&gt;
&lt;p&gt;Additionally, Zope versions prior to 2.12 require Python 2.4, which is
not available on newer versions of Ubuntu.&lt;/p&gt;
&lt;p&gt;Unfortunately, Readline support (i.e provides nifty things like the
ability to see your command history via the up arrow) is not enabled by
default when compiling your own custom python in Ubuntu. To be able to
compile python and enable readline support, we&lt;/p&gt;
&lt;p&gt;need to install some additional libraries.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jc@ubuntu:~$ &lt;span class=&quot;token function&quot;&gt;sudo&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;aptitude&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt; build-essential libreadline5-dev&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Now it’s time to download and extract the version of Python you would
like to install.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;jc@ubuntu&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:~$ &lt;span class=&quot;token function&quot;&gt;mkdir&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-p&lt;/span&gt; ~/src/python &lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;jc@ubuntu&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:~$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; ~/src/python/
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;jc@ubuntu&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:~/src/python$ &lt;span class=&quot;token function&quot;&gt;wget&lt;/span&gt; http://www.python.org/ftp/python/2.4.4/Python-2.4.4.tar.bz2
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;jc@ubuntu&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:~/src/python$ &lt;span class=&quot;token function&quot;&gt;tar&lt;/span&gt; xjf Python-2.4.4.tar.bz2
&lt;span class=&quot;token operator&quot;&gt;&amp;lt;&lt;/span&gt;jc@ubuntu&lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt;:~/src/python$ &lt;span class=&quot;token builtin class-name&quot;&gt;cd&lt;/span&gt; Python-2.4.4/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;We need to enable readline support by modifying the Setup.dist file. The
following one-liner will do the trick:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jc@ubuntu:~/src/python/Python-2.4.4$ &lt;span class=&quot;token function&quot;&gt;sed&lt;/span&gt; &lt;span class=&quot;token string&quot;&gt;&apos;s/#readline/readline/&apos;&lt;/span&gt; Modules/Setup.dist &lt;span class=&quot;token operator&quot;&gt;&gt;&lt;/span&gt; TMPFILE &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;mv&lt;/span&gt; TMPFILE Modules/Setup.dist&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Next comes cmmi (configure, make, make install). I like to install
Python in my home directory and would recommend it to anyone else. Hence
the &lt;code class=&quot;language-text&quot;&gt;--prefix&lt;/code&gt; argument.&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jc@ubuntu:~/src/python/Python-2.4.4$ ./configure &lt;span class=&quot;token parameter variable&quot;&gt;--prefix&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;/home/jc/python/python-2.4.4/ &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;token operator&quot;&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;make&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;install&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;Lastly, I make a sym-link to the new binary to make sure it’s in my execution PATH:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jc@ubuntu-12:59:~/$ &lt;span class=&quot;token function&quot;&gt;ln&lt;/span&gt; &lt;span class=&quot;token parameter variable&quot;&gt;-s&lt;/span&gt; /home/jc/python/python2.4/bin/python2.4 ~/bin/&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;You should now be able to call the python interpreter from the command line:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;jc@ubuntu-13:01:~/bin$ python2.4
Python &lt;span class=&quot;token number&quot;&gt;2.4&lt;/span&gt;.6 &lt;span class=&quot;token punctuation&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;token comment&quot;&gt;#2, Aug 19 2009, 17:13:56)&lt;/span&gt;
&lt;span class=&quot;token punctuation&quot;&gt;[&lt;/span&gt;GCC &lt;span class=&quot;token number&quot;&gt;4.3&lt;/span&gt;.2&lt;span class=&quot;token punctuation&quot;&gt;]&lt;/span&gt; on linux2 Type &lt;span class=&quot;token string&quot;&gt;&quot;help&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;copyright&quot;&lt;/span&gt;, &lt;span class=&quot;token string&quot;&gt;&quot;credits&quot;&lt;/span&gt; or &lt;span class=&quot;token string&quot;&gt;&quot;license&quot;&lt;/span&gt; &lt;span class=&quot;token keyword&quot;&gt;for&lt;/span&gt; &lt;span class=&quot;token function&quot;&gt;more&lt;/span&gt; information.&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;If you receive a &lt;code class=&quot;language-text&quot;&gt;command not found&lt;/code&gt; error, make sure that your &lt;code class=&quot;language-text&quot;&gt;~/bin&lt;/code&gt; directory is in your PATH by editing your .bashrc file (note the leading &lt;code class=&quot;language-text&quot;&gt;.&lt;/code&gt;).
For example, in my .bashrc file, I have the following PATH declaration:&lt;/p&gt;
&lt;div class=&quot;gatsby-highlight&quot; data-language=&quot;bash&quot;&gt;&lt;pre class=&quot;language-bash&quot;&gt;&lt;code class=&quot;language-bash&quot;&gt;&lt;span class=&quot;token assign-left variable&quot;&gt;&lt;span class=&quot;token environment constant&quot;&gt;PATH&lt;/span&gt;&lt;/span&gt;&lt;span class=&quot;token operator&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;token environment constant&quot;&gt;$PATH&lt;/span&gt;:/home/jc/bin&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;
&lt;p&gt;That’s it! Best of luck with your new python install.&lt;/p&gt;</content:encoded></item></channel></rss>