<commit_before>'use strict'

var express = require('express')
var router = module.exports = express.Router()
var Trail = require('../../models/trail')
var utils = require('./utils')

router.route('/') // this is /api/trails
    .get(function(req, res, next) {
      // query string will need updating.
      var query = {}
      if (req.query.center) {
        var pointArray = JSON.parse(req.query.center)
        query = {
          geometry: {
            $near: {
              $geometry: {
                type: "Point",
                coordinates: pointArray
              }
            }
          }
        }
      }
      Trail.find(query)
      .limit(500)
      .sort('')
      .exec()
      .then(
        trails => {
          console.log('found trails:', trails.length)
          res.status(200).json(trails)
        },
        err => res.status(500).json({'error': 'Internal Server Error', err })
       )
    })
router.route('/:id') // this is /api/trails/:id
    .get(function(req, res, next) {
      Trail.findOne({_id: req.params.id})
        .exec()
        .then(
          trails => res.status(200).json(trails),
          err => res.status(500).json({'error': 'Internal Server Error', err })
        )
    })

<commit_msg>removing util use<commit_after>'use strict'

var express = require('express')
var router = module.exports = express.Router()
var Trail = require('../../models/trail')

router.route('/') // this is /api/trails
    .get(function(req, res, next) {
      // query string will need updating.
      var query = {}
      if (req.query.center) {
        var pointArray = JSON.parse(req.query.center)
        query = {
          geometry: {
            $near: {
              $geometry: {
                type: "Point",
                coordinates: pointArray
              }
            }
          }
        }
      }
      Trail.find(query)
      .limit(500)
      .sort('')
      .exec()
      .then(
        trails => {
          console.log('found trails:', trails.length)
          res.status(200).json(trails)
        },
        err => res.status(500).json({'error': 'Internal Server Error', err })
       )
    })
router.route('/:id') // this is /api/trails/:id
    .get(function(req, res, next) {
      Trail.findOne({_id: req.params.id})
        .exec()
        .then(
          trails => res.status(200).json(trails),
          err => res.status(500).json({'error': 'Internal Server Error', err })
        )
    })

<|endoftext|>


<commit_before>/* A file with functionality that is enabled on each page. */

function bulk_email() {
    /*
    Look at all selected <input type="checkbox" email="example@example.org">
    tags on the webpage and join email addresses using comma as a separator
    (i.e. "first@example.org,second@example.org").

    If there is no selected checkbox with email address, display alert. If
    any of the selected email addresses is blank, display alert. Otherwise,
    open email client and pass those addresses.
    */
    var emails, href, blank_email_selected;
    emails = $('input[type=checkbox][email]:checked')
             .map(function () { return $(this).attr("email"); });
    blank_email_selected = emails.is(function() { return this == ""; });
    if (blank_email_selected) {
        alert("We don't know email address of some of the selected persons. First, unselect them.");
    } else if (emails.length == 0) {
        alert("Select at least one person.");
    } else {
        href = "mailto:?bcc=" + emails.toArray().join(",");
        window.location.href = href;
    }
}

/* See http://learn.jquery.com/plugins/basic-plugin-creation/ */
$.fn.updateSelectAllCheckbox = function () {
  return this.each(function() {
    /* At this moment, `this` is "select all" checkbox. */

    var checkboxes = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]');
    var checked = checkboxes.filter(':checked');
    if (checked.length == 0) { // all checkboxes are unchecked
      $(this).prop('checked', false);
      $(this).prop('indeterminate', false);
    } else if (checked.length == checkboxes.length) { // all checkboxes are checked
      $(this).prop('checked', true);
      $(this).prop('indeterminate', false);
    } else { // some checkboxes are checked and some are unchecked
      $(this).prop('checked', false);
      $(this).prop('indeterminate', true);
    }
    return this;
  });
};

/* See http://learn.jquery.com/plugins/basic-plugin-creation/ */
$.fn.updateIdsInHref = function () {
  // checked checkboxes
  var checked = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]').filter(':checked');
  // current URL
  var href = $(this).attr('href');
  // make URI.js object out of the URL
  var uri = URI(href);

  // extend query params
  uri = uri.query(function(data) {
    var ids = [];
    checked.map(function() {
      ids.push($(this).val());
    });
    data.ids = ids.join(",");
  });

  // update URL with new query parameters
  $(this).attr('href', uri.toString());

  return this;
}

function updateTrainingProgressForm() {
  /* At this moment, `this` should be <select> tag of "Type" field. */
  var type = $(this).find(":selected").text();
  var training_div = $(this).closest('form').find('#div_id_event');
  var url_div = $(this).closest('form').find('#div_id_url');

  if (type == 'Training') {
    training_div.show();
  } else {
    training_div.hide();
    var event = training_div.find('#id_event');
    if (event.val() != undefined) {
      event.val(null).trigger('change');
    }
  }

  if (type == 'SWC Homework' || type == 'DC Homework' || type == 'LC Homework') {
    url_div.show();
  } else {
    url_div.hide();
    url_div.find('#id_url').val("");
  }
}

$(document).ready(function() {
  /* Enable Bootstrap Tooltips by default. */
  $('[data-toggle="tooltip"]').tooltip();

  /*
  Enable Bootstrap Popovers by default.

  Example usage:

  Hover, focus or click me!
  */
  $('[data-toggle="popover"]').popover({placement: "auto"});

  /* Some pages may have checkboxes in tables selected by default; in those
  cases, we should update URL in a[amy-download-selected] when the page
  loads. */
  $('a[amy-download-selected]').each(function(i, obj) {
    $(this).updateIdsInHref();
  });

  /*
  Add <input type="checkbox" select-all-checkbox> to your form to let user
  select/unselect all checkboxes with respond-to-select-all-checkbox attribute
  in the form with single click.

  Based on http://stackoverflow.com/a/2228401.
  */
  /* Select/unselect all checkboxes when users clicks on "select all" checkbox. */
  $('[select-all-checkbox]').change(function() {
    var checkboxes = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]');
    if($(this).is(':checked')) {
        checkboxes.prop('checked', true);
    } else {
        checkboxes.prop('checked', false);
    }
    // below runs `updateIdsInHref` for all matching  (`.each` is required)
    $(this).closest('form').find('a[amy-download-selected]').each(function(i, obj) {
      $(this).updateIdsInHref();
    });
  });

  /* When a checkbox is clicked, update "select all" checkbox state to checked,
  unchecked or indeterminate (neither checked nor unchecked) depending
  on the state of all checkboxes. */
  $('[respond-to-select-all-checkbox]').change(function () {
    $(this).closest('form').find(':checkbox[select-all-checkbox]').updateSelectAllCheckbox();
    // below runs `updateIdsInHref` for all matching  (`.each` is required)
    $(this).closest('form').find('a[amy-download-selected]').each(function(i, obj) {
      $(this).updateIdsInHref();
    });
  });

  /* Set "select all" checkboxes to proper initial state. */
  $(':checkbox[select-all-checkbox]').updateSelectAllCheckbox();

  /*
  Add Mail selected people
  to your form to let the user write email to a group of selected people. You
  need to set up emails addresses on checkboxes:

      <input type="checkbox" email="example@example.org">

  Blank emails and checkboxes without email attribute will be ignored.
  */
  $('[bulk-email-on-click]').click(function () {
    bulk_email();
  });

  /*
  TrainingProgress forms: show/hide training and url fields, depending on
  selected TrainingProgress type.
  */

  var selectField = $('form.training-progress #id_requirement')
  selectField.change(updateTrainingProgressForm);
  updateTrainingProgressForm.call(selectField);

  /*
  When there is any autocomplete field with invalid value, prevent form
  submission. Focus on the invalid field when user tries to submit the form.
  */

  $('form').submit(function (event) {
    var invalidAutocompleteFields = $('.ui-autocomplete-input.ui-state-error');
    if (invalidAutocompleteFields.length > 0) {
      var firstInvalidField = invalidAutocompleteFields.first();
      firstInvalidField.focus();
      event.preventDefault();  // prevent submission
    }
  });

  /* Fix select2 widgets losing their focus. */
  $('select').on("select2:close", function () { $(this).focus(); });

  /* react on comment tab change: resize preview div */
  $('.comment-form a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    var target_pane = $(e.target).attr("href");
    var prev_target_pane = $(e.relatedTarget).attr("href");

    if (target_pane == "#preview") {
      if ($(target_pane).height() < $(prev_target_pane).height()) {
        $(target_pane).height($(prev_target_pane).height());
      }
    }
  })

  // check initial value for this proficient computing level
  if ($("#id_computing_levels_3").is(":checked")) {
    $("#computing_levels_warning").removeClass("d-none");
  } else {
    $("#computing_levels_warning").addClass("d-none");
  }

  $("#id_computing_levels_3").change(function() {
    // show warning if someone selects "Proficient"
    if($(this).is(':checked')) {
      $("#computing_levels_warning").removeClass("d-none");
    } else {
      $("#computing_levels_warning").addClass("d-none");
    }
  })

  // check initial value for the preferred dates
  if ($("#id_preferred_dates").val()) {
    $("#id_preferred_dates").datepicker('update');

    // read current input value and today's date
    var value = $("#id_preferred_dates").datepicker('getDate');
    var today = new Date();
    var time_diff = value.getTime() - today.getTime();

    // 3 months
    if (time_diff < 1000 * 60 * 60 * 24 * 30 * 3) {
      $("#preferred_dates_warning").removeClass("d-none");
    } else {
      $("#preferred_dates_warning").addClass("d-none");
    }
  }

  $("#id_preferred_dates").on("changeDate input", function(e){
    // update datepicker with current input value
    $(this).datepicker('update');

    // read current input value and today's date
    var value = $(this).datepicker('getDate');
    var today = new Date();
    var time_diff = value.getTime() - today.getTime();

    // 3 months
    if (time_diff < 1000 * 60 * 60 * 24 * 30 * 3) {
      $("#preferred_dates_warning").removeClass("d-none");
    } else {
      $("#preferred_dates_warning").addClass("d-none");
    }
  })
 });
<commit_msg>Shorten the timedelta for preferred_dates warning to show (90 -> 60 days)<commit_after>/* A file with functionality that is enabled on each page. */

function bulk_email() {
    /*
    Look at all selected <input type="checkbox" email="example@example.org">
    tags on the webpage and join email addresses using comma as a separator
    (i.e. "first@example.org,second@example.org").

    If there is no selected checkbox with email address, display alert. If
    any of the selected email addresses is blank, display alert. Otherwise,
    open email client and pass those addresses.
    */
    var emails, href, blank_email_selected;
    emails = $('input[type=checkbox][email]:checked')
             .map(function () { return $(this).attr("email"); });
    blank_email_selected = emails.is(function() { return this == ""; });
    if (blank_email_selected) {
        alert("We don't know email address of some of the selected persons. First, unselect them.");
    } else if (emails.length == 0) {
        alert("Select at least one person.");
    } else {
        href = "mailto:?bcc=" + emails.toArray().join(",");
        window.location.href = href;
    }
}

/* See http://learn.jquery.com/plugins/basic-plugin-creation/ */
$.fn.updateSelectAllCheckbox = function () {
  return this.each(function() {
    /* At this moment, `this` is "select all" checkbox. */

    var checkboxes = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]');
    var checked = checkboxes.filter(':checked');
    if (checked.length == 0) { // all checkboxes are unchecked
      $(this).prop('checked', false);
      $(this).prop('indeterminate', false);
    } else if (checked.length == checkboxes.length) { // all checkboxes are checked
      $(this).prop('checked', true);
      $(this).prop('indeterminate', false);
    } else { // some checkboxes are checked and some are unchecked
      $(this).prop('checked', false);
      $(this).prop('indeterminate', true);
    }
    return this;
  });
};

/* See http://learn.jquery.com/plugins/basic-plugin-creation/ */
$.fn.updateIdsInHref = function () {
  // checked checkboxes
  var checked = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]').filter(':checked');
  // current URL
  var href = $(this).attr('href');
  // make URI.js object out of the URL
  var uri = URI(href);

  // extend query params
  uri = uri.query(function(data) {
    var ids = [];
    checked.map(function() {
      ids.push($(this).val());
    });
    data.ids = ids.join(",");
  });

  // update URL with new query parameters
  $(this).attr('href', uri.toString());

  return this;
}

function updateTrainingProgressForm() {
  /* At this moment, `this` should be <select> tag of "Type" field. */
  var type = $(this).find(":selected").text();
  var training_div = $(this).closest('form').find('#div_id_event');
  var url_div = $(this).closest('form').find('#div_id_url');

  if (type == 'Training') {
    training_div.show();
  } else {
    training_div.hide();
    var event = training_div.find('#id_event');
    if (event.val() != undefined) {
      event.val(null).trigger('change');
    }
  }

  if (type == 'SWC Homework' || type == 'DC Homework' || type == 'LC Homework') {
    url_div.show();
  } else {
    url_div.hide();
    url_div.find('#id_url').val("");
  }
}

$(document).ready(function() {
  /* Enable Bootstrap Tooltips by default. */
  $('[data-toggle="tooltip"]').tooltip();

  /*
  Enable Bootstrap Popovers by default.

  Example usage:

  Hover, focus or click me!
  */
  $('[data-toggle="popover"]').popover({placement: "auto"});

  /* Some pages may have checkboxes in tables selected by default; in those
  cases, we should update URL in a[amy-download-selected] when the page
  loads. */
  $('a[amy-download-selected]').each(function(i, obj) {
    $(this).updateIdsInHref();
  });

  /*
  Add <input type="checkbox" select-all-checkbox> to your form to let user
  select/unselect all checkboxes with respond-to-select-all-checkbox attribute
  in the form with single click.

  Based on http://stackoverflow.com/a/2228401.
  */
  /* Select/unselect all checkboxes when users clicks on "select all" checkbox. */
  $('[select-all-checkbox]').change(function() {
    var checkboxes = $(this).closest('form').find(':checkbox[respond-to-select-all-checkbox]');
    if($(this).is(':checked')) {
        checkboxes.prop('checked', true);
    } else {
        checkboxes.prop('checked', false);
    }
    // below runs `updateIdsInHref` for all matching  (`.each` is required)
    $(this).closest('form').find('a[amy-download-selected]').each(function(i, obj) {
      $(this).updateIdsInHref();
    });
  });

  /* When a checkbox is clicked, update "select all" checkbox state to checked,
  unchecked or indeterminate (neither checked nor unchecked) depending
  on the state of all checkboxes. */
  $('[respond-to-select-all-checkbox]').change(function () {
    $(this).closest('form').find(':checkbox[select-all-checkbox]').updateSelectAllCheckbox();
    // below runs `updateIdsInHref` for all matching  (`.each` is required)
    $(this).closest('form').find('a[amy-download-selected]').each(function(i, obj) {
      $(this).updateIdsInHref();
    });
  });

  /* Set "select all" checkboxes to proper initial state. */
  $(':checkbox[select-all-checkbox]').updateSelectAllCheckbox();

  /*
  Add Mail selected people
  to your form to let the user write email to a group of selected people. You
  need to set up emails addresses on checkboxes:

      <input type="checkbox" email="example@example.org">

  Blank emails and checkboxes without email attribute will be ignored.
  */
  $('[bulk-email-on-click]').click(function () {
    bulk_email();
  });

  /*
  TrainingProgress forms: show/hide training and url fields, depending on
  selected TrainingProgress type.
  */

  var selectField = $('form.training-progress #id_requirement')
  selectField.change(updateTrainingProgressForm);
  updateTrainingProgressForm.call(selectField);

  /*
  When there is any autocomplete field with invalid value, prevent form
  submission. Focus on the invalid field when user tries to submit the form.
  */

  $('form').submit(function (event) {
    var invalidAutocompleteFields = $('.ui-autocomplete-input.ui-state-error');
    if (invalidAutocompleteFields.length > 0) {
      var firstInvalidField = invalidAutocompleteFields.first();
      firstInvalidField.focus();
      event.preventDefault();  // prevent submission
    }
  });

  /* Fix select2 widgets losing their focus. */
  $('select').on("select2:close", function () { $(this).focus(); });

  /* react on comment tab change: resize preview div */
  $('.comment-form a[data-toggle="tab"]').on('shown.bs.tab', function (e) {
    var target_pane = $(e.target).attr("href");
    var prev_target_pane = $(e.relatedTarget).attr("href");

    if (target_pane == "#preview") {
      if ($(target_pane).height() < $(prev_target_pane).height()) {
        $(target_pane).height($(prev_target_pane).height());
      }
    }
  })

  /* Additional messages for forms: they show up when a specific value is
     entered into the field */

  // check initial value for this proficient computing level
  if ($("#id_computing_levels_3").is(":checked")) {
    $("#computing_levels_warning").removeClass("d-none");
  } else {
    $("#computing_levels_warning").addClass("d-none");
  }

  $("#id_computing_levels_3").change(function() {
    // show warning if someone selects "Proficient"
    if($(this).is(':checked')) {
      $("#computing_levels_warning").removeClass("d-none");
    } else {
      $("#computing_levels_warning").addClass("d-none");
    }
  })

  // default cutoff time: 60 days
  var DEFAULT_WARNING_TIME = 1000 * 60 * 60 * 24 * 30 * 2;

  // check initial value for the preferred dates
  if ($("#id_preferred_dates").val()) {
    $("#id_preferred_dates").datepicker('update');

    // read current input value and today's date
    var value = $("#id_preferred_dates").datepicker('getDate');
    var today = new Date();
    var time_diff = value.getTime() - today.getTime();

    // 3 months
    if (time_diff < DEFAULT_WARNING_TIME) {
      $("#preferred_dates_warning").removeClass("d-none");
    } else {
      $("#preferred_dates_warning").addClass("d-none");
    }
  }

  $("#id_preferred_dates").on("changeDate input", function(e){
    // update datepicker with current input value
    $(this).datepicker('update');

    // read current input value and today's date
    var value = $(this).datepicker('getDate');
    var today = new Date();
    var time_diff = value.getTime() - today.getTime();

    // 3 months
    if (time_diff < DEFAULT_WARNING_TIME) {
      $("#preferred_dates_warning").removeClass("d-none");
    } else {
      $("#preferred_dates_warning").addClass("d-none");
    }
  })
 });
<|endoftext|>


<commit_before>var participants;		//people currently running an instance of the hangout

gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		participants = gapi.hangout.enabledParicipants;
		printParticipants();
	}
});

function printParticipants(){
	var members = "";
	for (var i = 0; i < participants.length; i++){
		members = members + participants[i].displayName;
	}
	document.getElementById('particpants').innerHTML = members;
}<commit_msg>added error logging<commit_after>var participants;		//people currently running an instance of the hangout

gapi.hangout.onApiReady.add(function(eventObj){
	if (eventObj.isApiReady) {
		participants = gapi.hangout.enabledParicipants;
		console.log(participants);
		printParticipants();
	}
});

function printParticipants(){
	var members = "";
	for (var i = 0; i < participants.length; i++){
		members = members + participants[i].displayName;
	}
	document.getElementById('particpants').innerHTML = members;
}<|endoftext|>


<commit_before>IonHeaderBar = {
  alignTitle: function () {
    var align = this.alignTitle || 'center';
    var $title = this.$('.title');

    if (Platform.isAndroid() && !this.alignTitle) {
      $title.addClass('title-left');
      return;
    }

    if (align === 'center') {
      $title.addClass('title-center');
    } else if (align === 'left') {
      $title.addClass('title-left');
    } else if (align === 'right') {
      $title.addClass('title-right');
    }
  },

  positionTitle: function () {
    var $title = this.$('.title');
    var $leftButton = $('.button.pull-left');
    var $rightButton = $('.button.pull-right');

    // Find out which button is wider,
    // use that to offset the title on both sides
    var leftButtonWidth = 0;
    var rightButtonWidth = 0;
    if ($leftButton.length) {
      $leftButton.each(function(index, element){
        leftButtonWidth += $(element).outerWidth();
      });
    }
    if ($rightButton.length) {
      $rightButton.each(function(index, element){
        rightButtonWidth += $(element).outerWidth();
      });
    }

    // If we're on Android, we only care about the left button
    var margin;
    if (Platform.isAndroid()) {
      margin = leftButtonWidth;
    } else {
      margin = Math.max(leftButtonWidth, rightButtonWidth);
    }
    $title.css('left', margin);
    $title.css('right', margin);
  }
};

Template.ionHeaderBar.created = function () {
  this.data = this.data || {};
};

Template.ionHeaderBar.rendered = function () {
  Session.set('hasHeader', true);
  IonHeaderBar.alignTitle.call(this);
  IonHeaderBar.positionTitle.call(this);
};

Template.ionHeaderBar.destroyed = function () {
  Session.set('hasHeader', false);
};

Template.ionHeaderBar.helpers({
  classes: function () {
    var classes = ['bar', 'bar-header'];

    if (this.class) {
      classes.push(this.class);
    } else {
      classes.push('bar-stable');
    }

    return classes.join(' ');
  }
});
<commit_msg>fix for #292<commit_after>IonHeaderBar = {
  alignTitle: function () {
    var align = this.data.alignTitle || 'center';
    var $title = this.$('.title');

    if (Platform.isAndroid() && !this.alignTitle) {
      $title.addClass('title-left');
      return;
    }

    if (align === 'center') {
      $title.addClass('title-center');
    } else if (align === 'left') {
      $title.addClass('title-left');
    } else if (align === 'right') {
      $title.addClass('title-right');
    }
  },

  positionTitle: function () {
    var $title = this.$('.title');
    var $leftButton = $('.button.pull-left');
    var $rightButton = $('.button.pull-right');

    // Find out which button is wider,
    // use that to offset the title on both sides
    var leftButtonWidth = 0;
    var rightButtonWidth = 0;
    if ($leftButton.length) {
      $leftButton.each(function(index, element){
        leftButtonWidth += $(element).outerWidth();
      });
    }
    if ($rightButton.length) {
      $rightButton.each(function(index, element){
        rightButtonWidth += $(element).outerWidth();
      });
    }

    // If we're on Android, we only care about the left button
    var margin;
    if (Platform.isAndroid()) {
      margin = leftButtonWidth;
    } else {
      margin = Math.max(leftButtonWidth, rightButtonWidth);
    }
    $title.css('left', margin);
    $title.css('right', margin);
  }
};

Template.ionHeaderBar.created = function () {
  this.data = this.data || {};
};

Template.ionHeaderBar.rendered = function () {
  Session.set('hasHeader', true);
  IonHeaderBar.alignTitle.call(this);
  IonHeaderBar.positionTitle.call(this);
};

Template.ionHeaderBar.destroyed = function () {
  Session.set('hasHeader', false);
};

Template.ionHeaderBar.helpers({
  classes: function () {
    var classes = ['bar', 'bar-header'];

    if (this.class) {
      classes.push(this.class);
    } else {
      classes.push('bar-stable');
    }

    return classes.join(' ');
  }
});
<|endoftext|>


<commit_before>// utility functions
function render(template, data){
  return swig.render($(template).html(), {locals: data});
}

// setup the backbone app and router
IAApp = new Backbone.Marionette.Application();

// set the regions on the page
IAApp.addRegions({
  surveyRegion: "#surveyContainer",
});

var sections;
IAApp.addInitializer(function(options) {
  // load the data
   sections = splitBySections(survey.form.fields);
  // load the survey view
  this.cv = new SurveyView({});
  IAApp.surveyRegion.show(this.cv);
});

var SurveyView = Backbone.View.extend({
  template: "#survey_template",
  end_template: "#end_template",
  save_template: "#save_template",
  events: {
    "click #next": "nextSection",
    "click #prev": "prevSection"
  },
  initialize: function() {
    // initialise survey
    this.count = 0;
    this.current_fields = [];
  },
  render: function() {
    if(this.count < sections.length){
      // draw the current question page
      // grab the current fields
      this.current_fields = sections[this.count];
      var progress = parseInt(this.count/sections.length*100);
      // render each of them
      var field_html = [];
      for(var cnt = 0; cnt < this.current_fields.length; cnt++){
        field_html.push(render("#" + this.current_fields[cnt].field_type + "_question_template", this.current_fields[cnt]));
      }
      this.$el.html(render(this.template, {title: survey.title, fields: field_html, count: this.count, length: sections.length, percent: progress}));
      _.defer(function(){
        // are there any datepickers that need to be created?
        $('.datepicker').datepicker({
            format: "dd-mm-yyyy"
        });
        $('.timepicker').timepicker();
      });
    } else {
      if(this.data_saved){
        // draw the end page
        this.$el.html(render(this.end_template, {content: survey.end_page}));
      } else {
        // draw the saving view
        this.$el.html(render(this.save_template, {content: survey.end_page}));
        // create an array of the results
        var results = [];
        for(var x = 0; x < sections.length; x++){
          for(var y = 0; y < sections[x].length; y++){
            results.push({
              cid: sections[x][y].cid,
              response: sections[x][y].last_value
            });
          }
        }
        var surveyView = this;
        // save the data
        $.ajax({
          type: "POST",
          url: "/survey/submit",
          data: {survey_id: survey._id, results: results},
          success: function(){
            surveyView.data_saved = true;
            surveyView.render();
          }
        });
      }
    }
  },
  prevSection: function(){
    if(this.checkValidity()){
      // save values in current section
      this.extractValues();
      // move to previous section
      this.count--;
      this.render();
    }
  },
  nextSection: function(){
    if(this.checkValidity()){
      // save values in current section
      this.extractValues();
      // move to next section
      this.count++;
      this.render();
    }
  },
  checkValidity: function(){
    for (index = 0; index < sections[this.count].length; ++index) {
      var field = sections[this.count][index];
      var elem = $("[name='input_" + field.cid + "']");
      var value = elem.val();
      if(field.field_type == 'text'||
        field.field_type == 'paragraph'){
        // check length bounds (on characters)
        if(field.field_options.minlength){
          if(value.length < field.field_options.minlength){
            // too short
            elem.focus();
            return false;
          }
        } else if(field.field_options.maxlength){
          if(value.length > field.field_options.minlength){
            // too long
            elem.focus();
            return false;
          }
        }
      } else if(field.field_type == 'radio'){
        // extract the correct value
        value = $("[name='input_"+field.cid+"']:checked").val();
      } else if(field.field_type == 'checkboxes'){
        // extract the correct value
        value = [];
        $("[name='input_"+field.cid+"']:checked").each(function(){
          value.push($(this).val());
        });
      } else if(field.field_type == "number"){
        if(isNaN(value)){
          // not a number
          alert("Please enter a valid number");
          elem.focus();
          return false;
        }
      }

      // check if required and not filled out
      if((value === undefined || value === '' || value.length === 0) && field.required){
        alert("'" + field.label + "' is required. Please enter a response.");
        elem.focus();
        return false;
      }
    }
    return true;
  },
  extractValues: function(){
    for (index = 0; index < sections[this.count].length; ++index) {
      var field = sections[this.count][index];
      if(field.field_type == 'text'||
        field.field_type == 'paragraph' ||
        field.field_type == 'number' ||
        field.field_type == 'dropdown' ||
        field.field_type == 'date' ||
        field.field_type == 'time'){
        // these types can easily be extracted with .val()
        field.last_value = $("#input_" + field.cid).val();
      } else if(field.field_type == 'radio'){
        // find the checked item
        field.last_value = $("[name='input_"+field.cid+"']:checked").val();
      } else if(field.field_type == 'checkboxes'){
        // loop over them all and find the checked items
        var selected = [];
        $("[name='input_"+field.cid+"']:checked").each(function(){
          selected.push($(this).val());
        });
        field.last_value = selected;
      }
    }
  }
});

// this function is used to split the survey onto multiple pages
function splitBySections(fields){
  var sections = [];
  var index = 0;
  for(var x = 0; x < fields.length; x++){
    // do we want a new page and is the current page not empty?
    if(fields[x].field_type == "section_break"){
      if(sections.length != index){
        index++;
      }
    } else {
      if(sections.length == index){
        sections.push([]);
      }
      sections[index].push(fields[x]);
    }
  }
  return sections;
}

IAApp.start();
<commit_msg>update: make progress show on first page<commit_after>// utility functions
function render(template, data){
  return swig.render($(template).html(), {locals: data});
}

// setup the backbone app and router
IAApp = new Backbone.Marionette.Application();

// set the regions on the page
IAApp.addRegions({
  surveyRegion: "#surveyContainer",
});

var sections;
IAApp.addInitializer(function(options) {
  // load the data
   sections = splitBySections(survey.form.fields);
  // load the survey view
  this.cv = new SurveyView({});
  IAApp.surveyRegion.show(this.cv);
});

var SurveyView = Backbone.View.extend({
  template: "#survey_template",
  end_template: "#end_template",
  save_template: "#save_template",
  events: {
    "click #next": "nextSection",
    "click #prev": "prevSection"
  },
  initialize: function() {
    // initialise survey
    this.count = 0;
    this.current_fields = [];
  },
  render: function() {
    if(this.count < sections.length){
      // draw the current question page
      // grab the current fields
      this.current_fields = sections[this.count];
      var progress = parseInt((this.count + 1) / (sections.length + 1) * 100);
      // render each of them
      var field_html = [];
      for(var cnt = 0; cnt < this.current_fields.length; cnt++){
        field_html.push(render("#" + this.current_fields[cnt].field_type + "_question_template", this.current_fields[cnt]));
      }
      this.$el.html(render(this.template, {title: survey.title, fields: field_html, count: this.count, length: sections.length, percent: progress}));
      _.defer(function(){
        // are there any datepickers that need to be created?
        $('.datepicker').datepicker({
            format: "dd-mm-yyyy"
        });
        $('.timepicker').timepicker();
      });
    } else {
      if(this.data_saved){
        // draw the end page
        this.$el.html(render(this.end_template, {content: survey.end_page}));
      } else {
        // draw the saving view
        this.$el.html(render(this.save_template, {content: survey.end_page}));
        // create an array of the results
        var results = [];
        for(var x = 0; x < sections.length; x++){
          for(var y = 0; y < sections[x].length; y++){
            results.push({
              cid: sections[x][y].cid,
              response: sections[x][y].last_value
            });
          }
        }
        var surveyView = this;
        // save the data
        $.ajax({
          type: "POST",
          url: "/survey/submit",
          data: {survey_id: survey._id, results: results},
          success: function(){
            surveyView.data_saved = true;
            surveyView.render();
          }
        });
      }
    }
  },
  prevSection: function(){
    if(this.checkValidity()){
      // save values in current section
      this.extractValues();
      // move to previous section
      this.count--;
      this.render();
    }
  },
  nextSection: function(){
    if(this.checkValidity()){
      // save values in current section
      this.extractValues();
      // move to next section
      this.count++;
      this.render();
    }
  },
  checkValidity: function(){
    for (index = 0; index < sections[this.count].length; ++index) {
      var field = sections[this.count][index];
      var elem = $("[name='input_" + field.cid + "']");
      var value = elem.val();
      if(field.field_type == 'text'||
        field.field_type == 'paragraph'){
        // check length bounds (on characters)
        if(field.field_options.minlength){
          if(value.length < field.field_options.minlength){
            // too short
            elem.focus();
            return false;
          }
        } else if(field.field_options.maxlength){
          if(value.length > field.field_options.minlength){
            // too long
            elem.focus();
            return false;
          }
        }
      } else if(field.field_type == 'radio'){
        // extract the correct value
        value = $("[name='input_"+field.cid+"']:checked").val();
      } else if(field.field_type == 'checkboxes'){
        // extract the correct value
        value = [];
        $("[name='input_"+field.cid+"']:checked").each(function(){
          value.push($(this).val());
        });
      } else if(field.field_type == "number"){
        if(isNaN(value)){
          // not a number
          alert("Please enter a valid number");
          elem.focus();
          return false;
        }
      }

      // check if required and not filled out
      if((value === undefined || value === '' || value.length === 0) && field.required){
        alert("'" + field.label + "' is required. Please enter a response.");
        elem.focus();
        return false;
      }
    }
    return true;
  },
  extractValues: function(){
    for (index = 0; index < sections[this.count].length; ++index) {
      var field = sections[this.count][index];
      if(field.field_type == 'text'||
        field.field_type == 'paragraph' ||
        field.field_type == 'number' ||
        field.field_type == 'dropdown' ||
        field.field_type == 'date' ||
        field.field_type == 'time'){
        // these types can easily be extracted with .val()
        field.last_value = $("#input_" + field.cid).val();
      } else if(field.field_type == 'radio'){
        // find the checked item
        field.last_value = $("[name='input_"+field.cid+"']:checked").val();
      } else if(field.field_type == 'checkboxes'){
        // loop over them all and find the checked items
        var selected = [];
        $("[name='input_"+field.cid+"']:checked").each(function(){
          selected.push($(this).val());
        });
        field.last_value = selected;
      }
    }
  }
});

// this function is used to split the survey onto multiple pages
function splitBySections(fields){
  var sections = [];
  var index = 0;
  for(var x = 0; x < fields.length; x++){
    // do we want a new page and is the current page not empty?
    if(fields[x].field_type == "section_break"){
      if(sections.length != index){
        index++;
      }
    } else {
      if(sections.length == index){
        sections.push([]);
      }
      sections[index].push(fields[x]);
    }
  }
  return sections;
}

IAApp.start();
<|endoftext|>


<commit_before>var database    = require('../database.js');
var paginate    = require('../paginate.js');

function paginated_query(req, res, query, params){
  var limit = 10;
  if(req.query.limit){
    limit = req.query.limit;
  }
  var page = 1;
  if(req.query.page){
    page = req.query.page;
  }
  paginate.paginate(query,
      {
        page : page,
        limit: limit,
        params: params
      },
      function (err, rows){
        if(err){
          console.log("An unexpected error happens.");
          return;
        }
        res.json(rows);
      }
  );
}

//eleicoes/:id/candidatos?page=2&limit=10&uf=BA
exports.findAll = function(req, res){
  var eleicao_id = req.params.id;
  var query = "SELECT id, nome, escolaridade, sexo, municipio, uf, cargo, numero, nacionalidade, tituloEleitoral, ocupacao, estadoCivil, situacaoCandidatura FROM Candidato WHERE eleicao_id = ? ";
  var params = [eleicao_id];
  if(req.query.uf){
    query = query + " AND uf = ? ";
    params = [eleicao_id, req.query.uf];
  }
  query = query + " ORDER BY nome";
  paginated_query(req, res, query, params);
}

exports.findById = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query = "SELECT id, nome, escolaridade, sexo, municipio, uf, cargo, numero, nacionalidade, tituloEleitoral, ocupacao, estadoCivil, situacaoCandidatura FROM Candidato WHERE id = ? AND eleicao_id = ? ORDER BY nome";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.receitas = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query = "SELECT * FROM Transacao WHERE creditado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.receitasTotal = function(req, res){
  eleicao_id = req.params.id;
  candidato_id = req.params.cand_id;
  database.connection.query(
      "SELECT sum(valor) as total FROM Transacao WHERE creditado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)",
      [candidato_id, eleicao_id],
      function(err, rows, fields){
        if(err) throw err;
        res.send(rows);
      });
}

exports.despesas = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query =
      "SELECT * FROM Transacao WHERE debitado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.despesasTotal = function(req, res){
  eleicao_id = req.params.id;
  candidato_id = req.params.cand_id;
  database.connection.query(
      "SELECT sum(valor) as total FROM Transacao WHERE debitado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)",
      [candidato_id, eleicao_id],
      function(err, rows, fields){
        if(err) throw err;
        res.send(rows);
      });
}
<commit_msg>Adiciona o parametro busca candidatos por nome<commit_after>var database    = require('../database.js');
var paginate    = require('../paginate.js');

function paginated_query(req, res, query, params){
  var limit = 10;
  if(req.query.limit){
    limit = req.query.limit;
  }
  var page = 1;
  if(req.query.page){
    page = req.query.page;
  }
  paginate.paginate(query,
      {
        page : page,
        limit: limit,
        params: params
      },
      function (err, rows){
        if(err){
          console.log("An unexpected error happens.");
          return;
        }
        res.json(rows);
      }
  );
}

//eleicoes/:id/candidatos?page=2&limit=10&uf=BA
exports.findAll = function(req, res){
  var eleicao_id = req.params.id;
  var query = "SELECT id, nome, escolaridade, sexo, municipio, uf, cargo, numero, nacionalidade, tituloEleitoral, ocupacao, estadoCivil, situacaoCandidatura FROM Candidato WHERE eleicao_id = ? ";
  var params = [eleicao_id];
  if(req.query.uf){
    query = query + " AND uf = ? ";
    params.push(req.query.uf);
  }
  if(req.query.search){
    query = query + " AND nome LIKE ? ";
    params.push('%'+req.query.search+'%');
  }
  query = query + " ORDER BY nome";
  paginated_query(req, res, query, params);
}

exports.findById = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query = "SELECT id, nome, escolaridade, sexo, municipio, uf, cargo, numero, nacionalidade, tituloEleitoral, ocupacao, estadoCivil, situacaoCandidatura FROM Candidato WHERE id = ? AND eleicao_id = ? ORDER BY nome";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.receitas = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query = "SELECT * FROM Transacao WHERE creditado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.receitasTotal = function(req, res){
  eleicao_id = req.params.id;
  candidato_id = req.params.cand_id;
  database.connection.query(
      "SELECT sum(valor) as total FROM Transacao WHERE creditado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)",
      [candidato_id, eleicao_id],
      function(err, rows, fields){
        if(err) throw err;
        res.send(rows);
      });
}

exports.despesas = function(req, res){
  var eleicao_id = req.params.id;
  var candidato_id = req.params.cand_id;
  var query =
      "SELECT * FROM Transacao WHERE debitado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)";
  paginated_query(req, res, query, [candidato_id, eleicao_id]);
}

exports.despesasTotal = function(req, res){
  eleicao_id = req.params.id;
  candidato_id = req.params.cand_id;
  database.connection.query(
      "SELECT sum(valor) as total FROM Transacao WHERE debitado_id = "+
        "(SELECT agenteEleitoral_id FROM Candidato WHERE id = ? AND eleicao_id = ?)",
      [candidato_id, eleicao_id],
      function(err, rows, fields){
        if(err) throw err;
        res.send(rows);
      });
}
<|endoftext|>


<commit_before>/**
 * Dependencies
 */
const assert = require('assert')
const base64url = require('base64url')
const crypto = require('webcrypto')
const {ab2str, ab2buf, hex} = require('./encodings')
const FormUrlencoded = require('./FormUrlencoded')
const URL = require('urlutils')

/**
 * Authentication Request
 */
class AuthenticationRequest {

  /**
   * Constructor
   */
  constructor (rp) {
    Object.assign(this, rp)
    assert(this.provider, 'Provider must be configured for RelyingParty')
    assert(this.provider.url, 'Provider URL must be configured for RelyingParty')
    assert(this.store, 'A session store must be configured for RelyingParty')
  }

  /**
   * popup
   *
   * @description
   * Configure the authorize popup window
   * Adapted from dropbox-js for ngDropbox
   *
   * @param {Number} popupWidth
   * @param {Number} popupHeight
   *
   * @returns {string}
   */
  static popup (popupWidth, popupHeight) {
    let x0, y0, width, height, popupLeft, popupTop

    // Metrics for the current browser window.
    x0 = window.screenX || window.screenLeft
    y0 = window.screenY || window.screenTop
    width = window.outerWidth || document.documentElement.clientWidth
    height = window.outerHeight || document.documentElement.clientHeight

    // Computed popup window metrics.
    popupLeft = Math.round(x0) + (width - popupWidth) / 2
    popupTop = Math.round(y0) + (height - popupHeight) / 2.5
    if (popupLeft < x0) { popupLeft = x0 }
    if (popupTop < y0) { popupTop = y0 }

    return 'width=' + popupWidth + ',height=' + popupHeight + ',' +
    'left=' + popupLeft + ',top=' + popupTop + ',' +
    'dialog=yes,dependent=yes,scrollbars=yes,location=yes'
  }

  /**
   * submit
   */
  submit (options) {
    let authenticate = this.authenticate

    assert(authenticate, 'RelyingParty must default authentication parameters.')

    this.uri(options).then(uri => {
      // detect runtime environment (browser vs Node.js)
      // and behave accordingly.
      // should this throw if called in Node.js?
      if (authenticate.display === 'popup') {
        let {width, height} = this.popup
        // window name should be some kind of client identifier
        window.open(uri, 'rp', AuthenticationRequest.popup(width, height))
      } else {
        window.location = uri
      }
    })
  }

  /**
   * uri
   */
  uri (options) {
    let store = this.store
    let provider = this.provider
    let configuration = provider.configuration

    assert(
      configuration,
      'OpenID Configuration required. Invoke the discover method.'
    )

    let endpoint = configuration.authorization_endpoint

    assert(
      endpoint,
      'OpenID Configuration does not specify the authorize endpoint.'
    )

    let registration = this.registration
    assert(registration, 'Registration must be provided for the RelyingParty.')

    let client_id = registration.client_id

    let defaults = this.defaults.authenticate
    let params = Object.assign({client_id}, defaults, options)

    return this.nonce().then(nonce => {
      params.nonce = nonce
      store['${client_id}:nonce'] = params.nonce

      let url = new URL(endpoint)
      url.search = FormUrlencoded.encode(params)

      return url.href
    })
  }

  /**
   * nonce
   */
  nonce (length = 16) {
    assert(this.registration, 'Missing client registration.')
    assert(this.registration.client_id, 'Client registration is missing client_id.')

    let namespace = this.registration.client_id
    let key = `${namespace}:nonce`
    let value = crypto.getRandomValues(new Uint8Array(length))
    let serialized = ab2str(value.buffer)
    this.store[key] = serialized

    return crypto.subtle.digest({
      name: 'SHA-256'
    }, value).then(hash => {
      let buffer = ab2buf(hash)
      return base64url(buffer.toString('hex'))
    })
  }

}

/**
 * Export
 */
module.exports = AuthenticationRequest
<commit_msg>wip(AuthenticationRequest): add note to constructor<commit_after>/**
 * Dependencies
 */
const assert = require('assert')
const base64url = require('base64url')
const crypto = require('webcrypto')
const {ab2str, ab2buf, hex} = require('./encodings')
const FormUrlencoded = require('./FormUrlencoded')
const URL = require('urlutils')

/**
 * Authentication Request
 */
class AuthenticationRequest {

  /**
   * Constructor
   */
  constructor (rp) {
    // TODO could we make use of Proxy instead of shallow copying?
    Object.assign(this, rp)
    assert(this.provider, 'Provider must be configured for RelyingParty')
    assert(this.provider.url, 'Provider URL must be configured for RelyingParty')
    assert(this.store, 'A session store must be configured for RelyingParty')
  }

  /**
   * popup
   *
   * @description
   * Configure the authorize popup window
   * Adapted from dropbox-js for ngDropbox
   *
   * @param {Number} popupWidth
   * @param {Number} popupHeight
   *
   * @returns {string}
   */
  static popup (popupWidth, popupHeight) {
    let x0, y0, width, height, popupLeft, popupTop

    // Metrics for the current browser window.
    x0 = window.screenX || window.screenLeft
    y0 = window.screenY || window.screenTop
    width = window.outerWidth || document.documentElement.clientWidth
    height = window.outerHeight || document.documentElement.clientHeight

    // Computed popup window metrics.
    popupLeft = Math.round(x0) + (width - popupWidth) / 2
    popupTop = Math.round(y0) + (height - popupHeight) / 2.5
    if (popupLeft < x0) { popupLeft = x0 }
    if (popupTop < y0) { popupTop = y0 }

    return 'width=' + popupWidth + ',height=' + popupHeight + ',' +
    'left=' + popupLeft + ',top=' + popupTop + ',' +
    'dialog=yes,dependent=yes,scrollbars=yes,location=yes'
  }

  /**
   * submit
   */
  submit (options) {
    let authenticate = this.authenticate

    assert(authenticate, 'RelyingParty must default authentication parameters.')

    this.uri(options).then(uri => {
      // detect runtime environment (browser vs Node.js)
      // and behave accordingly.
      // should this throw if called in Node.js?
      if (authenticate.display === 'popup') {
        let {width, height} = this.popup
        // window name should be some kind of client identifier
        window.open(uri, 'rp', AuthenticationRequest.popup(width, height))
      } else {
        window.location = uri
      }
    })
  }

  /**
   * uri
   */
  uri (options) {
    let store = this.store
    let provider = this.provider
    let configuration = provider.configuration

    assert(
      configuration,
      'OpenID Configuration required. Invoke the discover method.'
    )

    let endpoint = configuration.authorization_endpoint

    assert(
      endpoint,
      'OpenID Configuration does not specify the authorize endpoint.'
    )

    let registration = this.registration
    assert(registration, 'Registration must be provided for the RelyingParty.')

    let client_id = registration.client_id
    let defaults = this.defaults.authenticate
    let params = Object.assign({client_id}, defaults, options)

    return this.nonce().then(nonce => {
      params.nonce = nonce
      store['${client_id}:nonce'] = params.nonce

      let url = new URL(endpoint)
      url.search = FormUrlencoded.encode(params)

      return url.href
    })
  }

  /**
   * nonce
   */
  nonce (length = 16) {
    assert(this.registration, 'Missing client registration.')
    assert(this.registration.client_id, 'Client registration is missing client_id.')

    let namespace = this.registration.client_id
    let key = `${namespace}:nonce`
    let value = crypto.getRandomValues(new Uint8Array(length))
    let serialized = ab2str(value.buffer)
    this.store[key] = serialized

    return crypto.subtle.digest({
      name: 'SHA-256'
    }, value).then(hash => {
      let buffer = ab2buf(hash)
      return base64url(buffer.toString('hex'))
    })
  }

}

/**
 * Export
 */
module.exports = AuthenticationRequest
<|endoftext|>


<commit_before>/**
 * This file contains the common middleware used by your routes.
 *
 * Extend or replace these functions as your application requires.
 *
 * This structure is not enforced, and just a starting point. If
 * you have more middleware you may want to group it as separate
 * modules in your project's /lib directory.
 */

var _ = require('underscore'),
	querystring = require('querystring'),
	keystone = require('keystone');

/**
	Initialises the standard view locals

	The included layout depends on the navLinks array to generate
	the navigation in the header, you may wish to change this array
	or replace it with your own templates / logic.
*/

exports.initLocals = function(req, res, next) {

	var locals = res.locals;

	locals.navLinks = [
		{ label: 'Home',		key: 'home',		href: '/' },
		{ label: 'Blog',		key: 'blog',		href: '/blog' },
		{ label: 'Gallery',		key: 'gallery',		href: '/gallery' },
		{ label: 'Contact',		key: 'contact',		href: '/contact' }
	];

	locals.user = req.user;

	next();

};

/**
	Fetches and clears the flashMessages before a view is rendered
*/

exports.flashMessages = function(req, res, next) {

	var flashMessages = {
		info: req.flash('info'),
		success: req.flash('success'),
		warning: req.flash('warning'),
		error: req.flash('error')
	};

	res.locals.messages = _.any(flashMessages, function(msgs) { return msgs.length; }) ? flashMessages : false;

	next();

};

/**
	Prevents people from accessing protected pages when they're not signed in
 */

exports.requireUser = function(req, res, next) {

	if (!req.user) {
		req.flash('error', 'Please sign in to access this page.');
		res.redirect('/keystone/signin');
	} else {
		next();
	}

};
<commit_msg>Remove Blog/Gallery navigation items for now<commit_after>/**
 * This file contains the common middleware used by your routes.
 *
 * Extend or replace these functions as your application requires.
 *
 * This structure is not enforced, and just a starting point. If
 * you have more middleware you may want to group it as separate
 * modules in your project's /lib directory.
 */

var _ = require('underscore'),
	querystring = require('querystring'),
	keystone = require('keystone');

/**
	Initialises the standard view locals

	The included layout depends on the navLinks array to generate
	the navigation in the header, you may wish to change this array
	or replace it with your own templates / logic.
*/

exports.initLocals = function(req, res, next) {

	var locals = res.locals;

	locals.navLinks = [
		{ label: 'Home',		key: 'home',		href: '/' },
		/*{ label: 'Blog',		key: 'blog',		href: '/blog' },
		{ label: 'Gallery',		key: 'gallery',		href: '/gallery' },*/
		{ label: 'Contact',		key: 'contact',		href: '/contact' }
	];

	locals.user = req.user;

	next();

};

/**
	Fetches and clears the flashMessages before a view is rendered
*/

exports.flashMessages = function(req, res, next) {

	var flashMessages = {
		info: req.flash('info'),
		success: req.flash('success'),
		warning: req.flash('warning'),
		error: req.flash('error')
	};

	res.locals.messages = _.any(flashMessages, function(msgs) { return msgs.length; }) ? flashMessages : false;

	next();

};

/**
	Prevents people from accessing protected pages when they're not signed in
 */

exports.requireUser = function(req, res, next) {

	if (!req.user) {
		req.flash('error', 'Please sign in to access this page.');
		res.redirect('/keystone/signin');
	} else {
		next();
	}

};
<|endoftext|>


<commit_before>if (typeof MiroCommunity === 'undefined') {
    MiroCommunity = {
        Widget: function(args) {
            this.init(args);
        },
        jsonP: function(path) {
            script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = path;
            document.getElementsByTagName('head')[0].appendChild(script);
            return script;
        },
        createElement: function(name, attrs) {
            elm = document.createElement(name);
            for (attr in attrs) {
                elm[attr] = attrs[attr];
            }
            return elm;
        },
        createSpan: function(content, className) {
            span = document.createElement('span');
            span.className = className;
            span.innerHTML = content;
            return span;
        }
    };
    MiroCommunity.Widget._counter = 0;
    MiroCommunity.Widget._addedStyles = false;
    MiroCommunity.Widget.prototype = function() {
        return {
            init: function(options) {
                this.opts = options;
                this.counter = ++MiroCommunity.Widget._counter;
                this.id = 'mc-widget-' + this.counter;
                this.scriptTag = null;
            },
            render: function () {
                this.addStyle();
                document.write('

');
                document.write(this.opts.title ? this.opts.title : 'Watch Videos from Miro Community');
                document.write('

');
                document.write('' + this.opts.domain + '
');
                this.load();
            },
            addStyle: function() {
            head = document.getElementsByTagName('head')[0];
                if (!MiroCommunity.Widget._addedStyles && this.opts.stylesheet !== '') {
                    link = document.createElement('link');
                    link.rel = 'stylesheet';
                    if (this.opts.stylesheet) {
                        link.href = this.opts.stylesheet;
                    } else {
                        link.href = 'http://' + this.opts.domain + '/css/widget.css';
                    }
                    head.appendChild(link);
                    MiroCommunity.Widget._addedStyles = true;
                }
                style = document.createElement('style');
                style.type = 'text/css';
                width = this.opts.width ? this.opts.width : 300;
                style.innerText = '#' + this.id + ', #' + this.id + ' ul {width: ' + width + 'px;}';
                head.appendChild(style);
            },
            load: function() {
                var t = this;
                ajax_path = 'http://' + t.opts.domain + '/feeds/json/' + t.opts.source;
                MiroCommunity['callback_' + t.counter] = function(json) {
                    t.scriptTag.parentNode.removeChild(t.scriptTag);
                    t.scriptTag = null;
                    var div = document.getElementById(t.id);
                    t.update(div, json);
                };
                t.scriptTag = MiroCommunity.jsonP(ajax_path + '?jsoncallback=MiroCommunity.callback_' + t.counter);
            },
            update: function(div, json) {
                var ul = div.getElementsByTagName('ul')[0];
                ul.innerHTML = ul.className = '';
                var count = this.opts.count ? this.opts.count : 4;
                var li = null;
                for (var i=0; i < json.items.length && i < count; i++) {
                    item = json.items[i];
                    li = MiroCommunity.createElement('li', {className: 'mc-video'});
                    link = MiroCommunity.createElement('a', {href: item.link});
                    thumb = MiroCommunity.createElement('span', {className: 'mc-thumbnail'});
                    var thumbnail = null;
                    if (item.thumbnail) {
                        thumbnail = item.thumbnail;
                    } else {
                        thumbnail = 'http://' + this.opts.domain + '/images/default_vid.gif';
                    }
                    thumb.appendChild(MiroCommunity.createElement('img', {
                        width: 120,
                        height: 90,
                        src: thumbnail}));
                    thumb.appendChild(MiroCommunity.createSpan('', 'mc-play'));
                    link.appendChild(thumb);
                    link.appendChild(MiroCommunity.createSpan(item.title, 'mc-title'));
                    link.appendChild(MiroCommunity.createSpan(item.when, 'mc-when'));
                    li.appendChild(link);
                    ul.appendChild(li);
                }
                if (li !== null) {
                    li.className += ' mc-last';
                }
            }
        };
    }();
}<commit_msg>make sure that the width gets set even on Firefox<commit_after>if (typeof MiroCommunity === 'undefined') {
    MiroCommunity = {
        Widget: function(args) {
            this.init(args);
        },
        jsonP: function(path) {
            script = document.createElement('script');
            script.type = 'text/javascript';
            script.src = path;
            document.getElementsByTagName('head')[0].appendChild(script);
            return script;
        },
        createElement: function(name, attrs) {
            elm = document.createElement(name);
            for (attr in attrs) {
                elm[attr] = attrs[attr];
            }
            return elm;
        },
        createSpan: function(content, className) {
            span = document.createElement('span');
            span.className = className;
            span.innerHTML = content;
            return span;
        }
    };
    MiroCommunity.Widget._counter = 0;
    MiroCommunity.Widget._addedStyles = false;
    MiroCommunity.Widget.prototype = function() {
        return {
            init: function(options) {
                this.opts = options;
                this.counter = ++MiroCommunity.Widget._counter;
                this.id = 'mc-widget-' + this.counter;
                this.scriptTag = null;
            },
            render: function () {
                this.addStyle();
                document.write('

');
                document.write(this.opts.title ? this.opts.title : 'Watch Videos from Miro Community');
                document.write('

');
                document.write('' + this.opts.domain + '
');
                this.load();
            },
            addStyle: function() {
                head = document.getElementsByTagName('head')[0];
                if (!MiroCommunity.Widget._addedStyles && this.opts.stylesheet !== '') {
                    link = document.createElement('link');
                    link.rel = 'stylesheet';
                    if (this.opts.stylesheet) {
                        link.href = this.opts.stylesheet;
                    } else {
                        link.href = 'http://' + this.opts.domain + '/css/widget.css';
                    }
                    head.appendChild(link);
                    MiroCommunity.Widget._addedStyles = true;
                }
                style = document.createElement('style');
                style.type = 'text/css';
                width = this.opts.width ? this.opts.width : 300;
                rules = document.createTextNode('#' + this.id + ', #' + this.id + ' ul {width: ' + width + 'px;}');
                if(style.styleSheet) {
                    style.styleSheet.cssText = rules.nodeValue;
                } else {
                    style.appendChild(rules);
                }
                head.appendChild(style);
            },
            load: function() {
                var t = this;
                ajax_path = 'http://' + t.opts.domain + '/feeds/json/' + t.opts.source;
                MiroCommunity['callback_' + t.counter] = function(json) {
                    t.scriptTag.parentNode.removeChild(t.scriptTag);
                    t.scriptTag = null;
                    var div = document.getElementById(t.id);
                    t.update(div, json);
                };
                t.scriptTag = MiroCommunity.jsonP(ajax_path + '?jsoncallback=MiroCommunity.callback_' + t.counter);
            },
            update: function(div, json) {
                var ul = div.getElementsByTagName('ul')[0];
                ul.innerHTML = ul.className = '';
                var count = this.opts.count ? this.opts.count : 4;
                var li = null;
                for (var i=0; i < json.items.length && i < count; i++) {
                    item = json.items[i];
                    li = MiroCommunity.createElement('li', {className: 'mc-video'});
                    link = MiroCommunity.createElement('a', {href: item.link});
                    thumb = MiroCommunity.createElement('span', {className: 'mc-thumbnail'});
                    var thumbnail = null;
                    if (item.thumbnail) {
                        thumbnail = item.thumbnail;
                    } else {
                        thumbnail = 'http://' + this.opts.domain + '/images/default_vid.gif';
                    }
                    thumb.appendChild(MiroCommunity.createElement('img', {
                        width: 120,
                        height: 90,
                        src: thumbnail}));
                    thumb.appendChild(MiroCommunity.createSpan('', 'mc-play'));
                    link.appendChild(thumb);
                    link.appendChild(MiroCommunity.createSpan(item.title, 'mc-title'));
                    link.appendChild(MiroCommunity.createSpan(item.when, 'mc-when'));
                    li.appendChild(link);
                    ul.appendChild(li);
                }
                if (li !== null) {
                    li.className += ' mc-last';
                }
            }
        };
    }();
}<|endoftext|>


<commit_before>var express = require('express');
var router = express.Router();

/* Send SMS */
router.get('/', function (req, res) {
    // Imports
    var fs = require('fs');
    var MongoClient = require('mongodb').MongoClient;

    // Defaults
    var configFile = 'bin/config.json';

    // Load config
    var configuration = JSON.parse(
        fs.readFileSync(configFile)
    );

    // Configure clockwork
    var clockwork = require('clockwork')({key: configuration.API_KEY});

    // Test message
    var sms_to = req.query.to;
    var sms_from = configuration.MIDDLEMAN_NUMBER;
    var sms_content = req.query.content;
    if(sms_to == "" || sms_content == "")
    {
        res.status(400);
    }

    clockwork.sendSms({To: sms_to, Content: sms_content, From: sms_from}, function (error, response) {
        if (error) {
            console.log('Error', error);
        } else {
            // Connect to the db and submit change
            MongoClient.connect(configuration.MONGO_URI, function (err, db) {
                if (!err) {
                    var collection = db.collection('messages');
                    var document = {'to': sms_to, 'from': sms_from, 'message': sms_content};
                    collection.insert(document, {w: 1}, function (err, result) {
                        if (err) {
                            console.log("Couldn't send to database");
                        }
                    });
                } else {
                    console.log("ERROR: Couldn't connect to remote mongo");
                }
            });
        }
    });
    res.json("{}");
});

module.exports = router;
<commit_msg>refactored<commit_after>var express = require('express');
var router = express.Router();

// Imports
var fs = require('fs');
var MongoClient = require('mongodb').MongoClient;

// Defaults
var configFile = 'bin/config.json';

// Load config
var configuration = JSON.parse(
    fs.readFileSync(configFile)
);

// Configure clockwork
var clockwork = require('clockwork')({key: configuration.API_KEY});

/* Send SMS */
router.get('/', function (req, res) {

    // Test message
    var sms_to = req.query.to;
    var sms_from = configuration.MIDDLEMAN_NUMBER;
    var sms_content = req.query.content;
    if(sms_to == "" || sms_content == "")
    {
        res.status(400);
    }

    clockwork.sendSms({To: sms_to, Content: sms_content, From: sms_from}, function (error, response) {
        if (error) {
            console.log('Error', error);
        } else {
            // Connect to the db and submit change
            MongoClient.connect(configuration.MONGO_URI, function (err, db) {
                if (!err) {
                    var collection = db.collection('messages');
                    var document = {'to': sms_to, 'from': sms_from, 'message': sms_content};
                    collection.insert(document, {w: 1}, function (err, result) {
                        if (err) {
                            console.log("Couldn't send to database");
                        }
                    });
                } else {
                    console.log("ERROR: Couldn't connect to remote mongo");
                }
            });
        }
    });
    res.json({});
});

module.exports = router;
<|endoftext|>


<commit_before>//Drag and Drop behavior
this.cutie = this.cutie || {};

(function(module){
    var DragAndDrop = function(props) {
        this.props = props;
    };

    DragAndDrop.prototype._isDragging = false;
    DragAndDrop.prototype._clickOffset = {};

    DragAndDrop.prototype.init = function(obj) {
        obj.addEventListener('mousedown', mousedown.bind(this, obj), false);
        obj.addEventListener('pressup', mouseup.bind(this, obj), false);
    }

    DragAndDrop.prototype.clean = function(obj) {
    }

    DragAndDrop.prototype.tick = function(obj) {
        if(this._isDragging) {
            var stage = cutie.getStage();
            obj.x = stage.mouseX - this._clickOffset.x;
            obj.y = stage.mouseY - this._clickOffset.y;
        }
    }

    function mousedown(obj, e) {
        this._isDragging = true;
        this._clickOffset.x = e.stageX - obj.x;
        this._clickOffset.y = e.stageY - obj.y;
    }

    function mouseup(obj, e) {
        this._isDragging = false;
    }

    module.DragAndDrop = DragAndDrop;
})(this.cutie);

/*
document.addEventListener('keyup', function(obj) {
                return function(e) {upLeftRight(e, obj); };
            } (this) , false);
*/<commit_msg>Cleaned up DragAndDrop.<commit_after>this.cutie = this.cutie || {};

(function(module){
    /**
     * This behavior makes the object able to be dragged and
     * dropped with the mouse/touch.
     * @param {Object} props
     *        <Description of properties.>
     */
    var DragAndDrop = function(props) {
        // ================================================
        // VARIABLE DECLARATIONS
        // ================================================
        var _isDragging = false;
        var _clickOffset = {};

        // ================================================
        // PUBLIC METHODS
        // ================================================
        this.init = function(obj) {
            obj.addEventListener('mousedown', mousedown.bind(this, obj), false);
            obj.addEventListener('pressup', mouseup.bind(this, obj), false);
        }

        this.clean = function(obj) {
        }

        this.tick = function(obj) {
            if(_isDragging) {
                var stage = cutie.getStage();
                obj.x = stage.mouseX - _clickOffset.x;
                obj.y = stage.mouseY - _clickOffset.y;
            }
        }

        // ================================================
        // PRIVATE METHODS
        // ================================================
        function mousedown(obj, e) {
            _isDragging = true;
            _clickOffset.x = e.stageX - obj.x;
            _clickOffset.y = e.stageY - obj.y;
        }

        function mouseup(obj, e) {
            _isDragging = false;
        }
    };

    // Copy our behavior into the module
    module.DragAndDrop = DragAndDrop;
})(this.cutie);<|endoftext|>


<commit_before>var today = new Date();
var day = '06';
var monthi = '09';
var monthf = '10';
var dayCheck = today.getDate();
var monthCheck = today.getMonth();

if(((monthCheck == 00 && dayCheck <= 6) || (monthCheck == 11 && dayCheck >= 2))) {
	var snowMax=35;var snowColor=["#DDD","#EEE"];var snowEntity="•";var snowSpeed=0.75;var snowMinSize=8;var snowMaxSize=24;var snowRefresh=50;var snowStyles="cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;";var snow=[],pos=[],coords=[],lefr=[],marginBottom,marginRight;function randomise(range){rand=Math.floor(range*Math.random());return rand;}
	function initSnow(){var snowSize=snowMaxSize- snowMinSize;marginBottom=document.body.scrollHeight- 5;marginRight=document.body.clientWidth- 15;for(i=0;i<=snowMax;i++){coords[i]=0;lefr[i]=Math.random()*15;pos[i]=0.03+ Math.random()/ 10;
	snow[i]=document.getElementById("flake"+ i);snow[i].style.fontFamily="inherit";snow[i].size=randomise(snowSize)+ snowMinSize;snow[i].style.fontSize=snow[i].size+"px";snow[i].style.color=snowColor[randomise(snowColor.length)];snow[i].style.zIndex=1000;snow[i].sink=snowSpeed*snow[i].size/5;snow[i].posX=randomise(marginRight- snow[i].size);snow[i].posY=randomise(2*marginBottom- marginBottom- 2*snow[i].size);snow[i].style.left=snow[i].posX+"px";snow[i].style.top=snow[i].posY+"px";}
	moveSnow();}
	function resize(){marginBottom=document.body.scrollHeight- 5;marginRight=document.body.clientWidth- 15;}
	function moveSnow(){for(i=0;i<=snowMax;i++){coords[i]+=pos[i];snow[i].posY+=snow[i].sink;snow[i].style.left=snow[i].posX+ lefr[i]*Math.sin(coords[i])+"px";snow[i].style.top=snow[i].posY+"px";if(snow[i].posY>=marginBottom- 2*snow[i].size||parseInt(snow[i].style.left)>(marginRight- 3*lefr[i])){snow[i].posX=randomise(marginRight- snow[i].size);snow[i].posY=0;}}
	setTimeout("moveSnow()",snowRefresh);}
	for(i=0;i<=snowMax;i++){document.write(""+ snowEntity+"");}
	window.onresize=resize;window.onload=initSnow;
}
<commit_msg>Update winter.js<commit_after>var today = new Date();
var day = '06';
var monthi = '09';
var monthf = '10';
var dayCheck = today.getDate();
var monthCheck = today.getMonth();

if(((monthCheck == 00 && dayCheck <= 6) || (monthCheck == 11 && dayCheck >= 2))) {
	var snowMax=45;var snowColor=["#DDD","#EEE"];var snowEntity="•";var snowSpeed=0.75;var snowMinSize=8;var snowMaxSize=30;var snowRefresh=50;var snowStyles="cursor: default; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; -o-user-select: none; user-select: none;";var snow=[],pos=[],coords=[],lefr=[],marginBottom,marginRight;function randomise(range){rand=Math.floor(range*Math.random());return rand;}
	function initSnow(){var snowSize=snowMaxSize- snowMinSize;marginBottom=document.body.scrollHeight- 5;marginRight=document.body.clientWidth- 15;for(i=0;i<=snowMax;i++){coords[i]=0;lefr[i]=Math.random()*15;pos[i]=0.03+ Math.random()/ 10;
	snow[i]=document.getElementById("flake"+ i);snow[i].style.fontFamily="inherit";snow[i].size=randomise(snowSize)+ snowMinSize;snow[i].style.fontSize=snow[i].size+"px";snow[i].style.color=snowColor[randomise(snowColor.length)];snow[i].style.zIndex=1000;snow[i].sink=snowSpeed*snow[i].size/5;snow[i].posX=randomise(marginRight- snow[i].size);snow[i].posY=randomise(2*marginBottom- marginBottom- 2*snow[i].size);snow[i].style.left=snow[i].posX+"px";snow[i].style.top=snow[i].posY+"px";}
	moveSnow();}
	function resize(){marginBottom=document.body.scrollHeight- 5;marginRight=document.body.clientWidth- 15;}
	function moveSnow(){for(i=0;i<=snowMax;i++){coords[i]+=pos[i];snow[i].posY+=snow[i].sink;snow[i].style.left=snow[i].posX+ lefr[i]*Math.sin(coords[i])+"px";snow[i].style.top=snow[i].posY+"px";if(snow[i].posY>=marginBottom- 2*snow[i].size||parseInt(snow[i].style.left)>(marginRight- 3*lefr[i])){snow[i].posX=randomise(marginRight- snow[i].size);snow[i].posY=0;}}
	setTimeout("moveSnow()",snowRefresh);}
	for(i=0;i<=snowMax;i++){document.write(""+ snowEntity+"");}
	window.onresize=resize;window.onload=initSnow;
}
<|endoftext|>


<commit_before>/* global dump */
/* jshint unused:false */

var _config = {DEBUG: false};
var _currentUserData;
var _presenceSocket;
var ports;
var browserPort;
var currentCall;
var currentUsers;

function openChatWindow() {
  browserPort.postEvent('social.request-chat', 'chat.html');
}

/**
 * Social API user profile data storage.
 * @param {Object|undefined}  initial  Initial data
 * @param {Object|undefined}  config   Environment configuration
 */
function UserData(initial, config) {
  var rootURL = config ? config.ROOTURL : '';

  this.defaults = {
    iconURL: rootURL + "/talkilla16.png",
    portrait: undefined,
    userName: undefined,
    displayName: undefined,
    profileURL: rootURL + "/user.html"
  };

  this.reset();

  if (initial) {
    for (var key in initial)
      this[key] = initial[key];
  }
}

UserData.prototype = {
  /**
   * Resets current properties to default ones.
   */
  reset: function() {
    for (var key in this.defaults)
      this[key] = this.defaults[key];
  }
};

var serverHandlers = {
  'users': function(data) {
    currentUsers = data;
    ports.broadcastEvent("talkilla.users", data);
  },

  'incoming_call': function(data) {
    currentCall = {port: undefined, data: data};
    openChatWindow();
  },

  'call_accepted': function(data) {
    currentCall.port.postEvent('talkilla.call-establishment', data);
  },

  'call_hangup': function(data) {
    currentCall.port.postEvent('talkilla.call-hangup', data);
    currentCall = undefined;
  }
};

function _presenceSocketOnMessage(event) {
  var data = JSON.parse(event.data);
  for (var eventType in data)
    if (eventType in serverHandlers)
      serverHandlers[eventType](data[eventType]);
    else
      ports.broadcastEvent("talkilla." + eventType, data[eventType]);
}

function _presenceSocketSendMessage(data) {
  _presenceSocket.send(data);
}

function _presenceSocketOnOpen(event) {
  "use strict";

  ports.broadcastEvent("talkilla.presence-open", event);
}

function _presenceSocketOnError(event) {
  "use strict";

  ports.broadcastEvent("talkilla.websocket-error", event);
}

function _presenceSocketOnClose(event) {
  "use strict";

  // XXX: this will need future work to handle retrying presence connections
  ports.broadcastEvent('talkilla.presence-unavailable', event.code);
  currentUsers = undefined;
}

function createPresenceSocket(nickname) {
  "use strict";

  _presenceSocket = new WebSocket(_config.WSURL + "?nick=" + nickname);
  _presenceSocket.onopen = _presenceSocketOnOpen;
  _presenceSocket.onmessage = _presenceSocketOnMessage;
  _presenceSocket.onerror = _presenceSocketOnError;
  _presenceSocket.onclose = _presenceSocketOnClose;

  ports.broadcastEvent("talkilla.presence-pending", {});
}

function sendAjax(url, method, data, cb) {
  var xhr = new XMLHttpRequest();

  xhr.onload = function(event) {
    // sinon.js can call us with a null event a second time, so just ignore it.
    if (!event)
      return;
    if (xhr.readyState === 4 && xhr.status === 200)
      return cb(null, xhr.responseText);
    cb(xhr.statusText);
  };

  xhr.onerror = function(event) {
    if (event && event.target)
      cb(event.target.status ? event.target.statusText : "We are offline");
  };

  xhr.open(method || 'GET', url, true);
  xhr.setRequestHeader("Content-Type", "application/json");
  xhr.send(JSON.stringify(data));
}

function loadconfig(cb) {
  sendAjax('/config.json', 'GET', {}, function(err, data) {
    var config;
    try {
      config = JSON.parse(data);
    } catch (err) {
      return cb(err);
    }
    cb(null, config);
  });
}

function _signinCallback(err, responseText) {
  if (err)
    return this.postEvent('talkilla.login-failure', err);
  var username = JSON.parse(responseText).nick;
  if (username) {
    _currentUserData.userName = _currentUserData.displayName = username;
    _currentUserData.portrait = "test.png";

    ports.broadcastEvent('talkilla.login-success', {
      username: username
    });

    browserPort.postEvent('social.user-profile', _currentUserData);
    createPresenceSocket(username);
  }
}

function _signoutCallback(err, responseText) {
  if (err)
    return this.postEvent('talkilla.error', 'Bad signout:' + err);

  _currentUserData.reset();
  browserPort.postEvent('social.user-profile', _currentUserData);
  currentUsers = undefined;
  ports.broadcastEvent('talkilla.logout-success');
}

var handlers = {
  // SocialAPI events
  'social.port-closing': function() {
    ports.remove(this);
  },

  'social.initialize': function() {
    browserPort = this;
  },

  // Talkilla events
  'talkilla.login': function(msg) {
    if (!msg.data || !msg.data.username) {
      return this.postEvent('talkilla.login-failure', 'no username specified');
    }

    this.postEvent('talkilla.login-pending', null);

    sendAjax('/signin', 'POST', {nick: msg.data.username},
      _signinCallback.bind(this));
  },

  'talkilla.logout': function() {
    if (!_currentUserData.userName) {
      return this.postEvent('talkilla.error',
                            'trying to logout when not logged in');
    }

    _presenceSocket.close();
    sendAjax('/signout', 'POST', {nick: _currentUserData.userName},
      _signoutCallback.bind(this));
  },

  'talkilla.call-start': function(event) {
    // XXX Temporarily work around to only allow one call at a time.
    if (!currentCall) {
      currentCall = {port: undefined, data: event.data};
      openChatWindow();
    }
  },

  'talkilla.chat-window-ready': function() {
    currentCall.port = this;

    if (_currentUserData.userName) {
      // If there's currenty a logged in user,
      this.postEvent('talkilla.login-success', {
        username: _currentUserData.userName
      });
    }

   // If this is an incoming call, we won't have the port yet.
    var topic = currentCall.data.offer ?
      "talkilla.call-incoming" :
      "talkilla.call-start";

    this.postEvent(topic, currentCall.data);
  },

  /**
   * The data for talkilla.offer-timeout is:
   *
   * - caller: The id of the user logged in
   * - callee: The id of the user to be called
   * - video: set to true to enable video
   * - audio: set to true to enable audio
   */
  'talkilla.offer-timeout': function(event) {
    ports.broadcastEvent("talkilla.offer-timeout", event.data);
  },

  /**
   * Called when the sidebar is ready.
   */
  'talkilla.sidebar-ready': function() {
    if (_currentUserData.userName) {
      // If there's currenty a logged in user,
      this.postEvent('talkilla.login-success', {
        username: _currentUserData.userName
      });
      if (currentUsers)
        this.postEvent('talkilla.users', currentUsers);
    }
  },

  /**
   * The data for talkilla.call-offer is:
   *
   * - callee: the person you are calling
   * - caller: the person who is calling you
   * - offer: an RTCSessionDescription containing the sdp data for the call.
   */
  'talkilla.call-offer': function(event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_offer': event.data }));
  },

  /**
   * The data for talkilla.call-answer is:
   *
   * - callee: the person you are calling
   * - caller: the person who is calling you
   * - offer: an RTCSessionDescription containing the sdp data for the call.
   */
  'talkilla.call-answer': function (event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_accepted': event.data }));
  },

  /**
   * Ends a call. The expected data is:
   *
   * - other: the person you are talking to.
   */
  'talkilla.call-hangup': function (event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_hangup': event.data }));
    currentCall = undefined;
  }
};

function Port(port) {
  this.port = port;
  this.id = port._portid;
  // configures this port
  port.onmessage = this.onmessage.bind(this);
}

Port.prototype = {
  /**
   * Posts an error event.
   * @param  {String} error
   */
  error: function(error) {
    this.postEvent("talkilla.error", error);
  },

  /**
   * Port message listener.
   * @param  {Event} event
   */
  onmessage: function(event) {
    var msg = event.data;
    if (msg && msg.topic && (msg.topic in handlers))
      handlers[msg.topic].call(this, msg);
    else
      this.error('Topic is missing or unknown');
  },

  /**
   * Posts a message event.
   * @param  {String} topic
   * @param  {Mixed}  data
   */
  postEvent: function(topic, data) {
    try {
      this.port.postMessage({topic: topic, data: data});
    } catch (e) {
      dump('port error: ' + e);
    }
  }
};

function PortCollection() {
  this.ports = {};
}

PortCollection.prototype = {
  /**
   * Configures and add a port to the stack.
   * @param  {Port} port
   */
  add: function(port) {
    if (port.id in this.ports)
      return;
    this.ports[port.id] = port;
  },

  /**
   * Removes a port from this collection.
   * @param  {Port} port
   */
  remove: function(port) {
    if (port && port.id)
      delete this.ports[port.id];
  },

  /**
   * Retrieves a port from the collection by its id.
   * @param  {String} id
   * @return {Port}
   */
  find: function(id) {
    return this.ports[id];
  },

  /**
   * Broadcasts a message to all ports.
   * @param  {String} topic
   * @param  {Mixed}  data
   */
  broadcastEvent: function(topic, data) {
    for (var id in this.ports)
      this.ports[id].postEvent(topic, data);
  },

  /**
   * Broadcasts an error message to all ports.
   * @param  {String} message
   */
  broadcastError: function(message) {
    for (var id in this.ports)
      this.ports[id].error(message);
  }
};

ports = new PortCollection();

function onconnect(event) {
  ports.add(new Port(event.ports[0]));
}

loadconfig(function(err, config) {
  if (err)
    return ports.broadcastError(err);
  _config = config;
  _currentUserData = new UserData({}, config);
});
<commit_msg>removed silented port errors<commit_after>/* jshint unused:false */

var _config = {DEBUG: false};
var _currentUserData;
var _presenceSocket;
var ports;
var browserPort;
var currentCall;
var currentUsers;

function openChatWindow() {
  browserPort.postEvent('social.request-chat', 'chat.html');
}

/**
 * Social API user profile data storage.
 * @param {Object|undefined}  initial  Initial data
 * @param {Object|undefined}  config   Environment configuration
 */
function UserData(initial, config) {
  var rootURL = config ? config.ROOTURL : '';

  this.defaults = {
    iconURL: rootURL + "/talkilla16.png",
    portrait: undefined,
    userName: undefined,
    displayName: undefined,
    profileURL: rootURL + "/user.html"
  };

  this.reset();

  if (initial) {
    for (var key in initial)
      this[key] = initial[key];
  }
}

UserData.prototype = {
  /**
   * Resets current properties to default ones.
   */
  reset: function() {
    for (var key in this.defaults)
      this[key] = this.defaults[key];
  }
};

var serverHandlers = {
  'users': function(data) {
    currentUsers = data;
    ports.broadcastEvent("talkilla.users", data);
  },

  'incoming_call': function(data) {
    currentCall = {port: undefined, data: data};
    openChatWindow();
  },

  'call_accepted': function(data) {
    currentCall.port.postEvent('talkilla.call-establishment', data);
  },

  'call_hangup': function(data) {
    currentCall.port.postEvent('talkilla.call-hangup', data);
    currentCall = undefined;
  }
};

function _presenceSocketOnMessage(event) {
  var data = JSON.parse(event.data);
  for (var eventType in data)
    if (eventType in serverHandlers)
      serverHandlers[eventType](data[eventType]);
    else
      ports.broadcastEvent("talkilla." + eventType, data[eventType]);
}

function _presenceSocketSendMessage(data) {
  _presenceSocket.send(data);
}

function _presenceSocketOnOpen(event) {
  "use strict";

  ports.broadcastEvent("talkilla.presence-open", event);
}

function _presenceSocketOnError(event) {
  "use strict";

  ports.broadcastEvent("talkilla.websocket-error", event);
}

function _presenceSocketOnClose(event) {
  "use strict";

  // XXX: this will need future work to handle retrying presence connections
  ports.broadcastEvent('talkilla.presence-unavailable', event.code);
  currentUsers = undefined;
}

function createPresenceSocket(nickname) {
  "use strict";

  _presenceSocket = new WebSocket(_config.WSURL + "?nick=" + nickname);
  _presenceSocket.onopen = _presenceSocketOnOpen;
  _presenceSocket.onmessage = _presenceSocketOnMessage;
  _presenceSocket.onerror = _presenceSocketOnError;
  _presenceSocket.onclose = _presenceSocketOnClose;

  ports.broadcastEvent("talkilla.presence-pending", {});
}

function sendAjax(url, method, data, cb) {
  var xhr = new XMLHttpRequest();

  xhr.onload = function(event) {
    // sinon.js can call us with a null event a second time, so just ignore it.
    if (!event)
      return;
    if (xhr.readyState === 4 && xhr.status === 200)
      return cb(null, xhr.responseText);
    cb(xhr.statusText);
  };

  xhr.onerror = function(event) {
    if (event && event.target)
      cb(event.target.status ? event.target.statusText : "We are offline");
  };

  xhr.open(method || 'GET', url, true);
  xhr.setRequestHeader("Content-Type", "application/json");
  xhr.send(JSON.stringify(data));
}

function loadconfig(cb) {
  sendAjax('/config.json', 'GET', {}, function(err, data) {
    var config;
    try {
      config = JSON.parse(data);
    } catch (err) {
      return cb(err);
    }
    cb(null, config);
  });
}

function _signinCallback(err, responseText) {
  if (err)
    return this.postEvent('talkilla.login-failure', err);
  var username = JSON.parse(responseText).nick;
  if (username) {
    _currentUserData.userName = _currentUserData.displayName = username;
    _currentUserData.portrait = "test.png";

    ports.broadcastEvent('talkilla.login-success', {
      username: username
    });

    browserPort.postEvent('social.user-profile', _currentUserData);
    createPresenceSocket(username);
  }
}

function _signoutCallback(err, responseText) {
  if (err)
    return this.postEvent('talkilla.error', 'Bad signout:' + err);

  _currentUserData.reset();
  browserPort.postEvent('social.user-profile', _currentUserData);
  currentUsers = undefined;
  ports.broadcastEvent('talkilla.logout-success');
}

var handlers = {
  // SocialAPI events
  'social.port-closing': function() {
    ports.remove(this);
  },

  'social.initialize': function() {
    browserPort = this;
  },

  // Talkilla events
  'talkilla.login': function(msg) {
    if (!msg.data || !msg.data.username) {
      return this.postEvent('talkilla.login-failure', 'no username specified');
    }

    this.postEvent('talkilla.login-pending', null);

    sendAjax('/signin', 'POST', {nick: msg.data.username},
      _signinCallback.bind(this));
  },

  'talkilla.logout': function() {
    if (!_currentUserData.userName) {
      return this.postEvent('talkilla.error',
                            'trying to logout when not logged in');
    }

    _presenceSocket.close();
    sendAjax('/signout', 'POST', {nick: _currentUserData.userName},
      _signoutCallback.bind(this));
  },

  'talkilla.call-start': function(event) {
    // XXX Temporarily work around to only allow one call at a time.
    if (!currentCall) {
      currentCall = {port: undefined, data: event.data};
      openChatWindow();
    }
  },

  'talkilla.chat-window-ready': function() {
    currentCall.port = this;

    if (_currentUserData.userName) {
      // If there's currenty a logged in user,
      this.postEvent('talkilla.login-success', {
        username: _currentUserData.userName
      });
    }

   // If this is an incoming call, we won't have the port yet.
    var topic = currentCall.data.offer ?
      "talkilla.call-incoming" :
      "talkilla.call-start";

    this.postEvent(topic, currentCall.data);
  },

  /**
   * The data for talkilla.offer-timeout is:
   *
   * - caller: The id of the user logged in
   * - callee: The id of the user to be called
   * - video: set to true to enable video
   * - audio: set to true to enable audio
   */
  'talkilla.offer-timeout': function(event) {
    ports.broadcastEvent("talkilla.offer-timeout", event.data);
  },

  /**
   * Called when the sidebar is ready.
   */
  'talkilla.sidebar-ready': function() {
    if (_currentUserData.userName) {
      // If there's currenty a logged in user,
      this.postEvent('talkilla.login-success', {
        username: _currentUserData.userName
      });
      if (currentUsers)
        this.postEvent('talkilla.users', currentUsers);
    }
  },

  /**
   * The data for talkilla.call-offer is:
   *
   * - callee: the person you are calling
   * - caller: the person who is calling you
   * - offer: an RTCSessionDescription containing the sdp data for the call.
   */
  'talkilla.call-offer': function(event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_offer': event.data }));
  },

  /**
   * The data for talkilla.call-answer is:
   *
   * - callee: the person you are calling
   * - caller: the person who is calling you
   * - offer: an RTCSessionDescription containing the sdp data for the call.
   */
  'talkilla.call-answer': function (event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_accepted': event.data }));
  },

  /**
   * Ends a call. The expected data is:
   *
   * - other: the person you are talking to.
   */
  'talkilla.call-hangup': function (event) {
    _presenceSocketSendMessage(JSON.stringify({ 'call_hangup': event.data }));
    currentCall = undefined;
  }
};

function Port(port) {
  this.port = port;
  this.id = port._portid;
  // configures this port
  port.onmessage = this.onmessage.bind(this);
}

Port.prototype = {
  /**
   * Posts an error event.
   * @param  {String} error
   */
  error: function(error) {
    this.postEvent("talkilla.error", error);
  },

  /**
   * Port message listener.
   * @param  {Event} event
   */
  onmessage: function(event) {
    var msg = event.data;
    if (msg && msg.topic && (msg.topic in handlers))
      handlers[msg.topic].call(this, msg);
    else
      this.error('Topic is missing or unknown');
  },

  /**
   * Posts a message event.
   * @param  {String} topic
   * @param  {Mixed}  data
   */
  postEvent: function(topic, data) {
    // FIXME: for no obvious reason, this may eventually fail if the port is
    //        closed, while it should never be the case
    this.port.postMessage({topic: topic, data: data});
  }
};

function PortCollection() {
  this.ports = {};
}

PortCollection.prototype = {
  /**
   * Configures and add a port to the stack.
   * @param  {Port} port
   */
  add: function(port) {
    if (port.id in this.ports)
      return;
    this.ports[port.id] = port;
  },

  /**
   * Removes a port from this collection.
   * @param  {Port} port
   */
  remove: function(port) {
    if (port && port.id)
      delete this.ports[port.id];
  },

  /**
   * Retrieves a port from the collection by its id.
   * @param  {String} id
   * @return {Port}
   */
  find: function(id) {
    return this.ports[id];
  },

  /**
   * Broadcasts a message to all ports.
   * @param  {String} topic
   * @param  {Mixed}  data
   */
  broadcastEvent: function(topic, data) {
    for (var id in this.ports)
      this.ports[id].postEvent(topic, data);
  },

  /**
   * Broadcasts an error message to all ports.
   * @param  {String} message
   */
  broadcastError: function(message) {
    for (var id in this.ports)
      this.ports[id].error(message);
  }
};

ports = new PortCollection();

function onconnect(event) {
  ports.add(new Port(event.ports[0]));
}

loadconfig(function(err, config) {
  if (err)
    return ports.broadcastError(err);
  _config = config;
  _currentUserData = new UserData({}, config);
});
<|endoftext|>