<commit_before>// Copyright (C) 2016 ncph Authors
// This file is free software: You can redistribute it and/or modify it under
// the terms of the GNU AGPLv3 or later. See COPYING for details.

// Implementation of the Fischer-Yates-Durstenfeld O(n) shuffle algorithm. This
// variant is non-destructive (does not modify the input array), and takes the
// random number generator as a parameter, for deterministic operation.
//
//   https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
//
function shuffle(orig, rng) {
  arr = orig.slice(0);
  for (var i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(rng.gen() * (i + 1));
    var tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  return arr;
}

// Implementation of a simple linear congruential generator, using the
// parameters from Teukolsky-Vetterling-Flannery's Numerical Recipes.
//
//   https://en.wikipedia.org/wiki/Linear_congruential_generator
//
function Lcg32(seed) {
  this.state = (seed + 0xad2158e3) % 0x100000000;
  this.advance(); this.advance(); this.advance(); this.advance();
}
Lcg32.prototype.advance = function() {
  this.state = (this.state * 1664525 + 1013904223) % 0x100000000;
};
Lcg32.prototype.gen = function() {
  this.advance();
  return this.state / 0x100000000;
};

var vid = document.getElementById('vid');
var vidCounter = 0;
var clipDuration = 60000;
var startingTimestamp;
var viewers;

function Clip(name) {
  this.name = name;
}
Clip.prototype.path = function() {
  return 'clips/opt/' + this.name + '.mp4';
};
Clip.prototype.play = function(offset) {
  vid.pause();
  if (this.cached !== undefined) {
    vid.src = this.cached;
  } else {
    vid.src = this.path() + '#t=' + offset / 1000;
  }
  vid.play();
  var noun = (vidCounter === 1) ? 'clip' : 'clips';
  document.getElementById('topleft').innerHTML = vidCounter + ' ' + noun + ' seen';
  ++vidCounter;
};
Clip.prototype.preload = function() {
  if (this.cached === undefined) {
    var req = new XMLHttpRequest();
    req.open('GET', this.path(), true);
    req.responseType = 'blob';
    req.onload = function() {
      if (this.status === 200) {
        this.cached = URL.createObjectURL(this.response);
      }
    };
    req.send();
  }
};

var clips = [
  new Clip('wicker-notthebees'),
  new Clip('zandalee-inevitable'),
  new Clip('firebirds-kiss'),
  new Clip('therock-gottago'),
  new Clip('driveangry-disrobe'),
  new Clip('faceoff-hallelujah'),
  new Clip('wildheart-sing'),
  new Clip('corelli-sing'),
  new Clip('leavinglas-meet'),
  new Clip('gone60s-letsride'),
  new Clip('boyinblue-mirin'),
  new Clip('guardingtess-hospital'),
  new Clip('8mm-becausehecould'),
  new Clip('adaptation-narcissistic'),
  new Clip('itcouldhappen-robbery'),
  new Clip('gone60s-cageintro'),
  new Clip('ghostrider-jump'),
  new Clip('matchstick-prefex'),
  new Clip('portofcall-pharmacy'),
  new Clip('conair-howcouldi'),
  new Clip('boyinblue-caught'),
  new Clip('leavinglas-proposition'),
  new Clip('natltreasure-riley'),
  new Clip('vk-shoo'),
];

// Get the permutation of clips for a given run.
//
// This computes a sequence such that the clips are always played in an order
// that appears random to humans, which very rarely should show a clip more than
// once in a single sitting.
//
// The sequence is first permuted using the runblock (blocks of 100 runs) as the
// seed, then split into groups of 6, and each group is permuted again using
// the run as the seed.
//
// By maintaing distinct groups within a runblock, seeing the same clip twice in
// a single sitting is only possible when straddling runblocks. Permuting groups
// as well adds variation between sequential runs. Within a runblock, the
// minimum spacing between two screenings of the same clip is N-6, where N is
// the total number of clips.
//
function getSequence(run) {
  var runBlock = Math.floor(run / 100);
  var permuted = shuffle(clips, new Lcg32(runBlock));

  var rng2 = new Lcg32(run);
  var permuted2 = [];
  for (var i = 0; i < permuted.length; i += 6) {
    var group = permuted.slice(i, i + 6);
    var shuffled = shuffle(group, rng2);
    permuted2 = permuted2.concat(shuffled);
  }
  return permuted2;
}

// Get the current clip from a timestamp.
function getClip(ts) {
  var total = Math.floor(ts / clipDuration);
  var run = Math.floor(total / clips.length);
  var clip = total % clips.length;
  var seq = getSequence(run);
  return seq[clip];
}

// Scheduler to be run every clipDuration milliseconds.
function scheduleVid(timestamp, offset) {
  var nextTimestamp = timestamp + clipDuration;
  window.setTimeout(scheduleVid, clipDuration - offset, nextTimestamp, 0);
  getClip(timestamp).play(offset);
  getClip(nextTimestamp).preload();
}

// Send a request to the backend. This is used for two things:
//
//   * If running for the first time, starts the video scheduling loop.
//   * Updates the viewer count.
//
function makeRequest() {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var response = xhr.responseXML.documentElement;
    if (startingTimestamp === undefined) {
      startingTimestamp = response.querySelector('timestamp').innerHTML;
      var rounded = Math.floor(startingTimestamp / clipDuration) * clipDuration;
      var offset = startingTimestamp % clipDuration;
      scheduleVid(rounded, offset);
    }
    var viewers = response.querySelector('viewers').innerHTML;
    var noun = (viewers === '1') ? 'person' : 'people';
    document.getElementById('topright').innerHTML = viewers + ' ' + noun + ' watching';
  };
  xhr.open('GET', 'cgi');
  xhr.responseType = 'document';
  xhr.send();
}

// Run this event at startup.
window.addEventListener('load', function() {
  window.setInterval(makeRequest, 15000);
  makeRequest();
});

// Register keyboard event handler.
window.addEventListener('keydown', function(event) {
  switch (event.key) {
  case 'ArrowDown':
    vid.volume = Math.max(0.0, vid.volume - 0.05);
    break;
  case 'ArrowUp':
    vid.volume = Math.min(1.0, vid.volume + 0.05);
    break;
  default:
    return;
  }
});
<commit_msg>js: Add more clips.<commit_after>// Copyright (C) 2016 ncph Authors
// This file is free software: You can redistribute it and/or modify it under
// the terms of the GNU AGPLv3 or later. See COPYING for details.

// Implementation of the Fischer-Yates-Durstenfeld O(n) shuffle algorithm. This
// variant is non-destructive (does not modify the input array), and takes the
// random number generator as a parameter, for deterministic operation.
//
//   https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
//
function shuffle(orig, rng) {
  arr = orig.slice(0);
  for (var i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(rng.gen() * (i + 1));
    var tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  return arr;
}

// Implementation of a simple linear congruential generator, using the
// parameters from Teukolsky-Vetterling-Flannery's Numerical Recipes.
//
//   https://en.wikipedia.org/wiki/Linear_congruential_generator
//
function Lcg32(seed) {
  this.state = (seed + 0xad2158e3) % 0x100000000;
  this.advance(); this.advance(); this.advance(); this.advance();
}
Lcg32.prototype.advance = function() {
  this.state = (this.state * 1664525 + 1013904223) % 0x100000000;
};
Lcg32.prototype.gen = function() {
  this.advance();
  return this.state / 0x100000000;
};

var vid = document.getElementById('vid');
var vidCounter = 0;
var clipDuration = 60000;
var startingTimestamp;
var viewers;

function Clip(name) {
  this.name = name;
}
Clip.prototype.path = function() {
  return 'clips/opt/' + this.name + '.mp4';
};
Clip.prototype.play = function(offset) {
  vid.pause();
  if (this.cached !== undefined) {
    vid.src = this.cached;
  } else {
    vid.src = this.path() + '#t=' + offset / 1000;
  }
  vid.play();
  var noun = (vidCounter === 1) ? 'clip' : 'clips';
  document.getElementById('topleft').innerHTML = vidCounter + ' ' + noun + ' seen';
  ++vidCounter;
};
Clip.prototype.preload = function() {
  if (this.cached === undefined) {
    var req = new XMLHttpRequest();
    req.open('GET', this.path(), true);
    req.responseType = 'blob';
    req.onload = function() {
      if (this.status === 200) {
        this.cached = URL.createObjectURL(this.response);
      }
    };
    req.send();
  }
};

var clips = [
  new Clip('wicker-notthebees'),
  new Clip('zandalee-inevitable'),
  new Clip('firebirds-kiss'),
  new Clip('therock-gottago'),
  new Clip('driveangry-disrobe'),
  new Clip('faceoff-hallelujah'),
  new Clip('wildheart-sing'),
  new Clip('corelli-sing'),
  new Clip('leavinglas-meet'),
  new Clip('gone60s-letsride'),
  new Clip('boyinblue-mirin'),
  new Clip('guardingtess-hospital'),
  new Clip('8mm-becausehecould'),
  new Clip('adaptation-narcissistic'),
  new Clip('itcouldhappen-robbery'),
  new Clip('gone60s-cageintro'),
  new Clip('ghostrider-jump'),
  new Clip('matchstick-prefex'),
  new Clip('portofcall-pharmacy'),
  new Clip('sorcerer-duck'),
  new Clip('conair-howcouldi'),
  new Clip('weatherman-archer'),
  new Clip('windtalkers-mess'),
  new Clip('boyinblue-caught'),
  new Clip('leavinglas-proposition'),
  new Clip('natltreasure-riley'),
  new Clip('wtc-pregnant'),
  new Clip('kissofdeath-pushup'),
  new Clip('familyman-alien'),
  new Clip('weatherman-frosty'),
  new Clip('knowing-shithappens'),
  new Clip('vk-shoo'),
  new Clip('raising-sorry'),
  new Clip('faceoff-bigride'),
  new Clip('wicker-burned'),
  new Clip('portofcall-lizard'),
  new Clip('vk-contract'),
  new Clip('vk-alphabet'),
  new Clip('wickerman-dronemustdie'),
  new Clip('weatherman-fastfood'),
  new Clip('matchstick-cleaning'),
  new Clip('matchstick-carpets'),
];

// Get the permutation of clips for a given run.
//
// This computes a sequence such that the clips are always played in an order
// that appears random to humans, which very rarely should show a clip more than
// once in a single sitting.
//
// The sequence is first permuted using the runblock (blocks of 100 runs) as the
// seed, then split into groups of 6, and each group is permuted again using
// the run as the seed.
//
// By maintaing distinct groups within a runblock, seeing the same clip twice in
// a single sitting is only possible when straddling runblocks. Permuting groups
// as well adds variation between sequential runs. Within a runblock, the
// minimum spacing between two screenings of the same clip is N-6, where N is
// the total number of clips.
//
function getSequence(run) {
  var runBlock = Math.floor(run / 100);
  var permuted = shuffle(clips, new Lcg32(runBlock));

  var rng2 = new Lcg32(run);
  var permuted2 = [];
  for (var i = 0; i < permuted.length; i += 6) {
    var group = permuted.slice(i, i + 6);
    var shuffled = shuffle(group, rng2);
    permuted2 = permuted2.concat(shuffled);
  }
  return permuted2;
}

// Get the current clip from a timestamp.
function getClip(ts) {
  var total = Math.floor(ts / clipDuration);
  var run = Math.floor(total / clips.length);
  var clip = total % clips.length;
  var seq = getSequence(run);
  return seq[clip];
}

// Scheduler to be run every clipDuration milliseconds.
function scheduleVid(timestamp, offset) {
  var nextTimestamp = timestamp + clipDuration;
  window.setTimeout(scheduleVid, clipDuration - offset, nextTimestamp, 0);
  getClip(timestamp).play(offset);
  getClip(nextTimestamp).preload();
}

// Send a request to the backend. This is used for two things:
//
//   * If running for the first time, starts the video scheduling loop.
//   * Updates the viewer count.
//
function makeRequest() {
  var xhr = new XMLHttpRequest();
  xhr.onload = function() {
    var response = xhr.responseXML.documentElement;
    if (startingTimestamp === undefined) {
      startingTimestamp = response.querySelector('timestamp').innerHTML;
      var rounded = Math.floor(startingTimestamp / clipDuration) * clipDuration;
      var offset = startingTimestamp % clipDuration;
      scheduleVid(rounded, offset);
    }
    var viewers = response.querySelector('viewers').innerHTML;
    var noun = (viewers === '1') ? 'person' : 'people';
    document.getElementById('topright').innerHTML = viewers + ' ' + noun + ' watching';
  };
  xhr.open('GET', 'cgi');
  xhr.responseType = 'document';
  xhr.send();
}

// Run this event at startup.
window.addEventListener('load', function() {
  window.setInterval(makeRequest, 15000);
  makeRequest();
});

// Register keyboard event handler.
window.addEventListener('keydown', function(event) {
  switch (event.key) {
  case 'ArrowDown':
    vid.volume = Math.max(0.0, vid.volume - 0.05);
    break;
  case 'ArrowUp':
    vid.volume = Math.min(1.0, vid.volume + 0.05);
    break;
  default:
    return;
  }
});
<|endoftext|>


<commit_before>// @flow

import React, { Component } from 'react';
import moment from 'moment-timezone';
import cx from 'classnames';
import Dropdown from 'app/components/Dropdown';
import Icon from 'app/components/Icon';
import createMonthlyCalendar from 'app/utils/createMonthlyCalendar';
import { createField } from './Field';
import TextInput from './TextInput';
import TimePicker from './TimePicker';
import styles from './DatePicker.css';
import config from 'app/config';

type Props = {
  onChange: (string) => void,
  className?: string,
  value: ?string,
  showTimePicker?: boolean,
  dateFormat?: string,
  name?: string,
};

type State = {
  pickerOpen: boolean,
  date: moment,
  value: moment,
};

function parseDateValue(value) {
  if (value) return moment(value);
  return moment();
}

class DatePicker extends Component<Props, State> {
  static defaultProps = {
    value: '',
    showTimePicker: true,
    dateFormat: 'lll',
  };

  static Field: any;

  state = {
    pickerOpen: false,
    date: moment(),
    value: parseDateValue(this.props.value),
  };

  onNext = () => {
    this.setState((prevState) => ({
      date: prevState.date.clone().add(1, 'month'),
    }));
  };

  onPrev = () => {
    this.setState((prevState) => ({
      date: prevState.date.clone().subtract(1, 'month'),
    }));
  };

  onChange = (day: moment) => {
    this.setState((prevState) => {
      const value = day
        .clone()
        .hour(prevState.value.hour())
        .minute(prevState.value.minute());

      return {
        value,
        pickerOpen: false,
      };
    }, this._notifyParent);
  };

  onChangeTime = (time: moment) => {
    this.setState((prevState) => {
      const value = prevState.value
        .clone()
        .hour(time.hour())
        .minute(time.minute());

      return {
        value,
      };
    }, this._notifyParent);
  };

  _notifyParent = () => this.props.onChange(this.state.value.toString());

  toggleDropdown = () => {
    this.setState((prevState) => ({
      pickerOpen: !prevState.pickerOpen,
    }));
  };

  render() {
    const { showTimePicker, className, name } = this.props;
    const { date } = this.state;

    return (
      <Dropdown
        show={this.state.pickerOpen}
        toggle={this.toggleDropdown}
        triggerComponent={
          <TextInput
            className={cx(styles.inputField, className)}
            value={moment
              .tz(this.state.value, config.timezone)
              .format(this.props.dateFormat)}
            name={name}
          />
        }
        componentClass="div"
        contentClassName={styles.dropdown}
        style={{ flex: 1 }}
      >

 e.stopPropagation()}>

            <button onClick={this.onPrev} className={styles.arrowIcon}>
              <Icon name="arrow-back" />
            </button>

{date.format('MMMM YYYY')}

            <button onClick={this.onNext} className={styles.arrowIcon}>
              <Icon name="arrow-forward" />
            </button>

            {createMonthlyCalendar(date).map((dateProps, i) => (
              <button
                key={i}
                className={cx(
                  styles.calendarItem,
                  dateProps.prevOrNextMonth && styles.prevOrNextMonth,
                  dateProps.day.isSame(this.state.value, 'day') &&
                    styles.selectedDate
                )}
                onClick={() => this.onChange(dateProps.day)}
                disabled={dateProps.prevOrNextMonth}
              >
                {dateProps.day.date()}
              </button>
            ))}

          {showTimePicker && (
            <TimePicker
              value={this.state.value.toISOString()}
              onChange={this.onChangeTime}
            />
          )}

      </Dropdown>
    );
  }
}

DatePicker.Field = createField(DatePicker);

export default DatePicker;
<commit_msg>Update datepicker field when props change<commit_after>// @flow

import React, { Component } from 'react';
import moment from 'moment-timezone';
import cx from 'classnames';
import Dropdown from 'app/components/Dropdown';
import Icon from 'app/components/Icon';
import createMonthlyCalendar from 'app/utils/createMonthlyCalendar';
import { createField } from './Field';
import TextInput from './TextInput';
import TimePicker from './TimePicker';
import styles from './DatePicker.css';
import config from 'app/config';

type Props = {
  onChange: (string) => void,
  className?: string,
  value: ?string,
  showTimePicker?: boolean,
  dateFormat?: string,
  name?: string,
};

type State = {
  pickerOpen: boolean,
  date: moment,
  value: moment,
};

function parseDateValue(value) {
  if (value) return moment(value);
  return moment();
}

class DatePicker extends Component<Props, State> {
  static defaultProps = {
    value: '',
    showTimePicker: true,
    dateFormat: 'lll',
  };

  static Field: any;

  state = {
    pickerOpen: false,
    date: moment(),
    value: parseDateValue(this.props.value),
  };

  onNext = () => {
    this.setState((prevState) => ({
      date: prevState.date.clone().add(1, 'month'),
    }));
  };

  onPrev = () => {
    this.setState((prevState) => ({
      date: prevState.date.clone().subtract(1, 'month'),
    }));
  };

  onChange = (day: moment) => {
    this.setState((prevState) => {
      const value = day
        .clone()
        .hour(prevState.value.hour())
        .minute(prevState.value.minute());

      return {
        value,
        pickerOpen: false,
      };
    }, this._notifyParent);
  };

  onChangeTime = (time: moment) => {
    this.setState((prevState) => {
      const value = prevState.value
        .clone()
        .hour(time.hour())
        .minute(time.minute());

      return {
        value,
      };
    }, this._notifyParent);
  };

  _notifyParent = () => this.props.onChange(this.state.value.toString());

  toggleDropdown = () => {
    this.setState((prevState) => ({
      pickerOpen: !prevState.pickerOpen,
    }));
  };

  componentDidUpdate(prevProps) {
    if (prevProps.value !== this.props.value) {
      this.setState({ value: parseDateValue(this.props.value) });
    }
  }

  render() {
    const { showTimePicker, className, name } = this.props;
    const { date } = this.state;

    return (
      <Dropdown
        show={this.state.pickerOpen}
        toggle={this.toggleDropdown}
        triggerComponent={
          <TextInput
            className={cx(styles.inputField, className)}
            value={moment
              .tz(this.state.value, config.timezone)
              .format(this.props.dateFormat)}
            name={name}
          />
        }
        componentClass="div"
        contentClassName={styles.dropdown}
        style={{ flex: 1 }}
      >

 e.stopPropagation()}>

            <button onClick={this.onPrev} className={styles.arrowIcon}>
              <Icon name="arrow-back" />
            </button>

{date.format('MMMM YYYY')}

            <button onClick={this.onNext} className={styles.arrowIcon}>
              <Icon name="arrow-forward" />
            </button>

            {createMonthlyCalendar(date).map((dateProps, i) => (
              <button
                key={i}
                className={cx(
                  styles.calendarItem,
                  dateProps.prevOrNextMonth && styles.prevOrNextMonth,
                  dateProps.day.isSame(this.state.value, 'day') &&
                    styles.selectedDate
                )}
                onClick={() => this.onChange(dateProps.day)}
                disabled={dateProps.prevOrNextMonth}
              >
                {dateProps.day.date()}
              </button>
            ))}

          {showTimePicker && (
            <TimePicker
              value={this.state.value.toISOString()}
              onChange={this.onChangeTime}
            />
          )}

      </Dropdown>
    );
  }
}

DatePicker.Field = createField(DatePicker);

export default DatePicker;
<|endoftext|>


<commit_before>
var Dashboard = function () {
    var me = this;
    var internal_networks = "";

    me.initialize = function () {
        // Retrieve internal domains
        var url = "json/rpc/get_internal_networks.php";
        var params = {};
        $.getJSON(url, params, function (data, textStatus, jqXHR) {
            internal_networks = data;
            add_time_window_control_listeners();
            plot_incoming_attacks_plot(internal_networks);
            load_attacks_table(INCOMING, internal_networks);
            load_attacks_table(OUTGOING, internal_networks);
            load_top_targets_table(COMPROMISE);
            load_top_targets_table(BRUTEFORCE);
        });
    };

    return me;
};

function add_time_window_control_listeners () {
    // Select 'Week' as default, i.e., if none has been selected
    if ($('.btn.active').length == 0) {
        $('.btn:contains(\"Week\")').addClass('active');
    }

    // General button handling
    $('.btn-group .btn').click(function () {
        // Check which button was selected before
        var prev_button_text = $('.btn-group .btn.active').text();

        // Do nothing if the already active button was clicked
        if ($(this).text() == prev_button_text) return;

        // Remove 'active' class from previously selected item(s)
        $('.btn-group .btn').removeClass('active');

        // Add 'active' class to newly selected item
        $(this).addClass('active');

        // Show loading message
        $('#attacks-plot ~ div.loading').show();
        $('#attacks-plot-header').hide();
        $('#attacks-plot').hide();

        // Replot 'incoming attacks' plot based on newly selected time window
        plot_incoming_attacks_plot($(this).text().toLowerCase());
    });
}

function load_attacks_table (type, internal_networks, period) {
    var url;

    if (type == INCOMING) {
        url = "json/data/get_incoming_attacks.php";
    } else {
        url = "json/data/get_outgoing_attacks.php";
    }

    var params = {
        'internal_networks': internal_networks
    };

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        var table = $('
');
        var head = $('
');
        var body = $('
');
        head.append(
            $('').text('Phases'),
            $('').text('Active'),
            $('').text('Attacker'),
            $('').text('Start time'),
            $('').text('Targets')
        ).appendTo(head);

        if (data.data.length == 0) {
            $('
').append(
                $('').text("No data available...")
            ).appendTo(body);
        } else {
            $.each(data.data, function () {
                var phases = $('
').addClass('phases').append(
                    $('
').addClass('phase scan'),
                    $('
').addClass('phase bruteforce'),
                    $('
').addClass('phase compromise')
                );

                // Phases
                if (jQuery.inArray(this.certainty, [ 0.25, 0.5, 0.75 ])) {
                    phases.find('div.phase.scan').addClass('on');
                }
                if (jQuery.inArray(this.certainty, [ 0.4, 0.5 ])) {
                    phases.find('div.phase.bruteforce').addClass('on');
                }
                if (jQuery.inArray(this.certainty, [ 0.65, 0.75 ])) {
                    phases.find('div.phase.compromise').addClass('on');
                }

                // Date
                var date = new Date(this.start_time * 1000);

                $('
').append(
                    $('').append(phases),
                    $('').html(""),
                    $('').append($('')
                            .addClass('ip-addr')
                            .attr('href', '#')
                            .text(this.attacker))
                            .click(function () {
                                var url = "json/html/get_host_details.php";
                                var params = {
                                    'host': $(this).text()
                                }
                                $.getJSON(url, params, function (data, textStatus, jqXHR) {
                                    // Overwrite modal title using Javascript, since Bootstrap uses a completely different element for modal headers and bodies
                                    $('#host-details h4.modal-title').text("Host details for " + params['host']);

                                    // Insert pre-rendered HTML into body
                                    $('#host-details div.modal-body').html(data.data);
                                    $('#host-details').modal({
                                        show: true
                                    });
                                });
                            }),
                    $('').text(date.toString("ddd. MMM d, yyyy HH:mm")),
                    $('').text(this.target_count)
                ).appendTo(body);
            });
        }

        head.appendTo(table);
        body.appendTo(table);

        if (type == INCOMING) {
            // Hide loading message and show divs related to plot
            $('#incoming-attacks-table ~ div.loading').hide();
            $('#incoming-attacks-table').show();
            table.appendTo($('#incoming-attacks-table'));
        } else {
            // Hide loading message and show divs related to plot
            $('#outgoing-attacks-table ~ div.loading').hide();
            $('#outgoing-attacks-table').show();
            table.appendTo($('#outgoing-attacks-table'));
        }
    });
}

function load_top_targets_table (type) {
    var url;

    if (type == BRUTEFORCE) {
        url = "json/data/get_top_targets_bruteforce.php";
    } else {
        url = "json/data/get_top_targets_compromise.php";
    }

    var params = {};

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        var table = $('
');
        var head = $('
');
        var body = $('
');
        head.append(
            $('').text('Target'),
            $('').text('Attacks'),
            $('').text('Compromises')
        ).appendTo(head);

        if (data.data.length == 0) {
            $('
').append(
                $('').text("No data available...")
            ).appendTo(body);
        } else {
            $.each(data.data, function () {
                $('
').append(
                    $('').append($('')
                        .addClass('ip-addr')
                        .attr('href', '#')
                        .text(this.target))
                        .click(function () {
                            var url = "json/html/get_host_details.php";
                            var params = {
                                'host': $(this).text()
                            }
                            $.getJSON(url, params, function (data, textStatus, jqXHR) {
                                // Overwrite modal title using Javascript, since Bootstrap uses a completely different element for modal headers and bodies
                                $('#host-details h4.modal-title').text("Host details for " + params['host']);

                                // Insert pre-rendered HTML into body
                                $('#host-details div.modal-body').html(data.data);
                                $('#host-details').modal({
                                    show: true
                                });
                            });
                        }),
                    $('').text(this.attack_count),
                    $('').text(this.compromise_count)
                ).appendTo(body);
            });
        }

        head.appendTo(table);
        body.appendTo(table);

        if (type == BRUTEFORCE) {
            // Hide loading message and show divs related to plot
            $('#top-targets-bruteforce-table ~ div.loading').hide();
            $('#top-targets-bruteforce-table').show();
            table.appendTo($('#top-targets-bruteforce-table'));
        } else {
            // Hide loading message and show divs related to plot
            $('#top-targets-compromise-table ~ div.loading').hide();
            $('#top-targets-compromise-table').show();
            table.appendTo($('#top-targets-compromise-table'));
        }
    });
}

function plot_incoming_attacks_plot (internal_networks, period) {
    if (typeof(period) === 'undefined') {
        period = 'week';
    }

    var url = "json/data/get_incoming_attacks_plot.php";
    var now = parseInt((new Date().getTime()) / 1000);
    var max_start_time = now;

    var min_start_time;
    if (period == 'day') {
        min_start_time = now - (24 * 60 * 60);
    } else if (period == 'month') {
        min_start_time = now - (30 * 24 * 60 * 60);
    } else {
        min_start_time = now - (7 * 24 * 60 * 60);
    }

    var params = {
        'min_start_time': min_start_time, // Go 7 days back in time
        'max_start_time': max_start_time
    };

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        // Scan attacks
        var plot_scan_data = new Array();
        plot_scan_data['label'] = "Scan";
        plot_scan_data['color'] = "rgb(26, 150, 212)";
        plot_scan_data['data'] = new Array();
        $.each(data.data.scan, function (time, attacks) {
            plot_scan_data['data'].push([time * 1000, attacks]);
        });

        // Brute-force attacks
        var plot_bruteforce_data = new Array();
        plot_bruteforce_data['label'] = "Brute-force";
        plot_bruteforce_data['color'] = "rgb(250, 100, 45)";
        plot_bruteforce_data['data'] = new Array();
        $.each(data.data.bruteforce, function (time, attacks) {
            plot_bruteforce_data['data'].push([time * 1000, attacks]);
        });

        // Compromise attacks
        var plot_compromise_data = new Array();
        plot_compromise_data['label'] = "Compromise";
        plot_compromise_data['color'] = "rgb(220, 0, 8)";
        plot_compromise_data['data'] = new Array();
        $.each(data.data.compromise, function (time, attacks) {
            plot_compromise_data['data'].push([time * 1000, attacks]);
        });

        var last_day = -1;
        var options = {
            bars: {
                backgroundColor: null,
                show: true
            },
            lines: {
                show: false,
                steps: false
            },
            grid: {
                hoverable: true,
                clickable: true,
                borderWidth: 0
            },
            series: {
                stack: true
            },
            legend: {
                container: $('#attacks-plot-legend'),
                noColumns: 3,
                labelFormatter: function (label, series) {
                    return "" + label + '';
                }
            },
            xaxis: {
                mode: "time",
                min: min_start_time * 1000,
                max: max_start_time * 1000,
                twelveHourClock : false,
                tickFormatter: function (val, axis) {
                    var date = new Date();
                    date.setTime(val);
                    var label = "";
                    var week = (max_start_time - min_start_time >= 604800);

                    // 'date > Dashboard.getStartTime()' is there to make sure that selected date is actually visible
                    if (date.getDate() != last_day && date > min_start_time * 1000) {
                        last_day = date.getDate();
                        var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
                        label += date.getDate() + " " + months[date.getMonth()];

                        if (!week) {
                            label += ",
";
                        }
                    }

                    if (!week) {
                        var minutes = date.getMinutes();
                        if (minutes < 10) {
                            minutes = "0" + minutes;
                        }
                        label += date.getHours() + ":" + minutes;
                    }

                    return label;
                },
                tickLength: 0
            },
            yaxis: {
                min: 0,
                minTickSize: 1,
                tickDecimals: 0
            }
        };

        // Hide loading message and show divs related to plot
        $('#attacks-plot ~ div.loading').hide();
        $('#attacks-plot-header').show();
        $('#attacks-plot').show();

        $.plot($('#attacks-plot'),
                [ plot_scan_data, plot_bruteforce_data, plot_compromise_data ], options);
    });
}

// Constants
var BRUTEFORCE = 1;
var COMPROMISE = 2;
var INCOMING = 1;
var OUTGOING = 2;
<commit_msg>Fixed a bug that caused the brute-force phase icon to not always be shown correctly (logic)<commit_after>
var Dashboard = function () {
    var me = this;
    var internal_networks = "";

    me.initialize = function () {
        // Retrieve internal domains
        var url = "json/rpc/get_internal_networks.php";
        var params = {};
        $.getJSON(url, params, function (data, textStatus, jqXHR) {
            internal_networks = data;
            add_time_window_control_listeners();
            plot_incoming_attacks_plot(internal_networks);
            load_attacks_table(INCOMING, internal_networks);
            load_attacks_table(OUTGOING, internal_networks);
            load_top_targets_table(COMPROMISE);
            load_top_targets_table(BRUTEFORCE);
        });
    };

    return me;
};

function add_time_window_control_listeners () {
    // Select 'Week' as default, i.e., if none has been selected
    if ($('.btn.active').length == 0) {
        $('.btn:contains(\"Week\")').addClass('active');
    }

    // General button handling
    $('.btn-group .btn').click(function () {
        // Check which button was selected before
        var prev_button_text = $('.btn-group .btn.active').text();

        // Do nothing if the already active button was clicked
        if ($(this).text() == prev_button_text) return;

        // Remove 'active' class from previously selected item(s)
        $('.btn-group .btn').removeClass('active');

        // Add 'active' class to newly selected item
        $(this).addClass('active');

        // Show loading message
        $('#attacks-plot ~ div.loading').show();
        $('#attacks-plot-header').hide();
        $('#attacks-plot').hide();

        // Replot 'incoming attacks' plot based on newly selected time window
        plot_incoming_attacks_plot($(this).text().toLowerCase());
    });
}

function load_attacks_table (type, internal_networks, period) {
    var url;

    if (type == INCOMING) {
        url = "json/data/get_incoming_attacks.php";
    } else {
        url = "json/data/get_outgoing_attacks.php";
    }

    var params = {
        'internal_networks': internal_networks
    };

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        var table = $('
');
        var head = $('
');
        var body = $('
');
        head.append(
            $('').text('Phases'),
            $('').text('Active'),
            $('').text('Attacker'),
            $('').text('Start time'),
            $('').text('Targets')
        ).appendTo(head);

        if (data.data.length == 0) {
            $('
').append(
                $('').text("No data available...")
            ).appendTo(body);
        } else {
            $.each(data.data, function () {
                var phases = $('
').addClass('phases').append(
                    $('
').addClass('phase scan'),
                    $('
').addClass('phase bruteforce'),
                    $('
').addClass('phase compromise')
                );

                // Phases
                if (jQuery.inArray(this.certainty, [ 0.25, 0.5, 0.75 ])) {
                    phases.find('div.phase.scan').addClass('on');
                }
                if (jQuery.inArray(this.certainty, [ 0.4, 0.5, 0.65, 0.75 ])) {
                    phases.find('div.phase.bruteforce').addClass('on');
                }
                if (jQuery.inArray(this.certainty, [ 0.65, 0.75 ])) {
                    phases.find('div.phase.compromise').addClass('on');
                }

                // Date
                var date = new Date(this.start_time * 1000);

                $('
').append(
                    $('').append(phases),
                    $('').html(""),
                    $('').append($('')
                            .addClass('ip-addr')
                            .attr('href', '#')
                            .text(this.attacker))
                            .click(function () {
                                var url = "json/html/get_host_details.php";
                                var params = {
                                    'host': $(this).text()
                                }
                                $.getJSON(url, params, function (data, textStatus, jqXHR) {
                                    // Overwrite modal title using Javascript, since Bootstrap uses a completely different element for modal headers and bodies
                                    $('#host-details h4.modal-title').text("Host details for " + params['host']);

                                    // Insert pre-rendered HTML into body
                                    $('#host-details div.modal-body').html(data.data);
                                    $('#host-details').modal({
                                        show: true
                                    });
                                });
                            }),
                    $('').text(date.toString("ddd. MMM d, yyyy HH:mm")),
                    $('').text(this.target_count)
                ).appendTo(body);
            });
        }

        head.appendTo(table);
        body.appendTo(table);

        if (type == INCOMING) {
            // Hide loading message and show divs related to plot
            $('#incoming-attacks-table ~ div.loading').hide();
            $('#incoming-attacks-table').show();
            table.appendTo($('#incoming-attacks-table'));
        } else {
            // Hide loading message and show divs related to plot
            $('#outgoing-attacks-table ~ div.loading').hide();
            $('#outgoing-attacks-table').show();
            table.appendTo($('#outgoing-attacks-table'));
        }
    });
}

function load_top_targets_table (type) {
    var url;

    if (type == BRUTEFORCE) {
        url = "json/data/get_top_targets_bruteforce.php";
    } else {
        url = "json/data/get_top_targets_compromise.php";
    }

    var params = {};

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        var table = $('
');
        var head = $('
');
        var body = $('
');
        head.append(
            $('').text('Target'),
            $('').text('Attacks'),
            $('').text('Compromises')
        ).appendTo(head);

        if (data.data.length == 0) {
            $('
').append(
                $('').text("No data available...")
            ).appendTo(body);
        } else {
            $.each(data.data, function () {
                $('
').append(
                    $('').append($('')
                        .addClass('ip-addr')
                        .attr('href', '#')
                        .text(this.target))
                        .click(function () {
                            var url = "json/html/get_host_details.php";
                            var params = {
                                'host': $(this).text()
                            }
                            $.getJSON(url, params, function (data, textStatus, jqXHR) {
                                // Overwrite modal title using Javascript, since Bootstrap uses a completely different element for modal headers and bodies
                                $('#host-details h4.modal-title').text("Host details for " + params['host']);

                                // Insert pre-rendered HTML into body
                                $('#host-details div.modal-body').html(data.data);
                                $('#host-details').modal({
                                    show: true
                                });
                            });
                        }),
                    $('').text(this.attack_count),
                    $('').text(this.compromise_count)
                ).appendTo(body);
            });
        }

        head.appendTo(table);
        body.appendTo(table);

        if (type == BRUTEFORCE) {
            // Hide loading message and show divs related to plot
            $('#top-targets-bruteforce-table ~ div.loading').hide();
            $('#top-targets-bruteforce-table').show();
            table.appendTo($('#top-targets-bruteforce-table'));
        } else {
            // Hide loading message and show divs related to plot
            $('#top-targets-compromise-table ~ div.loading').hide();
            $('#top-targets-compromise-table').show();
            table.appendTo($('#top-targets-compromise-table'));
        }
    });
}

function plot_incoming_attacks_plot (internal_networks, period) {
    if (typeof(period) === 'undefined') {
        period = 'week';
    }

    var url = "json/data/get_incoming_attacks_plot.php";
    var now = parseInt((new Date().getTime()) / 1000);
    var max_start_time = now;

    var min_start_time;
    if (period == 'day') {
        min_start_time = now - (24 * 60 * 60);
    } else if (period == 'month') {
        min_start_time = now - (30 * 24 * 60 * 60);
    } else {
        min_start_time = now - (7 * 24 * 60 * 60);
    }

    var params = {
        'min_start_time': min_start_time, // Go 7 days back in time
        'max_start_time': max_start_time
    };

    $.getJSON(url, params, function (data, textStatus, jqXHR) {
        // Scan attacks
        var plot_scan_data = new Array();
        plot_scan_data['label'] = "Scan";
        plot_scan_data['color'] = "rgb(26, 150, 212)";
        plot_scan_data['data'] = new Array();
        $.each(data.data.scan, function (time, attacks) {
            plot_scan_data['data'].push([time * 1000, attacks]);
        });

        // Brute-force attacks
        var plot_bruteforce_data = new Array();
        plot_bruteforce_data['label'] = "Brute-force";
        plot_bruteforce_data['color'] = "rgb(250, 100, 45)";
        plot_bruteforce_data['data'] = new Array();
        $.each(data.data.bruteforce, function (time, attacks) {
            plot_bruteforce_data['data'].push([time * 1000, attacks]);
        });

        // Compromise attacks
        var plot_compromise_data = new Array();
        plot_compromise_data['label'] = "Compromise";
        plot_compromise_data['color'] = "rgb(220, 0, 8)";
        plot_compromise_data['data'] = new Array();
        $.each(data.data.compromise, function (time, attacks) {
            plot_compromise_data['data'].push([time * 1000, attacks]);
        });

        var last_day = -1;
        var options = {
            bars: {
                backgroundColor: null,
                show: true
            },
            lines: {
                show: false,
                steps: false
            },
            grid: {
                hoverable: true,
                clickable: true,
                borderWidth: 0
            },
            series: {
                stack: true
            },
            legend: {
                container: $('#attacks-plot-legend'),
                noColumns: 3,
                labelFormatter: function (label, series) {
                    return "" + label + '';
                }
            },
            xaxis: {
                mode: "time",
                min: min_start_time * 1000,
                max: max_start_time * 1000,
                twelveHourClock : false,
                tickFormatter: function (val, axis) {
                    var date = new Date();
                    date.setTime(val);
                    var label = "";
                    var week = (max_start_time - min_start_time >= 604800);

                    // 'date > Dashboard.getStartTime()' is there to make sure that selected date is actually visible
                    if (date.getDate() != last_day && date > min_start_time * 1000) {
                        last_day = date.getDate();
                        var months = [ "Jan", "Feb", "Mar", "Apr", "May", "Jun",
                                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" ];
                        label += date.getDate() + " " + months[date.getMonth()];

                        if (!week) {
                            label += ",
";
                        }
                    }

                    if (!week) {
                        var minutes = date.getMinutes();
                        if (minutes < 10) {
                            minutes = "0" + minutes;
                        }
                        label += date.getHours() + ":" + minutes;
                    }

                    return label;
                },
                tickLength: 0
            },
            yaxis: {
                min: 0,
                minTickSize: 1,
                tickDecimals: 0
            }
        };

        // Hide loading message and show divs related to plot
        $('#attacks-plot ~ div.loading').hide();
        $('#attacks-plot-header').show();
        $('#attacks-plot').show();

        $.plot($('#attacks-plot'),
                [ plot_scan_data, plot_bruteforce_data, plot_compromise_data ], options);
    });
}

// Constants
var BRUTEFORCE = 1;
var COMPROMISE = 2;
var INCOMING = 1;
var OUTGOING = 2;
<|endoftext|>


<commit_before>days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

var shopping_list = [[], []];
var shopping_list_ids = [[],[]];
var shopping_queued = [false, false];
var shopping_urls = [
   '581fafe836e0ef68e2777f67',
   '582fdea3aeeca26b9064c5c6'
];

current_list = 0;

function displayShopping() {
    for (list_id = 0; list_id < 2; list_id++) {
    	data = shopping_list[list_id];
    	$("#shopping_"+list_id).html("");
    	out = '
';
        if (data.length > 0) {
        	for (i = 0; i< data.length; i++) {
        		out += '
' + data[i] + '
';
        	}
        }
        else {
            out += '
No items
';
        }
    	out += '
';
    	$("#shopping_"+list_id).html(out);
    }
    highlight_list();
}

function highlight_list() {
    $("#list_"+current_list).addClass("list_selected");
    $("#list_"+((current_list + 1) % 2)).removeClass("list_selected");
}

function add_item_to_list(item) {
	var newCard = {
	  name: item,
	  idList: shopping_urls[current_list],
	  pos: 'top'
	};
	Trello.post('/cards/', newCard, load_lists);
}

function close_card(name) {
	index = -1;
	for (key in shopping_list[current_list]) {
		if (name == shopping_list[current_list][key]) {
			index = key;
			break;
		}
	}
    console.log(key);
	if (index != -1) {
		console.log(name + ' has index ' + index + ' and id ' + shopping_list_ids[current_list][key]);
		Trello.put('/cards/'+shopping_list_ids[current_list][key], {closed: true}, load_lists);
	}
}

function archive_all() {
    url = '/lists/' + shopping_urls[current_list] + '/archiveAllCards';
	Trello.post(url, load_lists);
}

var counter = 0;

function add_remove_item(item) {
    if (shopping_list[current_list].indexOf(item) >= 0) {
    	console.log("Item already in shopping list, removing");
    	close_card(item);
    }
    else {
    	console.log("Adding item to shopping list");
    	add_item_to_list(item);
    }
}

function lookupCode(code) {
	$.ajax({
		url: "https://raw.githubusercontent.com/markjones112358/Household-Barcode-Database/master/barcodes.json",
		datatype: "json"
	}).done(function(tmp_data) {
		code = $("#codefield").val();
		if (code == "9410000000015") {
            console.log("Switching lists");
            current_list = (++current_list) % 2;
            highlight_list();
		}
		//else if (code == "9410000000022") {
		//	console.log("Cant remove");
		//}
		else if (code == "9410000000022") {
			archive_all();
		}
        else if (code == "4935850351001") {
            add_remove_item("Bananas");
        }
        else if (code == "9410000000114") {
            add_remove_item("Avocado");
        }
        else if (code == "9415077094332") {
            add_remove_item("Tin foil");
        }
        else if (code == "9410000000138") {
            add_remove_item("Baby mayo");
        }
        else if (code == "9410000000121") {
            add_remove_item("Toothpaste");
        }
        else if (code == "9414812091988") {
            add_remove_item("Toilet paper");
        }
		else {
			data = $.parseJSON(tmp_data);
			if (code in data) {
				console.log("Barcode resolves to " + data[code]);
			    add_remove_item(data[code]);
			}
		}
		$("#codefield").val('');
		document.getElementById('codefield').focus();
	});
}

function loadShopping(list_id) {
    url = '/lists/' + shopping_urls[list_id] + '/cards';
	Trello.get(url, parseShopping, error)
}

function load_lists() {
    shopping_list = [[], []];
    shopping_list_ids = [[], []];
    loadShopping(0);
    loadShopping(1);
    displayShopping();
	document.getElementById('codefield').focus();
}

function start_list_loader() {
    load_lists()
	setTimeout(start_list_loader, 1000 * 60 * 5);
	document.getElementById('codefield').focus();
}

function parseShopping(data) {
    list_id = -1;
    if (data.length > 0) {
        list_id = shopping_urls.indexOf(data[0]['idList']);
    }
    if (list_id == -1) {
        console.log("Couldnt get the list id");
    }
    else {
    	for (key in data) {
    		shopping_list[list_id].push(data[key]['name'])
    		shopping_list_ids[list_id].push(data[key]['id'])
    	}
        shopping_queued[list_id] = true;
    }
	displayShopping();
}

$("html").keyup(function(event){
	if(event.keyCode == 13) {
		lookupCode($("#codefield").val());
	}
})

var success = function(successMsg) {
  console.log(successMsg);
};

var error = function(errorMsg) {
  console.log(errorMsg);
};

var authenticationSuccess = function() {
    load_lists();
};

var authenticationFailure = function() { console.log("Failed authentication"); };

Trello.authorize({
  type: 'popup',
  name: 'Getting Started Application',
  scope: {
    read: 'true',
    write: 'true' },
  expiration: 'never',
  success: authenticationSuccess,
  error: authenticationFailure
});

document.getElementById('codefield').focus();

start_list_loader();
<commit_msg>Fixed bug with list being displayed multiple times<commit_after>days = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']
months = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']

var shopping_list = [[], []];
var shopping_list_ids = [[],[]];
var shopping_queued = 0;
var shopping_urls = [
   '581fafe836e0ef68e2777f67',
   '582fdea3aeeca26b9064c5c6'
];

current_list = 0;

function displayShopping() {
	console.log("Displaying lists");
    for (list_id = 0; list_id < 2; list_id++) {
    	data = shopping_list[list_id];
    	$("#shopping_"+list_id).html("");
    	out = '
';
        if (data.length > 0) {
        	for (i = 0; i< data.length; i++) {
        		out += '
' + data[i] + '
';
        	}
        }
        else {
			// Dont display anything
        }
    	out += '
';
    	$("#shopping_"+list_id).html(out);
    }
    highlight_list();
	//displayShopping();
	document.getElementById('codefield').focus();
	console.log("Setting load list timer");
	setTimeout(load_lists, 1000 * 60 * 5);
}

function highlight_list() {
    $("#list_"+current_list).addClass("list_selected");
    $("#list_"+((current_list + 1) % 2)).removeClass("list_selected");
}

function add_item_to_list(item) {
	var newCard = {
	  name: item,
	  idList: shopping_urls[current_list],
	  pos: 'top'
	};
	Trello.post('/cards/', newCard, load_lists);
}

function close_card(name) {
	index = -1;
	for (key in shopping_list[current_list]) {
		if (name == shopping_list[current_list][key]) {
			index = key;
			break;
		}
	}
    console.log(key);
	if (index != -1) {
		console.log(name + ' has index ' + index + ' and id ' + shopping_list_ids[current_list][key]);
		Trello.put('/cards/'+shopping_list_ids[current_list][key], {closed: true}, load_lists);
	}
}

function archive_all() {
    url = '/lists/' + shopping_urls[current_list] + '/archiveAllCards';
	Trello.post(url, load_lists);
}

var counter = 0;

function add_remove_item(item) {
    if (shopping_list[current_list].indexOf(item) >= 0) {
    	console.log("Item already in shopping list, removing");
    	close_card(item);
    }
    else {
    	console.log("Adding item to shopping list");
    	add_item_to_list(item);
    }
}

function lookupCode(code) {
	$.ajax({
		url: "https://raw.githubusercontent.com/markjones112358/Household-Barcode-Database/master/barcodes.json",
		datatype: "json"
	}).done(function(tmp_data) {
		code = $("#codefield").val();
		if (code == "9410000000015") {
            console.log("Switching lists");
            current_list = (++current_list) % 2;
            highlight_list();
		}
		//else if (code == "9410000000022") {
		//	console.log("Cant remove");
		//}
		else if (code == "9410000000022") {
			archive_all();
		}
        else if (code == "4935850351001") {
            add_remove_item("Bananas");
        }
        else if (code == "9410000000114") {
            add_remove_item("Avocado");
        }
        else if (code == "9415077094332") {
            add_remove_item("Tin foil");
        }
        else if (code == "9410000000138") {
            add_remove_item("Baby mayo");
        }
        else if (code == "9410000000121") {
            add_remove_item("Toothpaste");
        }
        else if (code == "9414812091988") {
            add_remove_item("Toilet paper");
        }
		else {
			data = $.parseJSON(tmp_data);
			if (code in data) {
				console.log("Barcode resolves to " + data[code]);
			    add_remove_item(data[code]);
			}
		}
		$("#codefield").val('');
		document.getElementById('codefield').focus();
	});
}

function loadShopping(list_id) {
    url = '/lists/' + shopping_urls[list_id] + '/cards';
	Trello.get(url, parseShopping, error)
}

function load_lists() {
	console.log("Resetting cache and loading lists");
    shopping_list = [[], []];
    shopping_list_ids = [[], []];
    loadShopping(0);
    loadShopping(1);
    //Parse shopping takes care of displaying once both calls are done
}

function parseShopping(data, other, more) {
	console.log("Parsing returned list data...");
	console.log(data);
	console.log(other);
	console.log(more);
    list_id = -1;
    if (data.length > 0) {
        list_id = shopping_urls.indexOf(data[0]['idList']);
    }
    if (list_id == -1) {
        console.log("Couldnt get the list id - possibly the list is empty");
        shopping_queued++;
    }
    else {
    	for (key in data) {
    		shopping_list[list_id].push(data[key]['name'])
    		shopping_list_ids[list_id].push(data[key]['id'])
    	}
        shopping_queued++;
    }
    if (shopping_queued == 2) {
		displayShopping();
		shopping_queued = 0;
	}
}

$("html").keyup(function(event){
	if(event.keyCode == 13) {
		lookupCode($("#codefield").val());
	}
})

var success = function(successMsg) {
  console.log(successMsg);
};

var error = function(errorMsg) {
  console.log(errorMsg);
};

var authenticationSuccess = function() {
    load_lists();
    console.log("Starting the lost loader");
};

var authenticationFailure = function() { console.log("Failed authentication"); };

Trello.authorize({
  type: 'popup',
  name: 'Getting Started Application',
  scope: {
    read: 'true',
    write: 'true' },
  expiration: 'never',
  success: authenticationSuccess,
  error: authenticationFailure
});

document.getElementById('codefield').focus();

<|endoftext|>


<commit_before>/*
 * HomePage Messages
 *
 * This contains all the text for the HomePage component.
 */
import { defineMessages } from 'react-intl';

export default defineMessages({
  home: {
    id: 'boilerplate.components.Header.home',
<<<<<<< HEAD
    defaultMessage: 'Alkalmazottak',
=======
    defaultMessage: 'Alkalmazottak',
>>>>>>> c597ea7a7c47ab074f2295a6a500541c57f6a307
  },
  cars: {
    id: 'boilerplate.components.Header.cars',
    defaultMessage: 'AUTÓK',
  },
});
<commit_msg>fix conflicts<commit_after>/*
 * HomePage Messages
 *
 * This contains all the text for the HomePage component.
 */
import { defineMessages } from 'react-intl';

export default defineMessages({
  home: {
    id: 'boilerplate.components.Header.home',
    defaultMessage: 'ALKALMAZOTTAK',
  },
  cars: {
    id: 'boilerplate.components.Header.cars',
    defaultMessage: 'AUTÓK',
  },
});
<|endoftext|>


<commit_before>/*********************************************
 *  Copyright (c) 2014 AnsibleWorks, Inc.
 */
  /**
 *  @ngdoc function
 *  @name lib.ansible.function:RestServices
 *  @description
 * Generic accessor for Ansible Commander services
 *
 */
'use strict';
/**
* @ngdoc method
* @name lib.ansible.function:RestServices#Rest
* @methodOf lib.ansible.function:RestServices
* @description discuss reason to use this over built in functions with angular/jquery
*/
angular.module('RestServices', ['ngCookies', 'AuthService'])
    .factory('Rest', ['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
        function ($http, $rootScope, $cookieStore, $q, Authorization) {
            return {

                headers: {},

                setUrl: function (url) {
                    this.url = url;
                },
                checkExpired: function () {
                    return ($rootScope.sessionTimer) ? $rootScope.sessionTimer.isExpired() : false;
                },
                pReplace: function () {
                    //in our url, replace :xx params with a value, assuming
                    //we can find it in user supplied params.
                    var key, rgx;
                    for (key in this.params) {
                        rgx = new RegExp("\\:" + key, 'gm');
                        if (rgx.test(this.url)) {
                            this.url = this.url.replace(rgx, this.params[key]);
                            delete this.params[key];
                        }
                    }
                },
                createResponse: function (data, status) {
                    // Simulate an http response when a token error occurs
                    // http://stackoverflow.com/questions/18243286/angularjs-promises-simulate-http-promises

                    var promise = $q.reject({
                        data: data,
                        status: status
                    });
                    promise.success = function (fn) {
                        promise.then(function (response) {
                            fn(response.data, response.status);
                        }, null);
                        return promise;
                    };
                    promise.error = function (fn) {
                        promise.then(null, function (response) {
                            fn(response.data, response.status);
                        });
                        return promise;
                    };
                    return promise;
                },

                setHeader: function (hdr) {
                    // Pass in { key: value } pairs to be added to the header
                    for (var h in hdr) {
                        this.headers[h] = hdr[h];
                    }
                },
                get: function (args) {
                    args = (args) ? args : {};
                    this.params = (args.params) ? args.params : null;
                    this.pReplace();
                    var expired = this.checkExpired(),
                        token = Authorization.getToken();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'GET',
                            url: this.url,
                            headers: this.headers,
                            params: this.params
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                post: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'POST',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                put: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'PUT',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                destroy: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'DELETE',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                options: function () {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'OPTIONS',
                            url: this.url,
                            headers: this.headers
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                }
            };
        }
    ]);<commit_msg>JS Documentation Added documentation to lib/ansible/Rest.js<commit_after>/*********************************************
 *  Copyright (c) 2014 AnsibleWorks, Inc.
 */
/**
 *  @ngdoc function
 *  @name lib.ansible.function:RestServices
 *  @description
 *
 * A wrapper for angular's $http service. Post user authentication API requests should go through Rest rather than directly using $http. The goal is to decouple
 * the application from $http, allowing Rest or anything that provides the same methods to handle setting authentication headers and performing tasks such as checking
 * for an expired authentication token. Having this buffer between the application and $http will prove useful should the authentication scheme change.
 *
 * #.setUrl(<url>)
 *
 * Before calling an action methods (i.e. get, put, post, destroy, options) to send the request, call setUrl. Pass a string containing the URL endpoint and any parameters.
 * Note that $http will automaticall encode the URL, replacing spaces and special characters with appropriate %hex codes. Example URL values might include:
 *
 * ```
 *    /api/v1/inventories/9/
 *    /api/v1/credentials/?name=SSH Key&kind=ssh
 * ```
 *
 * When constructing the URL be sure to use the GetBasePath() method found in lib/ansible/Utilities.js. GetBasePath uses the response objects from /api and
 * /api/<version>/to construct the base portion of the path. This way the API version number and base endpoints are not hard-coded within the application.
 *
 * #Action methods: .get(), put(<JSON data object>), .post(<JSON data object>), .destroy(<JSON data object>), options()
 *
 * Use the method matching the REST action to be performed. In the case of put, post and destroy a JSON object can be passed as a parameter. If included,
 * it will be sent as part of the request.
 *
 * In every case a call to an action method returns a promise object, allowing the caller to pass reponse functions to the promise methods. The functions can inspect
 * the respoinse details and initiate action. For example:
 *
 * ```
 *     var url = GetBasePath('inventories') + $routeParams.id + '/';
 *     Rest.setUrl(url);
 *     Rest.get()
 *          .success(function(data) {
 *             // review the data object and take action
 *         })
 *         .error(function(status, data) {
 *             // handle the error - typically a call to ProcessErrors() found in lib/ansible/Utitlties.js
 *         });
 * ```
 *
 * ##Options Reqeusts
 *
 * options() requests are used by the GetChoices() method found in lib/ansible/Utilities.js. Sending an Options request to an API endpoint returns an object that includes
 * possible values for fields that are typically presented in the UI as dropdowns or <select> elements. GetChoices will inspect the response object for the request
 * field and return an array of { label: 'Choice Label', value: 'choice 1' } objects.
 *
 */

'use strict';

angular.module('RestServices', ['ngCookies', 'AuthService'])
    .factory('Rest', ['$http', '$rootScope', '$cookieStore', '$q', 'Authorization',
        function ($http, $rootScope, $cookieStore, $q, Authorization) {
            return {

                headers: {},

                setUrl: function (url) {
                    this.url = url;
                },
                checkExpired: function () {
                    return ($rootScope.sessionTimer) ? $rootScope.sessionTimer.isExpired() : false;
                },
                pReplace: function () {
                    //in our url, replace :xx params with a value, assuming
                    //we can find it in user supplied params.
                    var key, rgx;
                    for (key in this.params) {
                        rgx = new RegExp("\\:" + key, 'gm');
                        if (rgx.test(this.url)) {
                            this.url = this.url.replace(rgx, this.params[key]);
                            delete this.params[key];
                        }
                    }
                },
                createResponse: function (data, status) {
                    // Simulate an http response when a token error occurs
                    // http://stackoverflow.com/questions/18243286/angularjs-promises-simulate-http-promises

                    var promise = $q.reject({
                        data: data,
                        status: status
                    });
                    promise.success = function (fn) {
                        promise.then(function (response) {
                            fn(response.data, response.status);
                        }, null);
                        return promise;
                    };
                    promise.error = function (fn) {
                        promise.then(null, function (response) {
                            fn(response.data, response.status);
                        });
                        return promise;
                    };
                    return promise;
                },

                setHeader: function (hdr) {
                    // Pass in { key: value } pairs to be added to the header
                    for (var h in hdr) {
                        this.headers[h] = hdr[h];
                    }
                },
                get: function (args) {
                    args = (args) ? args : {};
                    this.params = (args.params) ? args.params : null;
                    this.pReplace();
                    var expired = this.checkExpired(),
                        token = Authorization.getToken();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'GET',
                            url: this.url,
                            headers: this.headers,
                            params: this.params
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                post: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'POST',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                put: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'PUT',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                destroy: function (data) {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'DELETE',
                            url: this.url,
                            headers: this.headers,
                            data: data
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                },
                options: function () {
                    var token = Authorization.getToken(),
                        expired = this.checkExpired();
                    if (expired) {
                        return this.createResponse({
                            detail: 'Token is expired'
                        }, 401);
                    } else if (token) {
                        this.setHeader({
                            Authorization: 'Token ' + token
                        });
                        this.setHeader({
                            "X-Auth-Token": 'Token ' + token
                        });
                        return $http({
                            method: 'OPTIONS',
                            url: this.url,
                            headers: this.headers
                        });
                    } else {
                        return this.createResponse({
                            detail: 'Invalid token'
                        }, 401);
                    }
                }
            };
        }
    ]);<|endoftext|>


<commit_before>/**
 * project.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 request.js
 *
 */

/**
 */

/**
 * A TrakEM2 Web project.
 *
 * - contains abstract objects on top of a common project-specific semantic framework
 * - is related to one ore more stacks of statically aligned layers
 *   ( all stacks of a project are related by translation using physical dimensions )
 */
function Project( pid )
{
	this.getView = function()
	{
		return view;
	}

	/**
	 * add a stack to the project
	 */
	this.addStack = function( stack )
	{
		var opened = false;
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == stack.id )
			{
				stack = stacks[ i ];
				opened = true;
				break;
			}
		}
		if ( !opened )
		{
			stacks.push( stack );
			if ( rootWindow.getChild() == null )
				rootWindow.replaceChild( stack.getWindow() );
			else
				rootWindow.replaceChild( new CMWHSplitNode( rootWindow.getChild(), stack.getWindow() ) );

			stack.getWindow().focus();
			ui.onresize();
		}
		if ( stacks.length > 1 )
			self.moveTo( self.coordinates.z, self.coordinates.y, self.coordinates.x );
		else
		{
			var c = stack.projectCoordinates();
			self.moveTo( c.z, c.y, c.x );
		}

		self.setFocusedStack( stack );

		if ( !tool )
			tool = new Navigator();
		self.setTool( tool );

		return;
	}

	/**
	 * get one of the projects currently opened stacks
	 */
	this.getStack = function( sid )
	{
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == sid ) return stacks[ i ];
		}
		return false;
	}

	/**
	 * remove a stack from the list
	 */
	this.removeStack = function( sid )
	{
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == sid )
			{
				stacks.splice( i, 1 );
				if ( stacks.length == 0 )
					self.unregister();
				else
					stacks[ ( i + 1 ) % stacks.length ].getWindow().focus();
			}
		}
		ui.onresize();
		return;
	}

	/**
	 * focus a stack and blur the rest
	 */
	this.setFocusedStack = function( stack )
	{
		self.focusedStack = stack;
		if ( tool )
			self.focusedStack.setTool( tool );
		window.onresize();
		return;
	}

	/**
	 * focus the next or prior stack
	 */
	this.switchFocus = function( s )
	{
		var i;
		for ( i = 0; i < stacks.length; ++i )
			if ( self.focusedStack == stacks[ i ] ) break;

		stacks[ ( i + stacks.length + s ) % stacks.length ].getWindow().focus();
		return;
	}

	//!< Associative array of selected objects
	// in the Treenode Table and Object Tree.
	// I.e. enables communication between the Object Tree and the Table of Nodes.
	this.selectedObjects = {
		'tree_object': {},
		'table_treenode': {},
		'selectedneuron': null,
		'selectedskeleton': null
	};

	this.hideToolbars = function()
	{
		document.getElementById( "toolbar_nav" ).style.display = "none";
		document.getElementById( "toolbar_text" ).style.display = "none";
		document.getElementById( "toolbar_crop" ).style.display = "none";
		document.getElementById( "toolbar_trace" ).style.display = "none";
	}

	this.setTool = function( newTool )
	{
		if ( tool )
			tool.destroy();
		tool = newTool;

		if ( !self.focusedStack && stacks.length > 0 )
			self.focusedStack = stacks[ 0 ];

		if ( self.focusedStack )
			self.focusedStack.getWindow().focus();

		window.onresize();
		WindowMaker.setKeyShortcuts();
		return;
	}

	this.getTool = function( )
	{
		return tool;
	}

	this.toggleShow = function( m )
	{
		switch ( m )
		{
		case "text":
			if ( show_textlabels && mode != "text" )
			{
				show_textlabels = false;
				document.getElementById( "show_button_text" ).className = "button";
				for ( var i = 0; i < stacks.length; ++i )
					stacks[ i ].showTextlabels( false );
			}
			else
			{
				show_textlabels = true;
				for ( var i = 0; i < stacks.length; ++i )
					stacks[ i ].showTextlabels( true );
				document.getElementById( "show_button_text" ).className = "button_active";
			}
		}
		return;
	}

	/**
	 * register all GUI elements
	 */
	this.register = function()
	{
		document.getElementById( "content" ).style.display = "none";
		document.body.appendChild( view );
		ui.registerEvent( "onresize", resize );
		window.onresize();

		document.onkeydown = onkeydown;

		return;
	}

	/**
	 * unregister and remove all stacks, free the event-handlers, hide the stack-toolbar
	 *
	 * @todo: should not the stack handle the navigation toolbar?
	 */
	this.unregister = function()
	{
		if ( tool ) tool.unregister();

		//! close all windows
		//rootWindow.closeAllChildren();
		rootWindow.close();

		ui.removeEvent( "onresize", resize );
		try
		{
			document.body.removeChild( view );
		}
		catch ( error ) {}
		self.id = 0;
		document.onkeydown = null;
		document.getElementById( "content" ).style.display = "block";

		project = null;

		return;
	}

	/**
	 * set the project to be editable or not
	 */
	this.setEditable = function(bool)
	{
		editable = bool;
		if (editable) {
			document.getElementById("toolbox_edit").style.display = "block";
			document.getElementById("toolbox_data").style.display = "block";
		}
		else
		{
			document.getElementById("toolbox_edit").style.display = "none";
			document.getElementById("toolbox_data").style.display = "none";
		}
		window.onresize();

		return;
	}

	/**
	 * move all stacks to the physical coordinates
	 */
	this.moveTo = function(
		zp,
		yp,
		xp,
		sp )
	{
		self.coordinates.x = xp;
		self.coordinates.y = yp;
		self.coordinates.z = zp;

		for ( var i = 0; i < stacks.length; ++i )
		{
			stacks[ i ].moveTo( zp, yp, xp, sp );
		}
		if ( tool && tool.redraw )
			tool.redraw();
		return;
	}

	/**
	 * create a URL to the current view
	 */
	this.createURL = function()
	{
		var coords;
		var url="?pid=" + self.id;
		if ( stacks.length > 0 )
		{
			//coords = stacks[ 0 ].projectCoordinates();		//!< @todo get this from the SELECTED stack to avoid approximation errors!
			url += "&zp=" + self.coordinates.z + "&yp=" + self.coordinates.y + "&xp=" + self.coordinates.x;
			url += "&tool=" + project.getTool().toolname;
			for ( var i = 0; i < stacks.length; ++i )
			{
				url += "&sid" + i + "=" + stacks[ i ].id + "&s" + i + "=" + stacks[ i ].s;
			}
		}
		return url;
	}

	/**
	 * create a textlabel on the server
	 */
	this.createTextlabel = function( tlx, tly, tlz, tlr, scale )
	{
		icon_text_apply.style.display = "block";
		requestQueue.register(
			'model/textlabel.create.php',
			'POST',
			{
				pid : project.id,
				x : tlx,
				y : tly,
				z : tlz,
				r : parseInt( document.getElementById( "fontcolourred" ).value ) / 255,
				g : parseInt( document.getElementById( "fontcolourgreen" ).value ) / 255,
				b : parseInt( document.getElementById( "fontcolourblue" ).value ) / 255,
				a : 1,
				type : "text",
				scaling : ( document.getElementById( "fontscaling" ).checked ? 1 : 0 ),
				fontsize : ( document.getElementById( "fontscaling" ).checked ?
							Math.max( 16 / scale, parseInt( document.getElementById( "fontsize" ).value ) ) :
							parseInt( document.getElementById( "fontsize" ).value ) ) * tlr,
				fontstyle : ( document.getElementById( "fontstylebold" ).checked ? "bold" : "" )
			},
			function( status, text, xml )
			{
				statusBar.replaceLast( text );

				if ( status == 200 )
				{
					icon_text_apply.style.display = "none";
					for ( var i = 0; i < stacks.length; ++i )
					{
						stacks[ i ].updateTextlabels();
					}
					if ( text && text != " " )
					{
						var e = eval( "(" + text + ")" );
						if ( e.error )
						{
							alert( e.error );
						}
						else
						{
						}
					}
				}
				return true;
			} );
		return;
	}

	/** This function should return true if there was any action
		linked to the key code, or false otherwise. */

	this.handleKeyPress = function( e ) {
		var keyAction = keyCodeToAction[e.keyCode];
		if (keyAction) {
			keyAction.run(e);
			return true;
		} else {
			return false;
		}
	}

	var onkeydown = function( e )
	{
		var projectKeyPress;
		var key;
		var shift;
		var alt;
		var ctrl;
		var keyAction;

		/* The code here used to modify 'e' and pass it
		   on, but Firefox no longer allows this.  So, create
		   a fake event object instead, and pass that down. */
		var fakeEvent = {};

		if ( e )
		{
			if ( e.keyCode ) {
				key = e.keyCode;
			} else if ( e.charCode ) {
				key = e.charCode;
			} else {
				key = e.which;
			}
			fakeEvent.keyCode = key;
			fakeEvent.shiftKey = e.shiftKey;
			fakeEvent.altKey = e.altKey;
			fakeEvent.ctrlKey = e.ctrlKey;
			shift = e.shiftKey;
			alt = e.altKey;
			ctrl = e.ctrlKey;
		}
		else if ( event && event.keyCode )
		{
			fakeEvent.keyCode = event.keyCode;
			fakeEvent.shiftKey = event.shiftKey;
			fakeEvent.altKey = event.altKey;
			fakeEvent.ctrlKey = event.ctrlKey;
			shift = event.shiftKey;
			alt = event.altKey;
			ctrl = event.ctrlKey;
		}
		fakeEvent.target = UI.getTargetElement(e || event);
		var n = fakeEvent.target.nodeName.toLowerCase();
		var fromATextField = false;
		if (n == "input") {
			var inputType = fakeEvent.target.type.toLowerCase();
			if (inputType == "text" || inputType == "password") {
				fromATextField = true;
			}
		}
		if (!(fromATextField || n == "textarea" || n == "area")) //!< @todo exclude all useful keyboard input elements e.g. contenteditable...
		{
			if (tool && tool.handleKeyPress(fakeEvent)) {
				return false;
			} else {
				projectKeyPress = self.handleKeyPress(fakeEvent);
				return ! projectKeyPress;
			}
		} else {
			return true;
		}
	}

	/**
	 * Get project ID.
	 */
	this.getId = function(){ return pid; }

	// initialise
	var self = this;
	this.id = pid;
	if ( typeof ui == "undefined" ) ui = new UI();
	if ( typeof requestQueue == "undefined" ) requestQueue = new RequestQueue();

	var tool = null;

	var view = rootWindow.getFrame();
	view.className = "projectView";

	this.coordinates =
	{
		x : 0,
		y : 0,
		z : 0
	};

	var template;				//!< DTD like abstract object tree (classes)
	var data;					//!< instances in a DOM representation

	var stacks = new Array();	//!< a list of stacks related to the project
	this.focusedStack;

	var editable = false;
	var mode = "move";
	var show_textlabels = true;

	var icon_text_apply = document.getElementById( "icon_text_apply" );

	/** The only actions that should be added to Project are those
	    that should be run regardless of the current tool, such as
	    actions that switch tools. */

	var actions = [];

	this.addAction = function ( action ) {
		actions.push( action );
	}

	this.getActions = function () {
		return actions;
	}

	/** FIXME: also add F1 to open the key shortcuts help?

	    FIXME: 1 is a bad shortcut to switch tool (1-5 should be used
	    for setting confidences instead) */

	this.addAction( new Action({
		helpText: "Switch to skeleton tracing mode",
		buttonID: 'trace_button_skeleton',
		keyShortcuts: {
			'1': [ 49 ]
		},
		run: function (e) {
			project.setTool( new TracingTool() );
			return false;
		}
	}) );

	this.addAction( new Action({
		helpText: "Switch to the next open stack (or the previous with Shift+Tab)",
		keyShortcuts: {
			'Tab': [ 9 ]
		},
		run: function (e) {
			if (e.shiftKey) {
				project.switchFocus(-1);
			} else {
				project.switchFocus(1);
			}
			//e.stopPropagation();
			return false;
		}
	}) );

	var keyCodeToAction = getKeyCodeToActionMap(actions);

	setButtonClicksFromActions(actions);

}
<commit_msg>Comment out the setting of project-wide buttons before refactoring<commit_after>/**
 * project.js
 *
 * requirements:
 *	 tools.js
 *	 ui.js
 *	 request.js
 *
 */

/**
 */

/**
 * A TrakEM2 Web project.
 *
 * - contains abstract objects on top of a common project-specific semantic framework
 * - is related to one ore more stacks of statically aligned layers
 *   ( all stacks of a project are related by translation using physical dimensions )
 */
function Project( pid )
{
	this.getView = function()
	{
		return view;
	}

	/**
	 * add a stack to the project
	 */
	this.addStack = function( stack )
	{
		var opened = false;
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == stack.id )
			{
				stack = stacks[ i ];
				opened = true;
				break;
			}
		}
		if ( !opened )
		{
			stacks.push( stack );
			if ( rootWindow.getChild() == null )
				rootWindow.replaceChild( stack.getWindow() );
			else
				rootWindow.replaceChild( new CMWHSplitNode( rootWindow.getChild(), stack.getWindow() ) );

			stack.getWindow().focus();
			ui.onresize();
		}
		if ( stacks.length > 1 )
			self.moveTo( self.coordinates.z, self.coordinates.y, self.coordinates.x );
		else
		{
			var c = stack.projectCoordinates();
			self.moveTo( c.z, c.y, c.x );
		}

		self.setFocusedStack( stack );

		if ( !tool )
			tool = new Navigator();
		self.setTool( tool );

		return;
	}

	/**
	 * get one of the projects currently opened stacks
	 */
	this.getStack = function( sid )
	{
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == sid ) return stacks[ i ];
		}
		return false;
	}

	/**
	 * remove a stack from the list
	 */
	this.removeStack = function( sid )
	{
		for ( var i = 0; i < stacks.length; ++i )
		{
			if ( stacks[ i ].id == sid )
			{
				stacks.splice( i, 1 );
				if ( stacks.length == 0 )
					self.unregister();
				else
					stacks[ ( i + 1 ) % stacks.length ].getWindow().focus();
			}
		}
		ui.onresize();
		return;
	}

	/**
	 * focus a stack and blur the rest
	 */
	this.setFocusedStack = function( stack )
	{
		self.focusedStack = stack;
		if ( tool )
			self.focusedStack.setTool( tool );
		window.onresize();
		return;
	}

	/**
	 * focus the next or prior stack
	 */
	this.switchFocus = function( s )
	{
		var i;
		for ( i = 0; i < stacks.length; ++i )
			if ( self.focusedStack == stacks[ i ] ) break;

		stacks[ ( i + stacks.length + s ) % stacks.length ].getWindow().focus();
		return;
	}

	//!< Associative array of selected objects
	// in the Treenode Table and Object Tree.
	// I.e. enables communication between the Object Tree and the Table of Nodes.
	this.selectedObjects = {
		'tree_object': {},
		'table_treenode': {},
		'selectedneuron': null,
		'selectedskeleton': null
	};

	this.hideToolbars = function()
	{
		document.getElementById( "toolbar_nav" ).style.display = "none";
		document.getElementById( "toolbar_text" ).style.display = "none";
		document.getElementById( "toolbar_crop" ).style.display = "none";
		document.getElementById( "toolbar_trace" ).style.display = "none";
	}

	this.setTool = function( newTool )
	{
		if ( tool )
			tool.destroy();
		tool = newTool;

		if ( !self.focusedStack && stacks.length > 0 )
			self.focusedStack = stacks[ 0 ];

		if ( self.focusedStack )
			self.focusedStack.getWindow().focus();

		window.onresize();
		WindowMaker.setKeyShortcuts();
		return;
	}

	this.getTool = function( )
	{
		return tool;
	}

	this.toggleShow = function( m )
	{
		switch ( m )
		{
		case "text":
			if ( show_textlabels && mode != "text" )
			{
				show_textlabels = false;
				document.getElementById( "show_button_text" ).className = "button";
				for ( var i = 0; i < stacks.length; ++i )
					stacks[ i ].showTextlabels( false );
			}
			else
			{
				show_textlabels = true;
				for ( var i = 0; i < stacks.length; ++i )
					stacks[ i ].showTextlabels( true );
				document.getElementById( "show_button_text" ).className = "button_active";
			}
		}
		return;
	}

	/**
	 * register all GUI elements
	 */
	this.register = function()
	{
		document.getElementById( "content" ).style.display = "none";
		document.body.appendChild( view );
		ui.registerEvent( "onresize", resize );
		window.onresize();

		document.onkeydown = onkeydown;

		return;
	}

	/**
	 * unregister and remove all stacks, free the event-handlers, hide the stack-toolbar
	 *
	 * @todo: should not the stack handle the navigation toolbar?
	 */
	this.unregister = function()
	{
		if ( tool ) tool.unregister();

		//! close all windows
		//rootWindow.closeAllChildren();
		rootWindow.close();

		ui.removeEvent( "onresize", resize );
		try
		{
			document.body.removeChild( view );
		}
		catch ( error ) {}
		self.id = 0;
		document.onkeydown = null;
		document.getElementById( "content" ).style.display = "block";

		project = null;

		return;
	}

	/**
	 * set the project to be editable or not
	 */
	this.setEditable = function(bool)
	{
		editable = bool;
		if (editable) {
			document.getElementById("toolbox_edit").style.display = "block";
			document.getElementById("toolbox_data").style.display = "block";
		}
		else
		{
			document.getElementById("toolbox_edit").style.display = "none";
			document.getElementById("toolbox_data").style.display = "none";
		}
		window.onresize();

		return;
	}

	/**
	 * move all stacks to the physical coordinates
	 */
	this.moveTo = function(
		zp,
		yp,
		xp,
		sp )
	{
		self.coordinates.x = xp;
		self.coordinates.y = yp;
		self.coordinates.z = zp;

		for ( var i = 0; i < stacks.length; ++i )
		{
			stacks[ i ].moveTo( zp, yp, xp, sp );
		}
		if ( tool && tool.redraw )
			tool.redraw();
		return;
	}

	/**
	 * create a URL to the current view
	 */
	this.createURL = function()
	{
		var coords;
		var url="?pid=" + self.id;
		if ( stacks.length > 0 )
		{
			//coords = stacks[ 0 ].projectCoordinates();		//!< @todo get this from the SELECTED stack to avoid approximation errors!
			url += "&zp=" + self.coordinates.z + "&yp=" + self.coordinates.y + "&xp=" + self.coordinates.x;
			url += "&tool=" + project.getTool().toolname;
			for ( var i = 0; i < stacks.length; ++i )
			{
				url += "&sid" + i + "=" + stacks[ i ].id + "&s" + i + "=" + stacks[ i ].s;
			}
		}
		return url;
	}

	/**
	 * create a textlabel on the server
	 */
	this.createTextlabel = function( tlx, tly, tlz, tlr, scale )
	{
		icon_text_apply.style.display = "block";
		requestQueue.register(
			'model/textlabel.create.php',
			'POST',
			{
				pid : project.id,
				x : tlx,
				y : tly,
				z : tlz,
				r : parseInt( document.getElementById( "fontcolourred" ).value ) / 255,
				g : parseInt( document.getElementById( "fontcolourgreen" ).value ) / 255,
				b : parseInt( document.getElementById( "fontcolourblue" ).value ) / 255,
				a : 1,
				type : "text",
				scaling : ( document.getElementById( "fontscaling" ).checked ? 1 : 0 ),
				fontsize : ( document.getElementById( "fontscaling" ).checked ?
							Math.max( 16 / scale, parseInt( document.getElementById( "fontsize" ).value ) ) :
							parseInt( document.getElementById( "fontsize" ).value ) ) * tlr,
				fontstyle : ( document.getElementById( "fontstylebold" ).checked ? "bold" : "" )
			},
			function( status, text, xml )
			{
				statusBar.replaceLast( text );

				if ( status == 200 )
				{
					icon_text_apply.style.display = "none";
					for ( var i = 0; i < stacks.length; ++i )
					{
						stacks[ i ].updateTextlabels();
					}
					if ( text && text != " " )
					{
						var e = eval( "(" + text + ")" );
						if ( e.error )
						{
							alert( e.error );
						}
						else
						{
						}
					}
				}
				return true;
			} );
		return;
	}

	/** This function should return true if there was any action
		linked to the key code, or false otherwise. */

	this.handleKeyPress = function( e ) {
		var keyAction = keyCodeToAction[e.keyCode];
		if (keyAction) {
			keyAction.run(e);
			return true;
		} else {
			return false;
		}
	}

	var onkeydown = function( e )
	{
		var projectKeyPress;
		var key;
		var shift;
		var alt;
		var ctrl;
		var keyAction;

		/* The code here used to modify 'e' and pass it
		   on, but Firefox no longer allows this.  So, create
		   a fake event object instead, and pass that down. */
		var fakeEvent = {};

		if ( e )
		{
			if ( e.keyCode ) {
				key = e.keyCode;
			} else if ( e.charCode ) {
				key = e.charCode;
			} else {
				key = e.which;
			}
			fakeEvent.keyCode = key;
			fakeEvent.shiftKey = e.shiftKey;
			fakeEvent.altKey = e.altKey;
			fakeEvent.ctrlKey = e.ctrlKey;
			shift = e.shiftKey;
			alt = e.altKey;
			ctrl = e.ctrlKey;
		}
		else if ( event && event.keyCode )
		{
			fakeEvent.keyCode = event.keyCode;
			fakeEvent.shiftKey = event.shiftKey;
			fakeEvent.altKey = event.altKey;
			fakeEvent.ctrlKey = event.ctrlKey;
			shift = event.shiftKey;
			alt = event.altKey;
			ctrl = event.ctrlKey;
		}
		fakeEvent.target = UI.getTargetElement(e || event);
		var n = fakeEvent.target.nodeName.toLowerCase();
		var fromATextField = false;
		if (n == "input") {
			var inputType = fakeEvent.target.type.toLowerCase();
			if (inputType == "text" || inputType == "password") {
				fromATextField = true;
			}
		}
		if (!(fromATextField || n == "textarea" || n == "area")) //!< @todo exclude all useful keyboard input elements e.g. contenteditable...
		{
			if (tool && tool.handleKeyPress(fakeEvent)) {
				return false;
			} else {
				projectKeyPress = self.handleKeyPress(fakeEvent);
				return ! projectKeyPress;
			}
		} else {
			return true;
		}
	}

	/**
	 * Get project ID.
	 */
	this.getId = function(){ return pid; }

	// initialise
	var self = this;
	this.id = pid;
	if ( typeof ui == "undefined" ) ui = new UI();
	if ( typeof requestQueue == "undefined" ) requestQueue = new RequestQueue();

	var tool = null;

	var view = rootWindow.getFrame();
	view.className = "projectView";

	this.coordinates =
	{
		x : 0,
		y : 0,
		z : 0
	};

	var template;				//!< DTD like abstract object tree (classes)
	var data;					//!< instances in a DOM representation

	var stacks = new Array();	//!< a list of stacks related to the project
	this.focusedStack;

	var editable = false;
	var mode = "move";
	var show_textlabels = true;

	var icon_text_apply = document.getElementById( "icon_text_apply" );

	/** The only actions that should be added to Project are those
	    that should be run regardless of the current tool, such as
	    actions that switch tools. */

	var actions = [];

	this.addAction = function ( action ) {
		actions.push( action );
	}

	this.getActions = function () {
		return actions;
	}

	/** FIXME: also add F1 to open the key shortcuts help?

	    FIXME: 1 is a bad shortcut to switch tool (1-5 should be used
	    for setting confidences instead) */

	this.addAction( new Action({
		helpText: "Switch to skeleton tracing mode",
		buttonID: 'trace_button_skeleton',
		keyShortcuts: {
			'1': [ 49 ]
		},
		run: function (e) {
			project.setTool( new TracingTool() );
			return false;
		}
	}) );

	this.addAction( new Action({
		helpText: "Switch to the next open stack (or the previous with Shift+Tab)",
		keyShortcuts: {
			'Tab': [ 9 ]
		},
		run: function (e) {
			if (e.shiftKey) {
				project.switchFocus(-1);
			} else {
				project.switchFocus(1);
			}
			//e.stopPropagation();
			return false;
		}
	}) );

	var keyCodeToAction = getKeyCodeToActionMap(actions);

	// setButtonClicksFromActions(actions);

}
<|endoftext|>