<commit_before>'use strict';

const constant = require('lodash/constant');
const assert = require('assert');
const Bacon = require('baconjs');
const Rx = require('rx');
const Kefir = require('kefir');
const kefirBus = require('kefir-bus');

const baconCast = require('..');

function testStreamForOneValue(stream, value, callback) {
  var s = baconCast(Bacon, stream);
  var values = 0;
  s.onValue(function(x) {
    assert.strictEqual(x, value);
    values++;
  });
  s.onEnd(function() {
    assert.strictEqual(values, 1);
    callback();
  });
}

function shouldNotBeCalled() {
  throw new Error("Should not be called");
}

describe('baconCast', function() {
  describe('Bacon', function() {
    it('supports basic stream', function(done) {
      testStreamForOneValue(Bacon.later(0, shouldNotBeCalled), shouldNotBeCalled, done);
    });

    it('handles unsubscription', function(done) {
      var calls = 0;
      var s = baconCast(Bacon, Bacon.fromPoll(0, function() {
        if (++calls === 1) {
          return 'beep';
        } else {
          throw new Error("Should not happen");
        }
      }));
      s.take(1).onEnd(done);
    });

    it('supports all event types', function(done) {
      var s = baconCast(Bacon, Bacon.mergeAll(
        Bacon.once('beep'),
        Bacon.once(new Bacon.Error('bad')),
        Bacon.once(shouldNotBeCalled)
      ).toProperty('prop'));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Initial);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('works on mock stream object', function(done) {
      var unsubbed = 0;
      var s = baconCast(Bacon, {
        onValue: true,
        subscribe: function(sink) {
          sink({
            isInitial: constant(true), isNext: constant(false),
            isError: constant(false), isEnd: constant(false),
            value: constant('prop')
          });
          sink({
            isInitial: constant(false), isNext: constant(true),
            isError: constant(false), isEnd: constant(false),
            value: constant('beep')
          });
          setTimeout(function() {
            sink({
              isInitial: constant(false), isNext: constant(false),
              isError: constant(true), isEnd: constant(false),
              error: 'bad'
            });
            sink({
              isInitial: constant(false), isNext: constant(true),
              isError: constant(false), isEnd: constant(false),
              value: constant(shouldNotBeCalled)
            });
            sink({
              isInitial: constant(false), isNext: constant(false),
              isError: constant(false), isEnd: constant(true)
            });
            sink({
              isInitial: constant(false), isNext: constant(true),
              isError: constant(false), isEnd: constant(false),
              value: function() {
                throw new Error("Post-end event should not be evaluated");
              }
            });
          }, 0);

          return function() {
            unsubbed++;
          };
        }
      });

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Initial);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            assert.strictEqual(unsubbed, 1);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var bus = new Bacon.Bus();

      var s = baconCast(Bacon, bus);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      bus.push(1);
      bus.push(2);
      bus.end();
    });
  });

  describe('RxJS', function() {
    it('supports basic observable', function(done) {
      var s = baconCast(Bacon, Rx.Observable.from([
        'beep',
        shouldNotBeCalled
      ]));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('supports observable with error', function(done) {
      var err = new Error('some err');
      var s = baconCast(Bacon, Rx.Observable.from([
        'beep',
        shouldNotBeCalled
      ]).concat(Rx.Observable.throw(err)));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, err);
            break;
          case 4:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var subject = new Rx.Subject();

      var s = baconCast(Bacon, subject);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      subject.onNext(1);
      subject.onNext(2);
      subject.onCompleted();
    });
  });

  describe('RxJS 5', function() {
    // Shadow this name to let us know if we accidentally use Rx 4 in this test.
    const Rx = null; // eslint-disable-line no-unused-vars

    const {from} = require('@reactivex/rxjs/dist/package/observable/from');
    const {map} = require('@reactivex/rxjs/dist/package/operators/map');
    const {interval} = require('@reactivex/rxjs/dist/package/observable/interval');
    const {concat} = require('@reactivex/rxjs/dist/package/observable/concat');
    const {_throw} = require('@reactivex/rxjs/dist/package/observable/throw');
    const {Subject} = require('@reactivex/rxjs/dist/package/Subject');

    it('supports basic observable', function(done) {
      const s = baconCast(Bacon, from([
        'beep',
        shouldNotBeCalled
      ]));

      let calls = 0;
      s.subscribe(event => {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('supports observable with error', function(done) {
      const err = new Error('some err');
      const s = baconCast(Bacon, concat(from([
        'beep',
        shouldNotBeCalled
      ]), _throw(err)));

      let calls = 0;
      s.subscribe(event => {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, err);
            break;
          case 4:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      const subject = new Subject();

      const s = baconCast(Bacon, subject);

      let calls1 = 0, calls2 = 0;
      s.take(1).subscribe(event => {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      subject.next(1);
      subject.next(2);
      subject.complete();
    });
  });

  describe('Kefir', function() {
    it('supports basic stream', function(done) {
      testStreamForOneValue(Kefir.later(0, shouldNotBeCalled), shouldNotBeCalled, done);
    });

    it('handles unsubscription', function(done) {
      var calls = 0;
      var s = baconCast(Bacon, Kefir.fromPoll(0, function() {
        if (++calls === 1) {
          return 'beep';
        } else {
          throw new Error("Should not happen");
        }
      }));
      s.take(1).onEnd(done);
    });

    it('supports all event types', function(done) {
      var s = baconCast(Bacon, Kefir.merge([
        Kefir.later(0, 'beep'),
        Kefir.later(1, 'bad').flatMap(Kefir.constantError),
        Kefir.later(2, shouldNotBeCalled)
      ]).toProperty(constant('prop')));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var bus = new kefirBus();

      var s = baconCast(Bacon, bus);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      bus.emit(1);
      bus.emit(2);
      bus.end();
    });
  });

  describe('Constant', function() {
    it('transforms non-streams to single-item streams', function(done) {
      var value = {a: 5};
      testStreamForOneValue(value, value, done);
    });
  });
});
<commit_msg>Make test less timing sensitive.<commit_after>'use strict';

const constant = require('lodash/constant');
const assert = require('assert');
const Bacon = require('baconjs');
const Rx = require('rx');
const Kefir = require('kefir');
const kefirBus = require('kefir-bus');

const baconCast = require('..');

function testStreamForOneValue(stream, value, callback) {
  var s = baconCast(Bacon, stream);
  var values = 0;
  s.onValue(function(x) {
    assert.strictEqual(x, value);
    values++;
  });
  s.onEnd(function() {
    assert.strictEqual(values, 1);
    callback();
  });
}

function shouldNotBeCalled() {
  throw new Error("Should not be called");
}

describe('baconCast', function() {
  describe('Bacon', function() {
    it('supports basic stream', function(done) {
      testStreamForOneValue(Bacon.later(0, shouldNotBeCalled), shouldNotBeCalled, done);
    });

    it('handles unsubscription', function(done) {
      var calls = 0;
      var s = baconCast(Bacon, Bacon.fromPoll(0, function() {
        if (++calls === 1) {
          return 'beep';
        } else {
          throw new Error("Should not happen");
        }
      }));
      s.take(1).onEnd(done);
    });

    it('supports all event types', function(done) {
      var s = baconCast(Bacon, Bacon.mergeAll(
        Bacon.once('beep'),
        Bacon.once(new Bacon.Error('bad')),
        Bacon.once(shouldNotBeCalled)
      ).toProperty('prop'));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Initial);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('works on mock stream object', function(done) {
      var unsubbed = 0;
      var s = baconCast(Bacon, {
        onValue: true,
        subscribe: function(sink) {
          sink({
            isInitial: constant(true), isNext: constant(false),
            isError: constant(false), isEnd: constant(false),
            value: constant('prop')
          });
          sink({
            isInitial: constant(false), isNext: constant(true),
            isError: constant(false), isEnd: constant(false),
            value: constant('beep')
          });
          setTimeout(function() {
            sink({
              isInitial: constant(false), isNext: constant(false),
              isError: constant(true), isEnd: constant(false),
              error: 'bad'
            });
            sink({
              isInitial: constant(false), isNext: constant(true),
              isError: constant(false), isEnd: constant(false),
              value: constant(shouldNotBeCalled)
            });
            sink({
              isInitial: constant(false), isNext: constant(false),
              isError: constant(false), isEnd: constant(true)
            });
            sink({
              isInitial: constant(false), isNext: constant(true),
              isError: constant(false), isEnd: constant(false),
              value: function() {
                throw new Error("Post-end event should not be evaluated");
              }
            });
          }, 0);

          return function() {
            unsubbed++;
          };
        }
      });

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Initial);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            assert.strictEqual(unsubbed, 1);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var bus = new Bacon.Bus();

      var s = baconCast(Bacon, bus);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      bus.push(1);
      bus.push(2);
      bus.end();
    });
  });

  describe('RxJS', function() {
    it('supports basic observable', function(done) {
      var s = baconCast(Bacon, Rx.Observable.from([
        'beep',
        shouldNotBeCalled
      ]));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('supports observable with error', function(done) {
      var err = new Error('some err');
      var s = baconCast(Bacon, Rx.Observable.from([
        'beep',
        shouldNotBeCalled
      ]).concat(Rx.Observable.throw(err)));

      var calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, err);
            break;
          case 4:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var subject = new Rx.Subject();

      var s = baconCast(Bacon, subject);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      subject.onNext(1);
      subject.onNext(2);
      subject.onCompleted();
    });
  });

  describe('RxJS 5', function() {
    // Shadow this name to let us know if we accidentally use Rx 4 in this test.
    const Rx = null; // eslint-disable-line no-unused-vars

    const {from} = require('@reactivex/rxjs/dist/package/observable/from');
    const {map} = require('@reactivex/rxjs/dist/package/operators/map');
    const {interval} = require('@reactivex/rxjs/dist/package/observable/interval');
    const {concat} = require('@reactivex/rxjs/dist/package/observable/concat');
    const {_throw} = require('@reactivex/rxjs/dist/package/observable/throw');
    const {Subject} = require('@reactivex/rxjs/dist/package/Subject');

    it('supports basic observable', function(done) {
      const s = baconCast(Bacon, from([
        'beep',
        shouldNotBeCalled
      ]));

      let calls = 0;
      s.subscribe(event => {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('supports observable with error', function(done) {
      const err = new Error('some err');
      const s = baconCast(Bacon, concat(from([
        'beep',
        shouldNotBeCalled
      ]), _throw(err)));

      let calls = 0;
      s.subscribe(event => {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, err);
            break;
          case 4:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      const subject = new Subject();

      const s = baconCast(Bacon, subject);

      let calls1 = 0, calls2 = 0;
      s.take(1).subscribe(event => {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      subject.next(1);
      subject.next(2);
      subject.complete();
    });
  });

  describe('Kefir', function() {
    it('supports basic stream', function(done) {
      testStreamForOneValue(Kefir.later(0, shouldNotBeCalled), shouldNotBeCalled, done);
    });

    it('handles unsubscription', function(done) {
      var calls = 0;
      var s = baconCast(Bacon, Kefir.fromPoll(0, function() {
        if (++calls === 1) {
          return 'beep';
        } else {
          throw new Error("Should not happen");
        }
      }));
      s.take(1).onEnd(done);
    });

    it('supports all event types', function(done) {
      this.slow(100);
      const s = baconCast(Bacon, Kefir.merge([
        Kefir.later(0, 'beep'),
        Kefir.later(20, 'bad').flatMap(Kefir.constantError),
        Kefir.later(40, shouldNotBeCalled)
      ]).toProperty(constant('prop')));

      let calls = 0;
      s.subscribe(function(event) {
        switch(++calls) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'prop');
            break;
          case 2:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 'beep');
            break;
          case 3:
            assert(event instanceof Bacon.Error);
            assert.strictEqual(event.error, 'bad');
            break;
          case 4:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), shouldNotBeCalled);
            break;
          case 5:
            assert(event instanceof Bacon.End);
            done();
            break;
          default:
            throw new Error("Should not happen");
        }
      });
    });

    it('can listen on stream multiple times', function(done) {
      var bus = new kefirBus();

      var s = baconCast(Bacon, bus);

      var calls1 = 0, calls2 = 0;
      s.take(1).subscribe(function(event) {
        switch (++calls1) {
          case 1:
            assert(event instanceof Bacon.Next);
            assert.strictEqual(event.value(), 1);
            break;
          case 2:
            assert(event instanceof Bacon.End);

            s.subscribe(function(event) {
              switch (++calls2) {
                case 1:
                  assert(event instanceof Bacon.Next);
                  assert.strictEqual(event.value(), 2);
                  break;
                case 2:
                  assert(event instanceof Bacon.End);

                  setTimeout(function() {
                    s.subscribe(function(event) {
                      assert(event instanceof Bacon.End);
                      done();
                    });
                  }, 0);

                  break;
                default:
                  throw new Error("Should not happen");
              }
            });
            break;
          default:
            throw new Error("Should not happen");
        }
      });
      bus.emit(1);
      bus.emit(2);
      bus.end();
    });
  });

  describe('Constant', function() {
    it('transforms non-streams to single-item streams', function(done) {
      var value = {a: 5};
      testStreamForOneValue(value, value, done);
    });
  });
});
<|endoftext|>


<commit_before>var concat = require('../');
var should = require('should');
var os = require('os');
var path = require('path');
var File = require('gulp-util').File;
var Buffer = require('buffer').Buffer;
require('mocha');

describe('gulp-concat', function() {
  describe('concat()', function() {
    it('should concat two files', function(done) {
      var stream = concat("test.js");
      var fakeFile = new File({
        cwd: "/home/contra/",
        base: "/home/contra/test",
        path: "/home/contra/test/file.js",
        contents: new Buffer("wadup")
      });

      var fakeFile2 = new File({
        cwd: "/home/contra/",
        base: "/home/contra/test",
        path: "/home/contra/test/file2.js",
        contents: new Buffer("doe")
      });

      stream.on('data', function(newFile){
        should.exist(newFile);
        should.exist(newFile.path);
        should.exist(newFile.relative);
        should.exist(newFile.contents);

        var newFilePath = path.resolve(newFile.path);
        var expectedFilePath = path.resolve("/home/contra/test/test.js");
        newFilePath.should.equal(expectedFilePath);

        newFile.relative.should.equal("test.js");
        String(newFile.contents).should.equal("wadup\ndoe");
        Buffer.isBuffer(newFile.contents).should.equal(true);
        done();
      });
      stream.write(fakeFile);
      stream.write(fakeFile2);
      stream.end();
    });

    it('should concat two files by custom EOL', function(done) {
      var stream = concat("test.js", {newLine: '\r\n'});
      var fakeFile = new File({
        cwd: "/home/contra/",
        base: "/home/contra/test",
        path: "/home/contra/test/file.js",
        contents: new Buffer("wadup")
      });

      var fakeFile2 = new File({
        cwd: "/home/contra/",
        base: "/home/contra/test",
        path: "/home/contra/test/file2.js",
        contents: new Buffer("doe")
      });

      stream.on('data', function(newFile){
        should.exist(newFile);
        should.exist(newFile.path);
        should.exist(newFile.relative);
        should.exist(newFile.contents);

        var newFilePath = path.resolve(newFile.path);
        var expectedFilePath = path.resolve("/home/contra/test/test.js");
        newFilePath.should.equal(expectedFilePath);

        newFile.relative.should.equal("test.js");
        String(newFile.contents).should.equal("wadup\r\ndoe");
        Buffer.isBuffer(newFile.contents).should.equal(true);
        done();
      });
      stream.write(fakeFile);
      stream.write(fakeFile2);
      stream.end();
    });

  });
});
<commit_msg>Added empty newLine test. More files<commit_after>var concat = require('../');
var should = require('should');
var os = require('os');
var path = require('path');
var File = require('gulp-util').File;
var Buffer = require('buffer').Buffer;
require('mocha');

describe('gulp-concat', function() {
  describe('concat()', function() {

    oneFile    (concat('test.js'                   ), 'wadup', 'wadup');
    oneFile    (concat('test.js', {newLine: '\r\n'}), 'wadup', 'wadup');
    oneFile    (concat('test.js', {newLine: ''    }), 'wadup', 'wadup');

    twoFiles   (concat('test.js'                   ), 'wadup', 'doe', 'wadup\ndoe');
    twoFiles   (concat('test.js', {newLine: '\r\n'}), 'wadup', 'doe', 'wadup\r\ndoe');
    twoFiles   (concat('test.js', {newLine: ''    }), 'wadup', 'doe', 'wadupdoe');

    threeFiles (concat('test.js'                   ), 'wadup', 'doe', 'hey', 'wadup\ndoe\nhey');
    threeFiles (concat('test.js', {newLine: '\r\n'}), 'wadup', 'doe', 'hey', 'wadup\r\ndoe\r\nhey');
    threeFiles (concat('test.js', {newLine: ''    }), 'wadup', 'doe', 'hey', 'wadupdoehey');

    function oneFile(stream, contents, result) {
      it('should concat two files', function(done) {
        var fakeFile = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file1.js',
          contents: new Buffer(contents)
        });

        stream.on('data', function(newFile){
          should.exist(newFile);
          should.exist(newFile.path);
          should.exist(newFile.relative);
          should.exist(newFile.contents);

          var newFilePath = path.resolve(newFile.path);
          var expectedFilePath = path.resolve('/home/contra/test/test.js');
          newFilePath.should.equal(expectedFilePath);

          newFile.relative.should.equal('test.js');
          String(newFile.contents).should.equal(result);
          Buffer.isBuffer(newFile.contents).should.equal(true);
          done();
        });
        stream.write(fakeFile);
        stream.end();
      });
    };

    function twoFiles(stream, contents1, contents2, result) {
      it('should concat two files', function(done) {
        var fakeFile1 = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file1.js',
          contents: new Buffer(contents1)
        });

        var fakeFile2 = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file2.js',
          contents: new Buffer(contents2)
        });

        stream.on('data', function(newFile){
          should.exist(newFile);
          should.exist(newFile.path);
          should.exist(newFile.relative);
          should.exist(newFile.contents);

          var newFilePath = path.resolve(newFile.path);
          var expectedFilePath = path.resolve('/home/contra/test/test.js');
          newFilePath.should.equal(expectedFilePath);

          newFile.relative.should.equal('test.js');
          String(newFile.contents).should.equal(result);
          Buffer.isBuffer(newFile.contents).should.equal(true);
          done();
        });
        stream.write(fakeFile1);
        stream.write(fakeFile2);
        stream.end();
      });
    };

    function threeFiles(stream, contents1, contents2, contents3, result) {
      it('should concat three files', function(done) {
        var fakeFile1 = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file1.js',
          contents: new Buffer(contents1)
        });

        var fakeFile2 = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file2.js',
          contents: new Buffer(contents2)
        });

        var fakeFile3 = new File({
          cwd: '/home/contra/',
          base: '/home/contra/test',
          path: '/home/contra/test/file3.js',
          contents: new Buffer(contents3)
        });

        stream.on('data', function(newFile){
          should.exist(newFile);
          should.exist(newFile.path);
          should.exist(newFile.relative);
          should.exist(newFile.contents);

          var newFilePath = path.resolve(newFile.path);
          var expectedFilePath = path.resolve('/home/contra/test/test.js');
          newFilePath.should.equal(expectedFilePath);

          newFile.relative.should.equal('test.js');
          String(newFile.contents).should.equal(result);
          Buffer.isBuffer(newFile.contents).should.equal(true);
          done();
        });
        stream.write(fakeFile1);
        stream.write(fakeFile2);
        stream.write(fakeFile3);
        stream.end();
      });
    };

  });
});
<|endoftext|>


<commit_before>const ava = require('ava');
const { fs, tempFileLoc, tempDirLoc, tempFile, tempDir } = require('./lib');
const nextra = require('../src');

ava('standard usage', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc();
	await nextra.move(existing, move);

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('self', async test => {
	const existing = tempFile();
	test.deepEqual(await nextra.move(existing, existing, { overwrite: true }), await fs.accessAsync(existing));
});

ava('overwrite dir with file', async test => {
	const existing = tempFile();
	const move = tempDir();
	await test.throwsAsync(nextra.move(existing, move, { overwrite: true }));
});

ava('overwrite existing file', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFile();
	await nextra.move(existing, move, { overwrite: true });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('no overwrite non-existent file', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc();
	await nextra.move(existing, move, { overwrite: false });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('no overwrite existing file', async test => {
	const existing = tempFile();
	const move = tempFile();
	await test.throwsAsync(nextra.move(existing, move, { overwrite: false }));
});

ava('deep mkdirp', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc(tempDirLoc());
	await nextra.move(existing, move, { mkdirp: true });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('deep no mkdirp', async test => {
	const existing = tempFile();
	const move = tempFileLoc(tempDirLoc());
	await test.throwsAsync(nextra.move(existing, move, { mkdirp: false }));
});
<commit_msg>more tests<commit_after>const ava = require('ava');
const { fs, tempFileLoc, tempDirLoc, tempFile, tempDir } = require('./lib');
const nextra = require('../src');

ava('standard usage', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc();
	await nextra.move(existing, move);

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('self', async test => {
	const existing = tempFile();
	test.deepEqual(await nextra.move(existing, existing, { overwrite: true }), await fs.accessAsync(existing));
});

ava('overwrite dir with file', async test => {
	const existing = tempFile();
	const move = tempDir();
	await test.throwsAsync(nextra.move(existing, move, { overwrite: true }));
});

ava('overwrite existing file', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFile();
	await nextra.move(existing, move, { overwrite: true });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('no overwrite non-existent file', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc();
	await nextra.move(existing, move, { overwrite: false });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('no overwrite existing file', async test => {
	const existing = tempFile();
	const move = tempFile();
	await test.throwsAsync(nextra.move(existing, move, { overwrite: false }));
});

ava('deep mkdirp', async test => {
	test.plan(2);
	const existing = tempFile();
	const move = tempFileLoc(tempDirLoc());
	await nextra.move(existing, move, { mkdirp: true });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('deep no mkdirp', async test => {
	const existing = tempFile();
	const move = tempFileLoc(tempDirLoc());
	await test.throwsAsync(nextra.move(existing, move, { mkdirp: false }));
});

ava('overwrite full directory', async test => {
	test.plan(2);
	const existing = tempDir();
	tempFile(existing);
	const move = tempDir();
	tempFile(move);
	await nextra.move(existing, move, { overwrite: true });

	await test.notThrowsAsync(fs.accessAsync(move));
	await test.throwsAsync(fs.accessAsync(existing));
});

ava('no overwrite full directory', async test => {
	test.plan(2);
	const existing = tempDir();
	tempFile(existing);
	const move = tempDir();
	tempFile(move);
	await test.throwsAsync(nextra.move(existing, move, { overwrite: false }));
});
<|endoftext|>


<commit_before>(function() {
    'use strict';

    var fs      = require('fs'),
        path    = require('path'),
        os      = require('os'),
        zlib    = require('zlib'),

        pipe    = require('..'),
        test    = require('tape');

    test('file1 | file2: no error', function(t) {
        var tmp     = os.tmpdir(),
            name    = path.basename(__filename),
            nameTmp = path.join(tmp, name + Math.random());

         tryPipe(__filename, nameTmp, function() {
            var file1 = fs.readFileSync(__filename, 'utf8'),
                file2 = fs.readFileSync(nameTmp, 'utf8');

            fs.unlinkSync(nameTmp);

            t.equal(file1, file2, 'files equal');
            t.end();
         });
    });

    test('file1 | file2: write open EACESS', function(t) {
        var name    = path.basename(__filename),
            nameTmp = '/' + name + Math.random();

        tryPipe(__filename, nameTmp, function(error) {
            t.ok(error, error && error.message);

            t.end();
        });
    });

    test('file1 | file2: read open ENOENT', function(t) {
        var tmp     = os.tmpdir(),
            random  = Math.random(),
            name    = path.basename(__filename),
            nameTmp = path.join(tmp, name + random);

        tryPipe(__filename + random, nameTmp, function(error) {
            t.ok(error, error && error.message);

            t.end();
        });
    });

    test('file1 | gzip | file2: no errors', function(t) {
        var tmp         = os.tmpdir(),
            random      = Math.random(),
            name        = path.basename(__filename),
            nameTmp     = path.join(tmp, name + random),

            read        = fs.createReadStream(__filename),
            write       = fs.createWriteStream(nameTmp),
            zip         = zlib.createGzip();

        pipe([read, zip, write], function(error) {
            var file1   = fs.readFileSync(__filename, 'utf8'),
                file2   = fs.readFileSync(nameTmp),
                zip     = zlib.gzipSync(file1);

            fs.unlinkSync(nameTmp);

            t.notOk(error, 'no errors');
            t.deepEqual(zip, file2, 'file gziped');
            t.end();
        });
    });

    test('file1 | gzip', function(t) {
        var read        = fs.createReadStream(__filename),
            zip         = zlib.createGzip();

        pipe([read, zip], function(error) {
            t.notOk(error, 'no errors');
            t.end();
        });
    });

    function tryPipe(from, to, fn) {
        var read    = fs.createReadStream(from),
            write   = fs.createWriteStream(to);

        pipe([read, write], function(error) {
            fn(error);
        });
    }

})();
<commit_msg>test(pipe) add file1 | gzip: error<commit_after>(function() {
    'use strict';

    var fs      = require('fs'),
        path    = require('path'),
        os      = require('os'),
        zlib    = require('zlib'),

        pipe    = require('..'),
        test    = require('tape'),

        random  = Math.random();

    test('file1 | file2: no error', function(t) {
        var tmp     = os.tmpdir(),
            name    = path.basename(__filename),
            nameTmp = path.join(tmp, name + random);

         tryPipe(__filename, nameTmp, function() {
            var file1 = fs.readFileSync(__filename, 'utf8'),
                file2 = fs.readFileSync(nameTmp, 'utf8');

            fs.unlinkSync(nameTmp);

            t.equal(file1, file2, 'files equal');
            t.end();
         });
    });

    test('file1 | file2: write open EACESS', function(t) {
        var name    = path.basename(__filename),
            nameTmp = '/' + name + random;

        tryPipe(__filename, nameTmp, function(error) {
            t.ok(error, error && error.message);

            t.end();
        });
    });

    test('file1 | file2: read open ENOENT', function(t) {
        var tmp     = os.tmpdir(),
            name    = path.basename(__filename),
            nameTmp = path.join(tmp, name + random);

        tryPipe(__filename + random, nameTmp, function(error) {
            t.ok(error, error && error.message);

            t.end();
        });
    });

    test('file1 | gzip | file2: no errors', function(t) {
        var tmp         = os.tmpdir(),
            name        = path.basename(__filename),
            nameTmp     = path.join(tmp, name + random),

            read        = fs.createReadStream(__filename),
            write       = fs.createWriteStream(nameTmp),
            zip         = zlib.createGzip();

        pipe([read, zip, write], function(error) {
            var file1   = fs.readFileSync(__filename, 'utf8'),
                file2   = fs.readFileSync(nameTmp),
                zip     = zlib.gzipSync(file1);

            fs.unlinkSync(nameTmp);

            t.notOk(error, 'no errors');
            t.deepEqual(zip, file2, 'file gziped');
            t.end();
        });
    });

    test('file1 | gzip', function(t) {
        var read        = fs.createReadStream(__filename),
            zip         = zlib.createGzip();

        pipe([read, zip], function(error) {
            t.notOk(error, 'no errors');
            t.end();
        });
    });

    test('file1 | gzip: error ENOENT', function(t) {
        var read        = fs.createReadStream(__filename + random),
            zip         = zlib.createGzip();

        pipe([read, zip], function(error) {
            t.ok(error, error.message);
            t.end();
        });
    });

    function tryPipe(from, to, fn) {
        var read    = fs.createReadStream(from),
            write   = fs.createWriteStream(to);

        pipe([read, write], function(error) {
            fn(error);
        });
    }

})();
<|endoftext|>


<commit_before>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt"

wn.module_page["Selling"] = [
	{
		top: true,
		title: wn._("Documents"),
		icon: "icon-copy",
		items: [
			{
				label: wn._("Customer"),
				description: wn._("Customer database."),
				doctype:"Customer"
			},
			{
				label: wn._("Lead"),
				description: wn._("Database of potential customers."),
				doctype:"Lead"
			},
			{
				label: wn._("Opportunity"),
				description: wn._("Potential opportunities for selling."),
				doctype:"Opportunity"
			},
			{
				label: wn._("Quotation"),
				description: wn._("Quotes to Leads or Customers."),
				doctype:"Quotation"
			},
			{
				label: wn._("Sales Order"),
				description: wn._("Confirmed orders from Customers."),
				doctype:"Sales Order"
			},
		]
	},
	{
		title: wn._("Masters"),
		icon: "icon-book",
		items: [
			{
				label: wn._("Contact"),
				description: wn._("All Contacts."),
				doctype:"Contact"
			},
			{
				label: wn._("Address"),
				description: wn._("All Addresses."),
				doctype:"Address"
			},
			{
				label: wn._("Item"),
				description: wn._("All Products or Services."),
				doctype:"Item"
			},
		]
	},
	{
		title: wn._("Setup"),
		icon: "icon-cog",
		items: [
			{
				"label": wn._("Selling Settings"),
				"route": "Form/Selling Settings",
				"doctype":"Selling Settings",
				"description": wn.("Settings for Selling Module")
			},
			{
				"route":"Form/Shopping Cart Settings",
				"label":wn._("Shopping Cart Settings"),
				"description":wn._("Setup of Shopping Cart."),
				doctype:"Shopping Cart Settings"
			},
			{
				label: wn._("Sales Taxes and Charges Master"),
				description: wn._("Sales taxes template."),
				doctype:"Sales Taxes and Charges Master"
			},
			{
				label: wn._("Shipping Rules"),
				description: wn._("Rules to calculate shipping amount for a sale"),
				doctype:"Shipping Rule"
			},
			{
				label: wn._("Price List"),
				description: wn._("Mupltiple Item prices."),
				doctype:"Price List"
			},
			{
				label: wn._("Sales BOM"),
				description: wn._("Bundle items at time of sale."),
				doctype:"Sales BOM"
			},
			{
				label: wn._("Terms and Conditions"),
				description: wn._("Template of terms or contract."),
				doctype:"Terms and Conditions"
			},
			{
				label: wn._("Customer Group"),
				description: wn._("Customer classification tree."),
				route: "Sales Browser/Customer Group",
				doctype:"Customer Group"
			},
			{
				label: wn._("Territory"),
				description: wn._("Sales territories."),
				route: "Sales Browser/Territory",
				doctype:"Territory"
			},
			{
				"route":"Sales Browser/Sales Person",
				"label":wn._("Sales Person"),
				"description": wn._("Sales persons and targets"),
				doctype:"Sales Person"
			},
			{
				"route":"List/Sales Partner",
				"label": wn._("Sales Partner"),
				"description":wn._("Commission partners and targets"),
				doctype:"Sales Partner"
			},
			{
				"route":"Sales Browser/Item Group",
				"label":wn._("Item Group"),
				"description": wn._("Tree of item classification"),
				doctype:"Item Group"
			},
			{
				"route":"List/Campaign",
				"label":wn._("Campaign"),
				"description":wn._("Sales campaigns"),
				doctype:"Campaign"
			},
		]
	},
	{
		title: wn._("Tools"),
		icon: "icon-wrench",
		items: [
			{
				"route":"Form/SMS Center/SMS Center",
				"label":wn._("SMS Center"),
				"description":wn._("Send mass SMS to your contacts"),
				doctype:"SMS Center"
			},
		]
	},
	{
		title: wn._("Analytics"),
		right: true,
		icon: "icon-bar-chart",
		items: [
			{
				"label":wn._("Sales Analytics"),
				page: "sales-analytics"
			},
		]
	},
	{
		title: wn._("Reports"),
		right: true,
		icon: "icon-list",
		items: [
			{
				"label":wn._("Customer Addresses And Contacts"),
				route: "query-report/Customer Addresses And Contacts",
				doctype: "Contact"
			},
			{
				"label":wn._("Ordered Items To Be Delivered"),
				route: "query-report/Ordered Items To Be Delivered",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Sales Person-wise Transaction Summary"),
				route: "query-report/Sales Person-wise Transaction Summary",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Item-wise Sales History"),
				route: "query-report/Item-wise Sales History",
				doctype: "Item"
			},
			{
				"label":wn._("Territory Target Variance (Item Group-Wise)"),
				route: "query-report/Territory Target Variance Item Group-Wise",
				doctype: "Territory"
			},
			{
				"label":wn._("Sales Person Target Variance (Item Group-Wise)"),
				route: "query-report/Sales Person Target Variance Item Group-Wise",
				doctype: "Sales Person",
			},
			{
				"label":wn._("Customers Not Buying Since Long Time"),
				route: "query-report/Customers Not Buying Since Long Time",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Quotation Trend"),
				route: "query-report/Quotation Trends",
				doctype: "Quotation"
			},
			{
				"label":wn._("Sales Order Trend"),
				route: "query-report/Sales Order Trends",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Available Stock for Packing Items"),
				route: "query-report/Available Stock for Packing Items",
				doctype: "Item",
			},
			{
				"label":wn._("Pending SO Items For Purchase Request"),
				route: "query-report/Pending SO Items For Purchase Request",
				doctype: "Sales Order"
			},
		]
	}
]

pscript['onload_selling-home'] = function(wrapper) {
	wn.views.moduleview.make(wrapper, "Selling");
}<commit_msg>Fix translate selling_home.js<commit_after>// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd.
// License: GNU General Public License v3. See license.txt"

wn.module_page["Selling"] = [
	{
		top: true,
		title: wn._("Documents"),
		icon: "icon-copy",
		items: [
			{
				label: wn._("Customer"),
				description: wn._("Customer database."),
				doctype:"Customer"
			},
			{
				label: wn._("Lead"),
				description: wn._("Database of potential customers."),
				doctype:"Lead"
			},
			{
				label: wn._("Opportunity"),
				description: wn._("Potential opportunities for selling."),
				doctype:"Opportunity"
			},
			{
				label: wn._("Quotation"),
				description: wn._("Quotes to Leads or Customers."),
				doctype:"Quotation"
			},
			{
				label: wn._("Sales Order"),
				description: wn._("Confirmed orders from Customers."),
				doctype:"Sales Order"
			},
		]
	},
	{
		title: wn._("Masters"),
		icon: "icon-book",
		items: [
			{
				label: wn._("Contact"),
				description: wn._("All Contacts."),
				doctype:"Contact"
			},
			{
				label: wn._("Address"),
				description: wn._("All Addresses."),
				doctype:"Address"
			},
			{
				label: wn._("Item"),
				description: wn._("All Products or Services."),
				doctype:"Item"
			},
		]
	},
	{
		title: wn._("Setup"),
		icon: "icon-cog",
		items: [
			{
				"label": wn._("Selling Settings"),
				"route": "Form/Selling Settings",
				"doctype":"Selling Settings",
				"description": wn._("Settings for Selling Module")
			},
			{
				"route":"Form/Shopping Cart Settings",
				"label":wn._("Shopping Cart Settings"),
				"description":wn._("Setup of Shopping Cart."),
				doctype:"Shopping Cart Settings"
			},
			{
				label: wn._("Sales Taxes and Charges Master"),
				description: wn._("Sales taxes template."),
				doctype:"Sales Taxes and Charges Master"
			},
			{
				label: wn._("Shipping Rules"),
				description: wn._("Rules to calculate shipping amount for a sale"),
				doctype:"Shipping Rule"
			},
			{
				label: wn._("Price List"),
				description: wn._("Mupltiple Item prices."),
				doctype:"Price List"
			},
			{
				label: wn._("Sales BOM"),
				description: wn._("Bundle items at time of sale."),
				doctype:"Sales BOM"
			},
			{
				label: wn._("Terms and Conditions"),
				description: wn._("Template of terms or contract."),
				doctype:"Terms and Conditions"
			},
			{
				label: wn._("Customer Group"),
				description: wn._("Customer classification tree."),
				route: "Sales Browser/Customer Group",
				doctype:"Customer Group"
			},
			{
				label: wn._("Territory"),
				description: wn._("Sales territories."),
				route: "Sales Browser/Territory",
				doctype:"Territory"
			},
			{
				"route":"Sales Browser/Sales Person",
				"label":wn._("Sales Person"),
				"description": wn._("Sales persons and targets"),
				doctype:"Sales Person"
			},
			{
				"route":"List/Sales Partner",
				"label": wn._("Sales Partner"),
				"description":wn._("Commission partners and targets"),
				doctype:"Sales Partner"
			},
			{
				"route":"Sales Browser/Item Group",
				"label":wn._("Item Group"),
				"description": wn._("Tree of item classification"),
				doctype:"Item Group"
			},
			{
				"route":"List/Campaign",
				"label":wn._("Campaign"),
				"description":wn._("Sales campaigns"),
				doctype:"Campaign"
			},
		]
	},
	{
		title: wn._("Tools"),
		icon: "icon-wrench",
		items: [
			{
				"route":"Form/SMS Center/SMS Center",
				"label":wn._("SMS Center"),
				"description":wn._("Send mass SMS to your contacts"),
				doctype:"SMS Center"
			},
		]
	},
	{
		title: wn._("Analytics"),
		right: true,
		icon: "icon-bar-chart",
		items: [
			{
				"label":wn._("Sales Analytics"),
				page: "sales-analytics"
			},
		]
	},
	{
		title: wn._("Reports"),
		right: true,
		icon: "icon-list",
		items: [
			{
				"label":wn._("Customer Addresses And Contacts"),
				route: "query-report/Customer Addresses And Contacts",
				doctype: "Contact"
			},
			{
				"label":wn._("Ordered Items To Be Delivered"),
				route: "query-report/Ordered Items To Be Delivered",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Sales Person-wise Transaction Summary"),
				route: "query-report/Sales Person-wise Transaction Summary",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Item-wise Sales History"),
				route: "query-report/Item-wise Sales History",
				doctype: "Item"
			},
			{
				"label":wn._("Territory Target Variance (Item Group-Wise)"),
				route: "query-report/Territory Target Variance Item Group-Wise",
				doctype: "Territory"
			},
			{
				"label":wn._("Sales Person Target Variance (Item Group-Wise)"),
				route: "query-report/Sales Person Target Variance Item Group-Wise",
				doctype: "Sales Person",
			},
			{
				"label":wn._("Customers Not Buying Since Long Time"),
				route: "query-report/Customers Not Buying Since Long Time",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Quotation Trend"),
				route: "query-report/Quotation Trends",
				doctype: "Quotation"
			},
			{
				"label":wn._("Sales Order Trend"),
				route: "query-report/Sales Order Trends",
				doctype: "Sales Order"
			},
			{
				"label":wn._("Available Stock for Packing Items"),
				route: "query-report/Available Stock for Packing Items",
				doctype: "Item",
			},
			{
				"label":wn._("Pending SO Items For Purchase Request"),
				route: "query-report/Pending SO Items For Purchase Request",
				doctype: "Sales Order"
			},
		]
	}
]

pscript['onload_selling-home'] = function(wrapper) {
	wn.views.moduleview.make(wrapper, "Selling");
}<|endoftext|>


<commit_before>/**
 * Copyright 2012 Google, Inc. All Rights Reserved.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @fileoverview HUD overlay UI.
 *
 * @author benvanik@google.com (Ben Vanik)
 */

goog.provide('wtf.hud.Overlay');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classes');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('goog.string');
goog.require('goog.style');
goog.require('wtf.events.Keyboard');
goog.require('wtf.events.KeyboardScope');
goog.require('wtf.hud.LiveGraph');
goog.require('wtf.hud.SettingsDialog');
goog.require('wtf.hud.overlay');
goog.require('wtf.io.BufferedHttpWriteStream');
goog.require('wtf.trace');
goog.require('wtf.ui.ResizableControl');
goog.require('wtf.util.Options');

/**
 * HUD overlay control UI.
 *
 * @param {!wtf.trace.Session} session Current tracing session.
 * @param {!wtf.util.Options} options Options.
 * @param {Element=} opt_parentElement Element to display in.
 * @constructor
 * @extends {wtf.ui.ResizableControl}
 */
wtf.hud.Overlay = function(session, options, opt_parentElement) {
  var dom = goog.dom.getDomHelper(opt_parentElement);
  var parentElement = /** @type {!Element} */ (
      opt_parentElement || dom.getDocument().body);
  goog.base(
      this,
      wtf.ui.ResizableControl.Orientation.VERTICAL,
      'wtfHudSplitter',
      parentElement,
      dom);

  // Add stylesheet to page.
  // Note that we don't use GSS so that we can avoid another file dependency
  // and renaming issues.
  dom.appendChild(this.getParentElement(),
      /** @type {!Element} */ (goog.soy.renderAsFragment(
          wtf.hud.overlay.style, undefined, undefined, dom)));

  /**
   * Tracing session.
   * @type {!wtf.trace.Session}
   * @private
   */
  this.session_ = session;

  /**
   * Options.
   * @type {!wtf.util.Options}
   * @private
   */
  this.options_ = options;

  /**
   * Docking position.
   * @type {wtf.hud.Overlay.DockPosition_}
   * @private
   */
  this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT;

  /**
   * The number of buttons currently added.
   * @type {number}
   * @private
   */
  this.buttonCount_ = 0;

  /**
   * Graph canvas.
   * @type {!wtf.hud.LiveGraph}
   * @private
   */
  this.liveGraph_ = new wtf.hud.LiveGraph(
      session, options, this.getChildElement('wtfHudGraph'));
  this.registerDisposable(this.liveGraph_);

  var keyboard = wtf.events.Keyboard.getWindowKeyboard(dom.getWindow());

  /**
   * Keyboard shortcut scope.
   * @type {!wtf.events.KeyboardScope}
   * @private
   */
  this.keyboardScope_ = new wtf.events.KeyboardScope(keyboard);
  this.registerDisposable(this.keyboardScope_);

  // Initial resize.
  this.setSplitterLimits(59, 500);
  this.setSplitterSize(80);

  // Add buttons.
  this.addButton_(
      true, 'wtfHudButtonSend', 'Send to UI', 'f9',
      this.sendSnapshotClicked_, this);
  this.addButton_(
      true, 'wtfHudButtonSave', 'Save Snapshot', 'f10',
      this.saveSnapshotClicked_, this);
  this.addButton_(
      true, 'wtfHudButtonSettings', 'Settings', null,
      this.settingsClicked_, this);

  // Listen for options changes and reload.
  this.options_.addListener(
      wtf.util.Options.EventType.CHANGED, this.reloadOptions_, this);
  this.reloadOptions_();

  // TODO(benvanik): generate counter code
  /*
  'counters': [
    {
      'name': 'foo::bar',
      'min': 0,
      'max': 100,
      'style': 'bar',
      'format': '{CUR:2}ms ({MIN:2}-{MAX:2})'
    }, ...
  ]
  'default': {
    'display': 'foo::bar'
  }
  */
  // var providerInfos = wtf.data.getAllProviders();
  // var providerMap = {};
  // for (var n = 0; n < providerInfos.length; n++) {
  //   providerMap[providerInfos[n].name] = providerInfo;
  // }
  // for (var n = 0; n < counters.length; n++) {
  //   var counter = counters[n];
  //   var nameParts = counter.name.split('::');
  //   var providerInfo = providerMap[nameParts[0]];
  //   var eventInfo = providerInfo.getEventByName(nameParts[1]);
  //   //
  // }
};
goog.inherits(wtf.hud.Overlay, wtf.ui.ResizableControl);

/**
 * @override
 */
wtf.hud.Overlay.prototype.disposeInternal = function() {
  this.options_.removeListener(
      wtf.util.Options.EventType.CHANGED, this.reloadOptions_, this);
  goog.base(this, 'disposeInternal');
};

/**
 * Overlay docking position.
 * @enum {string}
 * @private
 */
wtf.hud.Overlay.DockPosition_ = {
  /**
   * Dock at the top-left of the screen.
   */
  TOP_LEFT: 'tl',

  /**
   * Dock at the bottom-left of the screen.
   */
  BOTTOM_LEFT: 'bl',

  /**
   * Dock at the top-right of the screen.
   */
  TOP_RIGHT: 'tr',

  /**
   * Dock at the bottom-right of the screen.
   */
  BOTTOM_RIGHT: 'br'
};

/**
 * @override
 */
wtf.hud.Overlay.prototype.createDom = function(dom) {
  return /** @type {!Element} */ (goog.soy.renderAsFragment(
      wtf.hud.overlay.control, undefined, undefined, dom));
};

/**
 * @override
 */
wtf.hud.Overlay.prototype.layoutInternal = function() {
  this.liveGraph_.layout();
};

/**
 * Reloads options.
 * @private
 */
wtf.hud.Overlay.prototype.reloadOptions_ = function() {
  var options = this.options_;

  switch (options.getString('wtf.hud.dock', 'br')) {
    case 'tl':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.TOP_LEFT;
      break;
    case 'bl':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_LEFT;
      break;
    case 'tr':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.TOP_RIGHT;
      break;
    case 'br':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT;
      break;
  }

  // Adjust position on page.
  var rootElement = this.getRootElement();
  switch (this.dockPosition_) {
    default:
    case wtf.hud.Overlay.DockPosition_.TOP_LEFT:
      goog.style.setStyle(rootElement, {
        'top': 0,
        'bottom': null,
        'left': 0,
        'right': null
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.TOP_LEFT);
      break;
    case wtf.hud.Overlay.DockPosition_.BOTTOM_LEFT:
      goog.style.setStyle(rootElement, {
        'top': null,
        'bottom': 0,
        'left': 0,
        'right': null
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.TOP_LEFT);
      break;
    case wtf.hud.Overlay.DockPosition_.TOP_RIGHT:
      goog.style.setStyle(rootElement, {
        'top': 0,
        'bottom': null,
        'left': null,
        'right': 0
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.BOTTOM_RIGHT);
      break;
    case wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT:
      goog.style.setStyle(rootElement, {
        'top': null,
        'bottom': 0,
        'left': null,
        'right': 0
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.BOTTOM_RIGHT);
      break;
  }
};

/**
 * Shows the overlay.
 */
wtf.hud.Overlay.prototype.show = function() {
  goog.style.setStyle(this.getRootElement(), 'display', '');
  this.liveGraph_.setEnabled(true);
};

/**
 * Hides the overlay.
 */
wtf.hud.Overlay.prototype.hide = function() {
  goog.style.setStyle(this.getRootElement(), 'display', 'none');
  this.liveGraph_.setEnabled(false);
};

/**
 * Advances the HUD time.
 * @param {number=} opt_time New time. Prefer using {@see wtf#now}.
 */
wtf.hud.Overlay.prototype.advance = function(opt_time) {
  this.liveGraph_.advance(opt_time);
};

/**
 * @typedef {{
 *   title: string,
 *   icon: string,
 *   shortcut: string?,
 *   callback: function(),
 *   scope: (Object|undefined)
 * }}
 */
wtf.hud.Overlay.ButtonInfo;

/**
 * Inserts a button to the left of the system buttons.
 * @param {!wtf.hud.Overlay.ButtonInfo} info Button info data.
 */
wtf.hud.Overlay.prototype.insertButton = function(info) {
  this.addButton_(
      false,
      info['icon'] || '',
      info['title'] || 'Action',
      info['shortcut'] || null,
      info['callback'],
      info['scope'] || undefined);
};

// TODO(benvanik): support toggleable actions
/**
 * Adds a button to the overlay button bar.
 * @param {boolean} isSystem System button.
 * @param {string} icon Data URI of an icon file or a CSS class name.
 * @param {string} title Title name for tooltips.
 * @param {string?} shortcut Shortcut key or null if not used.
 * @param {!function(this:T)} callback Callback when the action is invoked.
 * @param {T=} opt_scope Callback scope.
 * @template T
 * @private
 */
wtf.hud.Overlay.prototype.addButton_ = function(
    isSystem, icon, title, shortcut, callback, opt_scope) {
  // Create button.
  var dom = this.getDom();
  var el = dom.createElement(goog.dom.TagName.A);
  goog.dom.classes.add(el, 'wtfHudButton');
  el['title'] = title;
  var img = dom.createElement(goog.dom.TagName.IMG);
  img['alt'] = title;
  img['src'] = '';
  dom.appendChild(el, img);

  // Set icon.
  if (goog.string.startsWith(icon, 'data:')) {
    img['src'] = icon;
  } else {
    goog.dom.classes.add(el, icon);
  }

  // Add to DOM.
  var buttonBar = this.getChildElement('wtfHudButtons');
  if (isSystem) {
    dom.appendChild(buttonBar, el);
  } else {
    dom.insertChildAt(buttonBar, el, 0);
  }
  this.buttonCount_++;

  // Keyboard shortcut handler.
  if (shortcut) {
    this.keyboardScope_.addShortcut(shortcut, callback, opt_scope || this);
  }

  // Click handler.
  this.getHandler().listen(el,
      goog.events.EventType.CLICK, callback, false, opt_scope || this);

  // Measure and update extents.
  var splitterSize = this.getSplitterSize();
  var oldMinWidth = (this.buttonCount_ - 1) * 27 + 4;
  var newMinWidth = this.buttonCount_ * 27 + 4;
  this.setSplitterLimits(newMinWidth, 500);
  this.setSplitterSize((splitterSize - oldMinWidth) + newMinWidth);
};

/**
 * Handles clicks on the send to UI button.
 * @private
 */
wtf.hud.Overlay.prototype.sendSnapshotClicked_ = function() {
  // Send snapshot.
  this.sendSnapshot_();
};

/**
 * Handles clicks on the save button.
 * @private
 */
wtf.hud.Overlay.prototype.saveSnapshotClicked_ = function() {
  wtf.trace.snapshot();
};

/**
 * Handles clicks on the settings UI button.
 * @private
 */
wtf.hud.Overlay.prototype.settingsClicked_ = function() {
  // Show settings dialog.
  var dom = this.getDom();
  var body = dom.getDocument().body;
  goog.asserts.assert(body);
  var dialog = new wtf.hud.SettingsDialog(
      this.options_, body, dom);
};

/**
 * Sends a snapshot to the UI.
 * @private
 */
wtf.hud.Overlay.prototype.sendSnapshot_ = function() {
  // TODO(benvanik): something more sophisticated
  var host = COMPILED ? 'localhost:9023' : 'localhost:9024';
  host = this.options_.getString('wtf.app.endpoint', host);
  var url = 'http://' + host + '/snapshot/upload';

  // Capture snapshot into memory buffers.
  var buffers = [];
  wtf.trace.snapshot(function() {
    return new wtf.io.BufferedHttpWriteStream(url);
  });
};
<commit_msg>HUD buttons now have shortcut keys.<commit_after>/**
 * Copyright 2012 Google, Inc. All Rights Reserved.
 *
 * Use of this source code is governed by a BSD-style license that can be
 * found in the LICENSE file.
 */

/**
 * @fileoverview HUD overlay UI.
 *
 * @author benvanik@google.com (Ben Vanik)
 */

goog.provide('wtf.hud.Overlay');

goog.require('goog.asserts');
goog.require('goog.dom');
goog.require('goog.dom.TagName');
goog.require('goog.dom.classes');
goog.require('goog.events.EventType');
goog.require('goog.soy');
goog.require('goog.string');
goog.require('goog.style');
goog.require('wtf.events.Keyboard');
goog.require('wtf.events.KeyboardScope');
goog.require('wtf.hud.LiveGraph');
goog.require('wtf.hud.SettingsDialog');
goog.require('wtf.hud.overlay');
goog.require('wtf.io.BufferedHttpWriteStream');
goog.require('wtf.trace');
goog.require('wtf.ui.ResizableControl');
goog.require('wtf.util.Options');

/**
 * HUD overlay control UI.
 *
 * @param {!wtf.trace.Session} session Current tracing session.
 * @param {!wtf.util.Options} options Options.
 * @param {Element=} opt_parentElement Element to display in.
 * @constructor
 * @extends {wtf.ui.ResizableControl}
 */
wtf.hud.Overlay = function(session, options, opt_parentElement) {
  var dom = goog.dom.getDomHelper(opt_parentElement);
  var parentElement = /** @type {!Element} */ (
      opt_parentElement || dom.getDocument().body);
  goog.base(
      this,
      wtf.ui.ResizableControl.Orientation.VERTICAL,
      'wtfHudSplitter',
      parentElement,
      dom);

  // Add stylesheet to page.
  // Note that we don't use GSS so that we can avoid another file dependency
  // and renaming issues.
  dom.appendChild(this.getParentElement(),
      /** @type {!Element} */ (goog.soy.renderAsFragment(
          wtf.hud.overlay.style, undefined, undefined, dom)));

  /**
   * Tracing session.
   * @type {!wtf.trace.Session}
   * @private
   */
  this.session_ = session;

  /**
   * Options.
   * @type {!wtf.util.Options}
   * @private
   */
  this.options_ = options;

  /**
   * Docking position.
   * @type {wtf.hud.Overlay.DockPosition_}
   * @private
   */
  this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT;

  /**
   * The number of buttons currently added.
   * @type {number}
   * @private
   */
  this.buttonCount_ = 0;

  /**
   * Graph canvas.
   * @type {!wtf.hud.LiveGraph}
   * @private
   */
  this.liveGraph_ = new wtf.hud.LiveGraph(
      session, options, this.getChildElement('wtfHudGraph'));
  this.registerDisposable(this.liveGraph_);

  var keyboard = wtf.events.Keyboard.getWindowKeyboard(dom.getWindow());

  /**
   * Keyboard shortcut scope.
   * @type {!wtf.events.KeyboardScope}
   * @private
   */
  this.keyboardScope_ = new wtf.events.KeyboardScope(keyboard);
  this.registerDisposable(this.keyboardScope_);

  // Initial resize.
  this.setSplitterLimits(59, 500);
  this.setSplitterSize(80);

  // Add buttons.
  this.addButton_(
      true, 'wtfHudButtonSend', 'Send to UI', 'f9',
      this.sendSnapshotClicked_, this);
  this.addButton_(
      true, 'wtfHudButtonSave', 'Save Snapshot', 'f10',
      this.saveSnapshotClicked_, this);
  this.addButton_(
      true, 'wtfHudButtonSettings', 'Settings', null,
      this.settingsClicked_, this);

  // Listen for options changes and reload.
  this.options_.addListener(
      wtf.util.Options.EventType.CHANGED, this.reloadOptions_, this);
  this.reloadOptions_();

  // TODO(benvanik): generate counter code
  /*
  'counters': [
    {
      'name': 'foo::bar',
      'min': 0,
      'max': 100,
      'style': 'bar',
      'format': '{CUR:2}ms ({MIN:2}-{MAX:2})'
    }, ...
  ]
  'default': {
    'display': 'foo::bar'
  }
  */
  // var providerInfos = wtf.data.getAllProviders();
  // var providerMap = {};
  // for (var n = 0; n < providerInfos.length; n++) {
  //   providerMap[providerInfos[n].name] = providerInfo;
  // }
  // for (var n = 0; n < counters.length; n++) {
  //   var counter = counters[n];
  //   var nameParts = counter.name.split('::');
  //   var providerInfo = providerMap[nameParts[0]];
  //   var eventInfo = providerInfo.getEventByName(nameParts[1]);
  //   //
  // }
};
goog.inherits(wtf.hud.Overlay, wtf.ui.ResizableControl);

/**
 * @override
 */
wtf.hud.Overlay.prototype.disposeInternal = function() {
  this.options_.removeListener(
      wtf.util.Options.EventType.CHANGED, this.reloadOptions_, this);
  goog.base(this, 'disposeInternal');
};

/**
 * Overlay docking position.
 * @enum {string}
 * @private
 */
wtf.hud.Overlay.DockPosition_ = {
  /**
   * Dock at the top-left of the screen.
   */
  TOP_LEFT: 'tl',

  /**
   * Dock at the bottom-left of the screen.
   */
  BOTTOM_LEFT: 'bl',

  /**
   * Dock at the top-right of the screen.
   */
  TOP_RIGHT: 'tr',

  /**
   * Dock at the bottom-right of the screen.
   */
  BOTTOM_RIGHT: 'br'
};

/**
 * @override
 */
wtf.hud.Overlay.prototype.createDom = function(dom) {
  return /** @type {!Element} */ (goog.soy.renderAsFragment(
      wtf.hud.overlay.control, undefined, undefined, dom));
};

/**
 * @override
 */
wtf.hud.Overlay.prototype.layoutInternal = function() {
  this.liveGraph_.layout();
};

/**
 * Reloads options.
 * @private
 */
wtf.hud.Overlay.prototype.reloadOptions_ = function() {
  var options = this.options_;

  switch (options.getString('wtf.hud.dock', 'br')) {
    case 'tl':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.TOP_LEFT;
      break;
    case 'bl':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_LEFT;
      break;
    case 'tr':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.TOP_RIGHT;
      break;
    case 'br':
      this.dockPosition_ = wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT;
      break;
  }

  // Adjust position on page.
  var rootElement = this.getRootElement();
  switch (this.dockPosition_) {
    default:
    case wtf.hud.Overlay.DockPosition_.TOP_LEFT:
      goog.style.setStyle(rootElement, {
        'top': 0,
        'bottom': null,
        'left': 0,
        'right': null
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.TOP_LEFT);
      break;
    case wtf.hud.Overlay.DockPosition_.BOTTOM_LEFT:
      goog.style.setStyle(rootElement, {
        'top': null,
        'bottom': 0,
        'left': 0,
        'right': null
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.TOP_LEFT);
      break;
    case wtf.hud.Overlay.DockPosition_.TOP_RIGHT:
      goog.style.setStyle(rootElement, {
        'top': 0,
        'bottom': null,
        'left': null,
        'right': 0
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.BOTTOM_RIGHT);
      break;
    case wtf.hud.Overlay.DockPosition_.BOTTOM_RIGHT:
      goog.style.setStyle(rootElement, {
        'top': null,
        'bottom': 0,
        'left': null,
        'right': 0
      });
      this.setSizeFrom(wtf.ui.ResizableControl.SizeFrom.BOTTOM_RIGHT);
      break;
  }
};

/**
 * Shows the overlay.
 */
wtf.hud.Overlay.prototype.show = function() {
  goog.style.setStyle(this.getRootElement(), 'display', '');
  this.liveGraph_.setEnabled(true);
};

/**
 * Hides the overlay.
 */
wtf.hud.Overlay.prototype.hide = function() {
  goog.style.setStyle(this.getRootElement(), 'display', 'none');
  this.liveGraph_.setEnabled(false);
};

/**
 * Advances the HUD time.
 * @param {number=} opt_time New time. Prefer using {@see wtf#now}.
 */
wtf.hud.Overlay.prototype.advance = function(opt_time) {
  this.liveGraph_.advance(opt_time);
};

/**
 * @typedef {{
 *   title: string,
 *   icon: string,
 *   shortcut: string?,
 *   callback: function(),
 *   scope: (Object|undefined)
 * }}
 */
wtf.hud.Overlay.ButtonInfo;

/**
 * Inserts a button to the left of the system buttons.
 * @param {!wtf.hud.Overlay.ButtonInfo} info Button info data.
 */
wtf.hud.Overlay.prototype.insertButton = function(info) {
  this.addButton_(
      false,
      info['icon'] || '',
      info['title'] || 'Action',
      info['shortcut'] || null,
      info['callback'],
      info['scope'] || undefined);
};

// TODO(benvanik): support toggleable actions
/**
 * Adds a button to the overlay button bar.
 * @param {boolean} isSystem System button.
 * @param {string} icon Data URI of an icon file or a CSS class name.
 * @param {string} title Title name for tooltips.
 * @param {string?} shortcut Shortcut key or null if not used.
 * @param {!function(this:T)} callback Callback when the action is invoked.
 * @param {T=} opt_scope Callback scope.
 * @template T
 * @private
 */
wtf.hud.Overlay.prototype.addButton_ = function(
    isSystem, icon, title, shortcut, callback, opt_scope) {
  var fullTitle = title;
  if (shortcut) {
    fullTitle += ' (' + shortcut + ')';
  }

  // Create button.
  var dom = this.getDom();
  var el = dom.createElement(goog.dom.TagName.A);
  goog.dom.classes.add(el, 'wtfHudButton');
  el['title'] = fullTitle;
  var img = dom.createElement(goog.dom.TagName.IMG);
  img['alt'] = title;
  img['src'] = '';
  dom.appendChild(el, img);

  // Set icon.
  if (goog.string.startsWith(icon, 'data:')) {
    img['src'] = icon;
  } else {
    goog.dom.classes.add(el, icon);
  }

  // Add to DOM.
  var buttonBar = this.getChildElement('wtfHudButtons');
  if (isSystem) {
    dom.appendChild(buttonBar, el);
  } else {
    dom.insertChildAt(buttonBar, el, 0);
  }
  this.buttonCount_++;

  // Keyboard shortcut handler.
  if (shortcut) {
    this.keyboardScope_.addShortcut(shortcut, callback, opt_scope || this);
  }

  // Click handler.
  this.getHandler().listen(el,
      goog.events.EventType.CLICK, callback, false, opt_scope || this);

  // Measure and update extents.
  var splitterSize = this.getSplitterSize();
  var oldMinWidth = (this.buttonCount_ - 1) * 27 + 4;
  var newMinWidth = this.buttonCount_ * 27 + 4;
  this.setSplitterLimits(newMinWidth, 500);
  this.setSplitterSize((splitterSize - oldMinWidth) + newMinWidth);
};

/**
 * Handles clicks on the send to UI button.
 * @private
 */
wtf.hud.Overlay.prototype.sendSnapshotClicked_ = function() {
  // Send snapshot.
  this.sendSnapshot_();
};

/**
 * Handles clicks on the save button.
 * @private
 */
wtf.hud.Overlay.prototype.saveSnapshotClicked_ = function() {
  wtf.trace.snapshot();
};

/**
 * Handles clicks on the settings UI button.
 * @private
 */
wtf.hud.Overlay.prototype.settingsClicked_ = function() {
  // Show settings dialog.
  var dom = this.getDom();
  var body = dom.getDocument().body;
  goog.asserts.assert(body);
  var dialog = new wtf.hud.SettingsDialog(
      this.options_, body, dom);
};

/**
 * Sends a snapshot to the UI.
 * @private
 */
wtf.hud.Overlay.prototype.sendSnapshot_ = function() {
  // TODO(benvanik): something more sophisticated
  var host = COMPILED ? 'localhost:9023' : 'localhost:9024';
  host = this.options_.getString('wtf.app.endpoint', host);
  var url = 'http://' + host + '/snapshot/upload';

  // Capture snapshot into memory buffers.
  var buffers = [];
  wtf.trace.snapshot(function() {
    return new wtf.io.BufferedHttpWriteStream(url);
  });
};
<|endoftext|>