if (typeof window.FirebaseMixin == 'undefined') {
  window.FirebaseMixin = superclass => {
    if (!superclass) {
      superclass = class Superclass {};
    }

    return class extends superclass {
      constructor() {
        super();
        this.__firebaseMixinInit();
      }

      __firebaseMixinInit() {
        this.__modelsToLoad = 0;
        this.__watchSubjects = [];
      }

      noop() {}

      watchModel({ ref, property }) {
        const model = this;
        const subject = new Rx.Subject();
        const handler = ref.on('value', snap => {
          this[property] = snap.val();
          subject.next({ model: this, property });
        });
        const subscription = subject.filter(res => !res.ready).subscribe(res => {
          this.__modelsToLoad--;
          if (this.__modelsToLoad == 0) {
            subscription.unsubscribe();
            setTimeout(() => {
              subject.next({ model, ready: true });
            });
          }
        });

        subject.subscribe(this.noop, this.noop, () => ref.off('value', handler));

        this.__modelsToLoad++;
        this.__watchSubjects.push(subject);

        return subject;
      }

      unwatchModels() {
        this.__watchSubjects.forEach(subject => subject.complete());
        this.__firebaseMixinInit();
      }

      toArray(obj) {
        const result = [];
        for (let key in obj) {
          let value = obj[key];
          value.__key = key;
          result.push(value);
        }
        return result;
      }
    };
  };
}