Open Sourcing Espera for Android

Today I'm open sourcing one of my few closed source projects: Espera for Android

Espera for Android is the Android remote control for the already open source Espera media player.

The reason for open sourcing it is simple: It didn't make me any money (read: $0)

There is no point in keeping an application that doesn't have a viable business model closed source, so I'm opening it up for public contributions and in the next few days, I'm even making the existing premium features free.

Espera for Android is written with Xamarin for Android, Reactive Extensions, ReactiveUI and Akavache, so I hope it helps people who want to learn writing apps with these libraries.

Please note that this is my first Xamarin/Android application, so it may or may not follow the best practices of the Android platform.

Matching pairs in two observable sequences

For one of my projects that makes heavy use of Reactive Extensions, I needed to pair equal values in two observable sequences.

An example:

var sequence1 = new[]{3, 1, 4, 2}.ToObservable();
var sequence2 = new[]{1, 2, 3, 4}.ToObservable();

var result = sequence1.MatchPair(sequence2).Subscribe(x => Console.WriteLine("{0} {1}", x.Left, x.Right));

This should print

1 1
3 3
2 2
4 4

The distinction between the left and right element must be made, as I want this to work on any class and base the equality on a key selector.

My end result looked was this (you can also find this code here):

public static IObservable<Pair<T>> MatchPair<T, TKey>(this IObservable<T> left, IObservable<T> right, Func<T, TKey> keySelector)
{
    return Observable.Create<Pair<T>>(o =>
    {
        var leftCache = new List<T>();
        var rightCache = new List<T>();
        var gate = new object();
        var disposable = new CompositeDisposable();
        bool leftDone = false;
        bool rightDone = false;

        left.Subscribe(l =>
        {
            lock (gate)
            {
                // Look for the last element, as we want FIFO
                int lastIndex = rightCache.FindLastIndex(x => EqualityComparer<TKey>.Default.Equals(keySelector(x), keySelector(l)));

                if (lastIndex > -1)
                {
                    T element = rightCache[lastIndex];
                    rightCache.RemoveAt(lastIndex);

                    o.OnNext(new Pair<T>(l, element));
                }

                else
                {
                    leftCache.Add(l);
                }
            }
        }, ex =>
        {
            o.OnError(ex);
            disposable.Dispose();
        }, () =>
        {
            lock (gate)
            {
                leftDone = true;

                if (rightDone)
                {
                    o.OnCompleted();
                }
            }
        }).DisposeWith(disposable);

        right.Subscribe(r =>
        {
            lock (gate)
            {
                // Look for the last element, as we want FIFO
                int lastIndex = leftCache.FindLastIndex(x => EqualityComparer<TKey>.Default.Equals(keySelector(x), keySelector(r)));

                if (lastIndex > -1)
                {
                    T element = leftCache[lastIndex];
                    leftCache.RemoveAt(lastIndex);

                    o.OnNext(new Pair<T>(element, r));
                }

                else
                {
                    rightCache.Add(r);
                }
            }
        }, ex =>
        {
            o.OnError(ex);
            disposable.Dispose();
        }, () =>
        {
            lock (gate)
            {
                rightDone = true;

                if (leftDone)
                {
                    o.OnCompleted();
                }
            }
        }).DisposeWith(disposable);

        return disposable;
    });
}

In addition we need the Pair structure that stores the left and right value

public struct Pair<T>
{
    public Pair(T left, T right)
        : this()
    {
        this.Left = left;
        this.Right = right;
    }

    public T Left { get; private set; }

    public T Right { get; private set; }
}

and a small helper method for the CompositeDisposable class (Alternatively you can wrap the subscribe methods in a disposable.Add)

public static T DisposeWith<T>(this T disposable, CompositeDisposable with) where T : class, IDisposable
{
    if(disposable == null)
        throw new ArgumentNullException("disposable");

    if(with == null)
        throw new ArgumentNullException("with");

    with.Add(disposable);

    return disposable;
}

Azure rejects my credit card

Recently, I wanted to give Microsoft Azure a try. Since I'm already registered with Amazon AWS and Google Cloud, a registration with Azure should work too, right?

So I registered with my email address and password, entered my credit card information and pressed the register button.

We can't authorize the payment method. Please make sure the information is correct, or use another payment method. If you continue to get this message, please contact your financial institution.

Wat.

I'm 99.99% sure that I've entered everything correctly and tried it again. Nope, still doesn't work.

After a few days of back and forth with the Azure support, they told me the problem is that my credit card is a Prepaid card. Since I'm from Austria and really only need my credit card for buying small things on the internet, I don't have a different card.

The support also told me:

...the reason why we do not accept the prepaid card is because in past we have seen the subscriptions being disabled due to insufficient funds in the prepaid card.

While I can understand the reasoning behind this, I wonder why AWS and Google Cloud accept my credit card.

Well, seems like no Azure for me.

Link Github issues with Javascript

Here is a quick code snippet that I used in the new Mahapps.Metro News page to link Github issue numbers to their corresponding URL:

$(function() {
  $(".yourclass").each(function(element) {
    var replaced = $(this).html().replace(/(#([0-9]+))/g, '<a href="https://github.com/<your-repo-here>/issues/$2">$1</a>');
    $(this).html(replaced);
  });
})

Since we're keeping our release notes in our repository and just copy paste it into the Github releases section, this is a neat way to avoid linking each issue manually.

Better open source collaboration with Gitter

With Mahapps.Metro we've always had the problem that discussing new plans with the core team and the contributors, or questions from the users didn't really work over Github issues. The core team communicated over Skype and we also had an open IRC channel, which was really cumbersome since IRC doesn't preserve the chat history without everyone installing a bot that logs the history on their own server.

Today I discovered Gitter, a fancy new service that allows people to create chatrooms for projects on Github.

They're currently invite only (meaning only people with invites can create chatrooms but people without invites can join them), but after asking I almost immediately got an invite and created the MahApps.Metro chatroom

Gitter has an awesome Github integration, there's a configurable activity log on the right side of the chat where recent issues, pull requests, commits, etc are displayed. The chat also supports auto-linking of issues, code snippets and Markdown support.

After only a few hours, I've got most of our current contributors to switch from IRC to Gitter and what should I say, it's been an awesome experience.

The team of Gitter responds insanely fast to questions on Twitter and you can also drop in on the GitterHQ chatroom and ask them questions directly (they even changed that you don't need to be the owner of an organization, but only require push access in order to create a chatroom for a organization repository after I asked them if it was possible)

The bad parts

I don't have much to write here.

Gitter requires write access to your Github account, this is a limitation of the Github API, they have it described here and here

This isn't too much of a problem for me.

Update: Github has since updated their access permission model and Gitter doesn't require write access anymore

Conclusion

Gitter is an awesome piece of work and I believe it will simplify the collaboration on the projects I'm working on.

The only thing that's currently missing for me is an Android app, but from their website it seems that this is in work.