Report on the Dusseldorf XMPP sprint

| categories: xmpp, sprint, dusseldorf

Recently we held another XMPP sprint, this time in Dusseldorf at the Chaosdorf clubhouse.

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 XEP-369 MIX in clients and servers.

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.


XEP-0283 <moved/> (pep., Ge0rG)

XEP-0283 provides a mechanism for informing your contacts that you're changed your account and now have a new JID.

pep. and Ge0rG had a discussion on how to automate the operation entirely.

Currently the security considerations contain a clause which to them defeats the point of the XEP:

"In order to prevent other users from maliciously altering contacts the client SHOULD NOT automatically subscribe to a <moved/> JID when it receives an unsubscribe and SHOULD NOT automatically unsubscribe to a <moved/> JID when it receives a subscribe."

Also the XEP uses presence stanza only, which makes the whole operation rather ephemeral.

The plan is to change the XEP to use PEP mostly.

Programming, documentation and various other tasks

iNPUTmice added two new tests to the compliance tester, one for MUC Avatars and a check for CORS Headers on HTTP Upload, which is especially important for webchat clients like Converse.

He also tried to fix a bug in Conversations that happens intermittently on Android 9.

MattJ worked on the 0.11 release of Prosody. He also worked on adding support for CORS in mod_http_upload.

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.

Link Mauve worked on implementing Jingle in Converse, fixing bugs and updating strophe.jingle.js to not use jQuery. As part of this, he and I looked at better exception handling in Converse.

He also helped pep. and syndace with the slixmpp plugin interface and spent some time trying to deploy JSXC.

Roel worked on the article on how to configure a modern XMPP server. 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.

Roel and rtq3 also worked on a Spanish translation of the article.

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.

Andy joined us on Sunday and participated in discussions around the PR and OMEMO in general with iNPUTmice, pep and Syndace.

Haeckse showed us a demo of Chatty, the chat (and SMS) client that she is working on for the upcoming Purism phone.

I worked on adding support for XEP-0156 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 #1340.

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).



Much thanks to Chaosdorf, for generously making their clubhouse available for the sprint.

Kuro even made some chilli for lunch and baked a cake!

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.

I had proper Ramen for the first time on Sunday night and on Saturday we had some great sushi.

Future sprints

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.

Much of what makes sprints valuable is the social aspect of making friends and working together on something you all care about.

One way to judge the success of the sprint, is to consider how excited the participants are about organising and attending future sprints.

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.

Link Mauve indicated that he'd like to organize a sprint in Paris in 2019 and pep. thinks we should go to Sweden.

During our sprint we also found out that the Berlin XMPP Meetup group is considering organizing a sprint there soon.

Then there's also the upcoming 35C3, where there will be an XMPP assembly and the opportunity to hack together.

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.

Come chat with us

We hang out in the XMPP-Sprint groupchat and this is also where upcoming XMPP sprints will be discussed and planned.

You can visit the webchat at or click on to open it in an installed client.


Dusseldorf XMPP Sprint, 16 and 17 January 2018

Converse 4 released

| categories: xmpp, converse, omemo, community

After more than 7 months of active development, Converse 4 has finally been released.

Converse is an open source XMPP-based chat client written in JavaScript and which runs in your browser.

This release contains lots of highlights, including rewriting the UI to use Bootstrap 4, support for OMEMO Encryption of private messages, message corrections and file-sharing via HTTP file upload.

XMPP is an IETF standardized messaging and presence protocol with multiple independent server and client implementations.

Unlike other popular open source teamchat applications like Mattermost and, Converse doesn't depend on any particular server (e.g. backend) application. Any XMPP server which supports the relevant extensions (aka XEPs) will do.

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.

XMPP's killer feature

Picture of the USS Enterprise, defending the federation, I think... I'm not really a trekkie

XMPP allows for something called federation. Even if you've never heard the word being used in this context, you already know what it means if you've used email.

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.

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).

Federation is getting quite a lot of renewed attention lately, in large part due to the hype around the federated social networking site Mastodon which is based on the recently published ActivityPub standard.

You're not forced to federate when running an XMPP server for your organisation, friends or family, and sometimes it makes sense not to.

However it's in my opinion the killer feature of XMPP and one of the main reasons why I'm working on Converse.

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.

It's also something which the open source Slack-alikes like Mattermost and don't have.

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.

XMPP and federation can make this a reality.

In a world of federated chat apps, some people will use a commandline client like Poezio, a desktop client like Dino or a mobile client like Conversations (or a combination of all three).

There will also be a growing need for web-based chat clients, and that's were Converse comes in.

Federation not only provides choice between chat clients, it can also foster inter-departmental or inter-organisational communication.

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.

The same of course applies to large enterprises.

A decentralized and federation communications protocol can play a large role here, and I'm not just talking about chat apps.

The Salut à Toi project has shown how you can create a decentralized and federated issue tracker, while Movim has blogging and microblogging capabilities, all based on XMPP.

Converse's history

Converse was originally developed at as part of a web-based intranet for the Star Alliance airline group.

Back then it was developed as a Gtalk-like popover chat, like you still see on LinkedIn.

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.

A powerful plugin architecture and API was added, which allows you to add or remove features and change just about any behaviour.

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.

Full-page teamchat apps like Slack also became spectacularly successful.

I subsequently updated Converse to have different "view modes", which enable you to use it in different ways, depending on your needs.

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.

There is the "overlay" mode, which matches the original UX design:

A screenshot of Converse with overlayed chatboxes

A screenshot of Converse with overlayed chatboxes

Then there are the "embedded" and "mobile" modes:

A screenshot of Converse in embedded mode

A screenshot of Converse in embedded mode

A screenshot of Converse in mobile mode

A screenshot of Converse in mobile mode

And lastly there's the "fullscreen" mode, more similar in UX to teamchat applications like Slack and Discord.

A screenshot of Converse in fullpage mode

A screenshot of Converse in fullpage mode

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.

Working on Converse fulltime

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.

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.

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.

Consulting? Proprietary plugins? Hosting? Sponsorships?

I decided to first just focus on building the product, to make Converse better, and not to worry about making money just yet.

In part this is due to my bias as engineer, and being out of my comfort zone when trying to monetize something.

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.

It's the "if you build it, they will come" approach.

During this time, various people did in fact reach out to me and some of them funded further development.

I also got enough consulting and development gigs to keep the lights on and to keep me going.

Marc Laporte from Wikisuite funded many hours of work moving the UI to Bootstrap 4, and then some more.

Converse will become part of Wikisuite, together with the OpenFire XMPP server.

He gave me valuable advice on how to make a living off open source software and encouraged me to make the leap.

I also got a call from Happy Dev, 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.

Nicolas Vèrité, of Nayego funded responsiveness improvements while individuals like Christian Weiske and Rafael Munoz generously contributed funds as well.

Some people also backed me on Patreon and Liberapay.

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.

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.

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!

The archetypal nature of free software communities

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.

This has been for me one of the most magical and satisfying things about being involved in open source.

Community is archetypally feminine [1], 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.

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).

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.

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.

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.

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.

What does the future hold for Converse?

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.

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.

Message markup

Converse still doesn't support markdown-like syntax highlighting. This is a top-priority for future releases.

Voice messages

With voice messages I mean sending voice recordings, not audio streaming (although that might also come sometime).

My wife, friends and family use voice messages (via Conversations) a lot and I believe they'd be a useful addition to Converse as well.

Email notifications

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 Prosody I'm working on a potential solution.

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.

Making Converse a progressive web-app

There are various features of so-called progressive web apps which will make Converse a much better client, such as:

  • Push notifications even when Converse is not open.
  • Using IndexedDB for caching, thereby avoiding storage limitations of localStorage and sessionStorage.
  • Offline support for editing and sending messages.

Persistent login

Other webchat clients like Mattermost and can keep you constantly logged in via cookies or perhaps JWT.

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.

The Credential Management API might help here, but it's still Chrome-only and I haven't studied it enough to know whether it's a solution.

Another approach is to allow Converse to also use authentication cookies by adding support for them to XMPP servers.

Matthew Wild has already added support for cookie authentication to Prosody but more work needs to be done to get this working on

OAuth-based login

Converse already supports OAuth-based login, but it's not yet deployed to and more work can be done to fetch and show your user profile from the OAuth provider.

Let's build this together

There are many more features and improvements planned, too many to list here.

The health and sustainability of this project depends in large part on its community of users and contributors.

The community is invaluable in finding bugs, making feature suggestions and doing quality control that would otherwise not be possible given the circumstances.

Another important requirement for the long-term health and viability of the project is funding.

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. Patreon), funded feature requests or by using my services as an XMPP and Converse consultant and developer.

Another option is allowing an employee to spend some of their paid time on helping the project with bugfixes and other contributions.

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.

I also intend to soon start offering hosted solutions for organisations who want to use Converse as their preferred teamchat solution.

Please reach out to me here if you're interested.



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.

Recommended reading, if you're interested:

Disabling Disqus comments on my blog

| categories: disqus, comments

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.

Advertising has its time and place. Being informed of a useful product or service can be valuable.

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.

Adam Curtis' documentary "Century of the Self" brilliantly lays out the development of marketing as a tool of mass manipulation.

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.

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.

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.

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.

Eventually I'd like to create a comments plugin with Converse.js and based on XMPP and use that on this site.

2018 Gulaschprogrammiernacht and organizing sprints for XMPP

| categories: xmpp, converse, foss, omemo, plone

Recently I attended the Gulaschprogrammiernacht for the first time.

It's a hacker/maker event in the Zentrum für Kunst und Medien (Centre for Arts and Media) in Karlsruhe, Germany.

AFAIK it's organized by the local chapter of the infamous Chaos Computer Club.

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.

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.

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 Dino XMPP client also attended and hung out with us for a while and there was someone working on writing an XMPP connector for Empathy in C++.

XMPP hackers at Gulaschprogrammiernacht

Maxime worked on adding OMEMO support, to Poezio, and Daniel provided us with know-how and moral support. Daniel worked mainly on the Conversations Push Proxy.

We had some discussions around the value of holding regular sprints and I told them about my experience with sprints in the Plone community.

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 Commons-based peer production.

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.

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.

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.

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.

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.

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.

Maxime was particularly excited by our discussion and very quickly put word into action by planning and announcing an XMPP sprint in Cambridge, UK in August.

There's still time to vote on the date of the sprint and to suggest topics.

Hopefully this will be first of many more sprints and communit events.

Unmanned laptops at the Gulaschprogrammiernacht

Slack's bait and switch

| categories: xmpp, converse, foss, slack

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.

Here's the gist of their announcement:

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.

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.

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 <thread> element in the message stanza, as documented in XEP-201.

And emoji... there's nothing in XMPP that prevents people from sending emoji.


UPDATE: Several readers have pointed out that "emoji reactions" and emoji are different things. Emoji reactions can be tacked to a particular message.

Still, there's nothing fundamental about XMPP that prevents emoji reactions, and work is currently underway to add support for them.

The protocol is designed to be eXtensible (hence the X in XMPP) and new features are continuously being added.

Classic bait and switch

We all know the real reason Slack has closed off their gateways. Their business model dictates that they should.

Slack's business model is to record everything said in a workspace and then to sell you access to their record of your conversations.

They're a typical walled garden, information silo or Siren Server

So they have to close everything off, to make sure that people can't extract their conversations out of the silo.

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.

Facebook, who also built their chat app on XMPP at first allowed 3rd party XMPP clients to connect and then later dropped interoperability.

Twitter, although not using or supporting XMPP, had a vibrant 3rd party client ecosystem which they killed off once they felt big enough.

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.

On Federation

When we talk about "federation" in networks, we mean the ability to communicate between different service providers.

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.

You can email any other email address in the world, regardless of where that email address is hosted.

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 digimail, do you think they would standardise the digimail protocol and allow you to send messages to other digimail purveyors?

We all know the answer to that. They won't, and neither would Google, Microsoft or Facebook.

Heck, Facebook is actively trying to replace email since years.

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.

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.

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.

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.

What would it take for XMPP to take off?

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).

In so doing, they have closed off their discussions from search engines and they prevent people from accessing their past archives.

Slack has many cool features, and they work very well, I'm not going to deny it.

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:

Unfortunately XMPP clients have been lagging far behind in various respects.

One of the main problems is funding. The modern digital economy is largely set up around surveillance capitalism and user lock-in.

So attempts to create software that doesn't follow these precepts, often end up unfunded or underfunded.

However, our "weakness", is also our strength.

XMPP clients, and the XMPP network can provide something that Slack never can. Federation, free and open software, interoperability, extensibility and user choice.


For the last few years I've been working in my spare time on making a JavaScript XMPP chat client, called Converse.

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.

A screenshot of Converse as overlayed chatboxes

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.

You can try the fullscreen version at

A screenshot of Converse as a fullscreen application

If you have no-one to chat to, then come join the chat room.

This link will take you directly there (via

Converse still lacks lots of features that Slack has, but that's not because XMPP itself can't support those features.

What Converse however does 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.

We're actively working on adding new features and more and more people are joining in.

Moreover, anybody can host it and you can integrate it into any website.

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.

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.


Hacker News discussion

This blog post triggered a lively discussion on Hacker news, you can read that here:

Next Page »