<commit_before>var should = require('should'),
    request = require('supertest'),
    app = require('../../../app');

describe('/api/example', function () {
    describe('POST /api/example', function () {
        it('should return valid status', function (done) {
            request(app)
                .post('/api/example')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'Created record!'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'Sending you the list of examples.'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'sending you record with id of 123'
                    });
                    done();
                });
        });
    });

    describe('PUT /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .put('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'updated record with id 123'
                    });
                    done();
                });
        });
    });

    describe('DELETE /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .del('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'deleted record with id 123'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example/custom', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example/custom')
                .expect('Content-Type', /html/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.text.should.equal('
Hello from custom action controller
');
                    done();
                });
        });
    });
});
<commit_msg>use index.js for integration testing, not app.js<commit_after>var should = require('should'),
    request = require('supertest'),
    app = require('../../../index');

describe('/api/example', function () {
    describe('POST /api/example', function () {
        it('should return valid status', function (done) {
            request(app)
                .post('/api/example')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'Created record!'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'Sending you the list of examples.'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'sending you record with id of 123'
                    });
                    done();
                });
        });
    });

    describe('PUT /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .put('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'updated record with id 123'
                    });
                    done();
                });
        });
    });

    describe('DELETE /api/example/:id', function () {
        it('should return valid status', function (done) {
            request(app)
                .del('/api/example/123')
                .expect('Content-Type', /json/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.body.should.eql({
                        status: 'deleted record with id 123'
                    });
                    done();
                });
        });
    });

    describe('GET /api/example/custom', function () {
        it('should return valid status', function (done) {
            request(app)
                .get('/api/example/custom')
                .expect('Content-Type', /html/)
                .expect(200)
                .end(function (err, res) {
                    if (err) return done(err);
                    res.text.should.equal('
Hello from custom action controller
');
                    done();
                });
        });
    });
});
<|endoftext|>


<commit_before>(function() {

Dagaz.AI.AI_FRAME     = 1000;
Dagaz.AI.NOISE_FACTOR = 100;

var price =
  [   0, 100, 100, 100, 100, 100, 100, 100,   0,
    100, 150, 200, 200, 200, 200, 200, 150, 100,
    100, 200, 400, 400, 400, 400, 400, 200, 100,
    100, 200, 400, 500, 500, 500, 400, 200, 100,
    100, 200, 400, 500, 700, 500, 400, 200, 100,
    100, 200, 400, 500, 500, 500, 400, 200, 100,
    100, 200, 400, 400, 400, 400, 400, 200, 100,
    100, 150, 200, 200, 200, 200, 200, 150, 100,
      0, 100, 100, 100, 100, 100, 100, 100,   0 ];

function Ai(parent) {
  this.parent = parent;
}

var findBot = Dagaz.AI.findBot;

Dagaz.AI.findBot = function(type, params, parent) {
  if ((type == "fast") || (type == "opening")) {
      return new Ai(parent);
  } else {
      return findBot(type, params, parent);
  }
}

Dagaz.AI.getPrice = function(design, piece, pos) {
  return price[pos];
}

Dagaz.AI.see = function(design, board, move) {
  if (move.actions.length > 0) {
      var pos = move.actions[0][1][0];
      for (var dir = 0; dir < design.dirs.length; dir++) {
           var p = design.navigate(board.player, pos, dir);
           if (p !== null) {
               var piece = board.getPiece(p);
               if (piece !== null) {
                   var v = piece.getValue(0);
                   if ((v !== null) && (v == 1)) return true;
               }
           }
      }
  }
  return false;
}

var getEval = function(groups, player) {
  var d = null; var e = 0;
  _.each(groups, function(g) {
      if (g.player != player) return;
      if ((d === null) || (d > g.dame)) {
           d = g.dame;
           e = g.price;
      }
  });
  if (d === null) return 0;
  return e + 1000 * d;
}

Dagaz.AI.eval = function(design, params, board, player) {
  var done = []; var groups = [];
  _.each(design.allPositions(), function(pos) {
      if (_.indexOf(done, pos) >= 0) return;
      var piece = board.getPiece(pos);
      if (piece === null) return;
      var e = null; var d = []; var c = 0;
      var group = [ pos ];
      for (var i = 0; i < group.length; i++) {
          if ((e === null) || (e > price[group[i]])) {
               e = price[group[i]];
          }
          _.each(design.allDirections(), function(dir) {
               var p = design.navigate(player, group[i], dir);
               if (p === null) return;
               if (_.indexOf(done, p) >= 0) return;
               var x = board.getPiece(p);
               if (x === null) {
                   if (_.indexOf(d, p) < 0) d.push(p);
                   return;
               }
               if (x.player != piece.player) return;
               group.push(p);
               done.push(p);
               c++;
          });
      }
      groups.push({
          player: piece.player,
          dame:   d.length,
          price:  e,
          count:  c
      });
  });
  return getEval(groups, player) -
         getEval(groups, design.nextPlayer(player));
}

var isAtari = function(design, board, pos, player) {
  var r = false;
  _.each(design.allDirections(), function(dir) {
      var p = design.navigate(player, pos, dir);
      if (p === null) return;
      var piece = board.getPiece(p);
      if (piece === null) return;
      if (piece.player != player) return;
      var v = piece.getValue(0);
      if (v === null) return;
      if (v == 1) r = true;
  });
  return r;
}

var checkAdjust = function(design, board, player, pos, a, b) {
  var p = design.navigate(player, pos, a);
  if (p === null) return false;
  var piece = board.getPiece(p);
  if ((piece !== null) && (piece.player != player)) return true;
  p = design.navigate(player, p, b);
  if (p === null) return false;
  var piece = board.getPiece(p);
  return (piece !== null) && (piece.player != player);
}

Ai.prototype.setContext = function(ctx, board) {
  if (this.parent) {
      this.parent.setContext(ctx, board);
  }
  ctx.board = board;
  ctx.timestamp = Date.now();
}

Ai.prototype.getMove = function(ctx) {
  ctx.board.moves = Dagaz.AI.generate(ctx, ctx.board);
  if (ctx.board.moves.length > 0) {
      for (var i = 0; i < ctx.board.moves.length; i++) {
           var m = ctx.board.moves[i];
           if (m.actions.length > 0) {
               var pos = m.actions[0][1][0];
               if (isAtari(ctx.design, ctx.board, pos, ctx.design.nextPlayer(ctx.board.player))) {
                   return {
                      done: true,
                      move: m,
                      time: Date.now() - ctx.timestamp,
                      ai:  "fast"
                   };
               }
           }
      }
      for (var i = 0; i < ctx.board.moves.length; i++) {
           var m = ctx.board.moves[i];
           if (m.actions.length > 0) {
               var pos = m.actions[0][1][0];
               if (isAtari(ctx.design, ctx.board, pos, ctx.board.player)) {
                   return {
                      done: true,
                      move: m,
                      time: Date.now() - ctx.timestamp,
                      ai:  "fast"
                   };
               }
           }
      }
  }
  var best = null;
  _.each(ctx.board.moves, function(move) {
      var b = ctx.board.apply(move);
      var cnt = 0;
      _.each(ctx.design.allPositions(), function(pos) {
          var piece = b.getPiece(pos);
          if (piece === null) return;
          if (piece.player == ctx.board.player) return;
          var v = piece.getValue(0);
          if (v === null) return;
          if (v == 1) {
              if (ctx.design.inZone(0, ctx.board.player, pos)) cnt++;
              cnt++;
          }
      });
      if (cnt > 1) {
          best = move;
          return;
      }
  });
  if (best !== null) {
      return {
         done: true,
         move: best,
         time: Date.now() - ctx.timestamp,
         ai:  "best"
      };
  }
  if ((ctx.board.parent !== null) && (ctx.board.parent.parent === null)) {
      var moves = [];
      _.each(ctx.board.moves, function(move) {
          if (!move.isDropMove()) return;
          var pos = move.actions[0][1][0];
          if (checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 0, 3) || // w, n
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 3, 1) || // n, e
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 1, 2) || // n, s
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 2, 0)) { // s, w
              moves.push(move);
          }
      });
      if (moves.length > 0) {
          ctx.board.moves = moves;
      }
  }
  if (this.parent) {
      return this.parent.getMove(ctx);
  }
}

})();
<commit_msg>Atari Go (fixed)<commit_after>(function() {

Dagaz.AI.AI_FRAME     = 1000;
Dagaz.AI.NOISE_FACTOR = 100;

var price =
  [   0, 100, 100, 100, 100, 100, 100, 100,   0,
    100, 150, 200, 200, 200, 200, 200, 150, 100,
    100, 200, 400, 400, 400, 400, 400, 200, 100,
    100, 200, 400, 500, 500, 500, 400, 200, 100,
    100, 200, 400, 500, 700, 500, 400, 200, 100,
    100, 200, 400, 500, 500, 500, 400, 200, 100,
    100, 200, 400, 400, 400, 400, 400, 200, 100,
    100, 150, 200, 200, 200, 200, 200, 150, 100,
      0, 100, 100, 100, 100, 100, 100, 100,   0 ];

function Ai(parent) {
  this.parent = parent;
}

var findBot = Dagaz.AI.findBot;

Dagaz.AI.findBot = function(type, params, parent) {
  if ((type == "fast") || (type == "opening")) {
      return new Ai(parent);
  } else {
      return findBot(type, params, parent);
  }
}

Dagaz.AI.getPrice = function(design, piece, pos) {
  return price[pos];
}

Dagaz.AI.see = function(design, board, move) {
  if (move.actions.length > 0) {
      var pos = move.actions[0][1][0];
      for (var dir = 0; dir < design.dirs.length; dir++) {
           var p = design.navigate(board.player, pos, dir);
           if (p !== null) {
               var piece = board.getPiece(p);
               if (piece !== null) {
                   var v = piece.getValue(0);
                   if ((v !== null) && (v == 1)) return true;
               }
           }
      }
  }
  return false;
}

var getEval = function(groups, player) {
  var d = null; var e = 0;
  _.each(groups, function(g) {
      if (g.player != player) return;
      if ((d === null) || (d > g.dame)) {
           d = g.dame;
           e = g.price;
      }
  });
  if (d === null) return 0;
  return e + 1000 * d;
}

Dagaz.AI.eval = function(design, params, board, player) {
  var done = []; var groups = [];
  _.each(design.allPositions(), function(pos) {
      if (_.indexOf(done, pos) >= 0) return;
      var piece = board.getPiece(pos);
      if (piece === null) return;
      var e = null; var d = []; var c = 0;
      var group = [ pos ];
      for (var i = 0; i < group.length; i++) {
          if ((e === null) || (e > price[group[i]])) {
               e = price[group[i]];
          }
          _.each(design.allDirections(), function(dir) {
               var p = design.navigate(player, group[i], dir);
               if (p === null) return;
               if (_.indexOf(done, p) >= 0) return;
               var x = board.getPiece(p);
               if (x === null) {
                   if (_.indexOf(d, p) < 0) d.push(p);
                   return;
               }
               if (x.player != piece.player) return;
               group.push(p);
               done.push(p);
               c++;
          });
      }
      groups.push({
          player: piece.player,
          dame:   d.length,
          price:  e,
          count:  c
      });
  });
  return getEval(groups, player) -
         getEval(groups, design.nextPlayer(player));
}

var isAtari = function(design, board, pos, player) {
  var r = false;
  _.each(design.allDirections(), function(dir) {
      var p = design.navigate(player, pos, dir);
      if (p === null) return;
      var piece = board.getPiece(p);
      if (piece === null) return;
      if (piece.player != player) return;
      var v = piece.getValue(0);
      if (v === null) return;
      if (v == 1) r = true;
  });
  return r;
}

var checkAdjust = function(design, board, player, pos, a, b) {
  var p = design.navigate(player, pos, a);
  if (p === null) return false;
  var piece = board.getPiece(p);
  if ((piece !== null) && (piece.player != player)) return true;
  p = design.navigate(player, p, b);
  if (p === null) return false;
  var piece = board.getPiece(p);
  return (piece !== null) && (piece.player != player);
}

var isDoubleAtari = function(design, board, pos) {
  var piece = board.getPiece(pos);
  if (piece === null) return false;
  var v = piece.getValue(0);
  if (v === null) return false;
  if (v > 1) return false;
  for (var dir = 0; dir < design.dirs.length; dir++) {
       var p = design.navigate(board.player, pos, dir);
       if (p === null) continue;
       if (board.getPiece(p) === null) return true;
  }
  return false;
}

var isDeathAtari = function(design, board, pos) {
  if (!design.inZone(0, board.player, pos)) return false;
  var piece = board.getPiece(pos);
  if (piece === null) return false;
  var v = piece.getValue(0);
  if (v === null) return false;
  if (v > 1) return false;
  for (var dir = 0; dir < design.dirs.length; dir++) {
       var p = design.navigate(board.player, pos, dir);
       if (p === null) continue;
       if (board.getPiece(p) !== null) continue;
       p = design.navigate(board.player, p, dir);
       if (p === null) return true;
  }
  return false;
}

Ai.prototype.setContext = function(ctx, board) {
  if (this.parent) {
      this.parent.setContext(ctx, board);
  }
  ctx.board = board;
  ctx.timestamp = Date.now();
}

Ai.prototype.getMove = function(ctx) {
  ctx.board.moves = Dagaz.AI.generate(ctx, ctx.board);
  if (ctx.board.moves.length > 0) {
      for (var i = 0; i < ctx.board.moves.length; i++) {
           var m = ctx.board.moves[i];
           if (m.actions.length > 0) {
               var pos = m.actions[0][1][0];
               if (isAtari(ctx.design, ctx.board, pos, ctx.design.nextPlayer(ctx.board.player))) {
                   return {
                      done: true,
                      move: m,
                      time: Date.now() - ctx.timestamp,
                      ai:  "fast"
                   };
               }
           }
      }
      for (var i = 0; i < ctx.board.moves.length; i++) {
           var m = ctx.board.moves[i];
           if (m.actions.length > 0) {
               var pos = m.actions[0][1][0];
               if (isAtari(ctx.design, ctx.board, pos, ctx.board.player)) {
                   return {
                      done: true,
                      move: m,
                      time: Date.now() - ctx.timestamp,
                      ai:  "fast"
                   };
               }
           }
      }
  }
  var best = null;
  _.each(ctx.board.moves, function(move) {
      var b = ctx.board.apply(move);
      var cnt = 0;
      _.each(ctx.design.allPositions(), function(pos) {
          var piece = b.getPiece(pos);
          if (piece === null) return;
          if (piece.player == ctx.board.player) return;
          if (isDeathAtari(ctx.design, b, pos)) {
              best = move;
              return;
          }
          if (isDoubleAtari(ctx.design, b, pos)) cnt++;
      });
      if (cnt > 1) {
          best = move;
          return;
      }
  });
  if (best !== null) {
      return {
         done: true,
         move: best,
         time: Date.now() - ctx.timestamp,
         ai:  "best"
      };
  }
  if ((ctx.board.parent !== null) && (ctx.board.parent.parent === null)) {
      var moves = [];
      _.each(ctx.board.moves, function(move) {
          if (!move.isDropMove()) return;
          var pos = move.actions[0][1][0];
          if (checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 0, 3) || // w, n
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 3, 1) || // n, e
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 1, 2) || // n, s
              checkAdjust(ctx.design, ctx.board, ctx.board.player, pos, 2, 0)) { // s, w
              moves.push(move);
          }
      });
      if (moves.length > 0) {
          ctx.board.moves = moves;
      }
  }
  if (this.parent) {
      return this.parent.getMove(ctx);
  }
}

})();
<|endoftext|>


<commit_before>// Stopgap atom.js file for handling normal browser things that atom
// does not yet have stable from the browser-side API.
// - Opening external links in default web browser
// - Saving files/downloads to disk
$(document).ready(function() {
    if (typeof process === 'undefined') return;
    if (typeof process.versions['atom-shell'] === undefined) return;

    var remote = require('remote');
    var shell = require('shell');
    var http = require('http');
    var url = require('url');
    var fs = require('fs');

    $('body').on('click', 'a', function(ev) {
        var uri = url.parse(ev.currentTarget.href);

        // Opening external URLs.
        if (uri.hostname && uri.hostname !== 'localhost') {
            shell.openExternal(ev.currentTarget.href);
            return false;
        }

        // File saving.
        var fileTypes = {
            tm2z: 'Package',
            mbtiles: 'Tiles',
            png: 'Image',
            jpg: 'Image',
            jpeg: 'Image'
        }
        var typeExtension = uri.pathname.split('.').pop().toLowerCase();
        var typeLabel = fileTypes[typeExtension];
        if (typeLabel) {
            var filePath = remote.require('dialog').showSaveDialog({
                title: 'Save ' + typeLabel,
                defaultPath: '~/Untitled ' + typeLabel + '.' + typeExtension
            });
            if (filePath) {
                uri.method = 'GET';
                var writeStream = fs.createWriteStream(filePath);
                var req = http.request(uri, function(res) {
                    if (res.statusCode !== 200) return;
                    res.pipe(writeStream);
                });
                req.end();
            }
            return false;
        }
        // Passthrough everything else.
    });
});
<commit_msg>add filter for file extension, works on win!<commit_after>// Stopgap atom.js file for handling normal browser things that atom
// does not yet have stable from the browser-side API.
// - Opening external links in default web browser
// - Saving files/downloads to disk
$(document).ready(function() {
    if (typeof process === 'undefined') return;
    if (typeof process.versions['atom-shell'] === undefined) return;

    var remote = require('remote');
    var shell = require('shell');
    var http = require('http');
    var url = require('url');
    var fs = require('fs');

    $('body').on('click', 'a', function(ev) {
        var uri = url.parse(ev.currentTarget.href);

        // Opening external URLs.
        if (uri.hostname && uri.hostname !== 'localhost') {
            shell.openExternal(ev.currentTarget.href);
            return false;
        }

        // File saving.
        var fileTypes = {
            tm2z: 'Package',
            mbtiles: 'Tiles',
            png: 'Image',
            jpg: 'Image',
            jpeg: 'Image'
        }
        var typeExtension = uri.pathname.split('.').pop().toLowerCase();
        var typeLabel = fileTypes[typeExtension];
        if (typeLabel) {
            var filePath = remote.require('dialog').showSaveDialog({
                title: 'Save ' + typeLabel,
                defaultPath: '~/Untitled ' + typeLabel + '.' + typeExtension,
                filters: [{ name: typeExtension.toUpperCase(), extensions: [typeExtension]}]
            });
            if (filePath) {
                uri.method = 'GET';
                var writeStream = fs.createWriteStream(filePath);
                var req = http.request(uri, function(res) {
                    if (res.statusCode !== 200) return;
                    res.pipe(writeStream);
                });
                req.end();
            }
            return false;
        }
        // Passthrough everything else.
    });
});
<|endoftext|>


<commit_before>import 'angular-mocks';

describe('Controller: journalUploadCtrl', function() {
  var scope;

  beforeEach(angular.mock.module('confRegistrationWebApp'));

  var testData, $httpBackend, $controller;
  beforeEach(
    angular.mock.inject(function(
      $rootScope,
      _$controller_,
      _testData_,
      _$httpBackend_,
    ) {
      $controller = _$controller_;
      testData = _testData_;
      $httpBackend = _$httpBackend_;
      scope = $rootScope.$new();

      $controller('journalUploadCtrl', {
        $scope: scope,
        registrations: { registrations: [testData.singleRegistration] },
        conference: testData.conference,
        reports: testData.accountTransfersReportList,
        permissions: {},
        confId: '123456',
      });
    }),
  );

  it('refresh should call api and refresh scope data', () => {
    scope.accountTransfers = [];

    $httpBackend
      .whenGET(/^conferences\/.*\/registrations.*/)
      .respond(201, { registrations: [testData.singleRegistration] });

    scope.refresh();
    $httpBackend.flush();

    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();

    expect(scope.accountTransfers.length).toBeGreaterThan(0);
  });

  describe('account transfer reports', () => {
    it('sets accountTransfers to specific reports accountTransfers', () => {
      scope.accountTransfers[testData.singleRegistration.accountTransfers];

      expect(scope.currentReportId).toEqual(null);

      scope.currentReportId = '59d56562-b97e-4cc8-a6f3-305f207042a4';

      scope.$digest();

      expect(scope.accountTransfers).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[0],
      ]);

      expect(scope.accountTransfersWithErrors).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[1],
      ]);
    });

    it('refreshes account transfer data if currentReportId is set to null', () => {
      scope.currentReportId = '59d56562-b97e-4cc8-a6f3-305f207042a4';

      scope.$digest();

      expect(scope.accountTransfers).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[0],
      ]);

      expect(scope.accountTransfersWithErrors).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[1],
      ]);

      $httpBackend
        .whenGET(/^conferences\/.*\/registrations.*/)
        .respond(201, { registrations: [testData.singleRegistration] });

      scope.currentReportId = null;

      $httpBackend.flush();

      scope.$digest();

      expect(scope.currentReportId).toEqual(null);

      expect(scope.accountTransfers[0].id).toEqual(
        testData.singleRegistration.accountTransfers[0].id,
      );
    });
  });

  describe('accountTransfersToInclude', () => {
    it('adds a single account transfer to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      scope.refreshAccountTransfersToInclude(scope.accountTransfers[0]);

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toBeGreaterThan(0);
      expect(scope.accountTransfersToInclude).toContain(
        scope.accountTransfers[0],
      );
    });

    it('removes a single account transfer from accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      scope.refreshAccountTransfersToInclude(scope.accountTransfers[0]);

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toBe(0);
      expect(scope.accountTransfersToInclude).toEqual([]);
    });

    it('returns true if all account transfers have been added to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      const result = scope.allAccountTransfersIncluded();

      expect(result).toBeTruthy();
    });

    it('returns false if all account transfers have not been added to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      const result = scope.allAccountTransfersIncluded();

      expect(result).toBeFalsy();
    });

    it('adds all account transfers to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      scope.addAllTransfersToInclude();

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toEqual(
        scope.accountTransfers.length,
      );
    });

    it('removes all account transfers from accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      scope.removeAllTransfersFromToInclude();

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toEqual(0);
      expect(scope.accountTransfersToInclude).toEqual([]);
    });

    it('gets remaining balance for account transfer', () => {
      const result = scope.getRemainingBalance(testData.singleRegistration.id);

      expect(result).toEqual(testData.singleRegistration.remainingBalance);
    });
  });
});
<commit_msg>additional journalUpload test change<commit_after>import 'angular-mocks';

describe('Controller: journalUploadCtrl', function() {
  var scope;

  beforeEach(angular.mock.module('confRegistrationWebApp'));

  var testData, $httpBackend, $controller;
  beforeEach(
    angular.mock.inject(function(
      $rootScope,
      _$controller_,
      _testData_,
      _$httpBackend_,
    ) {
      $controller = _$controller_;
      testData = _testData_;
      $httpBackend = _$httpBackend_;
      scope = $rootScope.$new();

      $controller('journalUploadCtrl', {
        $scope: scope,
        registrations: { registrations: [testData.singleRegistration] },
        conference: testData.conference,
        reports: testData.accountTransfersReportList,
        permissions: {},
        confId: '123456',
      });
    }),
  );

  it('refresh should call api and refresh scope data', () => {
    scope.accountTransfers = [];

    $httpBackend
      .whenGET(/^conferences\/.*\/registrations.*/)
      .respond(201, { registrations: [testData.singleRegistration] });

    scope.refresh();
    $httpBackend.flush();

    $httpBackend.verifyNoOutstandingExpectation();
    $httpBackend.verifyNoOutstandingRequest();

    expect(scope.accountTransfers.length).toBeGreaterThan(0);
    expect(scope.reports.length).toBeGreaterThan(0);
  });

  describe('account transfer reports', () => {
    it('sets accountTransfers to specific reports accountTransfers', () => {
      scope.accountTransfers[testData.singleRegistration.accountTransfers];

      expect(scope.currentReportId).toEqual(null);

      scope.currentReportId = '59d56562-b97e-4cc8-a6f3-305f207042a4';

      scope.$digest();

      expect(scope.accountTransfers).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[0],
      ]);

      expect(scope.accountTransfersWithErrors).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[1],
      ]);
    });

    it('refreshes account transfer data if currentReportId is set to null', () => {
      scope.currentReportId = '59d56562-b97e-4cc8-a6f3-305f207042a4';

      scope.$digest();

      expect(scope.accountTransfers).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[0],
      ]);

      expect(scope.accountTransfersWithErrors).toEqual([
        testData.accountTransfersReportList[0].accountTransfers[1],
      ]);

      $httpBackend
        .whenGET(/^conferences\/.*\/registrations.*/)
        .respond(201, { registrations: [testData.singleRegistration] });

      scope.currentReportId = null;

      $httpBackend.flush();

      scope.$digest();

      expect(scope.currentReportId).toEqual(null);

      expect(scope.accountTransfers[0].id).toEqual(
        testData.singleRegistration.accountTransfers[0].id,
      );
    });
  });

  describe('accountTransfersToInclude', () => {
    it('adds a single account transfer to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      scope.refreshAccountTransfersToInclude(scope.accountTransfers[0]);

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toBeGreaterThan(0);
      expect(scope.accountTransfersToInclude).toContain(
        scope.accountTransfers[0],
      );
    });

    it('removes a single account transfer from accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      scope.refreshAccountTransfersToInclude(scope.accountTransfers[0]);

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toBe(0);
      expect(scope.accountTransfersToInclude).toEqual([]);
    });

    it('returns true if all account transfers have been added to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      const result = scope.allAccountTransfersIncluded();

      expect(result).toBeTruthy();
    });

    it('returns false if all account transfers have not been added to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      const result = scope.allAccountTransfersIncluded();

      expect(result).toBeFalsy();
    });

    it('adds all account transfers to accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [];

      scope.addAllTransfersToInclude();

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toEqual(
        scope.accountTransfers.length,
      );
    });

    it('removes all account transfers from accountTransfersToInclude', () => {
      scope.accountTransfers = [testData.singleRegistration.accountTransfers];
      scope.accountTransfersToInclude = [
        testData.singleRegistration.accountTransfers,
      ];

      scope.removeAllTransfersFromToInclude();

      scope.refresh();

      expect(scope.accountTransfersToInclude.length).toEqual(0);
      expect(scope.accountTransfersToInclude).toEqual([]);
    });

    it('gets remaining balance for account transfer', () => {
      const result = scope.getRemainingBalance(testData.singleRegistration.id);

      expect(result).toEqual(testData.singleRegistration.remainingBalance);
    });
  });
});
<|endoftext|>


<commit_before>/* jslint node: true */
'use strict';

var spawn			= require('child_process').spawn;
var events			= require('events');

var _				= require('lodash');
var pty				= require('ptyw.js');
var decode 			= require('iconv-lite').decode;
var net				= require('net');
var async			= require('async');

exports.Door		= Door;

function Door(client, exeInfo) {
	events.EventEmitter.call(this);

	this.client			= client;
	this.exeInfo		= exeInfo;

	this.exeInfo.encoding	= this.exeInfo.encoding || 'cp437';

	//
	//	Members of exeInfo:
	//	cmd
	//	args[]
	//	env{}
	//	cwd
	//	io
	//	encoding
	//	dropFile
	//	node
	//	inhSocket
	//
}

require('util').inherits(Door, events.EventEmitter);

Door.prototype.run = function() {

	var self = this;

	var doorData = function(data) {
		//	:TODO: skip decoding if we have a match, e.g. cp437 === cp437
		self.client.term.write(decode(data, self.exeInfo.encoding));
	};

	var restore = function(piped) {
		if(self.client.term.output) {
			self.client.term.output.unpipe(piped);
			self.client.term.output.resume();
		}
	};

	var sockServer;

	async.series(
		[
			function prepareServer(callback) {
				if('socket' === self.exeInfo.io) {
					sockServer =  net.createServer(function connected(conn) {

						sockServer.getConnections(function connCount(err, count) {

							//	We expect only one connection from our DOOR/emulator/etc.
							if(!err && count <= 1) {
								self.client.term.output.pipe(conn);

								conn.on('data', doorData);

								conn.on('end', function ended() {
									restore(conn);
								});

								conn.on('error', function error(err) {
									self.client.log.info('Door socket server connection error: ' + err.message);
									restore(conn);
								});
							}
						});
					});

					sockServer.listen(0, function listening() {
						callback(null);
					});
				} else {
					callback(null);
				}
			},
			function launch(callback) {
				//	Expand arg strings, e.g. {dropFile} -> DOOR32.SYS
				var args = _.clone(self.exeInfo.args);	//	we need a copy so the original is not modified

				for(var i = 0; i < args.length; ++i) {
					args[i] = self.exeInfo.args[i].format({
						dropFile		: self.exeInfo.dropFile,
						node			: self.exeInfo.node.toString(),
						//inhSocket		: self.exeInfo.inhSocket.toString(),
						srvPort			: sockServer ? sockServer.address().port.toString() : '-1',
						userId			: self.client.user.userId.toString(),
					});
				}

				var door = pty.spawn(self.exeInfo.cmd, args, {
					cols : self.client.term.termWidth,
					rows : self.client.term.termHeight,
					//	:TODO: cwd
					env	: self.exeInfo.env,
				});

				if('stdio' === self.exeInfo.io) {
					self.client.log.debug('Using stdio for door I/O');

					self.client.term.output.pipe(door);

					door.on('data', doorData);

					door.on('close', function closed() {
						restore(door);
					});
				} else if('socket' === self.exeInfo.io) {
					self.client.log.debug(
						{ port : sockServer.address().port },
						'Using temporary socket server for door I/O');
				}

				door.on('exit', function exited(code) {
					self.client.log.info( { code : code }, 'Door exited');

					if(sockServer) {
						sockServer.close();
					}

					door.removeAllListeners();

					self.emit('finished');
				});
			}
		],
		function complete(err) {
			if(err) {
				self.client.log.warn( { error : err.toString() }, 'Failed executing door');
			}
		}
	);
};<commit_msg>Backup restore() when 'close' fails to fire<commit_after>/* jslint node: true */
'use strict';

var spawn			= require('child_process').spawn;
var events			= require('events');

var _				= require('lodash');
var pty				= require('ptyw.js');
var decode 			= require('iconv-lite').decode;
var net				= require('net');
var async			= require('async');

exports.Door		= Door;

function Door(client, exeInfo) {
	events.EventEmitter.call(this);

	this.client			= client;
	this.exeInfo		= exeInfo;

	this.exeInfo.encoding	= this.exeInfo.encoding || 'cp437';

	//
	//	Members of exeInfo:
	//	cmd
	//	args[]
	//	env{}
	//	cwd
	//	io
	//	encoding
	//	dropFile
	//	node
	//	inhSocket
	//
}

require('util').inherits(Door, events.EventEmitter);

Door.prototype.run = function() {

	var self = this;

	var doorData = function(data) {
		//	:TODO: skip decoding if we have a match, e.g. cp437 === cp437
		self.client.term.write(decode(data, self.exeInfo.encoding));
	};

	var restored = false;

	var restore = function(piped) {
		if(!restored && self.client.term.output) {
			self.client.term.output.unpipe(piped);
			self.client.term.output.resume();
			restored = true;
		}
	};

	var sockServer;

	async.series(
		[
			function prepareServer(callback) {
				if('socket' === self.exeInfo.io) {
					sockServer =  net.createServer(function connected(conn) {

						sockServer.getConnections(function connCount(err, count) {

							//	We expect only one connection from our DOOR/emulator/etc.
							if(!err && count <= 1) {
								self.client.term.output.pipe(conn);

								conn.on('data', doorData);

								conn.on('end', function ended() {
									restore(conn);
								});

								conn.on('error', function error(err) {
									self.client.log.info('Door socket server connection error: ' + err.message);
									restore(conn);
								});
							}
						});
					});

					sockServer.listen(0, function listening() {
						callback(null);
					});
				} else {
					callback(null);
				}
			},
			function launch(callback) {
				//	Expand arg strings, e.g. {dropFile} -> DOOR32.SYS
				var args = _.clone(self.exeInfo.args);	//	we need a copy so the original is not modified

				for(var i = 0; i < args.length; ++i) {
					args[i] = self.exeInfo.args[i].format({
						dropFile		: self.exeInfo.dropFile,
						node			: self.exeInfo.node.toString(),
						//inhSocket		: self.exeInfo.inhSocket.toString(),
						srvPort			: sockServer ? sockServer.address().port.toString() : '-1',
						userId			: self.client.user.userId.toString(),
					});
				}

				var door = pty.spawn(self.exeInfo.cmd, args, {
					cols : self.client.term.termWidth,
					rows : self.client.term.termHeight,
					//	:TODO: cwd
					env	: self.exeInfo.env,
				});

				if('stdio' === self.exeInfo.io) {
					self.client.log.debug('Using stdio for door I/O');

					self.client.term.output.pipe(door);

					door.on('data', doorData);

					door.on('close', function closed() {
						restore(door);
					});
				} else if('socket' === self.exeInfo.io) {
					self.client.log.debug(
						{ port : sockServer.address().port },
						'Using temporary socket server for door I/O');
				}

				door.on('exit', function exited(code) {
					self.client.log.info( { code : code }, 'Door exited');

					if(sockServer) {
						sockServer.close();
					}

					//	we may not get a close
					if('stdio' === self.exeInfo.io) {
						restore(door);
					}

					door.removeAllListeners();

					self.emit('finished');
				});
			}
		],
		function complete(err) {
			if(err) {
				self.client.log.warn( { error : err.toString() }, 'Failed executing door');
			}
		}
	);
};<|endoftext|>


<commit_before>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {CSS} from '../../../build/amp-next-page-0.1.css';
import {MultidocManager} from '../../../src/runtime';
import {PositionObserverFidelity} from '../../../src/service/position-observer/position-observer-worker';
import {Services} from '../../../src/services';
import {dev} from '../../../src/log';
import {fetchDocument} from '../../../src/document-fetcher';
import {getAmpdoc, getServiceForDoc} from '../../../src/service';
import {
  installPositionObserverServiceForDoc,
} from '../../../src/service/position-observer/position-observer-impl';
import {installStylesForDoc} from '../../../src/style-installer';
import {layoutRectLtwh} from '../../../src/layout-rect';
import {removeElement} from '../../../src/dom';
import {setStyle} from '../../../src/style';
import {triggerAnalyticsEvent} from '../../../src/analytics';

// TODO(emarchiori): Make this a configurable parameter.
const SEPARATOR_RECOS = 3;

const MAX_ARTICLES = 2;

const PRERENDER_VIEWPORT_COUNT = 3;

const TAG = 'amp-next-page';

/**
 * @typedef {{
 *   ampUrl: string,
 *   amp: ?Object,
 *   recUnit: {el: ?Element, isObserving: boolean},
 *   cancelled: boolean
 * }}
 */
export let DocumentRef;

/**
 * Window-scoped service to handle the amp-next-page lifecycle. Handles all
 * events and page lifecycle for the first {@code AmpNextPage} element
 * registered. All subsequent registrations will be ignored.
 */
export class NextPageService {
  /**
   * Creates an instance of NextPageService.
   */
  constructor() {
    /** @private {?Window} */
    this.win_ = null;

    /** @private {?Element} */
    this.element_ = null;

    /** @private {?./config.AmpNextPageConfig} */
    this.config_ = null;

    /** @private {string} */
    this.hideSelector_;

    /** @private {?Element} */
    this.separator_ = null;

    /** @private {?../../../src/service/resources-impl.Resources} */
    this.resources_ = null;

    /** @private {?MultidocManager} */
    this.multidocManager_ = null;

    /** @private {number} */
    this.nextArticle_ = 0;

    /** @private {boolean} */
    this.documentQueued_ = false;

    /** @private {?../../../src/service/viewer-impl.Viewer} */
    this.viewer_ = null;

    /** @private {?../../../src/service/viewport/viewport-impl.Viewport} */
    this.viewport_ = null;

    /** @private {?../../../src/service/position-observer/position-observer-impl.PositionObserver} */
    this.positionObserver_ = null;

    /** @private @const {!Array<!DocumentRef>} */
    this.documentRefs_ = [];

    /** @private {?DocumentRef} */
    this.activeDocumentRef_ = null;

    /** @private {function(!Element): !Promise} */
    this.appendPageHandler_ = () => {};
  }

  /** Returns true if the service has already been initialized. */
  isActive() {
    return this.config_ !== null;
  }

  /**
   * Registers the window-scoped service against the specified {@code
   * recommendationsOb}. Only the first call to this method will be used, any
   * subsequent calls will be ignored.
   * @param {!Element} element {@link AmpNextPage} element.
   * @param {!./config.AmpNextPageConfig} config Element configuration.
   * @param {?Element} separator Separator element to display between pages. If
   *     none is specified a default hairline separator will be used.
   */
  register(element, config, separator) {
    if (this.isActive()) {
      return;
    }

    const ampDoc = getAmpdoc(element);
    const {win} = ampDoc;

    this.config_ = config;
    this.win_ = win;
    this.separator_ = separator || this.createDefaultSeparator_();
    this.element_ = element;

    if (this.config_.hideSelectors) {
      this.hideSelector_ = this.config_.hideSelectors.join(',');
    }

    this.viewer_ = Services.viewerForDoc(ampDoc);
    this.viewport_ = Services.viewportForDoc(ampDoc);
    this.resources_ = Services.resourcesForDoc(ampDoc);
    this.multidocManager_ =
        new MultidocManager(win, Services.ampdocServiceFor(win),
            Services.extensionsFor(win), Services.timerFor(win));

    installPositionObserverServiceForDoc(ampDoc);
    this.positionObserver_ = getServiceForDoc(ampDoc, 'position-observer');

    const documentRef =
        createDocumentRef(win.document.location.url, win.document.title);
    this.documentRefs_.push(documentRef);
    this.activeDocumentRef_ = this.documentRefs_[0];

    this.viewport_.onScroll(() => this.scrollHandler_());
    this.viewport_.onResize(() => this.scrollHandler_());

    // Check scroll position immediately to handle documents which are shorter
    // than the viewport.
    this.scrollHandler_();
  }

  /**
   * Sets the handler to be called with a
   * @param {function(!Element): !Promise} handler Handler to be called when
   *     a new page needs adding to the DOM, with a container element for that
   *     page.
   */
  setAppendPageHandler(handler) {
    this.appendPageHandler_ = handler;
  }

  /**
   * Attach a ShadowDoc using the given document.
   * @param {!Element} shadowRoot Root element to attach the shadow document to.
   * @param {!Document} doc Document to attach.
   * @return {?Object} Return value of {@link MultidocManager#attachShadowDoc}
   */
  attachShadowDoc_(shadowRoot, doc) {
    if (this.hideSelector_) {
      const elements = doc.querySelectorAll(this.hideSelector_);
      for (let i = 0; i < elements.length; i++) {
        elements[i].classList.add('i-amphtml-next-page-hidden');
      }
    }

    // Drop any amp-analytics tags from the child doc. We want to reuse the
    // parent config instead.
    const analytics = doc.querySelectorAll('amp-analytics');
    for (let i = 0; i < analytics.length; i++) {
      const item = analytics[i];
      removeElement(item);
    }

    const amp =
        this.multidocManager_.attachShadowDoc(shadowRoot, doc, '', {});
    installStylesForDoc(amp.ampdoc, CSS, null, false, TAG);

    const body = amp.ampdoc.getBody();
    body.classList.add('i-amphtml-next-page-document');

    return amp;
  }

  /**
   * Creates a default hairline separator element to go between two documents.
   * @return {!Element}
   */
  createDefaultSeparator_() {
    const separator = this.win_.document.createElement('div');
    separator.classList.add('amp-next-page-default-separator');
    return separator;
  }

  /**
   * Append a new article if still possible.
   */
  appendNextArticle_() {
    if (this.nextArticle_ < this.config_.pages.length) {
      const next = this.config_.pages[this.nextArticle_];
      const documentRef = createDocumentRef(next.ampUrl);
      this.documentRefs_.push(documentRef);

      const container = this.win_.document.createElement('div');

      const separator = this.separator_.cloneNode(true);
      separator.removeAttribute('separator');
      container.appendChild(separator);

      const articleLinks = this.createArticleLinks_(this.nextArticle_);
      container.appendChild(articleLinks);
      documentRef.recUnit.el = articleLinks;

      const shadowRoot = this.win_.document.createElement('div');
      container.appendChild(shadowRoot);

      const page = this.nextArticle_;
      this.appendPageHandler_(container).then(() => {
        this.positionObserver_.observe(separator, PositionObserverFidelity.LOW,
            position => this.positionUpdate_(page, position));
        this.positionObserver_.observe(articleLinks,
            PositionObserverFidelity.LOW,
            unused => this.articleLinksPositionUpdate_(documentRef));
      });

      // Don't fetch the next article if we've rendered the maximum on screen.
      // We just want the article links.
      if (this.nextArticle_ >= MAX_ARTICLES) {
        return;
      }

      this.nextArticle_++;
      fetchDocument(/** @type {!Window} */ (this.win_), next.ampUrl, {ampCors: false})
          .then(doc => new Promise((resolve, reject) => {
            if (documentRef.cancelled) {
              // User has reached the end of the document already, don't render.
              resolve();
              return;
            }

            if (documentRef.recUnit.isObserving) {
              this.positionObserver_.unobserve(articleLinks);
              documentRef.recUnit.isObserving = true;
            }
            this.resources_.mutateElement(container, () => {
              try {
                const amp = this.attachShadowDoc_(shadowRoot, doc);
                documentRef.amp = amp;

                setStyle(documentRef.recUnit.el, 'display', 'none');
                this.documentQueued_ = false;
                resolve();
              } catch (e) {
                reject(e);
              }
            });
          }),
          e => dev().error(TAG, `failed to fetch ${next.ampUrl}`, e))
          .catch(e => dev().error(TAG,
              `failed to attach shadow document for ${next.ampUrl}`, e))
          // The new page may be short and the next may already need fetching.
          .then(() => this.scrollHandler_());
    }
  }

  /**
   * Creates a recommendation unit with links to articles, starting from a given
   * one.
   * @param {number} nextPage Index of the next unseen page to use as the first
   *     recommendation in the list.
   * @return {!Element} Container element for the recommendations.
   */
  createArticleLinks_(nextPage) {
    const doc = this.win_.document;
    const currentArticle = nextPage - 1;
    let article = nextPage;
    let currentAmpUrl = '';
    if (nextPage > 0) {
      currentAmpUrl = this.documentRefs_[currentArticle].ampUrl;
    }

    const element = doc.createElement('div');
    element.classList.add('amp-next-page-links');

    while (article < this.config_.pages.length &&
           article - nextPage < SEPARATOR_RECOS) {
      const next = this.config_.pages[article];
      article++;

      const articleHolder = doc.createElement('a');
      articleHolder.href = next.ampUrl;
      articleHolder.classList.add(
          'i-amphtml-reco-holder-article', 'amp-next-page-link');
      articleHolder.addEventListener('click', e => {
        this.triggerAnalyticsEvent_(
            'amp-next-page-click', next.ampUrl, currentAmpUrl);
        const a2a =
            this.viewer_.navigateToAmpUrl(next.ampUrl, 'content-discovery');
        if (a2a) {
          // A2A is enabled, don't navigate the browser.
          e.preventDefault();
        }
      });

      const imageElement = doc.createElement('div');
      imageElement.classList.add(
          'i-amphtml-next-article-image', 'amp-next-page-image');
      setStyle(imageElement, 'background-image', `url(${next.image})`);
      articleHolder.appendChild(imageElement);

      const titleElement = doc.createElement('div');
      titleElement.classList.add(
          'i-amphtml-next-article-title', 'amp-next-page-text');

      titleElement.textContent = next.title;
      articleHolder.appendChild(titleElement);

      element.appendChild(articleHolder);
    }

    return element;
  }

  /**
   * Handles scroll events from the viewport and appends the next document when
   * the user comes within {@code PRERENDER_VIEWPORT_COUNT} viewports of the
   * end.
   * @private
   */
  scrollHandler_() {
    if (this.documentQueued_) {
      return;
    }

    const viewportSize = this.viewport_.getSize();
    const viewportBox =
        layoutRectLtwh(0, 0, viewportSize.width, viewportSize.height);
    this.viewport_.getClientRectAsync(dev().assertElement(this.element_))
        .then(elementBox => {
          if (this.documentQueued_) {
            return;
          }

          const prerenderHeight =
              PRERENDER_VIEWPORT_COUNT * viewportSize.height;
          if (elementBox.bottom - viewportBox.bottom < prerenderHeight) {
            this.documentQueued_ = true;
            this.appendNextArticle_();
          }
        });
  }

  /**
   * Handles updates from the {@code PositionObserver} indicating a change in
   * the position of a page separator in the viewport.
   * @param {number} i Index of the documentRef this recommendation unit is
   *     attached to.
   * @param {?../../../src/service/position-observer/position-observer-worker.PositionInViewportEntryDef} position
   *     Position of the current recommendation unit in the viewport.
   */
  positionUpdate_(i, position) {
    // We're only interested when the recommendations exit the viewport
    if (!position || position.positionRect !== null) {
      return;
    }

    let documentRef;
    let analyticsEvent = '';

    if (position.relativePos === 'top') {
      documentRef = this.documentRefs_[i + 1];
      analyticsEvent = 'amp-next-page-scroll';
    } else if (position.relativePos === 'bottom') {
      documentRef = this.documentRefs_[i];
      analyticsEvent = 'amp-next-page-scroll-back';
    }

    if (documentRef && documentRef.amp) {
      this.triggerAnalyticsEvent_(analyticsEvent,
          documentRef.ampUrl, this.activeDocumentRef_.ampUrl);
      this.setActiveDocument_(documentRef);
    }
  }

  /**
   * Handles updates from the {@code PositionObserver} indicating a change in
   * the position of the recommendation unit in the viewport. Used to indicate
   * when the recommendation unit has entered the viewport, and should not be
   * hidden from view automatically.
   * @param {!DocumentRef} documentRef Reference to the active document.
   */
  articleLinksPositionUpdate_(documentRef) {
    documentRef.cancelled = true;
    if (documentRef.recUnit.isObserving) {
      this.positionObserver_.unobserve(
          dev().assertElement(documentRef.recUnit.el));
      documentRef.recUnit.isObserving = false;
    }
  }

  /**
   * Sets the specified document as active, updating the document title and URL.
   * @param {!DocumentRef} documentRef Reference to the document to set as
   *     active.
   * @private
   */
  setActiveDocument_(documentRef) {
    const {amp} = documentRef;
    this.win_.document.title = amp.title || '';
    this.activeDocumentRef_ = documentRef;
    this.setActiveDocumentInHistory_(documentRef);

    // TODO(peterjosling): Send request to viewer with title/URL
    // TODO(emarchiori): Consider updating position fixed elements.
  }

  /**
   * @param {!DocumentRef} documentRef
   * @private
   */
  setActiveDocumentInHistory_(documentRef) {
    if (!this.win_.history || !this.win_.history.replaceState) {
      return;
    }

    const urlService = Services.urlForDoc(dev().assertElement(this.element_));
    const {title} = documentRef.amp;
    const {pathname, search} = urlService.parse(documentRef.ampUrl);
    this.win_.history.replaceState({}, title, pathname + search);
  }

  /**
   * Wrapper around {@code triggerAnalyticsEvent}.
   * @param {string} eventType
   * @param {string} toURL The new url after the event.
   * @param {string=} fromURL The old URL before the event.
   */
  triggerAnalyticsEvent_(eventType, toURL, fromURL) {
    fromURL = fromURL || '';

    const vars = {toURL, fromURL};
    triggerAnalyticsEvent(dev().assertElement(this.element_), eventType, vars);
  }
}

/**
 * Creates a new {@link DocumentRef} for the specified URL.
 * @param {string} ampUrl AMP URL of the document.
 * @param {string=} title Document title, if known before loading.
 * @return {!DocumentRef} Ref object initialised with the given URL.
 */
function createDocumentRef(ampUrl, title) {
  const amp = (title) ? {title} : null;
  return {
    ampUrl,
    amp,
    recUnit: {
      el: null,
      isObserving: false,
    },
    cancelled: false,
  };
}
<commit_msg>🐛 amp-next-page: Fix initial documentRef ampUrl assignment (#17599)<commit_after>/**
 * Copyright 2018 The AMP HTML Authors. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS-IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

import {CSS} from '../../../build/amp-next-page-0.1.css';
import {MultidocManager} from '../../../src/runtime';
import {PositionObserverFidelity} from '../../../src/service/position-observer/position-observer-worker';
import {Services} from '../../../src/services';
import {dev} from '../../../src/log';
import {fetchDocument} from '../../../src/document-fetcher';
import {getAmpdoc, getServiceForDoc} from '../../../src/service';
import {
  installPositionObserverServiceForDoc,
} from '../../../src/service/position-observer/position-observer-impl';
import {installStylesForDoc} from '../../../src/style-installer';
import {layoutRectLtwh} from '../../../src/layout-rect';
import {removeElement} from '../../../src/dom';
import {setStyle} from '../../../src/style';
import {triggerAnalyticsEvent} from '../../../src/analytics';

// TODO(emarchiori): Make this a configurable parameter.
const SEPARATOR_RECOS = 3;

const MAX_ARTICLES = 2;

const PRERENDER_VIEWPORT_COUNT = 3;

const TAG = 'amp-next-page';

/**
 * @typedef {{
 *   ampUrl: string,
 *   amp: ?Object,
 *   recUnit: {el: ?Element, isObserving: boolean},
 *   cancelled: boolean
 * }}
 */
export let DocumentRef;

/**
 * Window-scoped service to handle the amp-next-page lifecycle. Handles all
 * events and page lifecycle for the first {@code AmpNextPage} element
 * registered. All subsequent registrations will be ignored.
 */
export class NextPageService {
  /**
   * Creates an instance of NextPageService.
   */
  constructor() {
    /** @private {?Window} */
    this.win_ = null;

    /** @private {?Element} */
    this.element_ = null;

    /** @private {?./config.AmpNextPageConfig} */
    this.config_ = null;

    /** @private {string} */
    this.hideSelector_;

    /** @private {?Element} */
    this.separator_ = null;

    /** @private {?../../../src/service/resources-impl.Resources} */
    this.resources_ = null;

    /** @private {?MultidocManager} */
    this.multidocManager_ = null;

    /** @private {number} */
    this.nextArticle_ = 0;

    /** @private {boolean} */
    this.documentQueued_ = false;

    /** @private {?../../../src/service/viewer-impl.Viewer} */
    this.viewer_ = null;

    /** @private {?../../../src/service/viewport/viewport-impl.Viewport} */
    this.viewport_ = null;

    /** @private {?../../../src/service/position-observer/position-observer-impl.PositionObserver} */
    this.positionObserver_ = null;

    /** @private @const {!Array<!DocumentRef>} */
    this.documentRefs_ = [];

    /** @private {?DocumentRef} */
    this.activeDocumentRef_ = null;

    /** @private {function(!Element): !Promise} */
    this.appendPageHandler_ = () => {};
  }

  /** Returns true if the service has already been initialized. */
  isActive() {
    return this.config_ !== null;
  }

  /**
   * Registers the window-scoped service against the specified {@code
   * recommendationsOb}. Only the first call to this method will be used, any
   * subsequent calls will be ignored.
   * @param {!Element} element {@link AmpNextPage} element.
   * @param {!./config.AmpNextPageConfig} config Element configuration.
   * @param {?Element} separator Separator element to display between pages. If
   *     none is specified a default hairline separator will be used.
   */
  register(element, config, separator) {
    if (this.isActive()) {
      return;
    }

    const ampDoc = getAmpdoc(element);
    const {win} = ampDoc;

    this.config_ = config;
    this.win_ = win;
    this.separator_ = separator || this.createDefaultSeparator_();
    this.element_ = element;

    if (this.config_.hideSelectors) {
      this.hideSelector_ = this.config_.hideSelectors.join(',');
    }

    this.viewer_ = Services.viewerForDoc(ampDoc);
    this.viewport_ = Services.viewportForDoc(ampDoc);
    this.resources_ = Services.resourcesForDoc(ampDoc);
    this.multidocManager_ =
        new MultidocManager(win, Services.ampdocServiceFor(win),
            Services.extensionsFor(win), Services.timerFor(win));

    installPositionObserverServiceForDoc(ampDoc);
    this.positionObserver_ = getServiceForDoc(ampDoc, 'position-observer');

    const documentRef =
        createDocumentRef(win.document.location.href, win.document.title);
    this.documentRefs_.push(documentRef);
    this.activeDocumentRef_ = this.documentRefs_[0];

    this.viewport_.onScroll(() => this.scrollHandler_());
    this.viewport_.onResize(() => this.scrollHandler_());

    // Check scroll position immediately to handle documents which are shorter
    // than the viewport.
    this.scrollHandler_();
  }

  /**
   * Sets the handler to be called with a
   * @param {function(!Element): !Promise} handler Handler to be called when
   *     a new page needs adding to the DOM, with a container element for that
   *     page.
   */
  setAppendPageHandler(handler) {
    this.appendPageHandler_ = handler;
  }

  /**
   * Attach a ShadowDoc using the given document.
   * @param {!Element} shadowRoot Root element to attach the shadow document to.
   * @param {!Document} doc Document to attach.
   * @return {?Object} Return value of {@link MultidocManager#attachShadowDoc}
   */
  attachShadowDoc_(shadowRoot, doc) {
    if (this.hideSelector_) {
      const elements = doc.querySelectorAll(this.hideSelector_);
      for (let i = 0; i < elements.length; i++) {
        elements[i].classList.add('i-amphtml-next-page-hidden');
      }
    }

    // Drop any amp-analytics tags from the child doc. We want to reuse the
    // parent config instead.
    const analytics = doc.querySelectorAll('amp-analytics');
    for (let i = 0; i < analytics.length; i++) {
      const item = analytics[i];
      removeElement(item);
    }

    const amp =
        this.multidocManager_.attachShadowDoc(shadowRoot, doc, '', {});
    installStylesForDoc(amp.ampdoc, CSS, null, false, TAG);

    const body = amp.ampdoc.getBody();
    body.classList.add('i-amphtml-next-page-document');

    return amp;
  }

  /**
   * Creates a default hairline separator element to go between two documents.
   * @return {!Element}
   */
  createDefaultSeparator_() {
    const separator = this.win_.document.createElement('div');
    separator.classList.add('amp-next-page-default-separator');
    return separator;
  }

  /**
   * Append a new article if still possible.
   */
  appendNextArticle_() {
    if (this.nextArticle_ < this.config_.pages.length) {
      const next = this.config_.pages[this.nextArticle_];
      const documentRef = createDocumentRef(next.ampUrl);
      this.documentRefs_.push(documentRef);

      const container = this.win_.document.createElement('div');

      const separator = this.separator_.cloneNode(true);
      separator.removeAttribute('separator');
      container.appendChild(separator);

      const articleLinks = this.createArticleLinks_(this.nextArticle_);
      container.appendChild(articleLinks);
      documentRef.recUnit.el = articleLinks;

      const shadowRoot = this.win_.document.createElement('div');
      container.appendChild(shadowRoot);

      const page = this.nextArticle_;
      this.appendPageHandler_(container).then(() => {
        this.positionObserver_.observe(separator, PositionObserverFidelity.LOW,
            position => this.positionUpdate_(page, position));
        this.positionObserver_.observe(articleLinks,
            PositionObserverFidelity.LOW,
            unused => this.articleLinksPositionUpdate_(documentRef));
      });

      // Don't fetch the next article if we've rendered the maximum on screen.
      // We just want the article links.
      if (this.nextArticle_ >= MAX_ARTICLES) {
        return;
      }

      this.nextArticle_++;
      fetchDocument(/** @type {!Window} */ (this.win_), next.ampUrl, {ampCors: false})
          .then(doc => new Promise((resolve, reject) => {
            if (documentRef.cancelled) {
              // User has reached the end of the document already, don't render.
              resolve();
              return;
            }

            if (documentRef.recUnit.isObserving) {
              this.positionObserver_.unobserve(articleLinks);
              documentRef.recUnit.isObserving = true;
            }
            this.resources_.mutateElement(container, () => {
              try {
                const amp = this.attachShadowDoc_(shadowRoot, doc);
                documentRef.amp = amp;

                setStyle(documentRef.recUnit.el, 'display', 'none');
                this.documentQueued_ = false;
                resolve();
              } catch (e) {
                reject(e);
              }
            });
          }),
          e => dev().error(TAG, `failed to fetch ${next.ampUrl}`, e))
          .catch(e => dev().error(TAG,
              `failed to attach shadow document for ${next.ampUrl}`, e))
          // The new page may be short and the next may already need fetching.
          .then(() => this.scrollHandler_());
    }
  }

  /**
   * Creates a recommendation unit with links to articles, starting from a given
   * one.
   * @param {number} nextPage Index of the next unseen page to use as the first
   *     recommendation in the list.
   * @return {!Element} Container element for the recommendations.
   */
  createArticleLinks_(nextPage) {
    const doc = this.win_.document;
    const currentArticle = nextPage - 1;
    let article = nextPage;
    let currentAmpUrl = '';
    if (nextPage > 0) {
      currentAmpUrl = this.documentRefs_[currentArticle].ampUrl;
    }

    const element = doc.createElement('div');
    element.classList.add('amp-next-page-links');

    while (article < this.config_.pages.length &&
           article - nextPage < SEPARATOR_RECOS) {
      const next = this.config_.pages[article];
      article++;

      const articleHolder = doc.createElement('a');
      articleHolder.href = next.ampUrl;
      articleHolder.classList.add(
          'i-amphtml-reco-holder-article', 'amp-next-page-link');
      articleHolder.addEventListener('click', e => {
        this.triggerAnalyticsEvent_(
            'amp-next-page-click', next.ampUrl, currentAmpUrl);
        const a2a =
            this.viewer_.navigateToAmpUrl(next.ampUrl, 'content-discovery');
        if (a2a) {
          // A2A is enabled, don't navigate the browser.
          e.preventDefault();
        }
      });

      const imageElement = doc.createElement('div');
      imageElement.classList.add(
          'i-amphtml-next-article-image', 'amp-next-page-image');
      setStyle(imageElement, 'background-image', `url(${next.image})`);
      articleHolder.appendChild(imageElement);

      const titleElement = doc.createElement('div');
      titleElement.classList.add(
          'i-amphtml-next-article-title', 'amp-next-page-text');

      titleElement.textContent = next.title;
      articleHolder.appendChild(titleElement);

      element.appendChild(articleHolder);
    }

    return element;
  }

  /**
   * Handles scroll events from the viewport and appends the next document when
   * the user comes within {@code PRERENDER_VIEWPORT_COUNT} viewports of the
   * end.
   * @private
   */
  scrollHandler_() {
    if (this.documentQueued_) {
      return;
    }

    const viewportSize = this.viewport_.getSize();
    const viewportBox =
        layoutRectLtwh(0, 0, viewportSize.width, viewportSize.height);
    this.viewport_.getClientRectAsync(dev().assertElement(this.element_))
        .then(elementBox => {
          if (this.documentQueued_) {
            return;
          }

          const prerenderHeight =
              PRERENDER_VIEWPORT_COUNT * viewportSize.height;
          if (elementBox.bottom - viewportBox.bottom < prerenderHeight) {
            this.documentQueued_ = true;
            this.appendNextArticle_();
          }
        });
  }

  /**
   * Handles updates from the {@code PositionObserver} indicating a change in
   * the position of a page separator in the viewport.
   * @param {number} i Index of the documentRef this recommendation unit is
   *     attached to.
   * @param {?../../../src/service/position-observer/position-observer-worker.PositionInViewportEntryDef} position
   *     Position of the current recommendation unit in the viewport.
   */
  positionUpdate_(i, position) {
    // We're only interested when the recommendations exit the viewport
    if (!position || position.positionRect !== null) {
      return;
    }

    let documentRef;
    let analyticsEvent = '';

    if (position.relativePos === 'top') {
      documentRef = this.documentRefs_[i + 1];
      analyticsEvent = 'amp-next-page-scroll';
    } else if (position.relativePos === 'bottom') {
      documentRef = this.documentRefs_[i];
      analyticsEvent = 'amp-next-page-scroll-back';
    }

    if (documentRef && documentRef.amp) {
      this.triggerAnalyticsEvent_(analyticsEvent,
          documentRef.ampUrl, this.activeDocumentRef_.ampUrl);
      this.setActiveDocument_(documentRef);
    }
  }

  /**
   * Handles updates from the {@code PositionObserver} indicating a change in
   * the position of the recommendation unit in the viewport. Used to indicate
   * when the recommendation unit has entered the viewport, and should not be
   * hidden from view automatically.
   * @param {!DocumentRef} documentRef Reference to the active document.
   */
  articleLinksPositionUpdate_(documentRef) {
    documentRef.cancelled = true;
    if (documentRef.recUnit.isObserving) {
      this.positionObserver_.unobserve(
          dev().assertElement(documentRef.recUnit.el));
      documentRef.recUnit.isObserving = false;
    }
  }

  /**
   * Sets the specified document as active, updating the document title and URL.
   * @param {!DocumentRef} documentRef Reference to the document to set as
   *     active.
   * @private
   */
  setActiveDocument_(documentRef) {
    const {amp} = documentRef;
    this.win_.document.title = amp.title || '';
    this.activeDocumentRef_ = documentRef;
    this.setActiveDocumentInHistory_(documentRef);

    // TODO(peterjosling): Send request to viewer with title/URL
    // TODO(emarchiori): Consider updating position fixed elements.
  }

  /**
   * @param {!DocumentRef} documentRef
   * @private
   */
  setActiveDocumentInHistory_(documentRef) {
    if (!this.win_.history || !this.win_.history.replaceState) {
      return;
    }

    const urlService = Services.urlForDoc(dev().assertElement(this.element_));
    const {title} = documentRef.amp;
    const {pathname, search} = urlService.parse(documentRef.ampUrl);
    this.win_.history.replaceState({}, title, pathname + search);
  }

  /**
   * Wrapper around {@code triggerAnalyticsEvent}.
   * @param {string} eventType
   * @param {string} toURL The new url after the event.
   * @param {string=} fromURL The old URL before the event.
   */
  triggerAnalyticsEvent_(eventType, toURL, fromURL) {
    fromURL = fromURL || '';

    const vars = {toURL, fromURL};
    triggerAnalyticsEvent(dev().assertElement(this.element_), eventType, vars);
  }
}

/**
 * Creates a new {@link DocumentRef} for the specified URL.
 * @param {string} ampUrl AMP URL of the document.
 * @param {string=} title Document title, if known before loading.
 * @return {!DocumentRef} Ref object initialised with the given URL.
 */
function createDocumentRef(ampUrl, title) {
  const amp = (title) ? {title} : null;
  return {
    ampUrl,
    amp,
    recUnit: {
      el: null,
      isObserving: false,
    },
    cancelled: false,
  };
}
<|endoftext|>


<commit_before>window.name = 'NG_DEFER_BOOTSTRAP!';

require.config({
    waitSeconds: 120,
    baseUrl : '/app',
    paths: {
      'authentication'      : 'services/authentication',
      'angular'             : 'libs/angular-flex/angular-flex',
      'ngRoute'             : 'libs/angular-route/angular-route.min',
      'ngSanitize'          : 'libs/angular-sanitize/angular-sanitize.min',
      'domReady'            : 'libs/requirejs-domready/domReady',
      'text'                : 'libs/requirejs-text/text',
      'bootstrap'           : 'libs/bootstrap/dist/js/bootstrap.min',
      'lodash'              : 'libs/lodash/lodash.min',
      'URIjs'               : 'libs/uri.js/src',
      'linqjs'              : 'libs/linqjs/linq.min',
      'leaflet'             : 'libs/leaflet/dist/leaflet',
      'jquery'              : 'libs/jquery/dist/jquery.min',
      'moment'              : 'libs/moment/moment',
      'leaflet-directive'   : 'js/libs/leaflet/angular-leaflet-directive',
      'ng-breadcrumbs'      : 'js/libs/ng-breadcrumbs/dist/ng-breadcrumbs.min',
      'bootstrap-datepicker': 'libs/bootstrap-datepicker/js/bootstrap-datepicker',
      'ionsound'            : 'libs/ionsound/js/ion.sound.min',
      'jqvmap'              : 'js/libs/jqvmap/jqvmap/jquery.vmap',
      'jqvmapworld'         : 'js/libs/jqvmap/jqvmap/maps/jquery.vmap.world',
      'ngAnimate'           : 'libs/angular-animate/angular-animate.min',
      'ngAria'              : 'libs/angular-aria/angular-aria.min',
      'ngMaterial'          : 'libs/angular-material/angular-material.min',
      'ngSmoothScroll'      : 'libs/ngSmoothScroll/angular-smooth-scroll.min',
      'ammap3WorldHigh'     : 'directives/reporting-display/worldEUHigh',
      'ammap3'              : 'libs/ammap3/ammap/ammap',
      'ammap-theme'         : 'libs/ammap3/ammap/themes/light',
      'ammap-resp'          : 'libs/ammap3/ammap/plugins/responsive/responsive',
      'ammap-export'        : 'libs/ammap3/ammap/plugins/export/export.min',
      'ammap-ex-fabric'     : 'libs/ammap3/ammap/plugins/export/libs/fabric.js/fabric.min',
      'ammap-ex-filesaver'  : 'libs/ammap3/ammap/plugins/export/libs/FileSaver.js/FileSaver.min',
      'ammap-ex-pdfmake'    : 'libs/ammap3/ammap/plugins/export/libs/pdfmake/pdfmake.min',
      'ammap-ex-vfs-fonts'  : 'libs/ammap3/ammap/plugins/export/libs/pdfmake/vfs_fonts',
      'ammap-ex-jszip'      : 'libs/ammap3/ammap/plugins/export/libs/jszip/jszip.min',
      'ammap-ex-xlsx'       : 'libs/ammap3/ammap/plugins/export/libs/xlsx/xlsx.min',
    },
    shim: {
      'libs/angular/angular'     : { deps: ['jquery'] },
      'angular'                  : { deps: ['libs/angular/angular'] },
      'ngRoute'                  : { deps: ['angular'] },
      'ngSanitize'               : { deps: ['angular'] },
      'leaflet-directive'        : { deps: ['angular', 'leaflet'], exports : 'L' },
      'ng-breadcrumbs'           : { deps: ['angular'] },
      'bootstrap'                : { deps: ['jquery'] },
      'linqjs'                   : { deps: [], exports : 'Enumerable' },
      'leaflet'                  : { deps: [], exports : 'L' },
      'bootstrap-datepicker'     : { deps: ['bootstrap'] },
      'jqvmap'                   : { deps: ['jquery'] },
      'jqvmapworld'              : { deps: ['jqvmap'] },
      'ionsound'                 : { deps: ['jquery'] },
      'ngAnimate'                : { deps: ['angular'] },
      'ngAria'                   : { deps: ['angular'] },
      'ngMaterial'               : { deps: ['angular', 'ngAnimate', 'ngAria'] },
      'ngSmoothScroll'           : { deps: ['angular'] },
      'ammapEU'                  : { deps: ['ammap3'] },
      'ammap3WorldHigh'          : { deps: ['ammap3'] },
      'ammap-theme'              : { deps: ['ammap3']},
      'ammap-resp'               : { deps: ['ammap3']},
      'ammap-export'             : { deps: ['ammap3']}
    },
});

// BOOT

require(['angular', 'domReady!', 'bootstrap', 'app', 'routes', 'index'], function(ng, doc){

    ng.bootstrap(doc, ['kmApp']);
    ng.resumeBootstrap();

});
<commit_msg>remove unused file reference<commit_after>window.name = 'NG_DEFER_BOOTSTRAP!';

require.config({
    waitSeconds: 120,
    baseUrl : '/app',
    paths: {
      'authentication'      : 'services/authentication',
      'angular'             : 'libs/angular-flex/angular-flex',
      'ngRoute'             : 'libs/angular-route/angular-route.min',
      'ngSanitize'          : 'libs/angular-sanitize/angular-sanitize.min',
      'domReady'            : 'libs/requirejs-domready/domReady',
      'text'                : 'libs/requirejs-text/text',
      'bootstrap'           : 'libs/bootstrap/dist/js/bootstrap.min',
      'lodash'              : 'libs/lodash/lodash.min',
      'URIjs'               : 'libs/uri.js/src',
      'linqjs'              : 'libs/linqjs/linq.min',
      'leaflet'             : 'libs/leaflet/dist/leaflet',
      'jquery'              : 'libs/jquery/dist/jquery.min',
      'moment'              : 'libs/moment/moment',
      'leaflet-directive'   : 'js/libs/leaflet/angular-leaflet-directive',
      'ng-breadcrumbs'      : 'js/libs/ng-breadcrumbs/dist/ng-breadcrumbs.min',
      'bootstrap-datepicker': 'libs/bootstrap-datepicker/js/bootstrap-datepicker',
      'ionsound'            : 'libs/ionsound/js/ion.sound.min',
      'jqvmap'              : 'js/libs/jqvmap/jqvmap/jquery.vmap',
      'jqvmapworld'         : 'js/libs/jqvmap/jqvmap/maps/jquery.vmap.world',
      'ngAnimate'           : 'libs/angular-animate/angular-animate.min',
      'ngAria'              : 'libs/angular-aria/angular-aria.min',
      'ngMaterial'          : 'libs/angular-material/angular-material.min',
      'ngSmoothScroll'      : 'libs/ngSmoothScroll/angular-smooth-scroll.min',
      'ammap3WorldHigh'     : 'directives/reporting-display/worldEUHigh',
      'ammap3'              : 'libs/ammap3/ammap/ammap',
      'ammap-theme'         : 'libs/ammap3/ammap/themes/light',
      'ammap-resp'          : 'libs/ammap3/ammap/plugins/responsive/responsive',
      'ammap-export'        : 'libs/ammap3/ammap/plugins/export/export.min',
      'ammap-ex-fabric'     : 'libs/ammap3/ammap/plugins/export/libs/fabric.js/fabric.min',
      'ammap-ex-filesaver'  : 'libs/ammap3/ammap/plugins/export/libs/FileSaver.js/FileSaver.min',
      'ammap-ex-pdfmake'    : 'libs/ammap3/ammap/plugins/export/libs/pdfmake/pdfmake.min',
      'ammap-ex-vfs-fonts'  : 'libs/ammap3/ammap/plugins/export/libs/pdfmake/vfs_fonts',
      'ammap-ex-jszip'      : 'libs/ammap3/ammap/plugins/export/libs/jszip/jszip.min',
      'ammap-ex-xlsx'       : 'libs/ammap3/ammap/plugins/export/libs/xlsx/xlsx.min',
    },
    shim: {
      'libs/angular/angular'     : { deps: ['jquery'] },
      'angular'                  : { deps: ['libs/angular/angular'] },
      'ngRoute'                  : { deps: ['angular'] },
      'ngSanitize'               : { deps: ['angular'] },
      'leaflet-directive'        : { deps: ['angular', 'leaflet'], exports : 'L' },
      'ng-breadcrumbs'           : { deps: ['angular'] },
      'bootstrap'                : { deps: ['jquery'] },
      'linqjs'                   : { deps: [], exports : 'Enumerable' },
      'leaflet'                  : { deps: [], exports : 'L' },
      'bootstrap-datepicker'     : { deps: ['bootstrap'] },
      'jqvmap'                   : { deps: ['jquery'] },
      'jqvmapworld'              : { deps: ['jqvmap'] },
      'ionsound'                 : { deps: ['jquery'] },
      'ngAnimate'                : { deps: ['angular'] },
      'ngAria'                   : { deps: ['angular'] },
      'ngMaterial'               : { deps: ['angular', 'ngAnimate', 'ngAria'] },
      'ngSmoothScroll'           : { deps: ['angular'] },
      'ammap3WorldHigh'          : { deps: ['ammap3'] },
      'ammap-theme'              : { deps: ['ammap3']},
      'ammap-resp'               : { deps: ['ammap3']},
      'ammap-export'             : { deps: ['ammap3']}
    },
});

// BOOT

require(['angular', 'domReady!', 'bootstrap', 'app', 'routes', 'index'], function(ng, doc){

    ng.bootstrap(doc, ['kmApp']);
    ng.resumeBootstrap();

});
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2011  JTalks.org Team
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

var Keymaps = {};

var escCode = 27;
var enterCode = 13;
var charMin = 60;
var charMax = 90;
var tabCode = 9;

Keymaps.review = function (e) {
    if (e.ctrlKey && e.keyCode == enterCode) {
        e.preventDefault();
        $(".review-container-controls-ok").click();
    }
    else if (e.keyCode == escCode) {
        e.preventDefault();
        $(".review-container-controls-cancel").click();
    }
};

Keymaps.reviewConfirmRemoveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(e.target).parents('.modal').find('.cancel').focus();
    }
}

Keymaps.reviewCancelRemoveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(e.target).parents('.modal').find('.btn-primary').focus();
    }
}

Keymaps.registrationSubmit = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signup-modal-dialog').find("#username").focus();
    }
}

Keymaps.registrationPassConfirm = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signup-modal-dialog').find("#captcha").focus();
    }
}

Keymaps.signinSubmit = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signin-modal-dialog').find("#j_username").focus();
    }
}

Keymaps.linksEditor = function (e) {
    if ((e.keyCode || e.charCode) == enterCode) {
        var but = $('#main-links-editor  #save-link:visible')[0]
        if (but && $(e.target).attr('id') != 'cancel-link') {
            e.preventDefault();
            but.click();
        }
    }

    if ((e.keyCode || e.charCode) == escCode) {
        var but = $('#main-links-editor #cancel-link:visible')[0]
        if (but) {
            e.preventDefault();
            but.click();
        }else{
            $('#main-links-editor .close').click();
        }
    }
}

Keymaps.linksEditorRemoveButton = function(e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #cancel-link').focus();
    }
}

Keymaps.linksEditorCancelButton = function(e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        if ($('#main-links-editor #remove-link:visible')[0]) {
            $('#main-links-editor #remove-link').focus();
        } else {
            $('#main-links-editor #link-title').focus();
        }
    }
}

Keymaps.linksEditorHintInput = function(e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #save-link').focus();
    }
}

Keymaps.linksEditorSaveButton = function(e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #cancel-link').focus();
    }
}

Keymaps.uploadBannerCancelButton = function(e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(this).closest("form[id^=uploadBannerModal]").find('#body').focus();
    }
}

Keymaps.moveTopicEditor = function(e) {
    if ((e.keyCode || e.charCode) == escCode) {
        var but = $('#move-topic-editor .close:visible')[0]
        if (but) {
            e.preventDefault();
            but.click();
        }
    }
}

Keymaps.defaultDialog = function (e) {
    //disable submit by enter
    if (e.keyCode == enterCode) {
        e.preventDefault();
        jDialog.dialog.find('.btn-primary:first').click();
    }
    if ((e.keyCode || e.charCode) == escCode) {
        jDialog.dialog.find('.close').click();
    }
}

//post,topic,pm forms
Keymaps.bbeditor = function(e) {
    if (e.ctrlKey && e.keyCode == enterCode) {
        e.preventDefault();
        $('input[type="submit"]').click();
    }
    //check bb-editor toolbar
    if($(e.target).parents('form').find('.btn-toolbar').length > 0){
        //if editor contains button with tooltip Ctrl + <char> than click
        if (e.ctrlKey && e.keyCode >= charMin && e.keyCode <= charMax) {
            var keyVal = String.fromCharCode(e.keyCode);
            var but = $('[data-original-title$="(Ctrl+' + keyVal + ')"]')
            if(but && but.length > 0){
                e.preventDefault();
                but.click();
            }
        }
    }
}

<commit_msg>#JC-1437 fixed<commit_after>/*
 * Copyright (C) 2011  JTalks.org Team
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
 */

var Keymaps = {};

var escCode = 27;
var enterCode = 13;
var charMin = 60;
var charMax = 90;
var tabCode = 9;

Keymaps.review = function (e) {
    if (e.ctrlKey && e.keyCode == enterCode) {
        e.preventDefault();
        $(".review-container-controls-ok").click();
    }
    else if (e.keyCode == escCode) {
        e.preventDefault();
        $(".review-container-controls-cancel").click();
    }
};

Keymaps.reviewConfirmRemoveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(e.target).parents('.modal').find('.cancel').focus();
    }
}

Keymaps.reviewCancelRemoveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(e.target).parents('.modal').find('.btn-primary').focus();
    }
}

Keymaps.registrationSubmit = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signup-modal-dialog').find("#username").focus();
    }
}

Keymaps.registrationPassConfirm = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signup-modal-dialog').find("#captcha").focus();
    }
}

Keymaps.signinSubmit = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#signin-modal-dialog').find("#j_username").focus();
    }
}

Keymaps.linksEditor = function (e) {
    if ((e.keyCode || e.charCode) == enterCode) {
        var but = $('#main-links-editor  #save-link:visible')[0]
        if (but && $(e.target).attr('id') != 'cancel-link') {
            e.preventDefault();
            but.click();
        }
    }

    if ((e.keyCode || e.charCode) == escCode) {
        var but = $('#main-links-editor #cancel-link:visible')[0]
        if (but) {
            e.preventDefault();
            but.click();
        } else {
            $('#main-links-editor .close').click();
        }
    }
}

Keymaps.linksEditorRemoveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #cancel-link').focus();
    }
}

Keymaps.linksEditorCancelButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        if ($('#main-links-editor #remove-link:visible')[0]) {
            $('#main-links-editor #remove-link').focus();
        } else {
            $('#main-links-editor #link-title').focus();
        }
    }
}

Keymaps.linksEditorHintInput = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #save-link').focus();
    }
}

Keymaps.linksEditorSaveButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $('#main-links-editor #cancel-link').focus();
    }
}

Keymaps.uploadBannerCancelButton = function (e) {
    if ((e.keyCode || e.charCode) == tabCode) {
        e.preventDefault();
        $(this).closest("form[id^=uploadBannerModal]").find('#body').focus();
    }
}

Keymaps.moveTopicEditor = function (e) {
    if ((e.keyCode || e.charCode) == escCode) {
        var but = $('#move-topic-editor .close:visible')[0]
        if (but) {
            e.preventDefault();
            but.click();
        }
    }
}

Keymaps.defaultDialog = function (e) {
    //disable submit by enter
    if (e.keyCode == enterCode) {
        //if focus on button then do action of button, else click submit
        if (!$(e.target).hasClass('btn')) {
            e.preventDefault();
            jDialog.dialog.find('.btn-primary:first').click();
        }

    }
    if ((e.keyCode || e.charCode) == escCode) {
        jDialog.dialog.find('.close').click();
    }
}

//post,topic,pm forms
Keymaps.bbeditor = function (e) {
    if (e.ctrlKey && e.keyCode == enterCode) {
        e.preventDefault();
        $('input[type="submit"]').click();
    }
    //check bb-editor toolbar
    if ($(e.target).parents('form').find('.btn-toolbar').length > 0) {
        //if editor contains button with tooltip Ctrl + <char> than click
        if (e.ctrlKey && e.keyCode >= charMin && e.keyCode <= charMax) {
            var keyVal = String.fromCharCode(e.keyCode);
            var but = $('[data-original-title$="(Ctrl+' + keyVal + ')"]')
            if (but && but.length > 0) {
                e.preventDefault();
                but.click();
            }
        }
    }
}

<|endoftext|>