<commit_before>/*
 * Copyright 2016 Studentmediene i Trondheim AS
 *
 * 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.
 */

'use strict';

angular.module('momusApp.services')
    .service('PersonService', function ($http) {
        let personExistsInArray = function(array, person){
            array.forEach(function(e){
                if(e.id == person.id){
                    return true;
                }
            });
            return false;
        };
        return {
            getCurrentUser: function () {
                return $http.get('/api/person/me', {cache: true});
            },
            getAll: function () {
                return $http.get('/api/person/', {cache: true});
            },
            getLandingPage: function () {
                return $http.get('/api/person/landing', {cache: true});
            },
            updateLandingPage: function(landing) {
                return $http.get('/api/person/landing/' + landing);

            },
            addPersonsToArray: function(array, persons){
                persons.forEach(function(person){
                    if(!personExistsInArray(array, person))
                        array.push(person);
                });
            }
        };
    });<commit_msg>Used too new javascript feature, reverted back to standard for-loop.<commit_after>/*
 * Copyright 2016 Studentmediene i Trondheim AS
 *
 * 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.
 */

'use strict';

angular.module('momusApp.services')
    .service('PersonService', function ($http) {
        function personExistsInArray(array, person){
            for(let i = 0; i < array.length; i++){
                if(array[i].id == person.id){
                    return true;
                }
            }
            return false;
        }
        return {
            getCurrentUser: function () {
                return $http.get('/api/person/me', {cache: true});
            },
            getAll: function () {
                return $http.get('/api/person/', {cache: true});
            },
            getLandingPage: function () {
                return $http.get('/api/person/landing', {cache: true});
            },
            updateLandingPage: function(landing) {
                return $http.get('/api/person/landing/' + landing);

            },
            addPersonsToArray: function(array, persons){
                for(let i = 0; i < persons.length;i++){
                    if(!personExistsInArray(array, persons[i])){
                        array.push(persons[i]);
                    }
                }
            }
        };
    });<|endoftext|>


<commit_before>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 18.06.18
 */
Imcms.require(
    ['jquery', 'imcms-components-builder', 'imcms-uuid-generator', 'imcms-languages-rest-api', 'imcms'],
    function ($, components, uuid, languagesRestApi, imcms) {
        function activateUserAdminRoles() {
            var $form = $('#user-edit-form');
            var $userAdminRoleIds = $form.find('input[name=userAdminRoleIds]');

            if (!$userAdminRoleIds.length) return;

            $userAdminRoleIds.attr('disabled', 'disabled');

            var isUserAdminSelected = $form.find('input[name=roleIds]')
                .find("option")
                .filter(function () {
                    var $option = $(this);
                    return ($option.text() === 'Useradmin' && $option.is(':selected'));
                })
                .length;

            if (isUserAdminSelected) {
                $userAdminRoleIds.removeAttr('disabled');
            }
        }

        function onSubmit(e) {
            var $form = $('#user-edit-form');

            if ($form.find('input[name=loginName]').val() === "") {
                e.preventDefault();
                alert($('#must-fill-mandatory-fields-text').val());
                return;
            }

            var $pass1 = $form.find('input[name=password1]');
            var $pass2 = $form.find('input[name=password2]');

            if ($pass1.val() === $pass2.val()) {
                $('[name=userPhoneNumber]').removeAttr('disabled');
                return;
            }

            e.preventDefault();
            $pass2.val("");
            $pass1.val("").focus();
            alert($('#pass-verification-failed-text').val());
        }

        function loadLanguages() {
            var $langSelectContainer = $('#languages-select-container');

            var selectAttributes = {
                text: $langSelectContainer.attr('data-text'),
                name: 'langCode'
            };

            var $select = components.selects.imcmsSelect("<div>", selectAttributes);
            $select.appendTo($langSelectContainer);

            languagesRestApi.read().done(function (languages) {

                languages = languages.map(function (lang) {
                    return {
                        'data-value': lang.code,
                        text: lang.name
                    }
                });

                components.selects.addOptionsToSelect(languages, $select, $select.selectValue);
                $select.selectValue(imcms.userLanguage);
            });
        }

        function bindOnEditClicked($phoneRow) {
            return function () {
                $phoneRow.find('[disabled]')
                    .removeAttr('disabled')
                    .end()
                    .find('.imcms-control')
                    .hide()
                    .end()
                    .find('.imcms-button--save')
                    .show()
                    .end()
                    .find('.imcms-input--phone')
                    .focus();
            }
        }

        function bindOnDeleteClicked($phoneRow) {
            return function () {
                $phoneRow.detach();
            }
        }

        function bindOnSaveClick($phoneRow) {
            return function () {
                $(this).hide();

                $phoneRow.find('.imcms-select,.imcms-input--phone')
                    .attr('disabled', 'disabled')
                    .end()
                    .find('.imcms-control')
                    .show();
            }
        }

        function addPhone(e) {
            e.preventDefault();

            var $phoneInput = $('#phone');
            var phone = $phoneInput.val().trim();

            if (!phone) return;

            $phoneInput.val('');

            var $phoneTypeContainer = $('#phone-type-select').parent();
            var $newRow = $phoneTypeContainer.clone(true, true);

            $newRow.addClass('imcms-text-box--existing-phone-box');

            var $editPhoneButton = components.controls.edit(bindOnEditClicked($newRow));
            var $deletePhoneButton = components.controls.remove(bindOnDeleteClicked($newRow));
            var $saveButton = components.buttons.saveButton({
                style: 'display: none;',
                click: bindOnSaveClick($newRow),
                text: 'Save'
            });

            $newRow.find('.imcms-label')
                .text('')
                .removeAttr('for')
                .end()
                .find('.imcms-select')
                .attr('disabled', 'disabled')
                .end()
                .find('#phone-type-selected')
                .removeAttr('id')
                .attr('name', 'userPhoneNumberType')
                .end()
                .find('#phone')
                .removeAttr('id')
                .attr('disabled', 'disabled')
                .attr('name', 'userPhoneNumber')
                .val(phone)
                .end()
                .find('#phone-type-select')
                .removeAttr('id')
                .end()
                .find('#button-add-phone')
                .detach()
                .end()
                .find('.imcms-text-box')
                .append();

            $newRow.append($saveButton, $deletePhoneButton, $editPhoneButton).insertAfter($phoneTypeContainer);
        }

        function filterNonDigits(e) {
            return ((e.ctrlKey || e.altKey || e.metaKey)
                || (/^[0-9()+.,-]+$/g.test(e.key))
                || (e.key === "Backspace")
                || (e.key === "Shift")
                || (e.key && e.key.indexOf && !!~e.key.indexOf("Arrow"))
            );
        }

        $(function () {
            $('input[name=loginName]').focus();
            activateUserAdminRoles();
            loadLanguages();

            components.selects.makeImcmsSelect($('#phone-type-select'));

            $('#select-role-ids').change(activateUserAdminRoles);
            $('#edit-user-submit-button').click(onSubmit);
            $('#button-add-phone').click(addPhone);

            $('.imcms-input--phone').keydown(filterNonDigits).on('paste', function (e) {
                e.preventDefault();
            });

            $('.imcms-text-box--existing-phone-box').each(function () {
                var $row = $(this);

                components.selects.makeImcmsSelect($row.find('.imcms-select'));

                $row.find('.imcms-button--save').click(bindOnSaveClick($row));
                $row.find('.imcms-control--remove').click(bindOnDeleteClicked($row));
                $row.find('.imcms-control--edit').click(bindOnEditClicked($row));
            });
        });
    }
);
<commit_msg>IMCMS-300 - New design to superadmin-pages: - Fixed field name.<commit_after>/**
 * @author Serhii Maksymchuk from Ubrainians for imCode
 * 18.06.18
 */
Imcms.require(
    ['jquery', 'imcms-components-builder', 'imcms-uuid-generator', 'imcms-languages-rest-api', 'imcms'],
    function ($, components, uuid, languagesRestApi, imcms) {
        function activateUserAdminRoles() {
            var $form = $('#user-edit-form');
            var $userAdminRoleIds = $form.find('input[name=userAdminRoleIds]');

            if (!$userAdminRoleIds.length) return;

            $userAdminRoleIds.attr('disabled', 'disabled');

            var isUserAdminSelected = $form.find('input[name=roleIds]')
                .find("option")
                .filter(function () {
                    var $option = $(this);
                    return ($option.text() === 'Useradmin' && $option.is(':selected'));
                })
                .length;

            if (isUserAdminSelected) {
                $userAdminRoleIds.removeAttr('disabled');
            }
        }

        function onSubmit(e) {
            var $form = $('#user-edit-form');

            if ($form.find('input[name=loginName]').val() === "") {
                e.preventDefault();
                alert($('#must-fill-mandatory-fields-text').val());
                return;
            }

            var $pass1 = $form.find('input[name=password]');
            var $pass2 = $form.find('input[name=password2]');

            if ($pass1.val() === $pass2.val()) {
                $('[name=userPhoneNumber]').removeAttr('disabled');
                return;
            }

            e.preventDefault();
            $pass2.val("");
            $pass1.val("").focus();
            alert($('#pass-verification-failed-text').val());
        }

        function loadLanguages() {
            var $langSelectContainer = $('#languages-select-container');

            var selectAttributes = {
                text: $langSelectContainer.attr('data-text'),
                name: 'langCode'
            };

            var $select = components.selects.imcmsSelect("<div>", selectAttributes);
            $select.appendTo($langSelectContainer);

            languagesRestApi.read().done(function (languages) {

                languages = languages.map(function (lang) {
                    return {
                        'data-value': lang.code,
                        text: lang.name
                    }
                });

                components.selects.addOptionsToSelect(languages, $select, $select.selectValue);
                $select.selectValue(imcms.userLanguage);
            });
        }

        function bindOnEditClicked($phoneRow) {
            return function () {
                $phoneRow.find('[disabled]')
                    .removeAttr('disabled')
                    .end()
                    .find('.imcms-control')
                    .hide()
                    .end()
                    .find('.imcms-button--save')
                    .show()
                    .end()
                    .find('.imcms-input--phone')
                    .focus();
            }
        }

        function bindOnDeleteClicked($phoneRow) {
            return function () {
                $phoneRow.detach();
            }
        }

        function bindOnSaveClick($phoneRow) {
            return function () {
                $(this).hide();

                $phoneRow.find('.imcms-select,.imcms-input--phone')
                    .attr('disabled', 'disabled')
                    .end()
                    .find('.imcms-control')
                    .show();
            }
        }

        function addPhone(e) {
            e.preventDefault();

            var $phoneInput = $('#phone');
            var phone = $phoneInput.val().trim();

            if (!phone) return;

            $phoneInput.val('');

            var $phoneTypeContainer = $('#phone-type-select').parent();
            var $newRow = $phoneTypeContainer.clone(true, true);

            $newRow.addClass('imcms-text-box--existing-phone-box');

            var $editPhoneButton = components.controls.edit(bindOnEditClicked($newRow));
            var $deletePhoneButton = components.controls.remove(bindOnDeleteClicked($newRow));
            var $saveButton = components.buttons.saveButton({
                style: 'display: none;',
                click: bindOnSaveClick($newRow),
                text: 'Save'
            });

            $newRow.find('.imcms-label')
                .text('')
                .removeAttr('for')
                .end()
                .find('.imcms-select')
                .attr('disabled', 'disabled')
                .end()
                .find('#phone-type-selected')
                .removeAttr('id')
                .attr('name', 'userPhoneNumberType')
                .end()
                .find('#phone')
                .removeAttr('id')
                .attr('disabled', 'disabled')
                .attr('name', 'userPhoneNumber')
                .val(phone)
                .end()
                .find('#phone-type-select')
                .removeAttr('id')
                .end()
                .find('#button-add-phone')
                .detach()
                .end()
                .find('.imcms-text-box')
                .append();

            $newRow.append($saveButton, $deletePhoneButton, $editPhoneButton).insertAfter($phoneTypeContainer);
        }

        function filterNonDigits(e) {
            return ((e.ctrlKey || e.altKey || e.metaKey)
                || (/^[0-9()+.,-]+$/g.test(e.key))
                || (e.key === "Backspace")
                || (e.key === "Shift")
                || (e.key && e.key.indexOf && !!~e.key.indexOf("Arrow"))
            );
        }

        $(function () {
            $('input[name=loginName]').focus();
            activateUserAdminRoles();
            loadLanguages();

            components.selects.makeImcmsSelect($('#phone-type-select'));

            $('#select-role-ids').change(activateUserAdminRoles);
            $('#edit-user-submit-button').click(onSubmit);
            $('#button-add-phone').click(addPhone);

            $('.imcms-input--phone').keydown(filterNonDigits).on('paste', function (e) {
                e.preventDefault();
            });

            $('.imcms-text-box--existing-phone-box').each(function () {
                var $row = $(this);

                components.selects.makeImcmsSelect($row.find('.imcms-select'));

                $row.find('.imcms-button--save').click(bindOnSaveClick($row));
                $row.find('.imcms-control--remove').click(bindOnDeleteClicked($row));
                $row.find('.imcms-control--edit').click(bindOnEditClicked($row));
            });
        });
    }
);
<|endoftext|>


<commit_before>/*jslint node: true, expr: true */
/* global before, after, describe, it */
"use strict";
var assert = require("assert");
var expect = require("chai").expect;
var Promise = require('bluebird');
var should = require('should');
var _ = require('lodash');

var models = require('../lib/models');

describe.only('Stats filters', function() {
  it('should return correct date filter', function(done) {
    var tests = [
      {date: new Date(2016, 2, 1, 21, 26, 22), days: 1, expected: new Date(2016, 2, 1)},
      {date: new Date(2016, 2, 1, 21, 26, 22), days: 2, expected: new Date(2016, 1, 29)}, // leap day
      {date: new Date(2016, 2, 2, 21, 26, 22), days: 2, expected: new Date(2016, 2, 1)},
      {date: new Date(2016, 2, 31, 0, 26, 22), days: 31, expected: new Date(2016, 2, 1)},
    ];
    tests.forEach(function (test) {
      var result = models.getDateFilter(test.date, test.days);
      (result - test.expected).should.equal(0);
    });
    done();
  });
});

<commit_msg>Remove .only<commit_after>/*jslint node: true, expr: true */
/* global before, after, describe, it */
"use strict";
var assert = require("assert");
var expect = require("chai").expect;
var Promise = require('bluebird');
var should = require('should');
var _ = require('lodash');

var models = require('../lib/models');

describe('Stats filters', function() {
  it('should return correct date filter', function(done) {
    var tests = [
      {date: new Date(2016, 2, 1, 21, 26, 22), days: 1, expected: new Date(2016, 2, 1)},
      {date: new Date(2016, 2, 1, 21, 26, 22), days: 2, expected: new Date(2016, 1, 29)}, // leap day
      {date: new Date(2016, 2, 2, 21, 26, 22), days: 2, expected: new Date(2016, 2, 1)},
      {date: new Date(2016, 2, 31, 0, 26, 22), days: 31, expected: new Date(2016, 2, 1)},
    ];
    tests.forEach(function (test) {
      var result = models.getDateFilter(test.date, test.days);
      (result - test.expected).should.equal(0);
    });
    done();
  });
});

<|endoftext|>


<commit_before>$(function() {
  var dataURL = '../scripts/stats.js/trend/json';
  var controlsURL = '../scripts/ddos.js/controls/json';
  var thresholdURL = '../scripts/ddos.js/threshold/json';
  var blockMinutesURL = '../scripts/ddos.js/blockminutes/json';
  var groupsURL = '../scripts/ddos.js/groups/json';
  var groupsInfoURL = '../scripts/ddos.js/groups/info/json';

  var defaults = {
    tab:0,
    charts0:'show',
    charts1:'hide',
    charts2:'hide',
    charts3:'hide',
    hlp0:'hide',
    hlp1:'hide',
    hlp2:'hide',
    hlp3:'hide',
    hlp4:'hide',
    hlp5:'hide'
  };

  var state = {};
  $.extend(state,defaults);

  function createQuery(params) {
    var query, key, value;
    for(key in params) {
      value = params[key];
      if(value == defaults[key]) continue;
      if(query) query += '&';
      else query = '';
      query += encodeURIComponent(key)+'='+encodeURIComponent(value);
    }
    return query;
  }

  function getState(key, defVal) {
    return window.sessionStorage.getItem(key) || state[key] || defVal;
  }

  function setState(key, val, showQuery) {
    state[key] = val;
    window.sessionStorage.setItem(key, val);
    if(showQuery) {
      var query = createQuery(state);
      window.history.replaceState({},'',query ? '?' + query : './');
    }
  }

  function setQueryParams(query) {
    var vars, params, i, pair;
    vars = query.split('&');
    params = {};
    for(i = 0; i < vars.length; i++) {
      pair = vars[i].split('=');
      if(pair.length == 2) setState(decodeURIComponent(pair[0]), decodeURIComponent(pair[1]),false);
    }
  }

  var search = window.location.search;
  if(search) setQueryParams(search.substring(1));

  $('#charts-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('charts'+idx, 'hide') == 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('charts'+idx, newIndex === 0 ? 'show' : 'hide', true);
        $.event.trigger({type:'updateChart'});
      }
    });
  });

  $('#help-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('hlp'+idx, 'hide') === 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('hlp'+idx, newIndex === 0 ? 'show' : 'hide', true);
      }
    });
  });

  $('#tabs').tabs({
    active: getState('tab', 0),
    activate: function(event, ui) {
      var newIndex = ui.newTab.index();
      setState('tab', newIndex, true);
      $.event.trigger({type:'updateChart'});
    },
    create: function(event,ui) {
      $.event.trigger({type:'updateChart'});
    }
  });

  var db = {};
  var showThreshold = true;
  $('#targets').chart({
    type: 'topn',
    stack: false,
    includeOther:false,
    metric: 'top-5-targets',
    legendHeadings: ['Target IP','Target Group'],
    hrule:[{name:'threshold',color:'red',scale:showThreshold}],
    units: 'Packets per Second'},
  db);
  $('#protocols').chart({
    type: 'topn',
    stack: false,
    includeOther:false,
    metric: 'top-5-protocols',
    legendHeadings: ['Target IP','Protocol Stack'],
    units: 'Packets per Second'},
  db);
  $('#attacks').chart({
    type: 'trend',
    stack: true,
    legend: ['Active','Failed','Pending'],
    metrics: ['controls_blocked','controls_failed','controls_pending'],
    units: 'Number of Controls'},
  db);
  $('#connections').chart({
    type: 'trend',
    stack: false,
    metrics: ['connections'],
    units: 'Connections'},
  db);

  var lastControlsID = 0;
  var dialog;
  var selectedTarget;
  function removeControl() {
    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'allow',address:selectedTarget}
    });
    dialog.dialog("close");
  }
  function installControl() {
    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'block',address:selectedTarget}
    });
    dialog.dialog("close");
  }
  function formatTime(ms) {
    var m = new Date(ms);
    return  m.getUTCFullYear() +"/"+
     ("0" + (m.getUTCMonth()+1)).slice(-2) +"/"+
     ("0" + m.getUTCDate()).slice(-2) + " " +
     ("0" + m.getUTCHours()).slice(-2) + ":" +
     ("0" + m.getUTCMinutes()).slice(-2) + ":" +
     ("0" + m.getUTCSeconds()).slice(-2);
  }

  var ctl_mode;
  function refreshControls() {
    $.ajax({
      url: controlsURL,
      dataType: 'json',
      success: function(data) {
        lastControlsID = data.id;
        ctl_mode = data.enabled ? "automatic" : "manual";
        if('automatic' === ctl_mode) $('#automatic').click();
        else $('#manual').click();
        var body = $('#controlstable tbody');
        var rows;
        if(data.controls.length) {
          rows = '';
          for(var i = 0; i < data.controls.length; i++) {
            var entry = data.controls[i];
            rows += '
';
            rows += '' + entry.target + '	';
            rows += '' + entry.group + '	';
            rows += '' + entry.protocol + '	';
            rows += '' + formatTime(entry.time) + '	';
            rows += '' + entry.status + '	';
            rows += '
';
          }
          body.html(rows);
          body
            .find('tr')
            .hover(
              function() { $(this).addClass("dynhoveron"); },
              function() { $(this).removeClass("dynhoveron"); }
            )
            .click(function() {
              var td = $(this).children()[0];
              selectedTarget = $(td).html();
              $('#target').html(selectedTarget);
              td = $(this).children()[4];
              var status = $(td).html();
              if('pending' !== status) {
                $(".ui-dialog-buttonpane button:contains('Install')")
                  .attr("disabled", true)
                  .addClass("ui-state-disabled");
              } else {
                $(".ui-dialog-buttonpane button:contains('Install')")
                  .attr("disabled", false)
                  .removeClass("ui-state-disabled");
              }
              dialog.dialog('open');
              $(':button').blur();
            });
        }
        else {
          rows = '
No active controls
';
          body.html(rows);
        }
      }
    });
  }

  function warningDialog(message) {
    $('
' + message + '
').dialog({dialogClass:'alert', modal:true, buttons:{'Close': function() { $(this).dialog('close'); }}})
  }

  function getThreshold() {
     $.ajax({
      url:thresholdURL,
      dataType:'json',
      success: function(data) {
        $('#threshold').spinner('value', data);
      }
    });
  }

  getThreshold();

  function setThreshold() {
    var threshold =  Math.round($('#threshold').spinner('value'));
    var settings = threshold;
    $.ajax({
      url:thresholdURL,
      type: 'POST',
      contentType:'application/json',
      data: JSON.stringify(settings)
    });
  }

  $('#threshold').spinner({min:10000,max:10000000,step:10000});
  $('#thresholdget').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(getThreshold);
  $('#thresholdset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(setThreshold);

  function getBlockMinutes() {
     $.ajax({
      url:blockMinutesURL,
      dataType:'json',
      success: function(data) {
        $('#blockminutes').spinner('value', data);
      }
    });
  }

  getBlockMinutes();

  function setBlockMinutes() {
    var blockminutes =  Math.round($('#blockminutes').spinner('value'));
    var settings = blockminutes;
    $.ajax({
      url:blockMinutesURL,
      type: 'POST',
      contentType:'application/json',
      data: JSON.stringify(settings)
    });
  }

  $('#blockminutes').spinner({min:10,max:1440,step:10});
  $('#blockminutesget').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(getBlockMinutes);
  $('#blockminutesset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(setBlockMinutes);

  function refreshGroups() {
    $.ajax({
      url:groupsInfoURL,
      dataType: 'json',
      success: function(data) {
        $('#numgroups').val(data.groups).removeClass(data.groups ? 'error' : 'good').addClass(data.groups ? 'good' : 'error');
        $('#numcidrs').val(data.cidrs).removeClass(data.cidrs ? 'error' : 'good').addClass(data.cidrs ? 'good' : 'error');
      }
    });
  }

  refreshGroups();

  function getGroups() {
    location.href = groupsURL;
  }

  $('#groupsrefresh').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(refreshGroups);
  $('#groupsget').button({icons:{primary:'ui-icon-search'},text:false}).click(getGroups);
  $('#groupsfile').hide().change(function(event) {
    var input = event.target;
    var reader = new FileReader();
    var $this = $(this);
    reader.onload = function(){
      var text = reader.result;
      $this.wrap('<form>').closest('form').get(0).reset();
      $this.unwrap();
      $.ajax({
        url:groupsURL,
        type: 'POST',
        contentType:'application/json',
        data:text,
        success:refreshGroups,
        error: function() { warningDialog('Badly formatted groups'); }
      });
    };
    reader.readAsText(input.files[0]);
  });
  $('#groupsset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(function() {$('#groupsfile').click();});

  function updateData(data) {
    if(!data
      || !data.trend
      || !data.trend.times
      || data.trend.times.length == 0) return;

    if(db.trend) {
      // merge in new data
      var maxPoints = db.trend.maxPoints;
      var remove = db.trend.times.length > maxPoints ? db.trend.times.length - maxPoints : 0;
      db.trend.times = db.trend.times.concat(data.trend.times);
      if(remove) db.trend.times = db.trend.times.slice(remove);
      for(var name in db.trend.trends) {
        db.trend.trends[name] = db.trend.trends[name].concat(data.trend.trends[name]);
        if(remove) db.trend.trends[name] = db.trend.trends[name].slice(remove);
      }
    } else db.trend = data.trend;

    db.trend.start = new Date(db.trend.times[0]);
    db.trend.end = new Date(db.trend.times[db.trend.times.length - 1]);
    db.trend.values = data.trend.values;

    $.event.trigger({type:'updateChart'});
  }

  function pollTrends() {
    $.ajax({
      url: dataURL,
      data: db.trend && db.trend.end ? {after:db.trend.end.getTime()} : null,
      success: function(data) {
        updateData(data);
        if(data && data.trend && data.trend.values && lastControlsID !== data.trend.values.control_id) refreshControls();
        setTimeout(pollTrends, 1000);
      },
      error: function(result,status,errorThrown) {
        setTimeout(pollTrends,5000);
      },
      timeout: 60000
    });
  };

  $(window).resize(function() {
    $.event.trigger({type:'updateChart'});
  });

  dialog = $('#dialog').dialog({
    modal:true,
    autoOpen:false,
    buttons: {
      Remove:removeControl,
      Install:installControl,
      Close: function() { dialog.dialog("close"); }
    }
  });
  $('#controller_mode').buttonset();
  $('#controller_mode').change(function(evt) {
    var newMode = $(evt.target).attr('id');
    if(newMode === ctl_mode) return;

    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'automatic' === newMode ? 'enable' : 'disable'}
    });
    ctl_mode = newMode;
  });
  pollTrends();
  refreshControls();
  refreshGroups();
});
<commit_msg>Avoid aliases with session storage<commit_after>$(function() {
  var dataURL = '../scripts/stats.js/trend/json';
  var controlsURL = '../scripts/ddos.js/controls/json';
  var thresholdURL = '../scripts/ddos.js/threshold/json';
  var blockMinutesURL = '../scripts/ddos.js/blockminutes/json';
  var groupsURL = '../scripts/ddos.js/groups/json';
  var groupsInfoURL = '../scripts/ddos.js/groups/info/json';

  var defaults = {
    tab:0,
    charts0:'show',
    charts1:'hide',
    charts2:'hide',
    charts3:'hide',
    hlp0:'hide',
    hlp1:'hide',
    hlp2:'hide',
    hlp3:'hide',
    hlp4:'hide',
    hlp5:'hide'
  };

  var state = {};
  $.extend(state,defaults);

  function createQuery(params) {
    var query, key, value;
    for(key in params) {
      value = params[key];
      if(value == defaults[key]) continue;
      if(query) query += '&';
      else query = '';
      query += encodeURIComponent(key)+'='+encodeURIComponent(value);
    }
    return query;
  }

  function getState(key, defVal) {
    return window.sessionStorage.getItem('ddos_blackhole_'+key) || state[key] || defVal;
  }

  function setState(key, val, showQuery) {
    state[key] = val;
    window.sessionStorage.setItem('ddos_blackhole_'+key, val);
    if(showQuery) {
      var query = createQuery(state);
      window.history.replaceState({},'',query ? '?' + query : './');
    }
  }

  function setQueryParams(query) {
    var vars, params, i, pair;
    vars = query.split('&');
    params = {};
    for(i = 0; i < vars.length; i++) {
      pair = vars[i].split('=');
      if(pair.length == 2) setState(decodeURIComponent(pair[0]), decodeURIComponent(pair[1]),false);
    }
  }

  var search = window.location.search;
  if(search) setQueryParams(search.substring(1));

  $('#charts-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('charts'+idx, 'hide') == 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('charts'+idx, newIndex === 0 ? 'show' : 'hide', true);
        $.event.trigger({type:'updateChart'});
      }
    });
  });

  $('#help-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('hlp'+idx, 'hide') === 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('hlp'+idx, newIndex === 0 ? 'show' : 'hide', true);
      }
    });
  });

  $('#tabs').tabs({
    active: getState('tab', 0),
    activate: function(event, ui) {
      var newIndex = ui.newTab.index();
      setState('tab', newIndex, true);
      $.event.trigger({type:'updateChart'});
    },
    create: function(event,ui) {
      $.event.trigger({type:'updateChart'});
    }
  });

  var db = {};
  var showThreshold = true;
  $('#targets').chart({
    type: 'topn',
    stack: false,
    includeOther:false,
    metric: 'top-5-targets',
    legendHeadings: ['Target IP','Target Group'],
    hrule:[{name:'threshold',color:'red',scale:showThreshold}],
    units: 'Packets per Second'},
  db);
  $('#protocols').chart({
    type: 'topn',
    stack: false,
    includeOther:false,
    metric: 'top-5-protocols',
    legendHeadings: ['Target IP','Protocol Stack'],
    units: 'Packets per Second'},
  db);
  $('#attacks').chart({
    type: 'trend',
    stack: true,
    legend: ['Active','Failed','Pending'],
    metrics: ['controls_blocked','controls_failed','controls_pending'],
    units: 'Number of Controls'},
  db);
  $('#connections').chart({
    type: 'trend',
    stack: false,
    metrics: ['connections'],
    units: 'Connections'},
  db);

  var lastControlsID = 0;
  var dialog;
  var selectedTarget;
  function removeControl() {
    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'allow',address:selectedTarget}
    });
    dialog.dialog("close");
  }
  function installControl() {
    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'block',address:selectedTarget}
    });
    dialog.dialog("close");
  }
  function formatTime(ms) {
    var m = new Date(ms);
    return  m.getUTCFullYear() +"/"+
     ("0" + (m.getUTCMonth()+1)).slice(-2) +"/"+
     ("0" + m.getUTCDate()).slice(-2) + " " +
     ("0" + m.getUTCHours()).slice(-2) + ":" +
     ("0" + m.getUTCMinutes()).slice(-2) + ":" +
     ("0" + m.getUTCSeconds()).slice(-2);
  }

  var ctl_mode;
  function refreshControls() {
    $.ajax({
      url: controlsURL,
      dataType: 'json',
      success: function(data) {
        lastControlsID = data.id;
        ctl_mode = data.enabled ? "automatic" : "manual";
        if('automatic' === ctl_mode) $('#automatic').click();
        else $('#manual').click();
        var body = $('#controlstable tbody');
        var rows;
        if(data.controls.length) {
          rows = '';
          for(var i = 0; i < data.controls.length; i++) {
            var entry = data.controls[i];
            rows += '
';
            rows += '' + entry.target + '	';
            rows += '' + entry.group + '	';
            rows += '' + entry.protocol + '	';
            rows += '' + formatTime(entry.time) + '	';
            rows += '' + entry.status + '	';
            rows += '
';
          }
          body.html(rows);
          body
            .find('tr')
            .hover(
              function() { $(this).addClass("dynhoveron"); },
              function() { $(this).removeClass("dynhoveron"); }
            )
            .click(function() {
              var td = $(this).children()[0];
              selectedTarget = $(td).html();
              $('#target').html(selectedTarget);
              td = $(this).children()[4];
              var status = $(td).html();
              if('pending' !== status) {
                $(".ui-dialog-buttonpane button:contains('Install')")
                  .attr("disabled", true)
                  .addClass("ui-state-disabled");
              } else {
                $(".ui-dialog-buttonpane button:contains('Install')")
                  .attr("disabled", false)
                  .removeClass("ui-state-disabled");
              }
              dialog.dialog('open');
              $(':button').blur();
            });
        }
        else {
          rows = '
No active controls
';
          body.html(rows);
        }
      }
    });
  }

  function warningDialog(message) {
    $('
' + message + '
').dialog({dialogClass:'alert', modal:true, buttons:{'Close': function() { $(this).dialog('close'); }}})
  }

  function getThreshold() {
     $.ajax({
      url:thresholdURL,
      dataType:'json',
      success: function(data) {
        $('#threshold').spinner('value', data);
      }
    });
  }

  getThreshold();

  function setThreshold() {
    var threshold =  Math.round($('#threshold').spinner('value'));
    var settings = threshold;
    $.ajax({
      url:thresholdURL,
      type: 'POST',
      contentType:'application/json',
      data: JSON.stringify(settings)
    });
  }

  $('#threshold').spinner({min:10000,max:10000000,step:10000});
  $('#thresholdget').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(getThreshold);
  $('#thresholdset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(setThreshold);

  function getBlockMinutes() {
     $.ajax({
      url:blockMinutesURL,
      dataType:'json',
      success: function(data) {
        $('#blockminutes').spinner('value', data);
      }
    });
  }

  getBlockMinutes();

  function setBlockMinutes() {
    var blockminutes =  Math.round($('#blockminutes').spinner('value'));
    var settings = blockminutes;
    $.ajax({
      url:blockMinutesURL,
      type: 'POST',
      contentType:'application/json',
      data: JSON.stringify(settings)
    });
  }

  $('#blockminutes').spinner({min:10,max:1440,step:10});
  $('#blockminutesget').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(getBlockMinutes);
  $('#blockminutesset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(setBlockMinutes);

  function refreshGroups() {
    $.ajax({
      url:groupsInfoURL,
      dataType: 'json',
      success: function(data) {
        $('#numgroups').val(data.groups).removeClass(data.groups ? 'error' : 'good').addClass(data.groups ? 'good' : 'error');
        $('#numcidrs').val(data.cidrs).removeClass(data.cidrs ? 'error' : 'good').addClass(data.cidrs ? 'good' : 'error');
      }
    });
  }

  refreshGroups();

  function getGroups() {
    location.href = groupsURL;
  }

  $('#groupsrefresh').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(refreshGroups);
  $('#groupsget').button({icons:{primary:'ui-icon-search'},text:false}).click(getGroups);
  $('#groupsfile').hide().change(function(event) {
    var input = event.target;
    var reader = new FileReader();
    var $this = $(this);
    reader.onload = function(){
      var text = reader.result;
      $this.wrap('<form>').closest('form').get(0).reset();
      $this.unwrap();
      $.ajax({
        url:groupsURL,
        type: 'POST',
        contentType:'application/json',
        data:text,
        success:refreshGroups,
        error: function() { warningDialog('Badly formatted groups'); }
      });
    };
    reader.readAsText(input.files[0]);
  });
  $('#groupsset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(function() {$('#groupsfile').click();});

  function updateData(data) {
    if(!data
      || !data.trend
      || !data.trend.times
      || data.trend.times.length == 0) return;

    if(db.trend) {
      // merge in new data
      var maxPoints = db.trend.maxPoints;
      var remove = db.trend.times.length > maxPoints ? db.trend.times.length - maxPoints : 0;
      db.trend.times = db.trend.times.concat(data.trend.times);
      if(remove) db.trend.times = db.trend.times.slice(remove);
      for(var name in db.trend.trends) {
        db.trend.trends[name] = db.trend.trends[name].concat(data.trend.trends[name]);
        if(remove) db.trend.trends[name] = db.trend.trends[name].slice(remove);
      }
    } else db.trend = data.trend;

    db.trend.start = new Date(db.trend.times[0]);
    db.trend.end = new Date(db.trend.times[db.trend.times.length - 1]);
    db.trend.values = data.trend.values;

    $.event.trigger({type:'updateChart'});
  }

  function pollTrends() {
    $.ajax({
      url: dataURL,
      data: db.trend && db.trend.end ? {after:db.trend.end.getTime()} : null,
      success: function(data) {
        updateData(data);
        if(data && data.trend && data.trend.values && lastControlsID !== data.trend.values.control_id) refreshControls();
        setTimeout(pollTrends, 1000);
      },
      error: function(result,status,errorThrown) {
        setTimeout(pollTrends,5000);
      },
      timeout: 60000
    });
  };

  $(window).resize(function() {
    $.event.trigger({type:'updateChart'});
  });

  dialog = $('#dialog').dialog({
    modal:true,
    autoOpen:false,
    buttons: {
      Remove:removeControl,
      Install:installControl,
      Close: function() { dialog.dialog("close"); }
    }
  });
  $('#controller_mode').buttonset();
  $('#controller_mode').change(function(evt) {
    var newMode = $(evt.target).attr('id');
    if(newMode === ctl_mode) return;

    $.ajax({
      url:controlsURL,
      type:'get',
      data:{action:'automatic' === newMode ? 'enable' : 'disable'}
    });
    ctl_mode = newMode;
  });
  pollTrends();
  refreshControls();
  refreshGroups();
});
<|endoftext|>


<commit_before>$(function() {
  var restPath =  '../scripts/top.js/';
  var shortcutsURL = restPath + 'shortcuts/json';
  var keysURL =  restPath + 'flowkeys/json';
  var topURL = restPath + 'flows/json';

  var SEP = '_SEP_';

  var defaults = {
    tab:0,
    hlp0:'show',
    hlp1:'hide',
    hlp2:'hide',
    keys:'',
    value:'',
    filter:'',
    topshow:50,
  };

  var state = {};
  $.extend(state,defaults);

  function nf(value,fix) {
    var suffixes = ["\u00B5", "m", "", "K", "M", "G", "T", "P", "E"];
    if (value === 0) return value;
    var i = 2;
    var divisor = 1;
    var factor = 1000;
    var absVal, scaled;
    absVal = Math.abs(value);
    while (i < suffixes.length) {
      if ((absVal / divisor) < factor) {
        break;
      }
      divisor *= factor;
      i++;
    }
    scaled = Math.round(absVal * factor / divisor) / factor;
    if(fix) scaled = scaled.toFixed(fix);
    return scaled + suffixes[i];
  };

  function createQuery(params) {
    var query, key, value;
    for(key in params) {
      value = params[key];
      if(value === defaults[key]) continue;
      if(query) query += '&';
      else query = '';
      query += encodeURIComponent(key)+'='+encodeURIComponent(value);
    }
    return query;
  }

  function getState(key, defVal) {
    return window.sessionStorage.getItem(key) || state[key] || defVal;
  }

  function setState(key, val, showQuery) {
    state[key] = val;
    window.sessionStorage.setItem(key, val);
    if(showQuery) {
      var query = createQuery(state);
      window.history.replaceState({},'',query ? '?' + query : './');
    }
  }

  function setQueryParams(query) {
    var vars = query.split('&');
    var params = {};
    for(var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=');
      if(pair.length === 2) setState(decodeURIComponent(pair[0]), decodeURIComponent(pair[1]),false);
    }
  }

  var search = window.location.search;
  if(search) setQueryParams(search.substring(1));

  $('#help-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('hlp'+idx, 'hide') === 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('hlp'+idx, newIndex === 0 ? 'show' : 'hide', true);
      }
    });
  });

  $('#tabs').tabs({
    active: getState('tab', 0),
    activate: function(event, ui) {
      var newIndex = ui.newTab.index();
      setState('tab', newIndex, true);
      $.event.trigger({type:'updateChart'});
    },
    create: function(event,ui) {
      $.event.trigger({type:'updateChart'});
    }
  });

  $('#clone_button').button({icons:{primary:'ui-icon-newwin'},text:false}).click(function() {
     window.open(window.location);
  });

  var top_keys = getState('keys','');
  var top_value = getState('value','');
  var top_filter = getState('filter','');

  $('#keys')
    .val(top_keys)
    .bind( "keydown", function( event ) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
        $( this ).autocomplete( "instance" ).menu.active ) {
	   event.preventDefault();
        }
      })
    .autocomplete({
      minLength: 0,
      source: function( request, response) {
	$.getJSON(keysURL, { search: request.term.split(/,\s*/).pop() }, response)
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var terms = this.value.split(/,\s*/);
        // remove the current input
        terms.pop();
        // add the selected item
        terms.push( ui.item.value );
        // add placeholder to get the comma-and-space at the end
        terms.push( "" );
        this.value = terms.join( "," );
        return false;
      }
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#value')
    .val(top_value)
    .autocomplete({
       minLength:0,
       source:['bps', 'Bps', 'fps']
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#filter')
    .val(top_filter)
    .bind( "keydown", function( event ) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
        $( this ).autocomplete( "instance" ).menu.active ) {
          event.preventDefault();
        }
    })
    .autocomplete({
      minLength: 0,
      source: function( request, response) {
        $.getJSON(keysURL, { search: request.term.split(/[&|(]\s*/).pop() }, response)
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var val = this.value;
        var re = /[&|(]/g;
        var end = 0;
        while(re.test(val)) { end = re.lastIndex; }
        this.value = val.substring(0,end) + ui.item.value + "=";
        return false;
      }
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#cleardef').button({icons:{primary:'ui-icon-cancel'},text:false}).click(function() {
    $('#keys').val('');
    $('#value').val('');
    $('#filter').val('');
    top_keys = '';
    top_value = '';
    top_filter = '';
    setState('keys',top_keys);
    setState('value',top_value);
    setState('filter',top_filter,true);
    emptyTopFlows();
  });
  $('#submitdef').button({icons:{primary:'ui-icon-check'},text:false}).click(function() {
    top_keys = $.trim($('#keys').val()).replace(/(,$)/g, "");
    top_value = $.trim($('#value').val());
    top_filter = $.trim($('#filter').val());
    setState('keys',top_keys);
    setState('value',top_value);
    setState('filter',top_filter,true);
    emptyTopFlows();
  });
  function valueToKey(val) {
    var key;
    switch(val) {
    case 'bps':
      key = 'bytes';
      break;
    case 'Bps':
      key = 'bytes';
      break;
    case 'fps':
      key = 'frames';
      break;
    default:
      key = val;
    }
    return key;
  }

  function valueToScale(val) {
    return 'bps' === val ? 8 : 1;
  }

  function valueToTitle(val) {
    var title;
    switch(val) {
    case 'bps':
      title = 'bits per second';
      break;
    case 'bytes':
      case 'Bps':
      title = 'bytes per second';
      break;
    case 'frames':
      case 'fps':
      title  = 'frames per second';
      break;
    case 'requests':
      title = 'requests per second';
      break;
    default:
      title = val;
    }
    return title;
  }

  function addFilter(key, value, filter) {
    var newFilter = filter;
    if(!newFilter) newFilter = "";
    if(newFilter.length > 0) newFilter += "&";
    newFilter += key + "='" + value + "'";
    $('#filter').val(newFilter);
    top_filter = newFilter;
    setState('filter', top_filter, true);
    emptyTopFlows();
  }

  function topFlowsClick(e) {
    if(e.data && e.data.query && e.data.values) {
      var col = $(this).parent().children().index($(this));
      var row = $(this).parent().parent().children().index($(this).parent());
      var key = e.data.query.keys.split(',')[col];
      var val = e.data.values[row].key.split(SEP)[col];
      addFilter(key,val,e.data.query.filter);
    }
  }

  function escapeHTML(t) { return $('
').text(t).html(); }

  function updateTopFlows(data,query,scale,title) {
    if($('#shortcutstable_wrapper').is(':visible')) return;

    var i, j, row, maxVal,val,barwidth,ncols = 1, table = '';
    table += '
';
    table += '
';
    if(query.keys && query.value) {
      var headers = query.keys.split(',');
      for(i = 0; i < headers.length; i++) {
        table += '' + headers[i] + '	';
      }
      table += '' + title + '	';
      ncols = headers.length + 1;
    }
    table += '
';
    table += '
';
    if(data && data.length > 0) {
      maxVal = data[0].value;
      for(i = 0; i < data.length; i++) {
        if(!data[i].key) continue;
        table += '
';
        row = data[i].key.split(SEP);
        for(j = 0; j < row.length; j++) {
          table += '' + escapeHTML(row[j]) + '	';
        }
        val = data[i].value;
        barwidth = maxVal > 0 ? Math.round((val / maxVal) * 60) : 0;
        barwidth = barwidth > 0 ? barwidth + "%" : "1px";
        table += '

' + nf(val * scale, 3) + '	';
        table += '
';
      }
    } else {
      table += '
no data
';
    }
    table += '
';
    table += '
';
    $('#flowtable').empty().append(table);
    $('#flowtable tbody .flowkey').click({query:query, values:data},topFlowsClick);
  }

  var $shortcutsTable;
  function initializeShortcutsTable() {
    $shortcutsTable = $('#shortcutstable').DataTable({
      ajax: {
        url: shortcutsURL,
        dataSrc: function(data) {
          return data;
        }
      },
      deferRenderer: true,
      columns:[
        {data:'category'},
        {data:'protocol'},
        {data:'description'}
      ],
      columnDefs: [ { targets: 2, orderable: false } ]
    })
    .page.len(getState('topshow'))
    .on('length', function(e,settings,len) {
      setState('topshow', len, true);
    })
    .on('xhr', function(e,settings,json) {
      var len = json.length || 0;
      $('#numshortcuts').val(len).removeClass(len ? 'error' : 'good').addClass(len ? 'good' : 'error');;
    })
    .on('click', 'tr', function(e) {
      var row = $shortcutsTable.row($(this));
      var shortcut = row.data();
      if(!shortcut) return;
      top_keys = shortcut.keys || '';
      top_value = shortcut.value || '';
      top_filter = shortcut.filter || '';
      $('#keys').val(top_keys);
      $('#value').val(top_value);
      $('#filter').val(top_filter);
      setState('keys', top_keys, false);
      setState('value', top_value, false);
      setState('filter', top_filter, true);
      emptyTopFlows();
    });
  }

  var running_topflows;
  var timeout_topflows;
  function pollTopFlows() {
    running_topflows = true;
    var query = {keys:top_keys,value:valueToKey(top_value),filter:top_filter};
    var scale = valueToScale(top_value);
    var title = valueToTitle(top_value);
    $.ajax({
      url: topURL,
      data: query,
      success: function(data) {
        if(running_topflows) {
          updateTopFlows(data,query, scale, title);
          timeout_topflows = setTimeout(pollTopFlows, 2000);
        }
      },
      error: function(result,status,errorThrown) {
        if(running_topflows) timeout_topflows = setTimeout(pollTopFlows, 2000);
      },
      timeout: 60000
    });
  }

  function stopPollTopFlows() {
    running_topflows = false;
    if(timeout_topflows) clearTimeout(timeout_topflows);
  }

  function emptyTopFlows() {
    stopPollTopFlows();
    if(!top_keys || !top_value) {
      $('#shortcutstable_wrapper').show();
      $('#flowtable').empty();
      return;
    }
    $('#shortcutstable_wrapper').hide();
    var query = {keys:top_keys,value:valueToKey(top_value),filter:top_filter};
    var scale = valueToScale(top_value);
    var title = valueToTitle(top_value);
    updateTopFlows([],query,scale,title);
    pollTopFlows();
  }

  function refreshShortcuts() {
    $shortcutsTable.ajax.reload();
  }

  function getShortcuts() {
    location.href = shortcutsURL;
  }

  function warningDialog(message) {
    $('
' + message + '
').dialog({dialogClass:'alert', modal:true, buttons:{'Close': function() { $(this).dialog('close'); }}})
  }

  $('#shortcutsrefresh').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(refreshShortcuts);
  $('#shortcutsget').button({icons:{primary:'ui-icon-search'},text:false}).click(getShortcuts);
  $('#shortcutsfile').hide().change(function(event) {
    var input = event.target;
    var reader = new FileReader();
    var $this = $(this);
    reader.onload = function(){
      var text = reader.result;
      $this.wrap('<form>').closest('form').get(0).reset();
      $this.unwrap();
      $.ajax({
        url:shortcutsURL,
        type: 'POST',
        contentType:'application/json',
        data:text,
        success:refreshShortcuts,
        error: function() { warningDialog('Badly formatted shortcuts'); }
      });
    };
    reader.readAsText(input.files[0]);
  });
  $('#shortcutsset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(function() {$('#shortcutsfile').click();});

  initializeShortcutsTable();
  emptyTopFlows();
});
<commit_msg>quote key when adding filter<commit_after>$(function() {
  var restPath =  '../scripts/top.js/';
  var shortcutsURL = restPath + 'shortcuts/json';
  var keysURL =  restPath + 'flowkeys/json';
  var topURL = restPath + 'flows/json';

  var SEP = '_SEP_';

  var defaults = {
    tab:0,
    hlp0:'show',
    hlp1:'hide',
    hlp2:'hide',
    keys:'',
    value:'',
    filter:'',
    topshow:50,
  };

  var state = {};
  $.extend(state,defaults);

  function nf(value,fix) {
    var suffixes = ["\u00B5", "m", "", "K", "M", "G", "T", "P", "E"];
    if (value === 0) return value;
    var i = 2;
    var divisor = 1;
    var factor = 1000;
    var absVal, scaled;
    absVal = Math.abs(value);
    while (i < suffixes.length) {
      if ((absVal / divisor) < factor) {
        break;
      }
      divisor *= factor;
      i++;
    }
    scaled = Math.round(absVal * factor / divisor) / factor;
    if(fix) scaled = scaled.toFixed(fix);
    return scaled + suffixes[i];
  };

  function createQuery(params) {
    var query, key, value;
    for(key in params) {
      value = params[key];
      if(value === defaults[key]) continue;
      if(query) query += '&';
      else query = '';
      query += encodeURIComponent(key)+'='+encodeURIComponent(value);
    }
    return query;
  }

  function getState(key, defVal) {
    return window.sessionStorage.getItem(key) || state[key] || defVal;
  }

  function setState(key, val, showQuery) {
    state[key] = val;
    window.sessionStorage.setItem(key, val);
    if(showQuery) {
      var query = createQuery(state);
      window.history.replaceState({},'',query ? '?' + query : './');
    }
  }

  function setQueryParams(query) {
    var vars = query.split('&');
    var params = {};
    for(var i = 0; i < vars.length; i++) {
      var pair = vars[i].split('=');
      if(pair.length === 2) setState(decodeURIComponent(pair[0]), decodeURIComponent(pair[1]),false);
    }
  }

  var search = window.location.search;
  if(search) setQueryParams(search.substring(1));

  $('#help-acc > div').each(function(idx) {
    $(this).accordion({
      heightStyle:'content',
      collapsible: true,
      active: getState('hlp'+idx, 'hide') === 'show' ? 0 : false,
      activate: function(event, ui) {
        var newIndex = $(this).accordion('option','active');
        setState('hlp'+idx, newIndex === 0 ? 'show' : 'hide', true);
      }
    });
  });

  $('#tabs').tabs({
    active: getState('tab', 0),
    activate: function(event, ui) {
      var newIndex = ui.newTab.index();
      setState('tab', newIndex, true);
      $.event.trigger({type:'updateChart'});
    },
    create: function(event,ui) {
      $.event.trigger({type:'updateChart'});
    }
  });

  $('#clone_button').button({icons:{primary:'ui-icon-newwin'},text:false}).click(function() {
     window.open(window.location);
  });

  var top_keys = getState('keys','');
  var top_value = getState('value','');
  var top_filter = getState('filter','');

  $('#keys')
    .val(top_keys)
    .bind( "keydown", function( event ) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
        $( this ).autocomplete( "instance" ).menu.active ) {
	   event.preventDefault();
        }
      })
    .autocomplete({
      minLength: 0,
      source: function( request, response) {
	$.getJSON(keysURL, { search: request.term.split(/,\s*/).pop() }, response)
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var terms = this.value.split(/,\s*/);
        // remove the current input
        terms.pop();
        // add the selected item
        terms.push( ui.item.value );
        // add placeholder to get the comma-and-space at the end
        terms.push( "" );
        this.value = terms.join( "," );
        return false;
      }
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#value')
    .val(top_value)
    .autocomplete({
       minLength:0,
       source:['bps', 'Bps', 'fps']
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#filter')
    .val(top_filter)
    .bind( "keydown", function( event ) {
      if ( event.keyCode === $.ui.keyCode.TAB &&
        $( this ).autocomplete( "instance" ).menu.active ) {
          event.preventDefault();
        }
    })
    .autocomplete({
      minLength: 0,
      source: function( request, response) {
        $.getJSON(keysURL, { search: request.term.split(/[&|(]\s*/).pop() }, response)
      },
      focus: function() {
        // prevent value inserted on focus
        return false;
      },
      select: function( event, ui ) {
        var val = this.value;
        var re = /[&|(]/g;
        var end = 0;
        while(re.test(val)) { end = re.lastIndex; }
        this.value = val.substring(0,end) + ui.item.value + "=";
        return false;
      }
    })
    .focus(function() { $(this).autocomplete('search'); });

  $('#cleardef').button({icons:{primary:'ui-icon-cancel'},text:false}).click(function() {
    $('#keys').val('');
    $('#value').val('');
    $('#filter').val('');
    top_keys = '';
    top_value = '';
    top_filter = '';
    setState('keys',top_keys);
    setState('value',top_value);
    setState('filter',top_filter,true);
    emptyTopFlows();
  });
  $('#submitdef').button({icons:{primary:'ui-icon-check'},text:false}).click(function() {
    top_keys = $.trim($('#keys').val()).replace(/(,$)/g, "");
    top_value = $.trim($('#value').val());
    top_filter = $.trim($('#filter').val());
    setState('keys',top_keys);
    setState('value',top_value);
    setState('filter',top_filter,true);
    emptyTopFlows();
  });
  function valueToKey(val) {
    var key;
    switch(val) {
    case 'bps':
      key = 'bytes';
      break;
    case 'Bps':
      key = 'bytes';
      break;
    case 'fps':
      key = 'frames';
      break;
    default:
      key = val;
    }
    return key;
  }

  function valueToScale(val) {
    return 'bps' === val ? 8 : 1;
  }

  function valueToTitle(val) {
    var title;
    switch(val) {
    case 'bps':
      title = 'bits per second';
      break;
    case 'bytes':
      case 'Bps':
      title = 'bytes per second';
      break;
    case 'frames':
      case 'fps':
      title  = 'frames per second';
      break;
    case 'requests':
      title = 'requests per second';
      break;
    default:
      title = val;
    }
    return title;
  }

  function addFilter(key, value, filter) {
    var newFilter = filter;
    if(!newFilter) newFilter = "";
    if(newFilter.length > 0) newFilter += "&";
    newFilter += "'" + key + "'='" + value + "'";
    $('#filter').val(newFilter);
    top_filter = newFilter;
    setState('filter', top_filter, true);
    emptyTopFlows();
  }

  function topFlowsClick(e) {
    if(e.data && e.data.query && e.data.values) {
      var col = $(this).parent().children().index($(this));
      var row = $(this).parent().parent().children().index($(this).parent());
      var key = e.data.query.keys.split(',')[col];
      var val = e.data.values[row].key.split(SEP)[col];
      addFilter(key,val,e.data.query.filter);
    }
  }

  function escapeHTML(t) { return $('
').text(t).html(); }

  function updateTopFlows(data,query,scale,title) {
    if($('#shortcutstable_wrapper').is(':visible')) return;

    var i, j, row, maxVal,val,barwidth,ncols = 1, table = '';
    table += '
';
    table += '
';
    if(query.keys && query.value) {
      var headers = query.keys.split(',');
      for(i = 0; i < headers.length; i++) {
        table += '' + headers[i] + '	';
      }
      table += '' + title + '	';
      ncols = headers.length + 1;
    }
    table += '
';
    table += '
';
    if(data && data.length > 0) {
      maxVal = data[0].value;
      for(i = 0; i < data.length; i++) {
        if(!data[i].key) continue;
        table += '
';
        row = data[i].key.split(SEP);
        for(j = 0; j < row.length; j++) {
          table += '' + escapeHTML(row[j]) + '	';
        }
        val = data[i].value;
        barwidth = maxVal > 0 ? Math.round((val / maxVal) * 60) : 0;
        barwidth = barwidth > 0 ? barwidth + "%" : "1px";
        table += '

' + nf(val * scale, 3) + '	';
        table += '
';
      }
    } else {
      table += '
no data
';
    }
    table += '
';
    table += '
';
    $('#flowtable').empty().append(table);
    $('#flowtable tbody .flowkey').click({query:query, values:data},topFlowsClick);
  }

  var $shortcutsTable;
  function initializeShortcutsTable() {
    $shortcutsTable = $('#shortcutstable').DataTable({
      ajax: {
        url: shortcutsURL,
        dataSrc: function(data) {
          return data;
        }
      },
      deferRenderer: true,
      columns:[
        {data:'category'},
        {data:'protocol'},
        {data:'description'}
      ],
      columnDefs: [ { targets: 2, orderable: false } ]
    })
    .page.len(getState('topshow'))
    .on('length', function(e,settings,len) {
      setState('topshow', len, true);
    })
    .on('xhr', function(e,settings,json) {
      var len = json.length || 0;
      $('#numshortcuts').val(len).removeClass(len ? 'error' : 'good').addClass(len ? 'good' : 'error');;
    })
    .on('click', 'tr', function(e) {
      var row = $shortcutsTable.row($(this));
      var shortcut = row.data();
      if(!shortcut) return;
      top_keys = shortcut.keys || '';
      top_value = shortcut.value || '';
      top_filter = shortcut.filter || '';
      $('#keys').val(top_keys);
      $('#value').val(top_value);
      $('#filter').val(top_filter);
      setState('keys', top_keys, false);
      setState('value', top_value, false);
      setState('filter', top_filter, true);
      emptyTopFlows();
    });
  }

  var running_topflows;
  var timeout_topflows;
  function pollTopFlows() {
    running_topflows = true;
    var query = {keys:top_keys,value:valueToKey(top_value),filter:top_filter};
    var scale = valueToScale(top_value);
    var title = valueToTitle(top_value);
    $.ajax({
      url: topURL,
      data: query,
      success: function(data) {
        if(running_topflows) {
          updateTopFlows(data,query, scale, title);
          timeout_topflows = setTimeout(pollTopFlows, 2000);
        }
      },
      error: function(result,status,errorThrown) {
        if(running_topflows) timeout_topflows = setTimeout(pollTopFlows, 2000);
      },
      timeout: 60000
    });
  }

  function stopPollTopFlows() {
    running_topflows = false;
    if(timeout_topflows) clearTimeout(timeout_topflows);
  }

  function emptyTopFlows() {
    stopPollTopFlows();
    if(!top_keys || !top_value) {
      $('#shortcutstable_wrapper').show();
      $('#flowtable').empty();
      return;
    }
    $('#shortcutstable_wrapper').hide();
    var query = {keys:top_keys,value:valueToKey(top_value),filter:top_filter};
    var scale = valueToScale(top_value);
    var title = valueToTitle(top_value);
    updateTopFlows([],query,scale,title);
    pollTopFlows();
  }

  function refreshShortcuts() {
    $shortcutsTable.ajax.reload();
  }

  function getShortcuts() {
    location.href = shortcutsURL;
  }

  function warningDialog(message) {
    $('
' + message + '
').dialog({dialogClass:'alert', modal:true, buttons:{'Close': function() { $(this).dialog('close'); }}})
  }

  $('#shortcutsrefresh').button({icons:{primary:'ui-icon-arrowrefresh-1-e'},text:false}).click(refreshShortcuts);
  $('#shortcutsget').button({icons:{primary:'ui-icon-search'},text:false}).click(getShortcuts);
  $('#shortcutsfile').hide().change(function(event) {
    var input = event.target;
    var reader = new FileReader();
    var $this = $(this);
    reader.onload = function(){
      var text = reader.result;
      $this.wrap('<form>').closest('form').get(0).reset();
      $this.unwrap();
      $.ajax({
        url:shortcutsURL,
        type: 'POST',
        contentType:'application/json',
        data:text,
        success:refreshShortcuts,
        error: function() { warningDialog('Badly formatted shortcuts'); }
      });
    };
    reader.readAsText(input.files[0]);
  });
  $('#shortcutsset').button({icons:{primary:'ui-icon-arrowstop-1-n'},text:false}).click(function() {$('#shortcutsfile').click();});

  initializeShortcutsTable();
  emptyTopFlows();
});
<|endoftext|>


<commit_before>UI.once('init', function(){
	var UI = this
	,   user = {}
	,   delay = 1500
	,   missed_messages = 0
	,   standard_title = document.title
	,   last_sound_time = 0;

	var titleAlternator = {
		start: function(){
			if(this.timer) return;
			this.show_standard = false
			this.timer = setInterval(this.alternate.bind(this), delay);
			this.alternate();
		},

		stop: function(){
			clearInterval(this.timer);
			this.timer = null;
			/* Changing the title within the onFocus event doesn't seem to have any effect */
			setTimeout(this.alternate.bind(this), 100);
		},

		alternate: function(){
			document.title = !this.timer || this.show_standard ? standard_title : (missed_messages + " Unread Messages");
			this.show_standard = !this.show_standard;
		}
	}

	UI.on('user_message', function(data){
		missed_messages += $.isArray(data) ? data.length : 1;
		if(user.away)	titleAlternator.start();
	});

	function onBlur(){
		user.away = true;
		missed_messages = 0;
	}

	function onFocus(){
		user.away = false;
		missed_messages = 0;
		titleAlternator.stop();
	}

	if($.browser.msie){
		document.onfocusin = onFocus;
		document.onfocusout = onBlur;
	}else{
		window.onfocus = onFocus;
		window.onblur = onBlur;
	}

	if(window.Audio){
		var sound;
		function ding(){
			if(!sound) sound = new Audio("/sounds/missed-message.wav");
			sound.play();
		}

		UI.on('user_message', function(data){
			if(user.away){
				var now = (new Date()).getTime();
				if(now - last_sound_time >= 3000){
					last_sound_time = now;
					ding();
					/* This seems to fix the issues we were having with Chrome */
					setTimeout(function(){sound.pause(); sound.currentTime =0;}, 2000)
				}
			}
		});
	}
});

<commit_msg>Change sound notification to happen at most every 60 seconds.<commit_after>UI.once('init', function(){
	var UI = this
	,   user = {}
	,   delay = 1500
	,   missed_messages = 0
	,   standard_title = document.title
	,   last_sound_time = 0;

	var titleAlternator = {
		start: function(){
			if(this.timer) return;
			this.show_standard = false
			this.timer = setInterval(this.alternate.bind(this), delay);
			this.alternate();
		},

		stop: function(){
			clearInterval(this.timer);
			this.timer = null;
			/* Changing the title within the onFocus event doesn't seem to have any effect */
			setTimeout(this.alternate.bind(this), 100);
		},

		alternate: function(){
			document.title = !this.timer || this.show_standard ? standard_title : (missed_messages + " Unread Messages");
			this.show_standard = !this.show_standard;
		}
	}

	UI.on('user_message', function(data){
		missed_messages += $.isArray(data) ? data.length : 1;
		if(user.away)	titleAlternator.start();
	});

	function onBlur(){
		user.away = true;
		missed_messages = 0;
	}

	function onFocus(){
		user.away = false;
		missed_messages = 0;
		titleAlternator.stop();
	}

	if($.browser.msie){
		document.onfocusin = onFocus;
		document.onfocusout = onBlur;
	}else{
		window.onfocus = onFocus;
		window.onblur = onBlur;
	}

	if(window.Audio){
		var sound;
		function ding(){
			if(!sound) sound = new Audio("/sounds/missed-message.wav");
			sound.play();
		}

		UI.on('user_message', function(data){
			if(user.away){
				var now = (new Date()).getTime();
				if(now - last_sound_time >= 60000){
					last_sound_time = now;
					ding();
					/* This seems to fix the issues we were having with Chrome */
					setTimeout(function(){sound.pause(); sound.currentTime =0;}, 2000)
				}
			}
		});
	}
});

<|endoftext|>


<commit_before>// avoids stack overflow for long lists
exports.forEach = function (array, func, callback) {
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null);
		func(array[i], function (err) {
			if (err)
				return callback(err);
			process.nextTick(step.bind(null, i + 1));
		});
	}
};

exports.map = function (array, func, callback) {
	var results = [];
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null, results);
		func(array[i], function (err, res) {
			if (err)
				return callback(err);
			results.push(res);
			process.nextTick(step.bind(null, i + 1));
		});
	}
};
<commit_msg>Use setImmediate in tail<commit_after>// avoids stack overflow for long lists
exports.forEach = function (array, func, callback) {
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null);
		func(array[i], function (err) {
			if (err)
				return callback(err);
			setImmediate(step, i + 1);
		});
	}
};

exports.map = function (array, func, callback) {
	var results = [];
	step(0);
	function step(i) {
		if (i >= array.length)
			return callback(null, results);
		func(array[i], function (err, res) {
			if (err)
				return callback(err);
			results.push(res);
			setImmediate(step, i + 1);
		});
	}
};
<|endoftext|>


<commit_before>var objects = [
  { name:'Mercury', distance:0.3871 },
  { name:'Venus', distance:0.7233 },
  { name:'Earth', distance:1, color: 'green' },
  { name:'Mars', distance:1.5237, color: 'red' },
  { name:'Jupiter', distance:5.2028 },
  { name:'Saturn', distance:9.5550 },
  { name:'Uranus', distance:19.1914 },
  { name:'Neptune', distance:30.1094 },
]

var SCALE = 15;

function orbit(d) { return d.distance * SCALE; }
function color(d) { return d.color ? d.color : '#aaa'; }

var vis = null;

var orbits = null;

var current_craft = null;
var current_step_idx = null;
var auto_forward = false;

function update_preview() {
    $("#detail-view").fadeOut(50);
    if (current_step_idx != null) {
        var step = Crafts[current_craft]['path'][current_step_idx];
        $("#clicked-craft").html(current_craft);
        $("#clicked-date").html(step[0]);

        var image_urls = Crafts[current_craft]['image_urls'];
        var url = image_urls[current_step()[0]] || "-";

        $("#detail-view img").attr("src", url);
        $("#detail-view a").attr("href", url);
        $("#detail-view").stop(true).fadeIn(50);
    }
}

function x_from_step(step) { return step[1] * SCALE; }
function y_from_step(step) { return -step[2] * SCALE; }

function current_path() { return Crafts[current_craft]['path']; }
function current_step() { return current_path()[current_step_idx]; }

function update_marker() {
  d3.select("#stepMarker").remove();
  vis.append("ellipse").attr("id", "stepMarker")
     .attr("cx", x_from_step(current_step())).attr("cy", y_from_step(current_step())).attr("rx", 3).attr("ry", 3).attr("fill", "blue");
}

function set_current_step(idx) {
    current_step_idx = Math.min(current_path().length - 1, Math.max(0, idx));
    update_preview();
    update_marker();
}

function change_current(direction) {
  if (current_step_idx == null) {
    if (direction == -1) {
      set_current_step(current_path().length - 1);
    } else {
      set_current_step(0);
    }
  } else {
    set_current_step(current_step_idx + direction);
  }
}

function do_the_auto_forwarding() {
  if (auto_forward)
    change_current(1);
}
setInterval(do_the_auto_forwarding, 1000);

$(document).keydown(function(e){
//    if (e.keyCode == 37) {
//       change_current(-1);
//       return false;
//    }
//    if (e.keyCode == 38) {
//       change_current(-10);
//       return false;
//    }
//    if (e.keyCode == 39) {
//       change_current(1);
//       return false;
//    }
//    if (e.keyCode == 40) {
//       change_current(10);
//       return false;
//    }
//    if (e.keyCode == 32) {
//       auto_forward = !auto_forward;
//       return false;
//    }
});

var Crafts = {};

function load_image_urls(name, on_done) {
    var image_urls = {};
    $.getJSON('urls_' + name + '.json', function(data) {
        for (var i = 0; i < data.length; i++) {
            var date_url = data[i];
            image_urls[date_url[0]] = date_url[1];
        }
        Crafts[name]['image_urls'] = image_urls;
        on_done();
    });
}

function load_path(name, on_done) {
    var path = [];
    $.getJSON('path_' + name + '.json', function(data) {
        Crafts[name]['path'] = data;
        console.log("LOADED", name, Crafts[name]);
        on_done();
    }).fail(function(jqXHR, textStatus, errorThrown) { alert("error" +  textStatus + " " + errorThrown); });
}

function show_craft(name) {
    var path = Crafts[name]['path'];
    var image_urls = Crafts[name]['image_urls'];
    var path_points = vis.selectAll('ellipse.step-' + name).data(path, function(p) { return p[0]; });

    function r_from_step(step) {
        if (image_urls[step[0]]) {
            return 3;
        } else {
            return 0.2;
        }
    }

    function on_step_click(step, idx) {
        current_craft = name;
        current_step_idx = idx;
        update_preview();
        update_marker();
        return false;
    }

    path_points
        .enter().append('ellipse').attr('class', 'step-' + name)
        .attr('cx', x_from_step).attr('cy', y_from_step).attr('rx', r_from_step).attr('ry', r_from_step)
        .attr('fill', 'green').attr('stroke', 'green')
        .attr('opacity', 1).classed('step', true)
        .on("mouseover",function(d,i) { d3.select(this).attr("fill","red"); })
        .on("mouseout",function(d,i) { d3.select(this).attr("fill","green"); })
        .on("click",on_step_click)
        .append('svg:title').text(function(p) { return p[0] + ": " + p[1] + "," + p[2];})
    ;
}

function load_craft(name) {
    Crafts[name] = {};
    load_image_urls(name, function () {
        load_path(name, function () {
            show_craft(name);
        });
    });
}

function start_viewer() {
    vis = d3.select("#view").append("svg").append('g').attr('transform','translate(200,350) rotate(-90)');

    orbits = vis.selectAll('ellipse.orbit').data(objects, function(d) { return d.name; });
    orbits
        .enter().append('ellipse').attr('cx',0).attr('cy',0).attr('rx',orbit).attr('ry',orbit)
        .attr('fill', 'none').attr('opacity',1).attr('stroke-width', 1).attr('stroke',color).classed('orbit',true);

    load_craft('vger1');
    load_craft('vger2');

    update_preview();
}
<commit_msg>Unlocked keys.<commit_after>var objects = [
  { name:'Mercury', distance:0.3871 },
  { name:'Venus', distance:0.7233 },
  { name:'Earth', distance:1, color: 'green' },
  { name:'Mars', distance:1.5237, color: 'red' },
  { name:'Jupiter', distance:5.2028 },
  { name:'Saturn', distance:9.5550 },
  { name:'Uranus', distance:19.1914 },
  { name:'Neptune', distance:30.1094 },
]

var SCALE = 15;

function orbit(d) { return d.distance * SCALE; }
function color(d) { return d.color ? d.color : '#aaa'; }

var vis = null;

var orbits = null;

var current_craft = null;
var current_step_idx = null;
var auto_forward = false;

function update_preview() {
    $("#detail-view").fadeOut(50);
    if (current_step_idx != null) {
        var step = Crafts[current_craft]['path'][current_step_idx];
        $("#clicked-craft").html(current_craft);
        $("#clicked-date").html(step[0]);

        var image_urls = Crafts[current_craft]['image_urls'];
        var url = image_urls[current_step()[0]] || "-";

        $("#detail-view img").attr("src", url);
        $("#detail-view a").attr("href", url);
        $("#detail-view").stop(true).fadeIn(50);
    }
}

function x_from_step(step) { return step[1] * SCALE; }
function y_from_step(step) { return -step[2] * SCALE; }

function current_path() { return Crafts[current_craft]['path']; }
function current_step() { return current_path()[current_step_idx]; }

function update_marker() {
  d3.select("#stepMarker").remove();
  vis.append("ellipse").attr("id", "stepMarker")
     .attr("cx", x_from_step(current_step())).attr("cy", y_from_step(current_step())).attr("rx", 3).attr("ry", 3).attr("fill", "blue");
}

function set_current_step(idx) {
    current_step_idx = Math.min(current_path().length - 1, Math.max(0, idx));
    update_preview();
    update_marker();
}

function change_current(direction) {
  if (current_step_idx == null) {
    if (direction == -1) {
      set_current_step(current_path().length - 1);
    } else {
      set_current_step(0);
    }
  } else {
    set_current_step(current_step_idx + direction);
  }
}

function do_the_auto_forwarding() {
  if (auto_forward)
    change_current(1);
}
setInterval(do_the_auto_forwarding, 1000);

$(document).keydown(function(e){
    if (e.keyCode == 37) {
       change_current(-1);
       return false;
    }
    if (e.keyCode == 38) {
       change_current(-10);
       return false;
    }
    if (e.keyCode == 39) {
       change_current(1);
       return false;
    }
    if (e.keyCode == 40) {
       change_current(10);
       return false;
    }
    if (e.keyCode == 32) {
       auto_forward = !auto_forward;
       return false;
    }
});

var Crafts = {};

function load_image_urls(name, on_done) {
    var image_urls = {};
    $.getJSON('urls_' + name + '.json', function(data) {
        for (var i = 0; i < data.length; i++) {
            var date_url = data[i];
            image_urls[date_url[0]] = date_url[1];
        }
        Crafts[name]['image_urls'] = image_urls;
        on_done();
    });
}

function load_path(name, on_done) {
    var path = [];
    $.getJSON('path_' + name + '.json', function(data) {
        Crafts[name]['path'] = data;
        console.log("LOADED", name, Crafts[name]);
        on_done();
    }).fail(function(jqXHR, textStatus, errorThrown) { alert("error" +  textStatus + " " + errorThrown); });
}

function show_craft(name) {
    var path = Crafts[name]['path'];
    var image_urls = Crafts[name]['image_urls'];
    var path_points = vis.selectAll('ellipse.step-' + name).data(path, function(p) { return p[0]; });

    function r_from_step(step) {
        if (image_urls[step[0]]) {
            return 3;
        } else {
            return 0.2;
        }
    }

    function on_step_click(step, idx) {
        current_craft = name;
        current_step_idx = idx;
        update_preview();
        update_marker();
        return false;
    }

    path_points
        .enter().append('ellipse').attr('class', 'step-' + name)
        .attr('cx', x_from_step).attr('cy', y_from_step).attr('rx', r_from_step).attr('ry', r_from_step)
        .attr('fill', 'green').attr('stroke', 'green')
        .attr('opacity', 1).classed('step', true)
        .on("mouseover",function(d,i) { d3.select(this).attr("fill","red"); })
        .on("mouseout",function(d,i) { d3.select(this).attr("fill","green"); })
        .on("click",on_step_click)
        .append('svg:title').text(function(p) { return p[0] + ": " + p[1] + "," + p[2];})
    ;
}

function load_craft(name) {
    Crafts[name] = {};
    load_image_urls(name, function () {
        load_path(name, function () {
            show_craft(name);
        });
    });
}

function start_viewer() {
    vis = d3.select("#view").append("svg").append('g').attr('transform','translate(200,350) rotate(-90)');

    orbits = vis.selectAll('ellipse.orbit').data(objects, function(d) { return d.name; });
    orbits
        .enter().append('ellipse').attr('cx',0).attr('cy',0).attr('rx',orbit).attr('ry',orbit)
        .attr('fill', 'none').attr('opacity',1).attr('stroke-width', 1).attr('stroke',color).classed('orbit',true);

    load_craft('vger1');
    load_craft('vger2');

    update_preview();
}
<|endoftext|>


<commit_before>Ext.define('devilry_nodeadmin.view.aggregatedstudentview.AggregatedStudentInfoOverview' ,{
  extend: 'Ext.container.Container',
  alias: 'widget.aggregatedstudentinfo',
  cls: 'bootstrap',
  title: 'Aggregated Student Info',

  store: 'AggregatedStudentInfoStore',

  layout: 'fit',
  padding: '40',
  autoScroll: true,

  items: [{
    xtype: 'box',
    itemId: 'AggregatedStudentInfoBox',
    //html: '
 Hello World
',
    tpl: ['
Aggregert Studentinformasjon
',
          '
{data.user.displayname} / {data.user.username}
',
              '<tpl for="data.grouped_by_hierarky">',
          '{[this.help(values)]}',
                  '
 {values}
',
                  '<tpl foreach=".">',
          '
{.}
',
          '<tpl for=".">',
          '{[this.help(values)]}',
          '</tpl>',
          '{[this.help(values)]}',
                      '
 {long_name}
',
                  '</tpl>',
              '</tpl>',{

                help: function(rec) {
                  console.log(rec);

                }

              }]

  }]

});
<commit_msg>* Nested JSON list working<commit_after>Ext.define('devilry_nodeadmin.view.aggregatedstudentview.AggregatedStudentInfoOverview' ,{
  extend: 'Ext.container.Container',
  alias: 'widget.aggregatedstudentinfo',
  cls: 'bootstrap',
  title: 'Aggregated Student Info',

  store: 'AggregatedStudentInfoStore',

  layout: 'fit',
  padding: '40',
  autoScroll: true,

  items: [{
    xtype: 'box',
    itemId: 'AggregatedStudentInfoBox',
    //html: '
 Hello World
',
    tpl: ['
Aggregert Studentinformasjon
',
          '
{data.user.displayname} / {data.user.username}
',
              '<tpl for="data.grouped_by_hierarky">',
                      '
 {long_name}
',
                      '<tpl for="periods">',
                          '
 {long_name}
',
                      '</tpl>',
              '</tpl>',
              {

                help: function(rec) {
                  console.log(rec);

                }

              }]

  }]

});
<|endoftext|>