<commit_before>export default class ExpensesService {
  constructor($http, UserService) {
    this.$inject = ['$http', 'UserService'];
    this.http = $http;
    this.UserService = UserService;
    this.expenses = [];
    this.transactions = {};

    this.calculateDebts = this.calculateDebts.bind(this);
    this.sortTransactions = this.sortTransactions.bind(this);
    this.getExpenses = this.getExpenses.bind(this);
    this.roundMoney = this.roundMoney.bind(this);
  }

  // ExpensesService data access methods
  returnExpenses() { return this.expenses; }

  returnTransactions() { return this.transactions; }

  calculateDebts() {
    let owed = 0;
    let debt = 0;
    console.log('Calculate debts', this.transactions);
    for (let id in this.transactions) {
      console.log('inside for loop of calc debts', id, this.transactions);
      this.transactions[id].forEach((transaction) => {
        console.log('transactionId, userid', transaction.to, this.UserService.user.id);
        if (transaction.to === this.UserService.user.id) {
          console.log('to fired');
          owed += transaction.amount;
        } else if (transaction.from === this.UserService.user.id) {
          console.log('from fired');
          debt += transaction.amount;
        }
      });

    }
    return {owed: owed, debt: debt, balance: this.roundMoney(owed - debt)};
  }

  sortTransactions(transactions) {
    this.transactions = {};
    transactions.forEach((transaction) => {
      if (!this.transactions[transaction.expenseId]) {
        this.transactions[transaction.expenseId] = [];
      }
      this.transactions[transaction.expenseId].push(transaction);
    });
  }

  newExpense(expense) {
    return this.http.post('/api/expenses', expense);
  }

  getExpenses(planId) {
    return this.http.get(`/api/expenses/${planId}`).then((res) => {
      this.expenses = res.data.expenses;
      console.log('get expenses', this.expenses);
      this.sortTransactions(res.data.transactions);
    });
  }

  addTransaction(expenseId) {
    return this.http.put(`/api/expenses/add/${expenseId}`).then(() => this.getExpenses());
  }

  removeTransaction(transactionId) {
    return this.http.delete(`/api/expenses/remove/${transactionId}`);
  }

  roundMoney(value) {
    return Number(Math.round(value + 'e+2') + 'e-2').toFixed(2);
  }

}
<commit_msg>Fixed rounding money for owed and debt<commit_after>export default class ExpensesService {
  constructor($http, UserService) {
    this.$inject = ['$http', 'UserService'];
    this.http = $http;
    this.UserService = UserService;
    this.expenses = [];
    this.transactions = {};

    this.calculateDebts = this.calculateDebts.bind(this);
    this.sortTransactions = this.sortTransactions.bind(this);
    this.getExpenses = this.getExpenses.bind(this);
    this.roundMoney = this.roundMoney.bind(this);
  }

  // ExpensesService data access methods
  returnExpenses() { return this.expenses; }

  returnTransactions() { return this.transactions; }

  calculateDebts() {
    let owed = 0;
    let debt = 0;
    console.log('Calculate debts', this.transactions);
    for (let id in this.transactions) {
      console.log('inside for loop of calc debts', id, this.transactions);
      this.transactions[id].forEach((transaction) => {
        console.log('transactionId, userid', transaction.to, this.UserService.user.id);
        if (transaction.to === this.UserService.user.id) {
          console.log('to fired');
          owed += transaction.amount;
        } else if (transaction.from === this.UserService.user.id) {
          console.log('from fired');
          debt += transaction.amount;
        }
      });

    }
    return {owed: this.roundMoney(owed), debt: this.roundMoney(debt), balance: this.roundMoney(owed - debt)};
  }

  sortTransactions(transactions) {
    this.transactions = {};
    transactions.forEach((transaction) => {
      if (!this.transactions[transaction.expenseId]) {
        this.transactions[transaction.expenseId] = [];
      }
      this.transactions[transaction.expenseId].push(transaction);
    });
  }

  newExpense(expense) {
    return this.http.post('/api/expenses', expense);
  }

  getExpenses(planId) {
    return this.http.get(`/api/expenses/${planId}`).then((res) => {
      this.expenses = res.data.expenses;
      console.log('get expenses', this.expenses);
      this.sortTransactions(res.data.transactions);
    });
  }

  addTransaction(expenseId) {
    return this.http.put(`/api/expenses/add/${expenseId}`).then(() => this.getExpenses());
  }

  removeTransaction(transactionId) {
    return this.http.delete(`/api/expenses/remove/${transactionId}`);
  }

  roundMoney(value) {
    return Number(Math.round(value + 'e+2') + 'e-2').toFixed(2);
  }

}
<|endoftext|>


<commit_before>'use strict';

describe('Stories Model', function () {
    var $http;

    beforeEach(module('Angello.Common'));

    beforeEach(module(function($provide) {
        $provide.value('AuthModel', {
            getCurrentUserId: function(){
                return 1;
            }
        });

        $provide.value('ENDPOINT_URI', function(){
            return 'http://test.com';
        })
    }));

    afterEach(inject(function($httpBackend) {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    }));

    it('test1', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {a:3};
        $httpBackend.when('GET', 'https://angello.firebaseio.com/clients/1/stories/.json').respond(response);

        var promise = StoriesModel.all();
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));

    it('test1', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {a:4};
        $httpBackend.when('GET', 'https://angello.firebaseio.com/clients/2/stories/.json').respond(response);

        var promise = StoriesModel.all();
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));
});<commit_msg>Finishing StoriesModle spec<commit_after>'use strict';

describe('Stories Model', function () {

    beforeEach(module('Angello.Common'));

    beforeEach(module(function($provide) {
        $provide.value('AuthModel', {
            getCurrentUserId: function(){
                return 1;
            }
        });

        $provide.constant('ENDPOINT_URI', 'http://test.com/');
    }));

    afterEach(inject(function($httpBackend) {
        $httpBackend.verifyNoOutstandingExpectation();
        $httpBackend.verifyNoOutstandingRequest();
    }));

    it('Should get all', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {};
        $httpBackend.when('GET', 'http://test.com/clients/1/stories/.json').respond(response);

        var promise = StoriesModel.all();
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));

    it('Should fetch', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {};
        $httpBackend.when('GET', 'http://test.com/clients/1/stories/1.json').respond(response);

        var promise = StoriesModel.fetch(1);
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));

    it('Should create', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {};
        $httpBackend.when('POST', 'http://test.com/clients/1/stories/.json').respond(response);

        var promise = StoriesModel.create({});
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));

    it('Should update', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {};
        $httpBackend.when('PUT', 'http://test.com/clients/1/stories/1.json').respond(response);

        var promise = StoriesModel.update(1, {});
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));

    it('Should destroy', inject(function(StoriesModel, $httpBackend, $rootScope) {
        var response = {};
        $httpBackend.when('DELETE', 'http://test.com/clients/1/stories/1.json').respond(response);

        var promise = StoriesModel.destroy(1);
        $httpBackend.flush();

        promise.then(function(result) {
            expect(result.data).toEqual(response);
        });
        $rootScope.$digest();
    }));
});<|endoftext|>


<commit_before>/**
 * jemul8 - JavaScript x86 Emulator
 * http://jemul8.com/
 *
 * Copyright 2013 jemul8.com (http://github.com/asmblah/jemul8)
 * Released under the MIT license
 * http://jemul8.com/MIT-LICENSE.txt
 */

/*global define */
define([
    "module",
    "js/util",
    "js/Jemul8"
], function (
    module,
    util,
    Jemul8
) {
    "use strict";

    var FAILED = 1,
        FINISHED = 2,
        PASSED = 0,
        TEST_PORT = 0x404;

    return {
        defineTest: function (name, callback, tools) {
            var emulator,
                registers;

            tools = tools || {};

            function init(done) {
                emulator = new Jemul8().createEmulator();
                registers = emulator.getCPURegisters();

                util.get("../../asm/tests/bdd/acceptance/real-mode/IODevice/" + name + ".bin").done(function (buffer) {
                    emulator.init().done(function () {
                        // Write harness machine code to memory @ 0x100
                        emulator.write({
                            data: buffer,
                            to:   0x00000100
                        });

                        // Point CPU at first loaded instruction
                        registers.cs.set(0x0000);
                        registers.eip.set(0x00000100);

                        done();
                    });
                });
            }

            (function () {
                var index = -1,
                    tests = [];

                (function nextTest() {
                    var description = "";
                    index += 1;

                    init(function () {
                        registers.ax.set(index);

                        emulator.on("io write", [TEST_PORT], function (value, length) {
                            var toolIndex = registers.ax.get();

                            if (toolIndex === 0) {
                                if (length !== 1) {
                                    throw new Error("Unsupported IO length " + length);
                                }

                                description += String.fromCharCode(value);
                            } else {
                                if (tools[toolIndex]) {
                                    tools[toolIndex](emulator);
                                } else {
                                    throw new Error("Unsupported test tool index: " + toolIndex);
                                }
                            }
                        });

                        // Run the emulator, wait for HLT
                        emulator.run().done(function () {
                            var result = registers.ax.get();

                            if (result === FINISHED) {
                                describe(name + " I/O device acceptance tests", function () {
                                    util.each(tests, function (test) {
                                        var description = test.description,
                                            result = test.result;

                                        it(description, function (done) {
                                            if (result === PASSED) {
                                                done();
                                            } else if (result === FAILED) {
                                                done(new Error("Assertion in VM failed"));
                                            } else {
                                                done(new Error("Invalid result in AX from test runner: " + result));
                                            }
                                        });
                                    });
                                });

                                callback();
                            } else {
                                tests.push({
                                    description: description,
                                    result: result
                                });
                                nextTest();
                            }
                        });
                    });
                }());
            }());
        }
    };
});
<commit_msg>Added support for "beforeEach" with I/O device acceptance tests<commit_after>/**
 * jemul8 - JavaScript x86 Emulator
 * http://jemul8.com/
 *
 * Copyright 2013 jemul8.com (http://github.com/asmblah/jemul8)
 * Released under the MIT license
 * http://jemul8.com/MIT-LICENSE.txt
 */

/*global define */
define([
    "module",
    "js/util",
    "js/Jemul8"
], function (
    module,
    util,
    Jemul8
) {
    "use strict";

    var FAILED = 1,
        FINISHED = 2,
        PASSED = 0,
        TEST_PORT = 0x404;

    return {
        defineTest: function (name, callback, options) {
            var beforeEach,
                emulator,
                registers;

            options = options || {};
            beforeEach = options.beforeEach || function () {};

            function init(done) {
                emulator = new Jemul8().createEmulator();
                registers = emulator.getCPURegisters();

                util.get("../../asm/tests/bdd/acceptance/real-mode/IODevice/" + name + ".bin").done(function (buffer) {
                    emulator.init().done(function () {
                        // Write harness machine code to memory @ 0x100
                        emulator.write({
                            data: buffer,
                            to:   0x00000100
                        });

                        // Point CPU at first loaded instruction
                        registers.cs.set(0x0000);
                        registers.eip.set(0x00000100);

                        done();
                    });
                });
            }

            (function () {
                var index = -1,
                    tests = [];

                (function nextTest() {
                    var description = "";
                    index += 1;

                    init(function () {
                        var options = beforeEach(emulator) || {},
                            helpers = options.helpers || {};

                        registers.ax.set(index);

                        emulator.on("io write", [TEST_PORT], function (value, length) {
                            var toolIndex = registers.ax.get();

                            if (toolIndex === 0) {
                                if (length !== 1) {
                                    throw new Error("Unsupported IO length " + length);
                                }

                                description += String.fromCharCode(value);
                            } else {
                                if (helpers[toolIndex]) {
                                    helpers[toolIndex]();
                                } else {
                                    throw new Error("Unsupported test tool index: " + toolIndex);
                                }
                            }
                        });

                        // Run the emulator, wait for HLT
                        emulator.run().done(function () {
                            var result = registers.ax.get();

                            if (result === FINISHED) {
                                describe(name + " I/O device acceptance tests", function () {
                                    util.each(tests, function (test) {
                                        var description = test.description,
                                            result = test.result;

                                        it(description, function (done) {
                                            if (result === PASSED) {
                                                done();
                                            } else if (result === FAILED) {
                                                done(new Error("Assertion in VM failed"));
                                            } else {
                                                done(new Error("Invalid result in AX from test runner: " + result));
                                            }
                                        });
                                    });
                                });

                                callback();
                            } else {
                                tests.push({
                                    description: description,
                                    result: result
                                });
                                nextTest();
                            }
                        });
                    });
                }());
            }());
        }
    };
});
<|endoftext|>


<commit_before>var async = require('async');
function EngineSmith(engine) {
  this.engine = engine;
}
EngineSmith.prototype = {
  // Create an image from a file via the engine
  'createImage': function (file, cb) {
    var engine = this.engine;
    async.waterfall([
      function createImage (cb) {
        engine.createImage(file, cb);
      },
      function savePath (img, cb) {
        // Save the buffer path to the image
        img._filepath = file;

        // Callback with the image
        cb(null, img);
      }
    ], cb);
  },
  // Sugar function for creating multiple images
  'createImages': function (files, cb) {
    // Map the files into their image counterparts
    // DEV: Magic number of 10 to prevent file descriptor overuse
    async.mapLimit(files, 10, this.createImage.bind(this), cb);
  },
  // Helper to create canvas via engine
  'createCanvas': function (width, height, cb) {
    var engine = this.engine;
    return engine.createCanvas(width, height, cb);
  }
};

// Export EngineSmith
module.exports = EngineSmith;<commit_msg>Added dev note on descriptor limit<commit_after>var async = require('async');
function EngineSmith(engine) {
  this.engine = engine;
}
EngineSmith.prototype = {
  // Create an image from a file via the engine
  'createImage': function (file, cb) {
    var engine = this.engine;
    async.waterfall([
      function createImage (cb) {
        engine.createImage(file, cb);
      },
      function savePath (img, cb) {
        // Save the buffer path to the image
        img._filepath = file;

        // Callback with the image
        cb(null, img);
      }
    ], cb);
  },
  // Sugar function for creating multiple images
  'createImages': function (files, cb) {
    // Map the files into their image counterparts
    // DEV: Magic number of 10 to prevent file descriptor overuse
    // This does not affect perf -- 12 seconds with 300, 11.5 with 10 for 2000 images (derp)
    async.mapLimit(files, 10, this.createImage.bind(this), cb);
  },
  // Helper to create canvas via engine
  'createCanvas': function (width, height, cb) {
    var engine = this.engine;
    return engine.createCanvas(width, height, cb);
  }
};

// Export EngineSmith
module.exports = EngineSmith;<|endoftext|>


<commit_before>const request = require('request');
const discord = require('discord.js');

module.exports = {
    usage: 'server - prints info about the server',
    run: (bot, message) => {
        let embed = new Discord.RichEmbed();
        embed.setTitle("Server Owner")
            .setColor("#ff7260")
            .setAuthor(message.guild.name, msg.guild.iconURL)
            .setDescription(message.guild.owner.user.username)
            .addField("Members", message.guild.members.size, true)
            .addField("Created", message.guild.createdAt.toString(), true)
            .addField("Emojis", message.guild.emojis.size > 0 ? message.guild.emojis.map(d => d.toString()).join(" ") : "None");
        message.channel.sendEmbed(embed)
    }
};<commit_msg>added server command<commit_after>const discord = require('discord.js');

module.exports = {
    usage: 'server - prints info about the server',
    run: (bot, message) => {
        let embed = new discord.RichEmbed();
        embed.setTitle('Server Owner')
            .setColor('#ff7260')
            .setAuthor(message.guild.name, message.guild.iconURL)
            .setDescription(message.guild.owner.user.username)
            .addField('Members', message.guild.members.size, true)
            .addField('Created', message.guild.createdAt.toString(), true)
            .addField('Emojis', message.guild.emojis.size > 0 ? message.guild.emojis.map(d => d.toString()).join(' ') : 'None');
        message.channel.sendEmbed(embed);
    },
};
<|endoftext|>


<commit_before>/* This is file contains the init function for the form editor as well
 * as those methods that didn’t fit anywhere else.
 *
 * The form is stored as Ruby-fied YAML file, e.g. a question is not
 * simply another array entry with many attributes but marked as an
 * Ruby Question Object. That way the YAML file can be directly read
 * into an Ruby object one can work with. Since YAML is easy to read
 * for humans, it was chosen as good-enough way to edit forms before
 * the form editor was created.
 *
 * To be actually able to create the form editor visible to the user,
 * a Ruby-YAML → JS Object → DOM Elements conversion has to be made
 * and the other way round for saving. The JS Object/JSON exists in
 * the editor’s data variable but is only used as intermediate or of
 * it’s convenient to store data there and then create the DOM from it.
 *
 * YAML → JS conversion is handled by JS-YAML. Since the AbstractForm
 * and its subclasses are not part of the standard YAML specs, JS-YAML
 * has been extended a bit. You can find that at the top of json2yaml.js
 *
 * JS → YAML conversion is handled by a modified version of JSON2YAML
 * which is located at the bottom of json2yaml. The main hack is to
 * treat common "rubyobject" named elements specifically so they appear
 * as proper Ruby-YAML objects.
 *
 * JS/DOM conversions are handled in the FormEditor all over the place.
 * Also adds links/buttons and style information to actually present the
 * form to the user while processing. */

function FormEditor() {
  // singleton, via http://stackoverflow.com/a/6876814
  if(arguments.callee.instance)
    return arguments.callee.instance;
  arguments.callee.instance = this;

  this.loadFormFromTextbox();

  // useful for testing
  this.animationSpeed = 500;

  // listeners and other initial setup work
  $("[type=numeric]").numeric({ decimal: false, negative: false });
  this.attachSectionHeadUpdater();
  this.attachQuestionHeadUpdater();
  this.attachChangeListenerForUndo();
  this.attachCollapsers();
  this.attachTextAreaAutosize();
  this.allowSortingCancelByEsc();

  this.checkSectionUpDownLinks();
  this.attachFormSubmit();
  $(document).ready(function() { $F().fixToolBoxScrolling(); });

  this.assert(this.groupTagStack.length == 0, "There are unclosed groups!");

  // hide original text edit box if form editor loaded successfully
  $("#form_content").parents("tr").hide();
}

/* @private
 * Loads the YAML sheet from the default text area and parses it into
 * a FormEditor. Should be only called once in production mode, but may
 * be useful when debugging. */
FormEditor.prototype.loadFormFromTextbox = function() {
  // (re)set default variables
  this.undoData = new Array();
  this.redoData = new Array();
  this.undoTmp = null;
  this.groupTagStack = new Array();
  this.languages = [":en"];
  this.data = this.getValue();
  this.invalidData = false;
  this.generatedHtml = "";

  // parsing
  this.parseAbstractForm(this.data);

  this.toggleSorting(false);
  this.toggleDeleting(false);
  this.toggleDuplicating(false);
};

/* @private
 * Run once function that makes the #form_tools element semi-fixed.
 * Semi-fixed means it should never appear outside of its container
 * while still staying on screen when the container is. */
FormEditor.prototype.fixToolBoxScrolling = function() {
  // via http://stackoverflow.com/a/2468193, adjusted values for our
  // case. Assume only vertical scrolling is possible (lines are to be
  // seen has horizontal). Positions are absolute (relative to beginning
  // of the page).
  var box = $("#form_tools");
  var cont = box.parent();

  // position the top line of the semi-fixed box has. Needs to be
  // detected here, because it changes if the element is set to fixed.
  // Can therefore only assume it does not change -- i.e. the content
  // before it keeps its height.
  var boxTop = box.offset().top;
  // position of the top line of the container. Since we must assume
  // boxTop does not change, there’s no harm doing so here as well.
  var contTop = cont.offset().top;

  var boxHeight = box.height();
  $(window).scroll(function() {
    // top line of pixels visible
    var visTop = $(window).scrollTop();
    // position the bottom line of the container has. Assume height may
    // change.
    var contBot = contTop + cont.height();

    // if the current scroll position is less than the top position of
    // the box it means that there’s still space between the upper
    // window border and box. I.e. if it were set to fixed, it would
    // spill over the top of the container.
    var hitContTop = visTop < boxTop;
    // if the current scroll position plus the height of the box exceeds
    // the position of the container, then the box would spill over the
    // bottom of the container.
    var hitContBottom = visTop+boxHeight > contBot;

    if(hitContTop)
      box.css({ position: "relative", top: "",  right: "" });
    else if(hitContBottom)
      box.css({ position: "absolute", top: contBot-boxHeight, right: "2.1rem" });
    else
      box.css({ position: "fixed", top: "0" , right: "2.1rem"  });
  });

  // run once
  $(window).scroll();
};

/* @public
 * Shortcut to get the FormEditor’s instance. Creates a new one if it
 * doesn’t exist yet. */
function $F() {
  return new FormEditor();
}

/* @public
 * @param Content to append to the FormEditor’s HTML storage string */
FormEditor.prototype.append = function(content) {
  this.generatedHtml += content + "\n";
};

/* @public
 * Determines if the given JS object is a multiple choice question.
 * @param question JS object
 * @return true, iff multiple choice question */
FormEditor.prototype.isQuestionMulti = function(question) {
  this.assert(question["db_column"] != null, "Was not given a question or it doesn’t have a db_column attribute.");
  return $.isArray(question["db_column"]);
};

/* @public
 * @param String to log, if console is available */
FormEditor.prototype.log = function(strng) {
  if(window.console) console.log(strng);
};

/* @public
 * @param String to warn, if console is available */
FormEditor.prototype.warn = function(strng) {
  if(window.console) console.warn(strng);
};

/* @public
 * Inserts a stacktrace in the console, if latter is available. */
FormEditor.prototype.trace = function() {
  if(window.console) console.trace();
}

/* @public
 * Asserts given expression is true, otherwise throws message.
 * @param expression to check
 * @param message to throw, if expression is not true */
FormEditor.prototype.assert = function(expression, message) {
  if (!expression) {
    this.invalidData = true;
    this.trace();
    throw(message);
  }
};

/* @public
 * Checks if the given expression is true; prints the message if it
 * isn’t. If expression is a function, the function will be executed.
 * If there’s no error, it’s assumed everything worked fine, otherwise
 * the message will be printed. The functions return value doesn’t
 * matter.
 * @param expression to check
 * @param message to show, if expression is not true */
FormEditor.prototype.test = function(expression, message) {
  if(typeof expression === "function") {
    try {
      expression.call();
    } catch(err) {
      this.warn(message);
      this.log(err);
    }
  } else if (!expression) {
    this.warn(message);
  }
};

/* Extends jQuery’s array method to include a “unique” function. */
$.extend({
  unique : function(anArray) {
   var result = [];
   $.each(anArray, function(i,v){
      if ($.inArray(v, result) == -1) result.push(v);
   });
   return result;
  }
});
<commit_msg>Alert the user of FormEditor failures<commit_after>/* This is file contains the init function for the form editor as well
 * as those methods that didn’t fit anywhere else.
 *
 * The form is stored as Ruby-fied YAML file, e.g. a question is not
 * simply another array entry with many attributes but marked as an
 * Ruby Question Object. That way the YAML file can be directly read
 * into an Ruby object one can work with. Since YAML is easy to read
 * for humans, it was chosen as good-enough way to edit forms before
 * the form editor was created.
 *
 * To be actually able to create the form editor visible to the user,
 * a Ruby-YAML → JS Object → DOM Elements conversion has to be made
 * and the other way round for saving. The JS Object/JSON exists in
 * the editor’s data variable but is only used as intermediate or of
 * it’s convenient to store data there and then create the DOM from it.
 *
 * YAML → JS conversion is handled by JS-YAML. Since the AbstractForm
 * and its subclasses are not part of the standard YAML specs, JS-YAML
 * has been extended a bit. You can find that at the top of json2yaml.js
 *
 * JS → YAML conversion is handled by a modified version of JSON2YAML
 * which is located at the bottom of json2yaml. The main hack is to
 * treat common "rubyobject" named elements specifically so they appear
 * as proper Ruby-YAML objects.
 *
 * JS/DOM conversions are handled in the FormEditor all over the place.
 * Also adds links/buttons and style information to actually present the
 * form to the user while processing. */

function FormEditor() {
  // singleton, via http://stackoverflow.com/a/6876814
  if(arguments.callee.instance)
    return arguments.callee.instance;
  arguments.callee.instance = this;

  this.loadFormFromTextbox();

  // useful for testing
  this.animationSpeed = 500;

  // listeners and other initial setup work
  $("[type=numeric]").numeric({ decimal: false, negative: false });
  this.attachSectionHeadUpdater();
  this.attachQuestionHeadUpdater();
  this.attachChangeListenerForUndo();
  this.attachCollapsers();
  this.attachTextAreaAutosize();
  this.allowSortingCancelByEsc();

  this.checkSectionUpDownLinks();
  this.attachFormSubmit();
  $(document).ready(function() { $F().fixToolBoxScrolling(); });

  this.assert(this.groupTagStack.length == 0, "There are unclosed groups!");

  // hide original text edit box if form editor loaded successfully
  $("#form_content").parents("tr").hide();
}

/* @private
 * Loads the YAML sheet from the default text area and parses it into
 * a FormEditor. Should be only called once in production mode, but may
 * be useful when debugging. */
FormEditor.prototype.loadFormFromTextbox = function() {
  // (re)set default variables
  this.undoData = new Array();
  this.redoData = new Array();
  this.undoTmp = null;
  this.groupTagStack = new Array();
  this.languages = [":en"];
  this.data = this.getValue();
  this.invalidData = false;
  this.generatedHtml = "";

  // parsing
  this.parseAbstractForm(this.data);

  this.toggleSorting(false);
  this.toggleDeleting(false);
  this.toggleDuplicating(false);
};

/* @private
 * Run once function that makes the #form_tools element semi-fixed.
 * Semi-fixed means it should never appear outside of its container
 * while still staying on screen when the container is. */
FormEditor.prototype.fixToolBoxScrolling = function() {
  // via http://stackoverflow.com/a/2468193, adjusted values for our
  // case. Assume only vertical scrolling is possible (lines are to be
  // seen has horizontal). Positions are absolute (relative to beginning
  // of the page).
  var box = $("#form_tools");
  var cont = box.parent();

  // position the top line of the semi-fixed box has. Needs to be
  // detected here, because it changes if the element is set to fixed.
  // Can therefore only assume it does not change -- i.e. the content
  // before it keeps its height.
  var boxTop = box.offset().top;
  // position of the top line of the container. Since we must assume
  // boxTop does not change, there’s no harm doing so here as well.
  var contTop = cont.offset().top;

  var boxHeight = box.height();
  $(window).scroll(function() {
    // top line of pixels visible
    var visTop = $(window).scrollTop();
    // position the bottom line of the container has. Assume height may
    // change.
    var contBot = contTop + cont.height();

    // if the current scroll position is less than the top position of
    // the box it means that there’s still space between the upper
    // window border and box. I.e. if it were set to fixed, it would
    // spill over the top of the container.
    var hitContTop = visTop < boxTop;
    // if the current scroll position plus the height of the box exceeds
    // the position of the container, then the box would spill over the
    // bottom of the container.
    var hitContBottom = visTop+boxHeight > contBot;

    if(hitContTop)
      box.css({ position: "relative", top: "",  right: "" });
    else if(hitContBottom)
      box.css({ position: "absolute", top: contBot-boxHeight, right: "2.1rem" });
    else
      box.css({ position: "fixed", top: "0" , right: "2.1rem"  });
  });

  // run once
  $(window).scroll();
};

/* @public
 * Shortcut to get the FormEditor’s instance. Creates a new one if it
 * doesn’t exist yet. */
function $F() {
  return new FormEditor();
}

/* @public
 * @param Content to append to the FormEditor’s HTML storage string */
FormEditor.prototype.append = function(content) {
  this.generatedHtml += content + "\n";
};

/* @public
 * Determines if the given JS object is a multiple choice question.
 * @param question JS object
 * @return true, iff multiple choice question */
FormEditor.prototype.isQuestionMulti = function(question) {
  this.assert(question["db_column"] != null, "Was not given a question or it doesn’t have a db_column attribute.");
  return $.isArray(question["db_column"]);
};

/* @public
 * @param String to log, if console is available */
FormEditor.prototype.log = function(strng) {
  if(window.console) console.log(strng);
};

/* @public
 * @param String to warn, if console is available */
FormEditor.prototype.warn = function(strng) {
  if(window.console) console.warn(strng);
};

/* @public
 * Inserts a stacktrace in the console, if latter is available. */
FormEditor.prototype.trace = function() {
  if(window.console) console.trace();
}

/* @public
 * Asserts given expression is true, otherwise throws message.
 * @param expression to check
 * @param message to throw, if expression is not true */
FormEditor.prototype.assert = function(expression, message) {
  if (!expression) {
    this.invalidData = true;
    this.trace();
    alert("The FormEditor… crashed. At least it encountered a situation it can’t handle. Maybe it still works, but you also might have data loss. If you haven’t saved you form yet, reloading will get you to an old version.");
    throw(message);
  }
};

/* @public
 * Checks if the given expression is true; prints the message if it
 * isn’t. If expression is a function, the function will be executed.
 * If there’s no error, it’s assumed everything worked fine, otherwise
 * the message will be printed. The functions return value doesn’t
 * matter.
 * @param expression to check
 * @param message to show, if expression is not true */
FormEditor.prototype.test = function(expression, message) {
  if(typeof expression === "function") {
    try {
      expression.call();
    } catch(err) {
      this.warn(message);
      this.log(err);
    }
  } else if (!expression) {
    this.warn(message);
  }
};

/* Extends jQuery’s array method to include a “unique” function. */
$.extend({
  unique : function(anArray) {
   var result = [];
   $.each(anArray, function(i,v){
      if ($.inArray(v, result) == -1) result.push(v);
   });
   return result;
  }
});
<|endoftext|>


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

  angular
    .module('app')
    .directive('contentHeight', contentHeight);

  contentHeight.inject = ['$window'];

  function contentHeight($window) {
    return {
      restrict: 'A',
      link: link
    };

    function link(scope, element) {
      setHeight();
      angular.element($window).on('resize', function () {
        setHeight();
      });

      function setHeight() {
        element.css({'min-height': $window.innerHeight - angular.element(document).find('.navbar').height() + 'px'});
      }

    }
  }
})();
<commit_msg>fix $inject<commit_after>(function () {
  'use strict';

  angular
    .module('app')
    .directive('contentHeight', contentHeight);

  contentHeight.$inject = ['$window'];

  function contentHeight($window) {
    return {
      restrict: 'A',
      link: link
    };

    function link(scope, element) {
      setHeight();
      angular.element($window).on('resize', function () {
        setHeight();
      });

      function setHeight() {
        element.css({'min-height': $window.innerHeight - angular.element(document).find('.navbar').height() + 'px'});
      }
    }
  }
})();
<|endoftext|>


<commit_before>// Module to control application life.
const {app}           = require('electron');

// Module to create native browser window.
var BrowserWindow = require('browser-window');

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {

  // Module for desktop integration
  var Shell         = require('shell');

  // Module for clipboard copy/paste integration
  var Clipboard     = require('clipboard');

  // Module for native system dialogs
  var Dialog = require('dialog');

  // Module for screens
  var Screen = require('screen');

  // Create a JSON::RPC server object
  var rpc = require('./node_modules/node-json-rpc');
  var server = new rpc.Server({
    port: 3333,
    host: '127.0.0.1',
    path: '/',
    strict: true
  });

  var handle = 0;
  var handleStore = {};
  var eventStore = [];

  server.addMethod('BrowserWindow-new', function(param, callback) {
    param = param || {};
    var x = param.x || 0;
    var y = param.y || 0;
    var width = param.width || 1024;
    var height = param.height || 768;
    var dev_tools_enabled = param.dev_tools_enabled || false;
    var show = param.show || false;
    var frame = param.frame || false;
    var kiosk = param.kiosk || false;

    // Create the browser window.
    var win = new BrowserWindow({
      "x"       : x,
      "y"       : y,
      "width"   : width,
      "height"  : height,
      "show"    : show,
      "frame"   : frame,
      "kiosk"   : kiosk,
    });

    var currentHandle = ++handle;
    handleStore[handle] = win;

    // Open the devtools.
    if(dev_tools_enabled) {
      win.openDevTools();
    }

    callback(0, currentHandle);
  });

  server.addMethod('BrowserWindow-on', function(param, callback) {
    var win = handleStore[param.handle];
    if(win && param.name) {
      win.on(param.name, function() {
        eventStore.push({
          id          : param.id,
          name        : param.name
        });
      });
    } else {
      // Invalid handle id
    }
    callback(0, {});
  });

  server.addMethod('BrowserWindow-load-url', function(param, callback) {
    param = param || {};
    var handle = param.handle;
    var url = param.url || ('file://' + __dirName + '/index.html');

    if(handle) {
      var win = handleStore[handle];
      if(win) {
        win.loadUrl(url);
      } else {
        // Invalid handle id
      }
    } else {
        // Invalid handle id
    }

    callback(0, {});
  });

  server.addMethod('BrowserWindow-show', function(param, callback) {
    param = param || {};
    var handle = param.handle;
    if(handle) {
      var win = handleStore[handle];
      if(win) {
        win.show();
      } else {
        // Invalid handle id
      }
    } else {
        // Invalid handle id
    }

    callback(0, {});
  });

  server.addMethod("get-pending-events", function(param, callback) {
    param = param || {};
    var result = {"events" : eventStore};
    eventStore = [];
    callback(0, result);
  });

  server.addMethod("App-quit", function(param, callback) {
    // We're done...
    setTimeout(function() {
      app.quit();
    }, 500)
    callback(0, {});
  });

  server.addMethod("Shell-show-item-in-folder", function(param, callback) {
    param = param || {};
    Shell.showItemInFolder(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-open-item", function(param, callback) {
    param = param || {};
    Shell.openItem(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-open-external", function(param, callback) {
    param = param || {};
    Shell.openExternal(param.url);
    callback(0, {});
  });

  server.addMethod("Shell-move-item-to-trash", function(param, callback) {
    param = param || {};
    Shell.moveItemToTrash(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-beep", function(param, callback) {
    Shell.beep();
    callback(0, {});
  });

  server.addMethod("Clipboard-read-text", function(param, callback) {
    param = param || {};
    var result =  {text: Clipboard.readText(param.type)};
    callback(0, result);
  });

  server.addMethod("Clipboard-write-text", function(param, callback) {
    param = param || {};
    var text = param.text || '';
    Clipboard.writeText(text, param.type);
    callback(0, {});
  });

  server.addMethod("Clipboard-clear", function(param, callback) {
    Clipboard.clear();
    callback(0, {});
  });

  server.addMethod("Dialog-show-open-dialog", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showOpenDialog(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-save-dialog", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showSaveDialog(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-message-box", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showMessageBox(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-error-box", function(param, callback) {
    param = param || {};
    var text    = param.text || '';
    var content = param.content || '';
    Dialog.showErrorBox(text, content);
    callback(0, {});
  });

  server.addMethod("Screen-on", function(param, callback) {
    console.log("TODO unimplemented Screen-on");
    callback(0, {});
  });

  server.addMethod("Screen-get_cursor_screen_point", function(param, callback) {
    var result =  {"result": Screen.getCursorScreenPoint()};
    callback(0, result);
  });

  server.addMethod("Screen-get_primary_display", function(param, callback) {
    var result =  {"result": Screen.getPrimaryDisplay()};
    callback(0, result);
  });

  server.addMethod("Screen-get-all-displays", function(param, callback) {
    var result =  {"result": Screen.getAllDisplays()};
    callback(0, result);
  });

  server.addMethod("Screen-get-display-nearest-point", function(param, callback) {
    param      = param || {};
    var point  = param.point   || {};
    var result =  {"result": Screen.getDisplayNearestPoint(point)};
    callback(0, result);
  });

  server.addMethod("Screen-get-display-matching", function(param, callback) {
    param      = param || {};
    var rect  = param.rect   || {};
    var result =  {"result": Screen.getDisplayMatching(rect)};
    callback(0, result);
  });

  server.addMethod("Process-versions", function(param, callback) {
    var result =  {"result": process.versions};
    callback(0, result);
  });

  server.addMethod('ping', function(param, callback) {
    callback(0, "pong");
  });

  // Start the server
  server.start(function (error) {
    if (error) {
      // server failed to start
      throw error;
    }
  });

});
<commit_msg>Init browser window properly.<commit_after>// Module to control application life.
const {app}           = require('electron');

// Quit when all windows are closed.
app.on('window-all-closed', function() {
  if (process.platform != 'darwin') {
    app.quit();
  }
});

// This method will be called when Electron has done everything
// initialization and ready for creating browser windows.
app.on('ready', function() {

  // Module for desktop integration
  var Shell         = require('shell');

  // Module for clipboard copy/paste integration
  var Clipboard     = require('clipboard');

  // Module for native system dialogs
  var Dialog = require('dialog');

  // Module for screens
  var Screen = require('screen');

  // Create a JSON::RPC server object
  var rpc = require('./node_modules/node-json-rpc');
  var server = new rpc.Server({
    port: 3333,
    host: '127.0.0.1',
    path: '/',
    strict: true
  });

  var handle = 0;
  var handleStore = {};
  var eventStore = [];

  server.addMethod('BrowserWindow-new', function(param, callback) {
    param = param || {};
    var x = param.x || 0;
    var y = param.y || 0;
    var width = param.width || 1024;
    var height = param.height || 768;
    var dev_tools_enabled = param.dev_tools_enabled || false;
    var show = param.show || false;
    var frame = param.frame || false;
    var kiosk = param.kiosk || false;

    // Create the browser window.
    var win = new app({
      "x"       : x,
      "y"       : y,
      "width"   : width,
      "height"  : height,
      "show"    : show,
      "frame"   : frame,
      "kiosk"   : kiosk,
    });

    var currentHandle = ++handle;
    handleStore[handle] = win;

    // Open the devtools.
    if(dev_tools_enabled) {
      win.openDevTools();
    }

    callback(0, currentHandle);
  });

  server.addMethod('BrowserWindow-on', function(param, callback) {
    var win = handleStore[param.handle];
    if(win && param.name) {
      win.on(param.name, function() {
        eventStore.push({
          id          : param.id,
          name        : param.name
        });
      });
    } else {
      // Invalid handle id
    }
    callback(0, {});
  });

  server.addMethod('BrowserWindow-load-url', function(param, callback) {
    param = param || {};
    var handle = param.handle;
    var url = param.url || ('file://' + __dirName + '/index.html');

    if(handle) {
      var win = handleStore[handle];
      if(win) {
        win.loadUrl(url);
      } else {
        // Invalid handle id
      }
    } else {
        // Invalid handle id
    }

    callback(0, {});
  });

  server.addMethod('BrowserWindow-show', function(param, callback) {
    param = param || {};
    var handle = param.handle;
    if(handle) {
      var win = handleStore[handle];
      if(win) {
        win.show();
      } else {
        // Invalid handle id
      }
    } else {
        // Invalid handle id
    }

    callback(0, {});
  });

  server.addMethod("get-pending-events", function(param, callback) {
    param = param || {};
    var result = {"events" : eventStore};
    eventStore = [];
    callback(0, result);
  });

  server.addMethod("App-quit", function(param, callback) {
    // We're done...
    setTimeout(function() {
      app.quit();
    }, 500)
    callback(0, {});
  });

  server.addMethod("Shell-show-item-in-folder", function(param, callback) {
    param = param || {};
    Shell.showItemInFolder(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-open-item", function(param, callback) {
    param = param || {};
    Shell.openItem(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-open-external", function(param, callback) {
    param = param || {};
    Shell.openExternal(param.url);
    callback(0, {});
  });

  server.addMethod("Shell-move-item-to-trash", function(param, callback) {
    param = param || {};
    Shell.moveItemToTrash(param.full_path);
    callback(0, {});
  });

  server.addMethod("Shell-beep", function(param, callback) {
    Shell.beep();
    callback(0, {});
  });

  server.addMethod("Clipboard-read-text", function(param, callback) {
    param = param || {};
    var result =  {text: Clipboard.readText(param.type)};
    callback(0, result);
  });

  server.addMethod("Clipboard-write-text", function(param, callback) {
    param = param || {};
    var text = param.text || '';
    Clipboard.writeText(text, param.type);
    callback(0, {});
  });

  server.addMethod("Clipboard-clear", function(param, callback) {
    Clipboard.clear();
    callback(0, {});
  });

  server.addMethod("Dialog-show-open-dialog", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showOpenDialog(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-save-dialog", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showSaveDialog(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-message-box", function(param, callback) {
    param = param || {};
    var handle  = param.handle   || -1;
    var win     = handleStore[handle];
    var options = param.options || {};
    var result = { "selected": Dialog.showMessageBox(win, options) };
    callback(0, result);
  });

  server.addMethod("Dialog-show-error-box", function(param, callback) {
    param = param || {};
    var text    = param.text || '';
    var content = param.content || '';
    Dialog.showErrorBox(text, content);
    callback(0, {});
  });

  server.addMethod("Screen-on", function(param, callback) {
    console.log("TODO unimplemented Screen-on");
    callback(0, {});
  });

  server.addMethod("Screen-get_cursor_screen_point", function(param, callback) {
    var result =  {"result": Screen.getCursorScreenPoint()};
    callback(0, result);
  });

  server.addMethod("Screen-get_primary_display", function(param, callback) {
    var result =  {"result": Screen.getPrimaryDisplay()};
    callback(0, result);
  });

  server.addMethod("Screen-get-all-displays", function(param, callback) {
    var result =  {"result": Screen.getAllDisplays()};
    callback(0, result);
  });

  server.addMethod("Screen-get-display-nearest-point", function(param, callback) {
    param      = param || {};
    var point  = param.point   || {};
    var result =  {"result": Screen.getDisplayNearestPoint(point)};
    callback(0, result);
  });

  server.addMethod("Screen-get-display-matching", function(param, callback) {
    param      = param || {};
    var rect  = param.rect   || {};
    var result =  {"result": Screen.getDisplayMatching(rect)};
    callback(0, result);
  });

  server.addMethod("Process-versions", function(param, callback) {
    var result =  {"result": process.versions};
    callback(0, result);
  });

  server.addMethod('ping', function(param, callback) {
    callback(0, "pong");
  });

  // Start the server
  server.start(function (error) {
    if (error) {
      // server failed to start
      throw error;
    }
  });

});
<|endoftext|>


<commit_before>'use strict';

viewModel.MonitoringAlarm = new Object();
var ma = viewModel.MonitoringAlarm;
ma.minDatetemp = new Date();
ma.maxDatetemp = new Date();

ma.minDateRet = new Date();
ma.maxDateRet = new Date();

vm.currentMenu('Alarm Data');
vm.currentTitle('Alarm Data');
vm.isShowDataAvailability(false);
vm.breadcrumb([
    { title: "Monitoring", href: '#' },
    { title: 'Alarm Data', href: viewModel.appName + 'page/monitoringalarm' }]);
var intervalTurbine = null;

ma.UpdateProjectList = function(project) {
    setTimeout(function(){
        $('#projectList').data('kendoDropDownList').value(project);
        $("#projectList").data("kendoDropDownList").trigger("change");
    },1000)
}
ma.UpdateTurbineList = function(turbineList) {
    if(turbineList.length == 0){
         $("#turbineList").multiselect('selectAll', false).multiselect("refresh");
    }else{
        $('#turbineList').multiselect("deselectAll", false).multiselect("refresh");
        $('#turbineList').multiselect('select', turbineList);
    }

}
ma.CreateGrid = function(gridType) {
    app.loading(true);
    $.when(fa.LoadData()).done(function () {
        var COOKIES = {};
        var cookieStr = document.cookie;
        var param = {
            period: fa.period,
            dateStart: fa.dateStart,
            dateEnd: fa.dateEnd,
            turbine: [],
            project: "",
            tipe: gridType,
        };

        if(localStorage.getItem("projectname") !==  null && localStorage.getItem("turbine") !== null) {
            var locTurbine = localStorage.getItem("turbine");
            param.turbine = locTurbine == "" ? [] : [locTurbine];
            param.project = localStorage.getItem("projectname");

            var tabActive = localStorage.getItem("tabActive");

            $.when(ma.UpdateProjectList(param.project)).done(function () {
                setTimeout(function(){
                    ma.UpdateTurbineList(param.turbine);

                    setTimeout(function() {
                        ma.LoadDataAvail(param.project, gridType);
                        if(tabActive !== null){
                            if(tabActive == "alarmRaw" ){
                                $("#alarmrawTab a:first-child").trigger('click');
                            }else{
                                ma.CreateGridAlarm(gridType, param);
                            }
                        }
                    },500);
                app.resetLocalStorage();
                }, 1500);
            });
        } else {
            param.turbine = fa.turbine();
            param.project = fa.project;
            ma.CreateGridAlarm(gridType, param);
        }

    });
}
ma.CreateGridAlarm = function(gridType, param) {
    var gridName = "#alarmGrid"
    var dt = new Date();
    var time = dt.getHours() + "" + dt.getMinutes() + "" + dt.getSeconds();
    var nameFile = "Monitoring Alarm Down_"+ moment(new Date()).format("Y-M-D")+"_"+time;
    var defaultsort = [ { field: "TimeStart", dir: "desc" }, { field: "TimeEnd", dir: "asc" } ]
    var url = viewModel.appName + "monitoringrealtime/getdataalarm";

    if(gridType == "warning") {
        gridName = "#warningGrid"
        nameFile = "Monitoring Alarm Warning";
    }

    if(gridType == "alarmraw"){
        gridName = "#alarmRawGrid"
        nameFile = "Monitoring Alarm Raw";
        defaultsort = [ { field: "TimeStamp", dir: "desc" } ]
    }

    var columns = [{
            field: "turbine",
            title: "Turbine",
            attributes: {
                style: "text-align:center;"
            },
            width: 90
        }, {
            field: "timestart",
            title: "Time Start",
            width: 170,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= moment.utc(data.timestart).format('DD-MMM-YYYY') #       #=moment.utc(data.timestart).format('HH:mm:ss')#"
        }, {
            field: "timeend",
            title: "Time End",
            width: 170,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= (moment.utc(data.timeend).format('DD-MM-YYYY') == '01-01-0001'?'Not yet finished' : (moment.utc(data.timeend).format('DD-MMM-YYYY') #       #=moment.utc(data.timeend).format('HH:mm:ss')))#"
        }, {
            field: "duration",
            title: "Duration (hh:mm:ss)",
             width: 120,
             attributes: {
                style: "text-align:center;"
            },
            template: "#= time(data.duration) #"
        }, {
            field: "alarmcode",
            title: "Alarm Code",
            attributes: {
                style: "text-align:center;"
            },
            width: 90,
        }, {
            field: "alarmdesc",
            title: "Description",
            width: 330
        }];

    if(gridType == "alarmraw"){
        columns = [{
            field: "turbine",
            title: "Turbine",
            attributes: {
                style: "text-align:center;"
            },
            width: 70
        }, {
            field: "timestamp",
            title: "Timestamp",
            width: 120,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= moment.utc(data.timestamp).format('DD-MMM-YYYY') #       #=moment.utc(data.timestamp).format('HH:mm:ss')#"
        }, {
            field: "tag",
            title: "Tag",
             width: 120,
             attributes: {
                style: "text-align:center;"
            },
        }, {
            field: "value",
            title: "Value",
            attributes: {
                style: "text-align:center;"
            },
            width: 70,
            // template: "#= kendo.toString(data.Timestamp,'n2') #"
        }, {
            field: "description",
            title: "Description",
            width: 200
        }, {
            field: "addinfo",
            title: "Note",
            width: 250
        }];
    }

    $(gridName).html('');
    $(gridName).kendoGrid({
        dataSource: {
            serverPaging: true,
            serverSorting: true,
            transport: {
                read: {
                    url: url,
                    type: "POST",
                    data: param,
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                },
                parameterMap: function(options) {
                    return JSON.stringify(options);
                }
            },
            schema: {
                data: function data(res) {
                    if (!app.isFine(res)) {
                        return;
                    }
                    var totalFreq = res.data.Total;
                    var totalHour = res.data.Duration;

                    ma.minDateRet = new Date(res.data.mindate);
                    ma.maxDateRet = new Date(res.data.maxdate);

                    ma.checkCompleteDate()

                    $('#alarm_duration').text((totalHour/3600).toFixed(2));
                    $('#alarm_frequency').text(totalFreq);

                    setTimeout(function(){
                        app.loading(false);
                    }, 300)

                    return res.data.Data;
                },
                total: function data(res) {
                    return res.data.Total;
                }
            },
            pageSize: 10,
            sort: defaultsort,
        },
        // toolbar: ["excel"],
        excel: {
            fileName: nameFile+".xlsx",
            filterable: true,
            allPages: true
        },
        // pdf: {
        //     fileName: nameFile+".pdf",
        // },
        sortable: true,
        pageable: {
            refresh: true,
            pageSizes: true,
            buttonCount: 5
        },
        columns: columns
    });
};

function time(s) {
    return new Date(s * 1e3).toISOString().slice(-13, -5);
}

ma.InitDateValue = function () {
    var maxDateData = new Date();

    var lastStartDate = new Date(Date.UTC(moment(maxDateData).get('year'), maxDateData.getMonth(), maxDateData.getDate(), 0, 0, 0, 0));
    var lastEndDate = new Date(Date.UTC(moment(maxDateData).get('year'), maxDateData.getMonth(), maxDateData.getDate(), 0, 0, 0, 0));

    $('#dateStart').data('kendoDatePicker').value(lastStartDate);
    $('#dateEnd').data('kendoDatePicker').value(lastEndDate);
}

ma.LoadDataAvail = function(projectname, gridType){
    //fa.LoadData();

    var payload = {
        project: projectname,
        tipe: gridType
    };

    toolkit.ajaxPost(viewModel.appName + "monitoringrealtime/getdataalarmavaildate", payload, function (res) {
        if (!app.isFine(res)) {
            return;
        }
        if (res.data.Data.length == 0) {
            res.data.Data = [];
        } else {
            if (res.data.Data.length > 0) {
                ma.minDatetemp = new Date(res.data.Data[0]);
                ma.maxDatetemp = new Date(res.data.Data[1]);
                app.currentDateData = new Date(res.data.Data[1]);

                $('#availabledatestart').html(kendo.toString(moment.utc(ma.minDatetemp).format('DD-MMMM-YYYY')));
                $('#availabledateend').html(kendo.toString(moment.utc(ma.maxDatetemp).format('DD-MMMM-YYYY')));

                $('#dateStart').data('kendoDatePicker').value( new Date(Date.UTC(moment( ma.maxDatetemp).get('year'),  ma.maxDatetemp.getMonth(),  ma.maxDatetemp.getDate() - 7, 0, 0, 0, 0)));
                $('#dateEnd').data('kendoDatePicker').value(kendo.toString(moment.utc(res.data.Data[1]).format('DD-MMM-YYYY')));

                ma.checkCompleteDate();
            }
        }
    });
}

ma.checkCompleteDate = function () {
    var currentDateData = moment.utc(ma.maxDatetemp).format('YYYY-MM-DD');
    var prevDateData = moment.utc(ma.minDatetemp).format('YYYY-MM-DD');

    var dateStart = moment.utc(ma.minDateRet).format('YYYY-MM-DD');
    var dateEnd = moment.utc(ma.maxDateRet).format('YYYY-MM-DD');

    if ((dateEnd > currentDateData) || (dateStart > currentDateData)) {
        fa.infoPeriodIcon(true);
    } else if ((dateEnd < prevDateData) || (dateStart < prevDateData)) {
        fa.infoPeriodIcon(true);
    } else {
        fa.infoPeriodIcon(false);
        fa.infoPeriodRange("");
    }
}

ma.ToByProject = function(){
    setTimeout(function(){
        app.loading(true);
        app.resetLocalStorage();
        var project =  $('#projectList').data('kendoDropDownList').value();
        localStorage.setItem('projectname', project);
        if(localStorage.getItem("projectname")){
            window.location = viewModel.appName + "page/monitoringbyproject";
        }
    },1500);
}

ma.exportToExcel = function(id){
    $("#"+id).getKendoGrid().saveAsExcel();
}

$(document).ready(function(){
    $('#btnRefresh').on('click', function () {
        fa.checkTurbine();
        if($('.nav').find('li.active').find('a.tab-custom').text() == "Alarm Down") {
            ma.CreateGrid("alarm");
        } else if($('.nav').find('li.active').find('a.tab-custom').text() == "Alarm Warning") {
            ma.CreateGrid("warning");
        }else{
            ma.CreateGrid("alarmraw");
        }
    });

    //setTimeout(function() {
        $.when(ma.InitDateValue()).done(function () {
            setTimeout(function() {
                ma.CreateGrid("alarm");
                ma.LoadDataAvail(fa.project, "alarm");
            }, 100);
        });
    //}, 300);

    $('#projectList').kendoDropDownList({
        change: function () {
            var project = $('#projectList').data("kendoDropDownList").value();
            fa.populateTurbine(project);
            ma.LoadDataAvail(project, "alarm");
        }
    });
});
<commit_msg>add column reduce availability<commit_after>'use strict';

viewModel.MonitoringAlarm = new Object();
var ma = viewModel.MonitoringAlarm;
ma.minDatetemp = new Date();
ma.maxDatetemp = new Date();

ma.minDateRet = new Date();
ma.maxDateRet = new Date();

vm.currentMenu('Alarm Data');
vm.currentTitle('Alarm Data');
vm.isShowDataAvailability(false);
vm.breadcrumb([
    { title: "Monitoring", href: '#' },
    { title: 'Alarm Data', href: viewModel.appName + 'page/monitoringalarm' }]);
var intervalTurbine = null;

ma.UpdateProjectList = function(project) {
    setTimeout(function(){
        $('#projectList').data('kendoDropDownList').value(project);
        $("#projectList").data("kendoDropDownList").trigger("change");
    },1000)
}
ma.UpdateTurbineList = function(turbineList) {
    if(turbineList.length == 0){
         $("#turbineList").multiselect('selectAll', false).multiselect("refresh");
    }else{
        $('#turbineList').multiselect("deselectAll", false).multiselect("refresh");
        $('#turbineList').multiselect('select', turbineList);
    }

}
ma.CreateGrid = function(gridType) {
    app.loading(true);
    $.when(fa.LoadData()).done(function () {
        var COOKIES = {};
        var cookieStr = document.cookie;
        var param = {
            period: fa.period,
            dateStart: fa.dateStart,
            dateEnd: fa.dateEnd,
            turbine: [],
            project: "",
            tipe: gridType,
        };

        if(localStorage.getItem("projectname") !==  null && localStorage.getItem("turbine") !== null) {
            var locTurbine = localStorage.getItem("turbine");
            param.turbine = locTurbine == "" ? [] : [locTurbine];
            param.project = localStorage.getItem("projectname");

            var tabActive = localStorage.getItem("tabActive");

            $.when(ma.UpdateProjectList(param.project)).done(function () {
                setTimeout(function(){
                    ma.UpdateTurbineList(param.turbine);

                    setTimeout(function() {
                        ma.LoadDataAvail(param.project, gridType);
                        if(tabActive !== null){
                            if(tabActive == "alarmRaw" ){
                                $("#alarmrawTab a:first-child").trigger('click');
                            }else{
                                ma.CreateGridAlarm(gridType, param);
                            }
                        }
                    },500);
                app.resetLocalStorage();
                }, 1500);
            });
        } else {
            param.turbine = fa.turbine();
            param.project = fa.project;
            ma.CreateGridAlarm(gridType, param);
        }

    });
}
ma.CreateGridAlarm = function(gridType, param) {
    var gridName = "#alarmGrid"
    var dt = new Date();
    var time = dt.getHours() + "" + dt.getMinutes() + "" + dt.getSeconds();
    var nameFile = "Monitoring Alarm Down_"+ moment(new Date()).format("Y-M-D")+"_"+time;
    var defaultsort = [ { field: "TimeStart", dir: "desc" }, { field: "TimeEnd", dir: "asc" } ]
    var url = viewModel.appName + "monitoringrealtime/getdataalarm";

    if(gridType == "warning") {
        gridName = "#warningGrid"
        nameFile = "Monitoring Alarm Warning";
    }

    if(gridType == "alarmraw"){
        gridName = "#alarmRawGrid"
        nameFile = "Monitoring Alarm Raw";
        defaultsort = [ { field: "TimeStamp", dir: "desc" } ]
    }

    var columns = [{
            field: "turbine",
            title: "Turbine",
            attributes: {
                style: "text-align:center;"
            },
            width: 90
        }, {
            field: "timestart",
            title: "Time Start",
            width: 170,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= moment.utc(data.timestart).format('DD-MMM-YYYY') #       #=moment.utc(data.timestart).format('HH:mm:ss')#"
        }, {
            field: "timeend",
            title: "Time End",
            width: 170,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= (moment.utc(data.timeend).format('DD-MM-YYYY') == '01-01-0001'?'Not yet finished' : (moment.utc(data.timeend).format('DD-MMM-YYYY') #       #=moment.utc(data.timeend).format('HH:mm:ss')))#"
        }, {
            field: "duration",
            title: "Duration (hh:mm:ss)",
             width: 120,
             attributes: {
                style: "text-align:center;"
            },
            template: "#= time(data.duration) #"
        }, {
            field: "alarmcode",
            title: "Alarm Code",
            attributes: {
                style: "text-align:center;"
            },
            width: 90,
        },{
            field: "alarmdesc",
            title: "Description",
            width: 300
        }];

    if(gridType == "alarm"){
        columns.push({
            field: "reduceavailability",
            title: "Reduce Availability",
            attributes: {
                style: "text-align:center;"
            },
            width: 120,
        });
    }

    if(gridType == "alarmraw"){
        columns = [{
            field: "turbine",
            title: "Turbine",
            attributes: {
                style: "text-align:center;"
            },
            width: 70
        }, {
            field: "timestamp",
            title: "Timestamp",
            width: 120,
            attributes: {
                style: "text-align:center;"
            },
            template: "#= moment.utc(data.timestamp).format('DD-MMM-YYYY') #       #=moment.utc(data.timestamp).format('HH:mm:ss')#"
        }, {
            field: "tag",
            title: "Tag",
             width: 120,
             attributes: {
                style: "text-align:center;"
            },
        }, {
            field: "value",
            title: "Value",
            attributes: {
                style: "text-align:center;"
            },
            width: 70,
            // template: "#= kendo.toString(data.Timestamp,'n2') #"
        }, {
            field: "description",
            title: "Description",
            width: 200
        }, {
            field: "addinfo",
            title: "Note",
            width: 250
        }];
    }

    $(gridName).html('');
    $(gridName).kendoGrid({
        dataSource: {
            serverPaging: true,
            serverSorting: true,
            transport: {
                read: {
                    url: url,
                    type: "POST",
                    data: param,
                    dataType: "json",
                    contentType: "application/json; charset=utf-8",
                },
                parameterMap: function(options) {
                    return JSON.stringify(options);
                }
            },
            schema: {
                data: function data(res) {
                    if (!app.isFine(res)) {
                        return;
                    }
                    var totalFreq = res.data.Total;
                    var totalHour = res.data.Duration;

                    ma.minDateRet = new Date(res.data.mindate);
                    ma.maxDateRet = new Date(res.data.maxdate);

                    ma.checkCompleteDate()

                    $('#alarm_duration').text((totalHour/3600).toFixed(2));
                    $('#alarm_frequency').text(totalFreq);

                    setTimeout(function(){
                        app.loading(false);
                    }, 300)

                    return res.data.Data;
                },
                total: function data(res) {
                    return res.data.Total;
                }
            },
            pageSize: 10,
            sort: defaultsort,
        },
        // toolbar: ["excel"],
        excel: {
            fileName: nameFile+".xlsx",
            filterable: true,
            allPages: true
        },
        // pdf: {
        //     fileName: nameFile+".pdf",
        // },
        sortable: true,
        pageable: {
            refresh: true,
            pageSizes: true,
            buttonCount: 5
        },
        columns: columns
    });
};

function time(s) {
    return new Date(s * 1e3).toISOString().slice(-13, -5);
}

ma.InitDateValue = function () {
    var maxDateData = new Date();

    var lastStartDate = new Date(Date.UTC(moment(maxDateData).get('year'), maxDateData.getMonth(), maxDateData.getDate(), 0, 0, 0, 0));
    var lastEndDate = new Date(Date.UTC(moment(maxDateData).get('year'), maxDateData.getMonth(), maxDateData.getDate(), 0, 0, 0, 0));

    $('#dateStart').data('kendoDatePicker').value(lastStartDate);
    $('#dateEnd').data('kendoDatePicker').value(lastEndDate);
}

ma.LoadDataAvail = function(projectname, gridType){
    //fa.LoadData();

    var payload = {
        project: projectname,
        tipe: gridType
    };

    toolkit.ajaxPost(viewModel.appName + "monitoringrealtime/getdataalarmavaildate", payload, function (res) {
        if (!app.isFine(res)) {
            return;
        }
        if (res.data.Data.length == 0) {
            res.data.Data = [];
        } else {
            if (res.data.Data.length > 0) {
                ma.minDatetemp = new Date(res.data.Data[0]);
                ma.maxDatetemp = new Date(res.data.Data[1]);
                app.currentDateData = new Date(res.data.Data[1]);

                $('#availabledatestart').html(kendo.toString(moment.utc(ma.minDatetemp).format('DD-MMMM-YYYY')));
                $('#availabledateend').html(kendo.toString(moment.utc(ma.maxDatetemp).format('DD-MMMM-YYYY')));

                $('#dateStart').data('kendoDatePicker').value( new Date(Date.UTC(moment( ma.maxDatetemp).get('year'),  ma.maxDatetemp.getMonth(),  ma.maxDatetemp.getDate() - 7, 0, 0, 0, 0)));
                $('#dateEnd').data('kendoDatePicker').value(kendo.toString(moment.utc(res.data.Data[1]).format('DD-MMM-YYYY')));

                ma.checkCompleteDate();
            }
        }
    });
}

ma.checkCompleteDate = function () {
    var currentDateData = moment.utc(ma.maxDatetemp).format('YYYY-MM-DD');
    var prevDateData = moment.utc(ma.minDatetemp).format('YYYY-MM-DD');

    var dateStart = moment.utc(ma.minDateRet).format('YYYY-MM-DD');
    var dateEnd = moment.utc(ma.maxDateRet).format('YYYY-MM-DD');

    if ((dateEnd > currentDateData) || (dateStart > currentDateData)) {
        fa.infoPeriodIcon(true);
    } else if ((dateEnd < prevDateData) || (dateStart < prevDateData)) {
        fa.infoPeriodIcon(true);
    } else {
        fa.infoPeriodIcon(false);
        fa.infoPeriodRange("");
    }
}

ma.ToByProject = function(){
    setTimeout(function(){
        app.loading(true);
        app.resetLocalStorage();
        var project =  $('#projectList').data('kendoDropDownList').value();
        localStorage.setItem('projectname', project);
        if(localStorage.getItem("projectname")){
            window.location = viewModel.appName + "page/monitoringbyproject";
        }
    },1500);
}

ma.exportToExcel = function(id){
    $("#"+id).getKendoGrid().saveAsExcel();
}

$(document).ready(function(){
    $('#btnRefresh').on('click', function () {
        fa.checkTurbine();
        if($('.nav').find('li.active').find('a.tab-custom').text() == "Alarm Down") {
            ma.CreateGrid("alarm");
        } else if($('.nav').find('li.active').find('a.tab-custom').text() == "Alarm Warning") {
            ma.CreateGrid("warning");
        }else{
            ma.CreateGrid("alarmraw");
        }
    });

    //setTimeout(function() {
        $.when(ma.InitDateValue()).done(function () {
            setTimeout(function() {
                ma.CreateGrid("alarm");
                ma.LoadDataAvail(fa.project, "alarm");
            }, 100);
        });
    //}, 300);

    $('#projectList').kendoDropDownList({
        change: function () {
            var project = $('#projectList').data("kendoDropDownList").value();
            fa.populateTurbine(project);
            ma.LoadDataAvail(project, "alarm");
        }
    });
});
<|endoftext|>


<commit_before>(function() {
  var width = window.innerWidth - 400,
    height = Math.floor(width * (9 / 16));

  if (width < 480) {
    map = document.getElementById("map");
    map.setAttribute("style", "float: left;");
    width = 480;
    height = Math.floor(width * (9 / 16));
  }

  var projection = d3.geo.wagner6()
    .scale((width + 1) / 2 / Math.PI)
    .translate([width / 2, height / 2])
    .precision(.1);

  var path = d3.geo.path()
    .projection(projection);

  var svg = d3.select('svg')
    .attr('height', height)
    .attr('width', width);

  d3.json("vendor/worldcountries.json", function(error, world) {
    svg.selectAll("path")
      .data(world.features)
      .enter()
      .insert("path", ":first-child")
      .attr({
        d: function(d) {return path(d)},
        id: function(d) {return d.properties.name},
        "class": "land"
      });

    svg.select("#Antarctica").remove();
  });

  var group = svg.append('g')
    .attr('class', 'classifications')

  var points = [];
  var users = [];

  var updateCountries = function(error, countries) {
    if (error) {
      clearInterval(countryFetcher);
      throw error;
    }

    var list = d3.select('.countries ul').selectAll('li')
      .data(countries.slice(0, 3), function(d) { return d[0]; })

    list.enter().append('li')
      .html(function(d) { return d[0] + ': '; });

    list.select('.count').text(function(d) { return d[1].toLocaleString() });

    list.exit().remove();
  }

  var update = function(error, classifications) {
    if (error) {
      clearInterval(fetcher);
      throw error;
    }

    points = points.concat(classifications.map(function(c) {
      return projection([
        c.location.longitude,
        c.location.latitude
      ]).concat([c.project, c.id]);
    }));

    users = users.concat(classifications.map(function(c) {
      return {
        subject: c.subject,
        country: c.location.country,
        city: c.location.city,
        user: c.user,
        avatar: c.user_id,
        project: c.project
      }
    }));

    users = users.reduce(function(m, u) {
      if (typeof u.user === 'undefined') {
        return m
      } else if (m.filter(function(mu) { return mu.avatar === u.avatar; }).length === 0) {
        if (u.user.split('@').length > 1)
          u.user = u.user.split('@')[0];
        return m.concat(u);
      } else {
        return m;
      }
    }, []);
  };

  var drawingPoints = [];

  var drawPoints = function() {
    if (drawingPoints.length === 1000)
      drawingPoints.shift();

    drawingPoints.push(points.pop());

    var dots = group.selectAll('circle')
      .data(drawingPoints, function(d) { return d[3]; });

    dots.enter().append('circle')
      .attr('cx', function(d) { return d[0]; })
      .attr('cy', function(d) { return d[1]; })
      .attr('class', function(d) { return d[2]; })
      .attr('r', 1)
      .transition().duration(200)
      .attr('r', 7)
      .transition().duration(500)
      .attr('r', 3);

    dots.exit().remove();
  };

  var avatarURI = "http://zooniverse-avatars.s3.amazonaws.com/ouroboros/"
  var usersList = d3.select('.classifiers ul');
  this.defaultAvatar = function(el) {
    var img = document.createElement('img')
    img.src = src="http://zooniverse-avatars.s3.amazonaws.com/default_forum_avatar.png";
    img.height = 50;
    img.width = 50;
    el.parentNode.replaceChild(img, el);
  };

  var drawUsers = function() {
    var scale = d3.scale.linear().domain([0, 5]).range([0, window.innerHeight])
    var classifiers = usersList.selectAll('li')
      .data(users.slice(0, 5), function(d) { return d.avatar; });

    classifiers.enter().append('li')
      .attr('class', 'classifiers')
      .style('top', function(d, i) { return scale(i + 1) + 'px'; })
      .html(drawUser);

    classifiers.transition().duration(1900)
      .style('top', function(d, i) { return scale(i) + "px"; });

    classifiers.exit()
      .transition().duration(1900)
      .style('top', function(d, i) { return scale(i - 1) + "px"; })
      .remove();

    if (users.length > 5)
      users.shift();
  };

  var drawUser = function(d) {
    var imgHeight = Math.floor(window.innerHeight / 5);
    imgHeight = (imgHeight > 340) ? 340 : imgHeight;
    return '

' + '

 ' + d.user + '

' + ((d.city !== '') ? d.city + ', ' : '') + d.country + '

';
  };

  d3.json("/classifications/99", update);
  d3.json("/countries", updateCountries);
  var countryFetcher = setInterval(function() {d3.json("/countries", updateCountries);}, 10000);
  var fetcher = setInterval(function() { d3.json('/classifications/9', update) }, 5000);
  var pointsDrawer = setInterval(drawPoints, 500);
  var userDrawer = setInterval(drawUsers, 2000);

}).call(this);
<commit_msg>User list scrolls with classification rate.  Various optimizations<commit_after>(function() {
  var countryFetcher, fetcher, pointsDrawer, userDrawer;

  var width = window.innerWidth - 400,
    height = Math.floor(width * (9 / 16));

  if (width < 480) {
    map = document.getElementById("map");
    map.setAttribute("style", "float: left;");
    width = 480;
    height = Math.floor(width * (9 / 16));
  }

  var projection = d3.geo.wagner6()
    .scale((width + 1) / 2 / Math.PI)
    .translate([width / 2, height / 2])
    .precision(.1);

  var path = d3.geo.path()
    .projection(projection);

  var svg = d3.select('svg')
    .attr('height', height)
    .attr('width', width);

  d3.json("vendor/worldcountries.json", function(error, world) {
    svg.selectAll("path")
      .data(world.features)
      .enter()
      .insert("path", ":first-child")
      .attr({
        d: function(d) {return path(d)},
        id: function(d) {return d.properties.name},
        "class": "land"
      });

    svg.select("#Antarctica").remove();
  });

  var group = svg.append('g')
    .attr('class', 'classifications')

  var points = [];
  var users = [];

  var updateCountries = function(error, countries) {
    if (error) {
      clearInterval(countryFetcher);
      throw error;
    }

    var list = d3.select('.countries ul').selectAll('li')
      .data(countries.slice(0, 3), function(d) { return d[0]; })

    list.enter().append('li')
      .html(function(d) { return d[0] + ': '; });

    list.select('.count').text(function(d) { return d[1].toLocaleString() });

    list.exit().remove();
  }

  var update = function(error, classifications) {
    if (error) {
      clearInterval(fetcher);
      throw error;
    }

    points = points.concat(classifications.map(function(c) {
      return projection([
        c.location.longitude,
        c.location.latitude
      ]).concat([c.project, c.id]);
    }));

    users = users.concat(classifications.map(function(c) {
      var subject = new Image;
      subject.src = c.subject;
      var avatar = new Image;
      if(c.user_id) {
        avatar.src = 'http://zooniverse-avatars.s3.amazonaws.com/ouroboros/' + c.user_id;
      }

      return {
        id: c.id,
        subject: c.subject,
        country: c.location.country,
        city: c.location.city,
        user: c.user,
        avatar: c.user_id,
        project: c.project
      }
    }));

    users = users.reduce(function(m, u) {
      if (typeof u.user === 'undefined') {
        u.user = 'not-logged-in';
        return m.concat(u);
      } else if (m.filter(function(mu) { return mu.id === u.id; }).length === 0) {
        u.user = u.user.split('@')[0];
        return m.concat(u);
      } else {
        return m;
      }
    }, []);
  };

  var drawingPoints = [];

  var drawPoints = function() {
    if (drawingPoints.length === 1000)
      drawingPoints.shift();

    drawingPoints.push(points.pop());

    var dots = group.selectAll('circle')
      .data(drawingPoints, function(d) { return d[3]; });

    dots.enter().append('circle')
      .attr('cx', function(d) { return d[0]; })
      .attr('cy', function(d) { return d[1]; })
      .attr('class', function(d) { return d[2]; })
      .attr('r', 1)
      .transition().duration(200)
      .attr('r', 7)
      .transition().duration(500)
      .attr('r', 3);

    dots.exit().remove();
  };

  var avatarURI = "http://zooniverse-avatars.s3.amazonaws.com/ouroboros/"
  var usersList = d3.select('.classifiers ul');
  this.defaultAvatar = function(el) {
    var img = document.createElement('img')
    img.src = src="http://zooniverse-avatars.s3.amazonaws.com/default_forum_avatar.png";
    img.height = 50;
    img.width = 50;
    el.parentNode.replaceChild(img, el);
  };

  var drawUsers = function() {
    var interval = 8000 * (1 / users.length)
    interval = Math.max(interval, 250);
    var transition = interval * 0.75;

    var scale = d3.scale.linear().domain([0, 5]).range([0, window.innerHeight])
    var classifiers = usersList.selectAll('li')
      .data(users.slice(0, 5), function(d) { return d.id; });

    classifiers.enter().append('li')
      .attr('class', 'classifiers')
      .style('top', function(d, i) { return scale(i + 1) + 'px'; })
      .html(drawUser);

    classifiers.transition().duration(transition)
      .style('top', function(d, i) { return scale(i) + "px"; });

    classifiers.exit()
      .transition().duration(transition)
      .style('top', function(d, i) { return scale(i - 1) + "px"; })
      .remove();

    if (users.length > 5) {
      users.shift();
    }

    if(userDrawer) {
      clearTimeout(userDrawer);
    }

    userDrawer = setTimeout(drawUsers, interval);
  };

  var drawUser = function(d) {
    var imgHeight = Math.floor(window.innerHeight / 5);
    imgHeight = (imgHeight > 340) ? 340 : imgHeight;
    var avatarSrc = d.user_id ? avatarURI + d.avatar : 'http://zooniverse-avatars.s3.amazonaws.com/default_forum_avatar.png'

    return '
' +
             '' +
           '
' +
           '
' +
             ' ' +
             '' +
               '
 ' + d.user + '
' +
               '
' + ((d.city !== '') ? d.city + ', ' : '') + d.country + '
' +
             '' +
           '
';
  };

  d3.json("/classifications/9", update);
  d3.json("/countries", updateCountries);
  countryFetcher = setInterval(function() {d3.json("/countries", updateCountries);}, 10000);
  fetcher = setInterval(function() { d3.json('/classifications/9', update) }, 2000);
  pointsDrawer = setInterval(drawPoints, 500);
  userDrawer = setTimeout(drawUsers, 1000);

}).call(this);
<|endoftext|>