<commit_before>var api_endpoint = "http://www.thomashart.me:4730/";
var sentence_list = [];
var sentence_index = 0;
var playing = false;
var stories;

$(document).ready(function() {
  pageturner_init();
});

function pageturner_init() {
  bindings();
  bindings_page();
  spanify_text_to_read();
  get_story_list();
}

function bindings() {

  // Nav
  $('.random-story-link').click(render_random_story);
  $('.all-stories-link').click(render_story_list);

  // Ajax links
  $('.ajax-link').click(ajax_link);

  // Player controls
  $('#btn_fast_backward').click(pageturner_fast_backward);
  $('#btn_backward').click(pageturner_backward);
  $('#btn_play').click(pageturner_play);
  $('#btn_pause').click(pageturner_pause);
  $('#btn_forward').click(pageturner_forward);

}

function bindings_page() {

  // Home Page Buttons
  $('#random_story').click(render_random_story);
  $('#story_list').click(render_story_list);

  // Story List Links
  $('.story-link').click(function() {
    var story_id = new Number($(this).attr('data-story-id'));
    render_story(story_id);
  });

}

function pageturner_fast_backward(e) {
  console.log('BUTTON fast backward');
  sentence_index = 0;
  stop_playing();
  $('#btn_pause').hide();
  $('#btn_play').show();
  prevent_default(e);
}
function pageturner_backward(e) {
  console.log('BUTTON backward');

  if(sentence_index > 0) {
    if(sentence_index > 1 && window.speechSynthesis.speaking) {
      sentence_index -= 2;
      window.speechSynthesis.cancel();
    }
    else {
      sentence_index -= 1;
    }
  }
  prevent_default(e);
}
function pageturner_play(e) {
  console.log('BUTTON play');
  $('#btn_pause').show();
  $('#btn_play').hide();
  play_sentence();
  prevent_default(e);
}
function pageturner_pause(e) {
  console.log('BUTTON pause');
  sentence_index -= 1;
  $('#btn_pause').hide();
  $('#btn_play').show();
  stop_playing();
  prevent_default(e);
}
function pageturner_forward(e) {
  console.log('BUTTON forward');
  if(window.speechSynthesis.speaking) {
    window.speechSynthesis.cancel();
  }
  prevent_default(e);
}

function spanify_text_to_read() {
  var text_div = $('#text_to_read');
  var body_text = text_div.html();
  if(typeof body_text !== 'undefined') {
    body_text = body_text.replace(/
/g, '
');
    body_text = body_text.replace(/<\/p>/g, '
');
    body_text = body_text.replace(/\./g, '.');
    body_text = body_text.replace(/,/g, ',');
    body_text = body_text.replace(/\!/g, '!');
    body_text = body_text.replace(/\?/g, '?');
    body_text = body_text.replace(/:/g, ':');
    body_text = body_text.replace(//g, '');
    body_text = body_text.replace(/<\/i>/g, '');
    body_text = body_text.replace(/\s*<\/span>/g, ' ');
    body_text = body_text.replace(/"<\/span>/g, '"');
    body_text = body_text.replace(/\)<\/span>/g, ')');
    text_div.html(body_text);
    sentence_list = $('#text_to_read span');
  }
}

function play_sentence() {
  playing = true;
  clear_highlighting();

  if(sentence_index < sentence_list.length) {
    var sentence = sentence_list.eq(sentence_index);
    sentence.css('background-color', 'yellow');
    var speech_text = sentence.text();
    if(speech_text != '') {
      var utterance = new SpeechSynthesisUtterance(speech_text);
      utterance.rate = 0.15;
      utterance.onend = function() {
        if(playing && !window.speechSynthesis.speaking) {
          play_sentence();
        }
      };
      window.speechSynthesis.speak(utterance);
      sentence_index += 1;
      setTimeout(function () {
        play_sentence_when_ready();
      }, 50);
    }
    else {
      sentence_index += 1;
      play_sentence();
    }
  }
  else {
    pageturner_fast_backward();
  }
}

function stop_playing() {
  $('#btn_pause').hide();
  $('#btn_play').show();
  playing = false;
  window.speechSynthesis.cancel();
  clear_highlighting();
}

function play_sentence_when_ready() {
  if(playing) {
    if (window.speechSynthesis.speaking) {
      setTimeout(function () {
        play_sentence_when_ready();
      }, 50);
    }
    else {
      play_sentence();
    }
  }
}

function clear_highlighting() {
  if(sentence_list.length > 0) {
    sentence_list.each(function() {
      $(this).css('background-color', '');
    });
  }
}

function prevent_default(e) {
  if(typeof e !== 'undefined') {
    e.preventDefault();
  }
}

function ajax_link(e) {
  var url = $(this).attr('href');
  close_navbar();
  $.get(url, render_content);
  e.preventDefault();
}

function render_content(content) {
  clear_progress();
  close_navbar();
  $('#site_content').html(content);
  spanify_text_to_read();
  bindings_page();
}

function clear_progress() {
  stop_playing();
  sentence_list = [];
  sentence_index = 0;
}

function get_story_list() {
  $.getJSON('./stories/story_list.json', function(data) {
    stories = data.stories;
    console.log(stories);
  });
}

function render_story_list(e) {
  var stories_html = '
';
  var idx = 0;
  stories.forEach(function(story) {
    stories_html += '
' + story.title + ' - Read Story
';
    idx++;
  });
  stories_html += '
';
  render_content(stories_html);
  e.preventDefault();
}

function render_story(idx) {
  var story = stories[idx];
  var story_html = '
';
  story_html += '
' + story.title + '
';
  story_html += '
By ' + story.author + '
';
  story_html += story.body + '
';
  story_html += '

Another Random Story

See All Stories

';
  render_content(story_html);
}

function render_random_story(e) {
  var story_idx = Math.floor(Math.random() * stories.length);
  render_story(story_idx);
  e.preventDefault();
}

function close_navbar() {
  if(!$('.navbar-toggle').hasClass('collapsed')) {
    $('.navbar-toggle').click();
  }
}
<commit_msg>Remove pointless API endpoint (uses local JSON file now)<commit_after>var sentence_list = [];
var sentence_index = 0;
var playing = false;
var stories;

$(document).ready(function() {
  pageturner_init();
});

function pageturner_init() {
  bindings();
  bindings_page();
  spanify_text_to_read();
  get_story_list();
}

function bindings() {

  // Nav
  $('.random-story-link').click(render_random_story);
  $('.all-stories-link').click(render_story_list);

  // Ajax links
  $('.ajax-link').click(ajax_link);

  // Player controls
  $('#btn_fast_backward').click(pageturner_fast_backward);
  $('#btn_backward').click(pageturner_backward);
  $('#btn_play').click(pageturner_play);
  $('#btn_pause').click(pageturner_pause);
  $('#btn_forward').click(pageturner_forward);

}

function bindings_page() {

  // Home Page Buttons
  $('#random_story').click(render_random_story);
  $('#story_list').click(render_story_list);

  // Story List Links
  $('.story-link').click(function() {
    var story_id = new Number($(this).attr('data-story-id'));
    render_story(story_id);
  });

}

function pageturner_fast_backward(e) {
  console.log('BUTTON fast backward');
  sentence_index = 0;
  stop_playing();
  $('#btn_pause').hide();
  $('#btn_play').show();
  prevent_default(e);
}
function pageturner_backward(e) {
  console.log('BUTTON backward');

  if(sentence_index > 0) {
    if(sentence_index > 1 && window.speechSynthesis.speaking) {
      sentence_index -= 2;
      window.speechSynthesis.cancel();
    }
    else {
      sentence_index -= 1;
    }
  }
  prevent_default(e);
}
function pageturner_play(e) {
  console.log('BUTTON play');
  $('#btn_pause').show();
  $('#btn_play').hide();
  play_sentence();
  prevent_default(e);
}
function pageturner_pause(e) {
  console.log('BUTTON pause');
  sentence_index -= 1;
  $('#btn_pause').hide();
  $('#btn_play').show();
  stop_playing();
  prevent_default(e);
}
function pageturner_forward(e) {
  console.log('BUTTON forward');
  if(window.speechSynthesis.speaking) {
    window.speechSynthesis.cancel();
  }
  prevent_default(e);
}

function spanify_text_to_read() {
  var text_div = $('#text_to_read');
  var body_text = text_div.html();
  if(typeof body_text !== 'undefined') {
    body_text = body_text.replace(/
/g, '
');
    body_text = body_text.replace(/<\/p>/g, '
');
    body_text = body_text.replace(/\./g, '.');
    body_text = body_text.replace(/,/g, ',');
    body_text = body_text.replace(/\!/g, '!');
    body_text = body_text.replace(/\?/g, '?');
    body_text = body_text.replace(/:/g, ':');
    body_text = body_text.replace(//g, '');
    body_text = body_text.replace(/<\/i>/g, '');
    body_text = body_text.replace(/\s*<\/span>/g, ' ');
    body_text = body_text.replace(/"<\/span>/g, '"');
    body_text = body_text.replace(/\)<\/span>/g, ')');
    text_div.html(body_text);
    sentence_list = $('#text_to_read span');
  }
}

function play_sentence() {
  playing = true;
  clear_highlighting();

  if(sentence_index < sentence_list.length) {
    var sentence = sentence_list.eq(sentence_index);
    sentence.css('background-color', 'yellow');
    var speech_text = sentence.text();
    if(speech_text != '') {
      var utterance = new SpeechSynthesisUtterance(speech_text);
      utterance.rate = 0.15;
      utterance.onend = function() {
        if(playing && !window.speechSynthesis.speaking) {
          play_sentence();
        }
      };
      window.speechSynthesis.speak(utterance);
      sentence_index += 1;
      setTimeout(function () {
        play_sentence_when_ready();
      }, 50);
    }
    else {
      sentence_index += 1;
      play_sentence();
    }
  }
  else {
    pageturner_fast_backward();
  }
}

function stop_playing() {
  $('#btn_pause').hide();
  $('#btn_play').show();
  playing = false;
  window.speechSynthesis.cancel();
  clear_highlighting();
}

function play_sentence_when_ready() {
  if(playing) {
    if (window.speechSynthesis.speaking) {
      setTimeout(function () {
        play_sentence_when_ready();
      }, 50);
    }
    else {
      play_sentence();
    }
  }
}

function clear_highlighting() {
  if(sentence_list.length > 0) {
    sentence_list.each(function() {
      $(this).css('background-color', '');
    });
  }
}

function prevent_default(e) {
  if(typeof e !== 'undefined') {
    e.preventDefault();
  }
}

function ajax_link(e) {
  var url = $(this).attr('href');
  close_navbar();
  $.get(url, render_content);
  e.preventDefault();
}

function render_content(content) {
  clear_progress();
  close_navbar();
  $('#site_content').html(content);
  spanify_text_to_read();
  bindings_page();
}

function clear_progress() {
  stop_playing();
  sentence_list = [];
  sentence_index = 0;
}

function get_story_list() {
  $.getJSON('./stories/story_list.json', function(data) {
    stories = data.stories;
    console.log(stories);
  });
}

function render_story_list(e) {
  var stories_html = '
';
  var idx = 0;
  stories.forEach(function(story) {
    stories_html += '
' + story.title + ' - Read Story
';
    idx++;
  });
  stories_html += '
';
  render_content(stories_html);
  e.preventDefault();
}

function render_story(idx) {
  var story = stories[idx];
  var story_html = '
';
  story_html += '
' + story.title + '
';
  story_html += '
By ' + story.author + '
';
  story_html += story.body + '
';
  story_html += '

Another Random Story

See All Stories

';
  render_content(story_html);
}

function render_random_story(e) {
  var story_idx = Math.floor(Math.random() * stories.length);
  render_story(story_idx);
  e.preventDefault();
}

function close_navbar() {
  if(!$('.navbar-toggle').hasClass('collapsed')) {
    $('.navbar-toggle').click();
  }
}
<|endoftext|>


<commit_before>/**
	paginateIt by Tony Samperi 2015
**/
$.paginateIt = function ($target, $count) {
    var self = this;
    this.fullData = $target.children().clone();
    this.visibleData = "";
    this.total = this.fullData.length;
    this.page = 1;
    this.count = $count || 10;
    this.totalPages = Math.ceil(this.total / this.count);
    //PAGINATOR
    this.paginatorTemplate = '
'+
                        '

'+
                        '
'+
                           '
'+
                                '<  '+
                                'pagina '+
                                'di'+
                                '>'+
                            '
'+
                        '
'+
                    '
';
    $(this.paginatorTemplate).insertAfter($target);
    this.paginator = $target.next();
    this.pagCurrent = self.paginator.find(".currentPage");
    this.pagTotal = self.paginator.find(".totalPages");
    this.pagNext = self.paginator.find(".paginator-next");
    this.pagPrev = self.paginator.find(".paginator-prev");
    this.pagNext.on("click", function () {
        self.nav("next");
    });
    this.pagPrev.on("click", function () {
        self.nav("prev");
    });
    this.nav = function (action) {
        switch (action) {
            case "prev":
                if (this.page > 1) {
                    this.page--;
                    self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                    $target.empty().append(self.visibleData);
                    self.pagCurrent.text(self.page);
                    self.pagTotal.text(self.totalPages);
                }
                break;
            case "next":
                if (this.page < this.totalPages) {
                    this.page++;
                    self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                    $target.empty().append(self.visibleData);
                    self.pagCurrent.text(self.page);
                    self.pagTotal.text(self.totalPages);
                }
                break;
            case "boot":
                self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                $target.empty().append(self.visibleData);
                self.pagCurrent.text(self.page);
                self.pagTotal.text(self.totalPages);
				break;
            default:
                console.error("WRONG ACTION!");
                break;
        }
    };
    self.nav("boot");
};

$(document).ready(function(){
    $("[paginate]").each(function(){
        if (isNaN(parseInt($(this).attr("paginate")))) {
            console.error("invalid \"paginate\" attribute at [paginate]", $(this));
            //SKIP TO NEXT ITERATION
            return true;
        }
        var $count = parseInt($(this).attr("paginate"));
        var doPag = new $.paginateIt($(this), $count);
    });
});
<commit_msg>v 1.0.1<commit_after>/**
 *	paginateIt by Tony Samperi 2018
 */
var style = "\
 div.paginator {\
	display: block;\
	float: left;\
	width: 100%;\
	clear: both;\
 }\
 \
 div.paginator:after {\
	display: table;\
 }\
 \
 span.paginator-prev,\
 span.paginator-next {\
	cursor: pointer;\
	color: #18bc9c;\
 }\
 \
 span.paginator-prev:hover,\
 span.paginator-next:hover {\
	font-weight: bold;\
 }\
";

"undefined" != typeof document && function(e, t) {
    var n = e.createElement("style");
    if (e.getElementsByTagName("head")[0].appendChild(n),
    n.styleSheet)
        n.styleSheet.disabled || (n.styleSheet.cssText = t);
    else
        try {
            n.innerHTML = t
        } catch (e) {
            n.innerText = t
        }
}(document, style);

$.paginateIt = function ($target, $count) {
    var self = this;
    this.fullData = $target.children().clone();
    this.visibleData = "";
    this.total = this.fullData.length;
    this.page = 1;
    this.count = $count || 10;
    this.totalPages = Math.ceil(this.total / this.count);
    //PAGINATOR
    this.paginatorTemplate = '
'+
                        '

'+
                        '
'+
                           '
'+
                                '<  '+
                                'page '+
                                ' of '+
                                ' >'+
                            '
'+
                        '
'+
                    '
';
    $(this.paginatorTemplate).insertAfter($target);
    this.paginator = $target.next();
    this.pagCurrent = self.paginator.find(".currentPage");
    this.pagTotal = self.paginator.find(".totalPages");
    this.pagNext = self.paginator.find(".paginator-next");
    this.pagPrev = self.paginator.find(".paginator-prev");
    this.pagNext.on("click", function () {
        self.nav("next");
    });
    this.pagPrev.on("click", function () {
        self.nav("prev");
    });
    this.nav = function (action) {
        switch (action) {
            case "prev":
                if (this.page > 1) {
                    this.page--;
                    self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                    $target.empty().append(self.visibleData);
                    self.pagCurrent.text(self.page);
                    self.pagTotal.text(self.totalPages);
                }
                break;
            case "next":
                if (this.page < this.totalPages) {
                    this.page++;
                    self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                    $target.empty().append(self.visibleData);
                    self.pagCurrent.text(self.page);
                    self.pagTotal.text(self.totalPages);
                }
                break;
            case "boot":
                self.visibleData = self.fullData.slice((self.page - 1) * self.count, self.page * self.count);
                $target.empty().append(self.visibleData);
                self.pagCurrent.text(self.page);
                self.pagTotal.text(self.totalPages);
				$target.css("minHeight", $target.height());
				break;
            default:
                console.error("WRONG ACTION!");
                break;
        }
    };
    self.nav("boot");
};

$(document).ready(function(){
    $("[paginate]").each(function(){
        if (isNaN(parseInt($(this).attr("paginate")))) {
            console.error("invalid \"paginate\" attribute at [paginate]", $(this));
            //SKIP TO NEXT ITERATION
            return true;
        }
        var $count = parseInt($(this).attr("paginate"));
        var doPag = new $.paginateIt($(this), $count);
    });
});
<|endoftext|>


<commit_before>'use strict';

var debug = require('debug')('Camera');
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var clone = require('./util/clone').clone;
var uuid = require('./util/uuid');
var Service = require('./Service').Service;
var Characteristic = require('./Characteristic').Characteristic;
var StreamController = require('./StreamController').StreamController;
var HomeKitTypes = require('./gen/HomeKitTypes');

var crypto = require('crypto');
var fs = require('fs');
var ip = require('ip');
var spawn = require('child_process').spawn;

module.exports = {
  Camera: Camera
};

function Camera() {
  this.services = [];
  this.streamControllers = [];

  this.pendingSessions = {};
  this.ongoingSessions = {};

  let options = {
    proxy: false, // Requires RTP/RTCP MUX Proxy
    disable_audio_proxy: false, // If proxy = true, you can opt out audio proxy via this
    srtp: true, // Supports SRTP AES_CM_128_HMAC_SHA1_80 encryption
    video: {
      resolutions: [
        [1920, 1080, 30], // Width, Height, framerate
        [320, 240, 15], // Apple Watch requires this configuration
        [1280, 960, 30],
        [1280, 720, 30],
        [1024, 768, 30],
        [640, 480, 30],
        [640, 360, 30],
        [480, 360, 30],
        [480, 270, 30],
        [320, 240, 30],
        [320, 180, 30]
      ],
      codec: {
        profiles: [0, 1, 2], // Enum, please refer StreamController.VideoCodecParamProfileIDTypes
        levels: [0, 1, 2] // Enum, please refer StreamController.VideoCodecParamLevelTypes
      }
    },
    audio: {
      comfort_noise: false,
      codecs: [
        {
          type: "OPUS", // Audio Codec
          samplerate: 24 // 8, 16, 24 KHz
        },
        {
          type: "AAC-eld",
          samplerate: 16
        }
      ]
    }
  }

  this.createCameraControlService();
  this._createStreamControllers(2, options);
}

Camera.prototype.handleSnapshotRequest = function(request, callback) {
  // Image request: {width: number, height: number}
  // Please override this and invoke callback(error, image buffer) when the snapshot is ready

  var snapshot = fs.readFileSync(__dirname + '/res/snapshot.jpg');
  callback(undefined, snapshot);
}

Camera.prototype.handleCloseConnection = function(connectionID) {
  this.streamControllers.forEach(function(controller) {
    controller.handleCloseConnection(connectionID);
  });
}

Camera.prototype.prepareStream = function(request, callback) {
  // Invoked when iOS device requires stream

  var sessionInfo = {};

  let sessionID = request["sessionID"];
  let targetAddress = request["targetAddress"];

  sessionInfo["address"] = targetAddress;

  var response = {};

  let videoInfo = request["video"];
  if (videoInfo) {
    let targetPort = videoInfo["port"];
    let srtp_key = videoInfo["srtp_key"];
    let srtp_salt = videoInfo["srtp_salt"];

    // SSRC is a 32 bit integer that is unique per stream
    let ssrc = crypto.randomBytes(4).readInt32BE(0, true);

    let videoResp = {
      port: targetPort,
      ssrc: ssrc,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["video"] = videoResp;

    sessionInfo["video_port"] = targetPort;
    sessionInfo["video_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["video_ssrc"] = ssrc;
  }

  let audioInfo = request["audio"];
  if (audioInfo) {
    let targetPort = audioInfo["port"];
    let srtp_key = audioInfo["srtp_key"];
    let srtp_salt = audioInfo["srtp_salt"];

    // SSRC is a 32 bit integer that is unique per stream
    let ssrc = crypto.randomBytes(4).readInt32BE(0, true);

    let audioResp = {
      port: targetPort,
      ssrc: ssrc,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["audio"] = audioResp;

    sessionInfo["audio_port"] = targetPort;
    sessionInfo["audio_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["audio_ssrc"] = ssrc;
  }

  let currentAddress = ip.address();
  var addressResp = {
    address: currentAddress
  };

  if (ip.isV4Format(currentAddress)) {
    addressResp["type"] = "v4";
  } else {
    addressResp["type"] = "v6";
  }

  response["address"] = addressResp;
  this.pendingSessions[uuid.unparse(sessionID)] = sessionInfo;

  callback(response);
}

Camera.prototype.handleStreamRequest = function(request) {
  // Invoked when iOS device asks stream to start/stop/reconfigure
  var sessionID = request["sessionID"];
  var requestType = request["type"];
  if (sessionID) {
    let sessionIdentifier = uuid.unparse(sessionID);

    if (requestType == "start") {
      var sessionInfo = this.pendingSessions[sessionIdentifier];
      if (sessionInfo) {
        var width = 1280;
        var height = 720;
        var fps = 30;
        var bitrate = 300;

        let videoInfo = request["video"];
        if (videoInfo) {
          width = videoInfo["width"];
          height = videoInfo["height"];

          let expectedFPS = videoInfo["fps"];
          if (expectedFPS < fps) {
            fps = expectedFPS;
          }

          bitrate = videoInfo["max_bit_rate"];
        }

        let targetAddress = sessionInfo["address"];
        let targetVideoPort = sessionInfo["video_port"];
        let videoKey = sessionInfo["video_srtp"];
        let videoSsrc = sessionInfo["video_ssrc"];

        let ffmpegCommand = '-re -f avfoundation -r 29.970000 -i 0:0 -threads 0 -vcodec libx264 -an -pix_fmt yuv420p -r '+ fps +' -f rawvideo -tune zerolatency -vf scale='+ width +':'+ height +' -b:v '+ bitrate +'k -bufsize '+ bitrate +'k -payload_type 99 -ssrc '+ videoSsrc +' -f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params '+videoKey.toString('base64')+' srtp://'+targetAddress+':'+targetVideoPort+'?rtcpport='+targetVideoPort+'&localrtcpport='+targetVideoPort+'&pkt_size=1378';
        let ffmpeg = spawn('ffmpeg', ffmpegCommand.split(' '), {env: process.env});
        this.ongoingSessions[sessionIdentifier] = ffmpeg;
      }

      delete this.pendingSessions[sessionIdentifier];
    } else if (requestType == "stop") {
      var ffmpegProcess = this.ongoingSessions[sessionIdentifier];
      if (ffmpegProcess) {
        ffmpegProcess.kill('SIGKILL');
      }

      delete this.ongoingSessions[sessionIdentifier];
    }
  }
}

Camera.prototype.createCameraControlService = function() {
  var controlService = new Service.CameraControl();

  // Developer can add control characteristics like rotation, night vision at here.

  this.services.push(controlService);
}

// Private

Camera.prototype._createStreamControllers = function(maxStreams, options) {
  let self = this;

  for (var i = 0; i < maxStreams; i++) {
    var streamController = new StreamController(i, options, self);

    self.services.push(streamController.service);
    self.streamControllers.push(streamController);
  }
}<commit_msg>Update SSRC generation.<commit_after>'use strict';

var debug = require('debug')('Camera');
var inherits = require('util').inherits;
var EventEmitter = require('events').EventEmitter;
var clone = require('./util/clone').clone;
var uuid = require('./util/uuid');
var Service = require('./Service').Service;
var Characteristic = require('./Characteristic').Characteristic;
var StreamController = require('./StreamController').StreamController;
var HomeKitTypes = require('./gen/HomeKitTypes');

var crypto = require('crypto');
var fs = require('fs');
var ip = require('ip');
var spawn = require('child_process').spawn;

module.exports = {
  Camera: Camera
};

function Camera() {
  this.services = [];
  this.streamControllers = [];

  this.pendingSessions = {};
  this.ongoingSessions = {};

  let options = {
    proxy: false, // Requires RTP/RTCP MUX Proxy
    disable_audio_proxy: false, // If proxy = true, you can opt out audio proxy via this
    srtp: true, // Supports SRTP AES_CM_128_HMAC_SHA1_80 encryption
    video: {
      resolutions: [
        [1920, 1080, 30], // Width, Height, framerate
        [320, 240, 15], // Apple Watch requires this configuration
        [1280, 960, 30],
        [1280, 720, 30],
        [1024, 768, 30],
        [640, 480, 30],
        [640, 360, 30],
        [480, 360, 30],
        [480, 270, 30],
        [320, 240, 30],
        [320, 180, 30]
      ],
      codec: {
        profiles: [0, 1, 2], // Enum, please refer StreamController.VideoCodecParamProfileIDTypes
        levels: [0, 1, 2] // Enum, please refer StreamController.VideoCodecParamLevelTypes
      }
    },
    audio: {
      comfort_noise: false,
      codecs: [
        {
          type: "OPUS", // Audio Codec
          samplerate: 24 // 8, 16, 24 KHz
        },
        {
          type: "AAC-eld",
          samplerate: 16
        }
      ]
    }
  }

  this.createCameraControlService();
  this._createStreamControllers(2, options);
}

Camera.prototype.handleSnapshotRequest = function(request, callback) {
  // Image request: {width: number, height: number}
  // Please override this and invoke callback(error, image buffer) when the snapshot is ready

  var snapshot = fs.readFileSync(__dirname + '/res/snapshot.jpg');
  callback(undefined, snapshot);
}

Camera.prototype.handleCloseConnection = function(connectionID) {
  this.streamControllers.forEach(function(controller) {
    controller.handleCloseConnection(connectionID);
  });
}

Camera.prototype.prepareStream = function(request, callback) {
  // Invoked when iOS device requires stream

  var sessionInfo = {};

  let sessionID = request["sessionID"];
  let targetAddress = request["targetAddress"];

  sessionInfo["address"] = targetAddress;

  var response = {};

  let videoInfo = request["video"];
  if (videoInfo) {
    let targetPort = videoInfo["port"];
    let srtp_key = videoInfo["srtp_key"];
    let srtp_salt = videoInfo["srtp_salt"];

    // SSRC is a 32 bit integer that is unique per stream
    let ssrcSource = crypto.randomBytes(4);
    ssrcSource[0] = 0;
    let ssrc = ssrcSource.readInt32BE(0, true);

    let videoResp = {
      port: targetPort,
      ssrc: ssrc,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["video"] = videoResp;

    sessionInfo["video_port"] = targetPort;
    sessionInfo["video_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["video_ssrc"] = ssrc;
  }

  let audioInfo = request["audio"];
  if (audioInfo) {
    let targetPort = audioInfo["port"];
    let srtp_key = audioInfo["srtp_key"];
    let srtp_salt = audioInfo["srtp_salt"];

    // SSRC is a 32 bit integer that is unique per stream
    let ssrcSource = crypto.randomBytes(4);
    ssrcSource[0] = 0;
    let ssrc = ssrcSource.readInt32BE(0, true);

    let audioResp = {
      port: targetPort,
      ssrc: ssrc,
      srtp_key: srtp_key,
      srtp_salt: srtp_salt
    };

    response["audio"] = audioResp;

    sessionInfo["audio_port"] = targetPort;
    sessionInfo["audio_srtp"] = Buffer.concat([srtp_key, srtp_salt]);
    sessionInfo["audio_ssrc"] = ssrc;
  }

  let currentAddress = ip.address();
  var addressResp = {
    address: currentAddress
  };

  if (ip.isV4Format(currentAddress)) {
    addressResp["type"] = "v4";
  } else {
    addressResp["type"] = "v6";
  }

  response["address"] = addressResp;
  this.pendingSessions[uuid.unparse(sessionID)] = sessionInfo;

  callback(response);
}

Camera.prototype.handleStreamRequest = function(request) {
  // Invoked when iOS device asks stream to start/stop/reconfigure
  var sessionID = request["sessionID"];
  var requestType = request["type"];
  if (sessionID) {
    let sessionIdentifier = uuid.unparse(sessionID);

    if (requestType == "start") {
      var sessionInfo = this.pendingSessions[sessionIdentifier];
      if (sessionInfo) {
        var width = 1280;
        var height = 720;
        var fps = 30;
        var bitrate = 300;

        let videoInfo = request["video"];
        if (videoInfo) {
          width = videoInfo["width"];
          height = videoInfo["height"];

          let expectedFPS = videoInfo["fps"];
          if (expectedFPS < fps) {
            fps = expectedFPS;
          }

          bitrate = videoInfo["max_bit_rate"];
        }

        let targetAddress = sessionInfo["address"];
        let targetVideoPort = sessionInfo["video_port"];
        let videoKey = sessionInfo["video_srtp"];
        let videoSsrc = sessionInfo["video_ssrc"];

        let ffmpegCommand = '-re -f avfoundation -r 29.970000 -i 0:0 -threads 0 -vcodec libx264 -an -pix_fmt yuv420p -r '+ fps +' -f rawvideo -tune zerolatency -vf scale='+ width +':'+ height +' -b:v '+ bitrate +'k -bufsize '+ bitrate +'k -payload_type 99 -ssrc '+ videoSsrc +' -f rtp -srtp_out_suite AES_CM_128_HMAC_SHA1_80 -srtp_out_params '+videoKey.toString('base64')+' srtp://'+targetAddress+':'+targetVideoPort+'?rtcpport='+targetVideoPort+'&localrtcpport='+targetVideoPort+'&pkt_size=1378';
        let ffmpeg = spawn('ffmpeg', ffmpegCommand.split(' '), {env: process.env});
        this.ongoingSessions[sessionIdentifier] = ffmpeg;
      }

      delete this.pendingSessions[sessionIdentifier];
    } else if (requestType == "stop") {
      var ffmpegProcess = this.ongoingSessions[sessionIdentifier];
      if (ffmpegProcess) {
        ffmpegProcess.kill('SIGKILL');
      }

      delete this.ongoingSessions[sessionIdentifier];
    }
  }
}

Camera.prototype.createCameraControlService = function() {
  var controlService = new Service.CameraControl();

  // Developer can add control characteristics like rotation, night vision at here.

  this.services.push(controlService);
}

// Private

Camera.prototype._createStreamControllers = function(maxStreams, options) {
  let self = this;

  for (var i = 0; i < maxStreams; i++) {
    var streamController = new StreamController(i, options, self);

    self.services.push(streamController.service);
    self.streamControllers.push(streamController);
  }
}<|endoftext|>


<commit_before>var zmq = require('zmq');
var Readable = require('readable-stream').Readable;
var debug = require('debug')('pigato:Client');
var uuid = require('node-uuid');
var util = require('util');
var events = require('events');
var _ = require('lodash');
var MDP = require('./mdp');
var putils = require('./utils');

var HEARTBEAT_LIVENESS = 3;

function Client(brokers, conf) {
  if (_.isString(brokers)) {
    brokers = [brokers];
  }
  this.brokers = brokers;

  this.conf = {
    autostart: false,
    heartbeat: 2500,
    timeout: 60000,
    retry: 0,
    name: 'C' + uuid.v4()
  };

  this.reqs = {};

  _.extend(this.conf, conf);

  events.EventEmitter.call(this);

  if (this.conf.autostart) {
    this.start();
  }
};
util.inherits(Client, events.EventEmitter);

Client.prototype.start = function() {
  var self = this;

  this.socket = zmq.socket('dealer');
  this.socket.identity = new Buffer(this.conf.name);

  this.socket.on('message', function() {
    self.onMsg.call(self, putils.args(arguments));
  });

  this.socket.on('error', function(err) {
    self.emitErr(err);
  });

  _.each(this.brokers, function(b) {
    self.socket.connect(b);
  });

  debug('Client connected to %s', this.broker);

  this.hbTimer = setInterval(function() {
    self.heartbeat();
    _.each(self.reqs, function(req, rid) {
      if (req.timeout > -1 && ((new Date()).getTime() > req.lts + req.timeout)) {
        self.onMsg([
          MDP.CLIENT, MDP.W_REPLY, '', new Buffer(rid), new Buffer('-1'),
          new Buffer(JSON.stringify('C_TIMEOUT'))
        ]);
      }
    });
  }, this.conf.heartbeat);
};

Client.prototype.stop = function() {
  var self = this;

  clearInterval(this.hbTimer);

  if (this.socket) {
    _.each(this.brokers, function(b) {
      self.socket.disconnect(b);
    });

    this.socket.close();

    delete this.socket;
  }
};

Client.prototype.send = function(msg) {
  if (!this.socket) {
    return;
  }
  this.socket.send(msg);
};

Client.prototype.onMsg = function(msg) {
  msg = putils.mparse(msg);

  var header = msg[0];
  var type = msg[1];

  if (header != MDP.CLIENT) {
    this.emitErr('ERR_MSG_HEADER');
    return;
  }

  if (msg.length < 3) {
    return;
  }

  var rid = msg[3];
  var req = this.reqs[rid];
  if (!req) {
    return;
  }

  var err = +msg[4] || 0;
  var data = msg[5] || null;

  if (data) {
    data = JSON.parse(data);
  }

  if (err === -1) {
    err = data;
    data = null;
  }

  if (type == MDP.W_REPLY || type == MDP.W_REPLY_PARTIAL) {
    req.lts = new Date().getTime();

    if (type == MDP.W_REPLY) {
      req._finalMsg = [err, data];
      req.ended = true;
      delete this.reqs[rid];
    }

    if (err) {
      req.stream.emit('error', err);
    }

    req.stream.push(data);

    if (type == MDP.W_REPLY) {
      req.stream.push(null);
    }
  } else {
    this.emitErr('ERR_MSG_TYPE');
  }
};

Client.prototype.emitErr = function(msg) {
  this.emit.apply(this, ['error', msg]);
};

function noop() {}

function _request(serviceName, data, opts) {
  var self = this;
  var rid = uuid.v4();

  if (typeof opts !== 'object') {
    opts = {};
  }

  _.each(['timeout', 'retry'], function(fld) {
    opts[fld] = opts[fld] !== undefined ? opts[fld] : self.conf[fld]
  });

  var req = this.reqs[rid] = {
    rid: rid,
    timeout: opts.timeout,
    ts: new Date().getTime(),
    opts: opts,
    heartbeat: function() {
      self.heartbeat(rid);
    },
    _finalMsg: null,
    ended: false
  };

  req.lts = req.ts;

  var stream = new Readable({ objectMode: true });

  stream._read = noop;
  stream.heartbeat = req.heartbeat;

  req.stream = stream;

  debug('C: send request', serviceName, rid);

  this.send([
    MDP.CLIENT, MDP.W_REQUEST, serviceName, rid,
    JSON.stringify(data), JSON.stringify(opts)
  ]);

  return req;
};

Client.prototype.requestStream = function(serviceName, data, opts) {
  return this.request(serviceName, data, opts);
};

Client.prototype.request = function() {
  var mode = 'stream';
  var serviceName = arguments[0];
  var data = arguments[1];
  var opts, partialCb, finalCb;

  if (arguments.length >= 4) {
    mode = 'callback';
    partialCb = arguments[2];
    finalCb = arguments[3];
    opts = arguments[4];
  } else {
    opts = arguments[2];
  }

  var req = _request.call(this, serviceName, data, opts);

  if (mode === 'callback') {
    req.stream.on('data', function(data) {
      if (req.ended) {
        return;
      }

      if (partialCb) {
        partialCb(null, data);
      }
    });

    req.stream.on('end', function() {
      var msg = req._finalMsg;

      if (finalCb) {
        finalCb(msg[0], msg[1]);
      }
    });

    req.stream.on('error', noop);

  } else {
    return req.stream;
  }
};

Client.prototype.heartbeat = function(rid) {
  var msg = [MDP.CLIENT, MDP.W_HEARTBEAT];
  if (rid) {
    msg.push(rid);
  }
  this.send(msg);
};

module.exports = Client;
<commit_msg>Minor code cleanup<commit_after>var zmq = require('zmq');
var Readable = require('readable-stream').Readable;
var debug = require('debug')('pigato:Client');
var uuid = require('node-uuid');
var util = require('util');
var events = require('events');
var _ = require('lodash');
var MDP = require('./mdp');
var putils = require('./utils');

var HEARTBEAT_LIVENESS = 3;

function Client(brokers, conf) {
  if (_.isString(brokers)) {
    brokers = [brokers];
  }
  this.brokers = brokers;

  this.conf = {
    autostart: false,
    heartbeat: 2500,
    timeout: 60000,
    retry: 0,
    name: 'C' + uuid.v4()
  };

  this.reqs = {};

  _.extend(this.conf, conf);

  events.EventEmitter.call(this);

  if (this.conf.autostart) {
    this.start();
  }
};
util.inherits(Client, events.EventEmitter);

Client.prototype.start = function() {
  var self = this;

  this.socket = zmq.socket('dealer');
  this.socket.identity = new Buffer(this.conf.name);

  this.socket.on('message', function() {
    self.onMsg.call(self, putils.args(arguments));
  });

  this.socket.on('error', function(err) {
    self.emitErr(err);
  });

  _.each(this.brokers, function(b) {
    self.socket.connect(b);
  });

  debug('Client connected to %s', this.broker);

  this.hbTimer = setInterval(function() {
    self.heartbeat();
    _.each(self.reqs, function(req, rid) {
      if (req.timeout > -1 && ((new Date()).getTime() > req.lts + req.timeout)) {
        self.onMsg([
          MDP.CLIENT, MDP.W_REPLY, '', new Buffer(rid), new Buffer('-1'),
          new Buffer(JSON.stringify('C_TIMEOUT'))
        ]);
      }
    });
  }, this.conf.heartbeat);
};

Client.prototype.stop = function() {
  var self = this;

  clearInterval(this.hbTimer);

  if (this.socket) {
    _.each(this.brokers, function(b) {
      self.socket.disconnect(b);
    });

    this.socket.close();

    delete this.socket;
  }
};

Client.prototype.send = function(msg) {
  if (!this.socket) {
    return;
  }
  this.socket.send(msg);
};

Client.prototype.onMsg = function(msg) {
  msg = putils.mparse(msg);

  var header = msg[0];
  var type = msg[1];

  if (header != MDP.CLIENT) {
    this.emitErr('ERR_MSG_HEADER');
    return;
  }

  if (msg.length < 3) {
    return;
  }

  var rid = msg[3];
  var req = this.reqs[rid];
  if (!req) {
    return;
  }

  var err = +msg[4] || 0;
  var data = msg[5] || null;

  if (data) {
    data = JSON.parse(data);
  }

  if (err === -1) {
    err = data;
    data = null;
  }

  if (type == MDP.W_REPLY || type == MDP.W_REPLY_PARTIAL) {
    req.lts = new Date().getTime();

    if (type == MDP.W_REPLY) {
      req._finalMsg = [err, data];
      req.ended = true;
      delete this.reqs[rid];
    }

    if (err) {
      req.stream.emit('error', err);
    }

    req.stream.push(data);

    if (type == MDP.W_REPLY) {
      req.stream.push(null);
    }
  } else {
    this.emitErr('ERR_MSG_TYPE');
  }
};

Client.prototype.emitErr = function(msg) {
  this.emit.apply(this, ['error', msg]);
};

function noop() {}

function _request(serviceName, data, _opts) {
  var self = this;
  var rid = uuid.v4();
  var opts = _.isObject(_opts) ? _opts : {};

  _.each(['timeout', 'retry'], function(fld) {
    opts[fld] = opts[fld] !== undefined ? opts[fld] : self.conf[fld]
  });

  var req = this.reqs[rid] = {
    rid: rid,
    timeout: opts.timeout,
    ts: new Date().getTime(),
    opts: opts,
    heartbeat: function() {
      self.heartbeat(rid);
    },
    _finalMsg: null,
    ended: false
  };

  req.lts = req.ts;

  var stream = new Readable({ objectMode: true });

  stream._read = noop;
  stream.heartbeat = req.heartbeat;

  req.stream = stream;

  debug('C: send request', serviceName, rid);

  this.send([
    MDP.CLIENT, MDP.W_REQUEST, serviceName, rid,
    JSON.stringify(data), JSON.stringify(opts)
  ]);

  return req;
};

Client.prototype.requestStream = function(serviceName, data, opts) {
  return this.request(serviceName, data, opts);
};

Client.prototype.request = function() {
  var mode = 'stream';
  var serviceName = arguments[0];
  var data = arguments[1];
  var opts, partialCb, finalCb;

  if (arguments.length >= 4) {
    mode = 'callback';
    partialCb = arguments[2];
    finalCb = arguments[3];
    opts = arguments[4];
  } else {
    opts = arguments[2];
  }

  var req = _request.call(this, serviceName, data, opts);

  if (mode === 'callback') {
    req.stream.on('data', function(data) {
      if (req.ended) {
        return;
      }

      if (partialCb) {
        partialCb(null, data);
      }
    });

    req.stream.on('end', function() {
      var msg = req._finalMsg;

      if (finalCb) {
        finalCb(msg[0], msg[1]);
      }
    });

    req.stream.on('error', noop);

  } else {
    return req.stream;
  }
};

Client.prototype.heartbeat = function(rid) {
  var msg = [MDP.CLIENT, MDP.W_HEARTBEAT];
  if (rid) {
    msg.push(rid);
  }
  this.send(msg);
};

module.exports = Client;
<|endoftext|>


<commit_before>/**
 * Created with JetBrains WebStorm.
 * User: mschwartz
 * Date: 6/23/13
 * Time: 12:38 PM
 * To change this template use File | Settings | File Templates.
 */

/** @module Cursor */

/*global require, exports */

"use strict";

var {BasicDBObject} = Packages.com.mongodb,
    {serialize, deserialize} = require('./BSON');

// DBQuery.Option.*

/**
 *
 * @param cursor
 * @constructor
 */
function Cursor( cursor ) {
    this.cursor = cursor;
}

decaf.extend(Cursor.prototype, {
    /**
     *
     * @param option
     * @returns {*}
     */
    addOption : function( option ) {
        this.cursor.addOption(option);
        return this;
    },

    /**
     *
     * @param size
     * @returns {*}
     */
    batchSize : function( size ) {
        this.cursor.batchSize(size);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    count : function() {
        return this.cursor.count();
    },

    /**
     *
     * @returns {*}
     */
    explain : function() {
        return this.cursor.explain();
    },

    /**
     *
     * @param index
     * @returns {*}
     */
    hint : function( index ) {
        return this.cursor.hint(index);
    },

    /**
     *
     * @param fn
     * @returns {Array}
     */
    map : function( fn ) {
        var result = [];
        while ( this.hasNext() ) {
            var next = this.next();
            if ( next && fn(next) ) {
                result.push(next);
            }
        }
        this.close();
        return result;
    },

    /**
     *
     * @param indexBounds
     * @returns {*}
     */
    max : function( indexBounds ) {
        this.cursor.max(indexBounds);
        return this;
    },

    /**
     *
     * @param indexBounds
     * @returns {*}
     */
    min : function( indexBounds ) {
        this.cursor.min(indexBounds);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    objsLeftInBatch : function() {
        return this.cursor.objsLeftInBatch();
    },

    /**
     *
     * @param mode
     * @param tagSet
     */
    readPref : function( mode, tagSet ) {
        this.cursor.readPref(mode, tagSet);
    },

    /**
     *
     * @returns {*}
     */
    showDiskLoc : function() {
        return this.cursor.showDiskLoc();
    },

    /**
     *
     * @returns {*|number}
     */
    size : function() {
        return this.cursor.size();
    },

    /**
     *
     * @returns {*}
     */
    snapshot : function() {
        this.cursor.snapshot();
        return this;
    },

    /**
     *
     * @param sort
     * @returns {*}
     */
    sort : function( sort ) {
        this.cursor = this.cursor.sort(serialize(sort));
        return this;
    },

    /**
     *
     * @returns {Array}
     */
    toArray : function() {
        var a = [];
        while ( this.hasNext() ) {
            a.push(this.next());
        }
        this.data = a;
        return a;
    },

    /**
     *
     * @param n
     * @returns {*}
     */
    skip : function( n ) {
        this.cursor = this.cursor.skip(n);
        return this;
    },

    /**
     *
     * @param n
     * @returns {*}
     */
    limit : function( n ) {
        this.cursor = this.cursor.limit(n);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    hasNext : function() {
        var ret = this.cursor && this.cursor.hasNext();
        if ( !ret ) {
            this.close();
        }
        return ret;
    },

    /**
     *
     * @returns {*}
     */
    next : function() {
        var ret = this.cursor && this.cursor.next();
        if ( ret ) {
            ret = deserialize(ret.toString());
        }
        else {
            this.close();
        }
        return ret;
    },

    /**
     *
     * @param fn
     */
    forEach : function( fn ) {
        if ( !this.cursor ) {
            return;
        }
        while ( this.hasNext() ) {
            var next = this.next();
            if ( next ) {
                fn(next);
            }
        }
        this.close();
    },

    /**
     *
     */
    close : function() {
        if ( this.cursor ) {
            this.cursor.close();
        }
        this.cursor = null;
    }

});

decaf.extend(exports, {
    Cursor : Cursor
});
<commit_msg>BSON serialize/deserialize methods<commit_after>/**
 * Created with JetBrains WebStorm.
 * User: mschwartz
 * Date: 6/23/13
 * Time: 12:38 PM
 * To change this template use File | Settings | File Templates.
 */

/** @module Cursor */

/*global require, exports */

"use strict";

var {BasicDBObject} = Packages.com.mongodb,
    {serialize, deserialize} = require('./BSON');

// DBQuery.Option.*

/**
 *
 * @param cursor
 * @constructor
 */
function Cursor( cursor ) {
    this.cursor = cursor;
}

decaf.extend(Cursor.prototype, {
    /**
     *
     * @param option
     * @returns {*}
     */
    addOption : function( option ) {
        this.cursor.addOption(option);
        return this;
    },

    /**
     *
     * @param size
     * @returns {*}
     */
    batchSize : function( size ) {
        this.cursor.batchSize(size);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    count : function() {
        return this.cursor.count();
    },

    /**
     *
     * @returns {*}
     */
    explain : function() {
        return this.cursor.explain();
    },

    /**
     *
     * @param index
     * @returns {*}
     */
    hint : function( index ) {
        return this.cursor.hint(index);
    },

    /**
     *
     * @param fn
     * @returns {Array}
     */
    map : function( fn ) {
        var result = [];
        while ( this.hasNext() ) {
            var next = this.next();
            if ( next && fn(next) ) {
                result.push(next);
            }
        }
        this.close();
        return result;
    },

    /**
     *
     * @param indexBounds
     * @returns {*}
     */
    max : function( indexBounds ) {
        this.cursor.max(indexBounds);
        return this;
    },

    /**
     *
     * @param indexBounds
     * @returns {*}
     */
    min : function( indexBounds ) {
        this.cursor.min(indexBounds);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    objsLeftInBatch : function() {
        return this.cursor.objsLeftInBatch();
    },

    /**
     *
     * @param mode
     * @param tagSet
     */
    readPref : function( mode, tagSet ) {
        this.cursor.readPref(mode, tagSet);
    },

    /**
     *
     * @returns {*}
     */
    showDiskLoc : function() {
        return this.cursor.showDiskLoc();
    },

    /**
     *
     * @returns {*|number}
     */
    size : function() {
        return this.cursor.size();
    },

    /**
     *
     * @returns {*}
     */
    snapshot : function() {
        this.cursor.snapshot();
        return this;
    },

    /**
     *
     * @param sort
     * @returns {*}
     */
    sort : function( sort ) {
        this.cursor = this.cursor.sort(serialize(sort));
        return this;
    },

    /**
     *
     * @returns {Array}
     */
    toArray : function() {
        var a = [];
        while ( this.hasNext() ) {
            a.push(this.next());
        }
        this.data = a;
        return a;
    },

    /**
     *
     * @param n
     * @returns {*}
     */
    skip : function( n ) {
        this.cursor = this.cursor.skip(n);
        return this;
    },

    /**
     *
     * @param n
     * @returns {*}
     */
    limit : function( n ) {
        this.cursor = this.cursor.limit(n);
        return this;
    },

    /**
     *
     * @returns {*}
     */
    hasNext : function() {
        var ret = this.cursor && this.cursor.hasNext();
        if ( !ret ) {
            this.close();
        }
        return ret;
    },

    /**
     *
     * @returns {*}
     */
    next : function() {
        var ret = this.cursor && this.cursor.next();
        if ( ret ) {
            ret = deserialize(ret);
        }
        else {
            this.close();
        }
        return ret;
    },

    /**
     *
     * @param fn
     */
    forEach : function( fn ) {
        if ( !this.cursor ) {
            return;
        }
        while ( this.hasNext() ) {
            var next = this.next();
            if ( next ) {
                fn(next);
            }
        }
        this.close();
    },

    /**
     *
     */
    close : function() {
        if ( this.cursor ) {
            this.cursor.close();
        }
        this.cursor = null;
    }

});

decaf.extend(exports, {
    Cursor : Cursor
});
<|endoftext|>


<commit_before>/**
 * Class Home
 * @Extend: Entity
 */

 //Falata implementar el danio a los denizen con damageLevel y lifeLevel
 //para eso se puede recorrer los childs hasta encontrar del tipo denizen
 //Falta implmenta que sucedera cuando lleguen a los topes
 //Falta implementar visual de la casa

define(['myclass', 'gma/Entity'], function (my, Entity) {

    "use strict";

    var Home = my.Class(Entity, {

        constructor: function (stage) {
            this.container = '#home_container';
            this.timeToDamage = 5000;
            this.timeToLife = 10000;
            this.minLevel = 0;
            this.maxLevel = 300;

            //Danio o vida que se pueden hacer a los denizen
            this.damageLevel = 0;
            this.lifeLevel = 0;

            //Vida por tipo de energia
            this.giveLifeEnergy =1;
            this.giveLifeWater = 1;
            this.giveLifeRecycling = 1;

            //Valores iniciales de vida
            this.vitality = 0;
            this.energy = 200;
            this.water = 200;
            this.recycling = 200;

            this.rooms = [];
            Home.Super.call(this, stage);
        },

        addRooms: function(rooms){
            var me = this;

            if(_.isArray(rooms)){
                _.each(rooms, function(value, key){
                    me.rooms.push(value);
                })
            } else {
                this.rooms.push(rooms);
            }
        },

        addDamageLevel: function(damage){
            this.damageLevel += damage;
        },

        removeDamage: function(damage){
            this.damageLevel -= damage;
        },

        addLifeLevel: function(life){
            this.lifeLevel += life;
        },

        removeLifeLevel: function(life){
            this.lifeLevel -= life;
        },

        setVitality: function(vitality) {
            $this.vitality = vitality;
        },

        setEnergy: function(energy) {
            $this.energy = energy;
        },

        setWater: function(water) {
            $this.water = water;
        },

        setRecycling: function(recycling) {
            $this.recycling = recycling;
        },

        addEnergy: function (energy) {
            this.energy += energy;
        },

        addWater: function (water) {
            this.water += water;
        },

        addRecycling: function(recycling) {
            this.recycling += recycling;
        },

        removeEnergy: function(energy){
            this.energy -= energy;
        },

        removeWater: function(water){
            this.water -= water;
        },

        removeRecycling: function(recycling){
            this.recycling -= recycling;
        },

        getRecycling: function (recycling) {
            this.recycling += recycling;
        },

        getVitality: function () {
            return this.energy + this.water + this.recycling;
        },

        removePower: function( water, energy, recycling){
            if(water){
                console.log('remove water');
                if(this.minLevel <= this.water - water){
                    this.removeWater(water);
                }
            }

            if(energy){
                if(this.minLevel <= this.energy - energy){
                    this.removeEnergy(energy);
                }
            }

            if(recycling){
                if(this.minLevel <= this.recycling - recycling){
                    this.removeRecycling(recycling);
                }
            }

            this.show();
        },

        addPower: function( water, energy, recycling){
            if(water){
                if(this.maxLevel >= this.water + water){
                    this.addWater(water);
                }
            }

            if(energy){
                if(this.maxLevel >= this.energy + energy){
                    this.addEnergy(energy);
                }
            }

            if(recycling){
                if(this.maxLevel >= this.recycling + recycling){
                    this.addRecycling(recycling);
                }
            }

            this.show();
        },

        damage: function(){
            var me = this;
            var damageEnergy = 0;
            var damageWater = 0;
            var damageRecycling = 0;

            _.each(this.rooms, function(room, key){
                damageEnergy += room.power.energy;
                damageWater += room.power.water;
                damageRecycling += room.power.recycling;
            });

            setTimeout( function(){
                me.removePower(damageWater, damageEnergy, damageRecycling);
                me.damage();
            },me.timeToDamage);
        },

        life: function(){
            var me = this;
            var lifeEnergy = 0;
            var lifeWater = 0;
            var lifeRecycling = 0;
            var damageEnergy = 0;
            var damageWater = 0;
            var damageRecycling = 0;

            _.each(this.rooms, function(room, key){
                damageEnergy += room.power.energy;
                damageWater += room.power.water;
                damageRecycling += room.power.recycling;
            });

            if(damageEnergy == 0){
                lifeEnergy = this.giveLifeEnergy;
            }

            if(damageWater == 0 ){
                lifeWater = this.giveLifeWater;
            }

            if(damageRecycling == 0 ){
                lifeRecycling = this.giveLifeRecycling;
            }

            setTimeout( function(){
                me.addPower(lifeWater, lifeEnergy, lifeRecycling);
                me.life();
            },me.timeToLife);
        },

        show: function(){
            var view = '' + this.getVitality() + '
';

            view += 'Agua: ' + this.water + '
';
            view += 'Energía: ' + this.energy + '
';
            view += 'Reciclado: ' + this.recycling + '
';

            $(this.container).html(view);
        },

        init: function(){
            this.show();
            this.damage();
            this.life();
        }

    });

    return Home;
});<commit_msg>Se comienza desarrollo para vitalidad de los denizen Se mejora la funcionalidad que administra la vitalidad de la casa<commit_after>/**
 * Class Home
 * @Extend: Entity
 */

 //Falata implementar el danio a los denizen con damageLevel y lifeLevel
 //para eso se puede recorrer los childs hasta encontrar del tipo denizen
 //Falta implmenta que sucedera cuando lleguen a los topes
 //Falta implementar visual de la casa

define(['myclass', 'gma/Entity'], function (my, Entity) {

    "use strict";

    var Home = my.Class(Entity, {

        constructor: function (stage) {
            this.container = '#home_container';
            this.timeToDamage = 5000;
            this.timeToLife = 11000;
            this.minLevel = 0;
            this.maxLevel = 300;

            //Daño o vida que se pueden hacer a los denizen
            this.damageDenizen = 0;
            this.lifeDenizen = 0;

            //Vida por tipo de energia
            this.giveLifeEnergy =1;
            this.giveLifeWater = 1;
            this.giveLifeRecycling = 1;

            //Valores iniciales de vida
            this.vitality = 0;
            this.energy = 200;
            this.water = 200;
            this.recycling = 200;

            this.rooms = [];
            this.denizen = [];
            Home.Super.call(this, stage);
        },

        addRooms: function(rooms){
            var me = this;

            if(_.isArray(rooms)){
                _.each(rooms, function(value, key){
                    me.rooms.push(value);
                })
            } else {
                this.rooms.push(rooms);
            }
        },

        damageDenizen : function(){
            _.each(this.denizen, function(denizen, key){
                denizen.vitality -= this.damageDenizen;
            });
        },

        addDamageDenizen: function(damage){
            this.damageDenizen += damage;
        },

        removeDamageDenizen: function(damage){
            this.damageDenizen -= damage;
        },

        addLifeLevel: function(life){
            this.lifeLevel += life;
        },

        removeLifeLevel: function(life){
            this.lifeLevel -= life;
        },

        setVitality: function(vitality) {
            $this.vitality = vitality;
        },

        setEnergy: function(energy) {
            $this.energy = energy;
        },

        setWater: function(water) {
            $this.water = water;
        },

        setRecycling: function(recycling) {
            $this.recycling = recycling;
        },

        addEnergy: function (energy) {
            this.energy += energy;
        },

        addWater: function (water) {
            this.water += water;
        },

        addRecycling: function(recycling) {
            this.recycling += recycling;
        },

        removeEnergy: function(energy){
            this.energy -= energy;
        },

        removeWater: function(water){
            this.water -= water;
        },

        removeRecycling: function(recycling){
            this.recycling -= recycling;
        },

        getRecycling: function (recycling) {
            this.recycling += recycling;
        },

        getVitality: function () {
            return this.energy + this.water + this.recycling;
        },

        removePower: function( water, energy, recycling){
            if(water){
                console.log('remove water');
                if(this.minLevel <= this.water - water){
                    this.removeWater(water);
                } else {
                    this.removeWater(this.water);
                }
            }

            if(energy){
                if(this.minLevel <= this.energy - energy){
                    this.removeEnergy(energy);
                } else {
                    this.removeEnergy(this.energy);
                }
            }

            if(recycling){
                if(this.minLevel <= this.recycling - recycling){
                    this.removeRecycling(recycling);
                } else {
                    this.removeRecycling(this.recycling);
                }
            }

            this.show();
        },

        addPower: function( water, energy, recycling){
            if(water){
                if(this.maxLevel >= this.water + water){
                    this.addWater(water);
                } else {
                    this.addWater(this.maxLevel - this.water);
                }
            }

            if(energy){
                if(this.maxLevel >= this.energy + energy){
                    this.addEnergy(energy);
                } else {
                    this.addEnergy(this.maxLevel - this.energy);
                }
            }

            if(recycling){
                if(this.maxLevel >= this.recycling + recycling){
                    this.addRecycling(recycling);
                } else {
                    this.addRecycling(this.maxLevel - this.recycling);
                }
            }

            this.show();
        },

        damage: function(){
            var me = this;
            var damageEnergy = 0;
            var damageWater = 0;
            var damageRecycling = 0;

            _.each(this.rooms, function(room, key){
                damageEnergy += room.power.energy;
                damageWater += room.power.water;
                damageRecycling += room.power.recycling;
            });

            setTimeout( function(){
                me.removePower(damageWater, damageEnergy, damageRecycling);
                me.damage();
            },me.timeToDamage);
        },

        life: function(){
            var me = this;
            var lifeEnergy = 0;
            var lifeWater = 0;
            var lifeRecycling = 0;
            var damageEnergy = 0;
            var damageWater = 0;
            var damageRecycling = 0;

            _.each(this.rooms, function(room, key){
                damageEnergy += room.power.energy;
                damageWater += room.power.water;
                damageRecycling += room.power.recycling;
            });

            if(damageEnergy == 0){
                lifeEnergy = this.giveLifeEnergy;
            }

            if(damageWater == 0 ){
                lifeWater = this.giveLifeWater;
            }

            if(damageRecycling == 0 ){
                lifeRecycling = this.giveLifeRecycling;
            }

            setTimeout( function(){
                me.addPower(lifeWater, lifeEnergy, lifeRecycling);
                me.life();
            },me.timeToLife);
        },

        show: function(){
            var view = '' + this.getVitality() + '
';

            view += 'Agua: ' + this.water + '
';
            view += 'Energía: ' + this.energy + '
';
            view += 'Reciclado: ' + this.recycling + '
';

            $(this.container).html(view);
        },

        init: function(){
            this.show();
            this.damage();
            this.damageDenizen
            this.life();
        }

    });

    return Home;
});<|endoftext|>


<commit_before>
/**
 * @typedef {Object} logging~LogRecord
 * @property {number} created Time when this record was created.
 * @property {string} name Name of the logger.
 * @property {number} levelno Numeric logging level.
 * @property {string} levelname Text logging level.
 * @property {string} message The logged message.
 * @property {Object=} error The logged error.
 * @property {Object=} extra Extra data.
 */

/**
 * @constructor Logger
 * @param {Object} manager
 * @param {Object} parent
 * @param {string} name
 * @param {number=} level
 */
function Logger(manager, parent, name, level) {
	level = level || Logger.NOTSET;

	if (Logger.getLevelName(level) === '') {
		throw new Error('[Invalid argument] Unknown level: \'' + level + '\'.');
	}

	/**
	 * Instance of manager, which holds the hierarchy of loggers.
	 * @type {Object}
	 */
	this._manager = manager;

	/**
	 * Parent logger.
	 * @type {Object}
	 */
	this._parent = parent;

	/**
	 * Name of this logger.
	 * @type {string}
	 */
	this._name = name;

	/**
	 * The threshold for this logger.
	 * @type {number}
	 */
	this._level = level;

	/**
	 * Array of set handlers.
	 * @type {Array}
	 */
	this._handlers = [];

	/**
	 * @type {boolean}
	 */
	this.disabled = false;

	/**
	 * @type {boolean}
	 */
	this.propagate = true;
}

Logger.NOTSET   = 0;
Logger.DEBUG    = 10;
Logger.INFO     = 20;
Logger.WARNING  = 30;
Logger.ERROR    = 40;
Logger.CRITICAL = 50;

/**
 * Return the textual representation of logging level.
 *
 * @param  {number} level
 * @return {string}
 */
Logger.getLevelName = function(level) {
	var levelName = '';

	if (level === Logger.DEBUG) {
		levelName = 'DEBUG';
	} else if (level === Logger.INFO) {
		levelName = 'INFO';
	} else if (level === Logger.WARNING) {
		levelName = 'WARNING';
	} else if (level === Logger.ERROR) {
		levelName = 'ERROR';
	} else if (level === Logger.CRITICAL) {
		levelName = 'CRITICAL';
	} else if (level === Logger.NOTSET) {
		levelName = 'NOTSET';
	}

	return levelName;
};

/**
 * Return the name of this logger.
 *
 * @return {string}
 */
Logger.prototype.getName = function() {
	return this._name;
};

/**
 * Return a logger which is a descendant to this one.
 *
 * @param  {string} suffix
 * @return {Object}
 */
Logger.prototype.getChild = function(suffix) {
	if (!suffix) {
		throw new Error('[Invalid argument] Argument suffix must be specified.');
	}
	var base = this._name === 'root' ? '' : this._name + '.';
	return this._manager.getLogger(base + suffix);
};

/**
 * Return the effective level for this logger.
 *
 * @return {number}
 */
Logger.prototype.getEffectiveLevel = function() {
	var logger = this;

	while (logger) {
		if (logger._level) {
			return logger._level;
		}
		logger = logger._parent;
	}

	return Logger.NOTSET;
};

/**
 * Is this logger enabled for specified level?
 *
 * @param  {number}  level
 * @return {boolean}
 */
Logger.prototype.isEnabledFor = function(level) {
	return !this.disabled && level >= this.getEffectiveLevel();
};

/**
 * Set the logging level of this logger.
 *
 * @param {number} level
 */
Logger.prototype.setLevel = function(level) {
	if (Logger.getLevelName(level) === '') {
		throw new Error('[Invalid argument] Unknown level: \'' + level + '\'.');
	}

	this._level = level;
};

/**
 * Add the specified handler to this logger.
 *
 * @param {Object} handler
 */
Logger.prototype.addHandler = function(handler) {
	if (typeof handler !== 'object') {
		throw new Error('[Invalid argument] Argument handler must be an object.');
	}

	this._handlers.push(handler);
};

/**
 * Remove the specified handler from this logger.
 *
 * @param  {Object} handler
 */
Logger.prototype.removeHandler = function(handler) {
	var index = this._handlers.indexOf(handler);
	if (index > -1) {
		this._handlers.splice(index, 1);
	}
};

/**
 * Log msg with severity 'DEBUG'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.debug = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.DEBUG, msg, error, extra);
};

/**
 * Log msg with severity 'INFO'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.info = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.INFO, msg, error, extra);
};

/**
 * Log msg with severity 'WARNING'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.warning = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.WARNING, msg, error, extra);
};

/**
 * Log msg with severity 'ERROR'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.error = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.ERROR, msg, error, extra);
};

/**
 * Log msg with severity 'CRITICAL'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.critical = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.CRITICAL, msg, error, extra);
};

/**
 * Return the text representation of this logger.
 *
 * @return {string}
 */
Logger.prototype.toString = function() {
	return '[object logging.Logger]';
};

/**
 * Create a LogRecord object.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 * @return {logging~LogRecord}
 */
Logger.prototype.makeRecord = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	var record = {
		created: Date.now(),
		name: this._name,
		levelno: level,
		levelname: Logger.getLevelName(level),
		message: msg
	};
	if (error) {
		record.error = error;
	}
	if (extra) {
		record = Object.assign(record, extra);
	}

	return record;
};

/**
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype._log = function(level, msg, error, extra) {
	if (this.isEnabledFor(level)) {
		this._callHandlers(this.makeRecord(level, msg, error, extra));
	}
};

/**
 * @param  {logging~LogRecord} record
 */
Logger.prototype._callHandlers = function(record) {
	var logger = this;

	while (logger) {
		logger._handlers.forEach(function(handler) {
			handler.handle(record);
		});

		if (this.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}
};

/**
 * @param  {number} level
 * @param  {string} msg
 */
Logger.prototype._callParent = function(level, msg) {
	this._parent[Logger.getLevelName(level)](msg);
};

module.exports = Logger;
<commit_msg>unused method removed<commit_after>
/**
 * @typedef {Object} logging~LogRecord
 * @property {number} created Time when this record was created.
 * @property {string} name Name of the logger.
 * @property {number} levelno Numeric logging level.
 * @property {string} levelname Text logging level.
 * @property {string} message The logged message.
 * @property {Object=} error The logged error.
 * @property {Object=} extra Extra data.
 */

/**
 * @constructor Logger
 * @param {Object} manager
 * @param {Object} parent
 * @param {string} name
 * @param {number=} level
 */
function Logger(manager, parent, name, level) {
	level = level || Logger.NOTSET;

	if (Logger.getLevelName(level) === '') {
		throw new Error('[Invalid argument] Unknown level: \'' + level + '\'.');
	}

	/**
	 * Instance of manager, which holds the hierarchy of loggers.
	 * @type {Object}
	 */
	this._manager = manager;

	/**
	 * Parent logger.
	 * @type {Object}
	 */
	this._parent = parent;

	/**
	 * Name of this logger.
	 * @type {string}
	 */
	this._name = name;

	/**
	 * The threshold for this logger.
	 * @type {number}
	 */
	this._level = level;

	/**
	 * Array of set handlers.
	 * @type {Array}
	 */
	this._handlers = [];

	/**
	 * @type {boolean}
	 */
	this.disabled = false;

	/**
	 * @type {boolean}
	 */
	this.propagate = true;
}

Logger.NOTSET   = 0;
Logger.DEBUG    = 10;
Logger.INFO     = 20;
Logger.WARNING  = 30;
Logger.ERROR    = 40;
Logger.CRITICAL = 50;

/**
 * Return the textual representation of logging level.
 *
 * @param  {number} level
 * @return {string}
 */
Logger.getLevelName = function(level) {
	var levelName = '';

	if (level === Logger.DEBUG) {
		levelName = 'DEBUG';
	} else if (level === Logger.INFO) {
		levelName = 'INFO';
	} else if (level === Logger.WARNING) {
		levelName = 'WARNING';
	} else if (level === Logger.ERROR) {
		levelName = 'ERROR';
	} else if (level === Logger.CRITICAL) {
		levelName = 'CRITICAL';
	} else if (level === Logger.NOTSET) {
		levelName = 'NOTSET';
	}

	return levelName;
};

/**
 * Return the name of this logger.
 *
 * @return {string}
 */
Logger.prototype.getName = function() {
	return this._name;
};

/**
 * Return a logger which is a descendant to this one.
 *
 * @param  {string} suffix
 * @return {Object}
 */
Logger.prototype.getChild = function(suffix) {
	if (!suffix) {
		throw new Error('[Invalid argument] Argument suffix must be specified.');
	}
	var base = this._name === 'root' ? '' : this._name + '.';
	return this._manager.getLogger(base + suffix);
};

/**
 * Return the effective level for this logger.
 *
 * @return {number}
 */
Logger.prototype.getEffectiveLevel = function() {
	var logger = this;

	while (logger) {
		if (logger._level) {
			return logger._level;
		}
		logger = logger._parent;
	}

	return Logger.NOTSET;
};

/**
 * Is this logger enabled for specified level?
 *
 * @param  {number}  level
 * @return {boolean}
 */
Logger.prototype.isEnabledFor = function(level) {
	return !this.disabled && level >= this.getEffectiveLevel();
};

/**
 * Set the logging level of this logger.
 *
 * @param {number} level
 */
Logger.prototype.setLevel = function(level) {
	if (Logger.getLevelName(level) === '') {
		throw new Error('[Invalid argument] Unknown level: \'' + level + '\'.');
	}

	this._level = level;
};

/**
 * Add the specified handler to this logger.
 *
 * @param {Object} handler
 */
Logger.prototype.addHandler = function(handler) {
	if (typeof handler !== 'object') {
		throw new Error('[Invalid argument] Argument handler must be an object.');
	}

	this._handlers.push(handler);
};

/**
 * Remove the specified handler from this logger.
 *
 * @param  {Object} handler
 */
Logger.prototype.removeHandler = function(handler) {
	var index = this._handlers.indexOf(handler);
	if (index > -1) {
		this._handlers.splice(index, 1);
	}
};

/**
 * Log msg with severity 'DEBUG'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.debug = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.DEBUG, msg, error, extra);
};

/**
 * Log msg with severity 'INFO'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.info = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.INFO, msg, error, extra);
};

/**
 * Log msg with severity 'WARNING'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.warning = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.WARNING, msg, error, extra);
};

/**
 * Log msg with severity 'ERROR'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.error = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.ERROR, msg, error, extra);
};

/**
 * Log msg with severity 'CRITICAL'.
 *
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype.critical = function(msg, error, extra) {
	error = error || null;
	extra = extra || null;

	this._log(Logger.CRITICAL, msg, error, extra);
};

/**
 * Return the text representation of this logger.
 *
 * @return {string}
 */
Logger.prototype.toString = function() {
	return '[object logging.Logger]';
};

/**
 * Create a LogRecord object.
 *
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 * @return {logging~LogRecord}
 */
Logger.prototype.makeRecord = function(level, msg, error, extra) {
	error = error || null;
	extra = extra || null;

	var record = {
		created: Date.now(),
		name: this._name,
		levelno: level,
		levelname: Logger.getLevelName(level),
		message: msg
	};
	if (error) {
		record.error = error;
	}
	if (extra) {
		record = Object.assign(record, extra);
	}

	return record;
};

/**
 * @param  {number} level
 * @param  {string} msg
 * @param  {Object=} error
 * @param  {Object=} extra
 */
Logger.prototype._log = function(level, msg, error, extra) {
	if (this.isEnabledFor(level)) {
		this._callHandlers(this.makeRecord(level, msg, error, extra));
	}
};

/**
 * @param  {logging~LogRecord} record
 */
Logger.prototype._callHandlers = function(record) {
	var logger = this;

	while (logger) {
		logger._handlers.forEach(function(handler) {
			handler.handle(record);
		});

		if (this.propagate) {
			logger = logger._parent;
		} else {
			logger = null;
		}
	}
};

module.exports = Logger;
<|endoftext|>


<commit_before>/* survol du txt */
$(".dep_map").on("mouseover", function() {
  dep = $(this).attr("id").substring(3);
  $(".map"+dep).mouseover();
})
$(".dep_map").on("mouseout", function() {
  dep = $(this).attr("id").substring(3);
  $(".map"+dep).mouseout();
})
/* survol de la map */
var d = { running: '0' };
$("area").on("mouseover", d, function(e) {
  $(this).addClass("hover");
  dep = $(this).attr("id").substring(3,9).replace(/-0$/, "");
  $(".dep"+dep).css("background-color", "#D1EA74");
  $(".dep"+dep).css("opacity", 0.8);
  if (e.data.running == 0) {
    d.running = 1;
    $(".map"+dep).filter(":not(.hover)").mouseover();
    d.running = 0;
  }
})
$("area").on("mouseout", function() {
  $(this).removeClass("hover");
  dep = $(this).attr("id").substring(3,9).replace(/-0$/, "");
  $(".dep"+dep).css("background-color", "#fff");
  $(".dep"+dep).css("opacity", 1);
  $(".map"+dep).filter(".hover").mouseout();
})
<commit_msg>ensure js works on maps<commit_after>$(document).ready(function(){
  /* survol du txt */
  $(".dep_map").on("mouseover", function() {
    dep = $(this).attr("id").substring(3);
  console.log(dep);
    $(".map"+dep).mouseover();
  });
  $(".dep_map").on("mouseout", function() {
    dep = $(this).attr("id").substring(3);
    $(".map"+dep).mouseout();
  });
  /* survol de la map */
  var d = { running: '0' };
  $("area").on("mouseover", d, function(e) {
    $(this).addClass("hover");
    dep = $(this).attr("id").substring(3,9).replace(/-0$/, "");
  console.log(dep, $(this));
    $(".dep"+dep).css("background-color", "#D1EA74");
    $(".dep"+dep).css("opacity", 0.8);
    if (e.data.running == 0) {
      d.running = 1;
      $(".map"+dep).filter(":not(.hover)").mouseover();
      d.running = 0;
    }
  });
  $("area").on("mouseout", function() {
    $(this).removeClass("hover");
    dep = $(this).attr("id").substring(3,9).replace(/-0$/, "");
    $(".dep"+dep).css("background-color", "#fff");
    $(".dep"+dep).css("opacity", 1);
    $(".map"+dep).filter(".hover").mouseout();
  });
});
<|endoftext|>


<commit_before><script type="text/javascript">
/* Jira Comment Numbering
 *
 * Inserts human-readable #1, #2, etc at the top of each comment.
 * Then other humans can type stuff like "I agree with comment #3"
 *
 * Put this in the announcement banner on your jira instance.
 * It's a bit pointless to have this as a tampermonkey script, as
 * you want to be able to use the numbers when communicating with
 * your colleagues, and tampermonkey will only put it in your
 * browser.
 *
 * TODO: Trigger the re-run of number_comments on expansion of
 *       show-more-comments, rather than doing it every 2 seconds
 *       regardless.
 * TODO: Allow #3 type notation within comments that will jump to
 *       the anchor of the referenced comment.
 *
 */
"use strict";

/* Whether to log stuff to console to show it working */
const JCN_LOG_TO_CONSOLE=false;

/* Insert child as the first child nodes of container. */
function prepend( container, child )
{
    container.insertBefore( child, container.childNodes[0] );
}

/* In a jira comments block, we start counting at 1 unless the "show more comments"
 * div is visible. In that case, we start at the number of hidden comments + 1
 */
function get_start_point( activity_comment )
{
    if ( ! activity_comment )
    {
        alert( 'activity_comment was null' );
        return 1;
    }
    var show_more =activity_comment.getElementsByClassName( 'show-more-comments' );
    if ( show_more.length === 0 )
    {
        return 1;
    }
    else
    {
        if ( JCN_LOG_TO_CONSOLE ) console.log( 'show-more found' );
        var number = show_more[0].getAttribute( 'data-collapsed-count' );
        if ( JCN_LOG_TO_CONSOLE ) console.log( number );
        return 1 + parseInt( number );
    }
}

/* true if and only if node is a textnode whose contents match text */
function isTextNodeMatching( node, text )
{
    if ( node.nodeType != 3 )
    {
        return false;
    }
    if ( JCN_LOG_TO_CONSOLE ) console.log( "existing: " + node.textContent );
    if ( JCN_LOG_TO_CONSOLE ) console.log( "new: " + text );
    return ( node.textContent == text ) ;
}

/* insert numbers to the start of the headers of comments on the browse page */
function number_comments( )
{
    if ( JCN_LOG_TO_CONSOLE ) console.log( 'number_comments start' );
    if ( ! document )
    {
        alert( 'document was null' );
        return;
    }
    var comments = document.getElementsByClassName( 'activity-comment' );
    var i;
    var offset = get_start_point( document.getElementById( 'issue_actions_container' ) );
    for ( i = 0; i < comments.length; i++ ) {
        if ( ! comments[i] )
        {
            alert( 'comments[i] was null' );
            continue;
        }
        var deets = comments[i].getElementsByClassName( 'action-details' );
        if ( JCN_LOG_TO_CONSOLE ) console.log( deets );
        var numberText =  "#" + ( i + offset );
        var firstChild =  deets[0].childNodes[0];
        if ( ! isTextNodeMatching( firstChild, numberText ) )
        {
            var newText = document.createTextNode( numberText );
            prepend( deets[0], newText );
        }
    }
    if ( JCN_LOG_TO_CONSOLE ) console.log( 'number_comments done' );
}

/* insert numbers and set an interval to repeat it. This is because triggering
 * number_comments on the click event of show-more-comments didn't always work.
 */
function number_comments_persistently( )
{
  setInterval( number_comments, 2000 );
  number_comments( );
}

/* once the DOM is loaded, start the modifications. */
document.addEventListener( "DOMContentLoaded", number_comments_persistently, false );

</script>
<commit_msg>removed alerts for logging (bad idea in setInterval handler!) now bails out when the page has no comments, avoiding an exception.<commit_after><script type="text/javascript">
/* Jira Comment Numbering
 *
 * Inserts human-readable #1, #2, etc at the top of each comment.
 * Then other humans can type stuff like "I agree with comment #3"
 *
 * Put this in the announcement banner on your jira instance.
 * It's a bit pointless to have this as a tampermonkey script, as
 * you want to be able to use the numbers when communicating with
 * your colleagues, and tampermonkey will only put it in your
 * browser.
 *
 * TODO: Trigger the re-run of number_comments on expansion of
 *       show-more-comments, rather than doing it every 2 seconds
 *       regardless.
 * TODO: Allow #3 type notation within comments that will jump to
 *       the anchor of the referenced comment.
 *
 */
"use strict";

/* Whether to log stuff to console to show it working */
const JCN_LOG_TO_CONSOLE=false;

/* Insert child as the first child nodes of container. */
function prepend( container, child )
{
    container.insertBefore( child, container.childNodes[0] );
}

/* In a jira comments block, we start counting at 1 unless the "show more comments"
 * div is visible. In that case, we start at the number of hidden comments + 1
 */
function get_start_point( issue_actions_container )
{
    if ( ! issue_actions_container )
    {
        if ( JCN_LOG_TO_CONSOLE ) console.log( "issue_actions_container was null" );
        return 1;
    }
    var show_more =issue_actions_container.getElementsByClassName( 'show-more-comments' );
    if ( show_more.length === 0 )
    {
        return 1;
    }
    else
    {
        if ( JCN_LOG_TO_CONSOLE ) console.log( 'show-more found' );
        var number = show_more[0].getAttribute( 'data-collapsed-count' );
        if ( JCN_LOG_TO_CONSOLE ) console.log( number );
        return 1 + parseInt( number );
    }
}

/* true if and only if node is a textnode whose contents match text */
function isTextNodeMatching( node, text )
{
    if ( node.nodeType != 3 )
    {
        return false;
    }
    if ( JCN_LOG_TO_CONSOLE ) console.log( "existing: " + node.textContent );
    if ( JCN_LOG_TO_CONSOLE ) console.log( "new: " + text );
    return ( node.textContent == text ) ;
}

/* insert numbers to the start of the headers of comments on the browse page */
function number_comments( )
{
    if ( JCN_LOG_TO_CONSOLE ) console.log( 'number_comments start' );
    if ( ! document )
    {
        if ( JCN_LOG_TO_CONSOLE ) console.log( "document was null" );
        return;
    }
    var comments = document.getElementsByClassName( 'activity-comment' );
    var i;
    var issue_actions_container = document.getElementById( 'issue_actions_container' )
    if ( ! issue_actions_container )
    {
        /* This doesn't look like an issue view; bail out. */
        return;
    }
    var offset = get_start_point( issue_actions_container );
    for ( i = 0; i < comments.length; i++ ) {
        if ( ! comments[i] )
        {
            alert( 'comments[i] was null' );
            continue;
        }
        var deets = comments[i].getElementsByClassName( 'action-details' );
        if ( JCN_LOG_TO_CONSOLE ) console.log( deets );
        var numberText =  "#" + ( i + offset );
        var firstChild =  deets[0].childNodes[0];
        if ( ! isTextNodeMatching( firstChild, numberText ) )
        {
            var newText = document.createTextNode( numberText );
            prepend( deets[0], newText );
        }
    }
    if ( JCN_LOG_TO_CONSOLE ) console.log( 'number_comments done' );
}

/* insert numbers and set an interval to repeat it. This is because triggering
 * number_comments on the click event of show-more-comments didn't always work.
 */
function number_comments_persistently( )
{
  setInterval( number_comments, 2000 );
  number_comments( );
}

/* once the DOM is loaded, start the modifications. */
document.addEventListener( "DOMContentLoaded", number_comments_persistently, false );

</script>
<|endoftext|>


<commit_before>const Writable = require('stream').Writable;
const Load = require('./Load');
const vocab = 'http://schema.jillix.net/vocab/';

function isBlankNode (string) {
    return string.indexOf('_:') === 0;
}

module.exports = (scope, event, session) => {

    const parser = new Writable({
        objectMode: true,
        write: (triple, enc, done) => {

            let subject = triple[0] || triple.subject;
            let predicate = triple[1] || triple.predicate;
            let object = triple[2] || triple.object;
            let instance;

            switch (predicate) {

                case vocab + 'onEnd':
                    event.end = object;
                    break;

                case vocab + 'onError':
                    event.err = object;
                    break;

                case vocab + 'module':
                    (instance = Load.Instance(scope, subject)) && Load.Module(scope, object, session, instance.done);
                    break;

                case vocab + 'roles':
                    (instance = Load.Instance(scope, subject)) && ((instance.roles = instance.roles || {})[object] = true);
                    break;

                case vocab + 'args':
                    object = object.slice(1, -1);

                    if (isBlankNode(subject)) {
                        event.get(subject).A = object;
                        break;
                    }

                    (instance = Load.Instance(scope, subject)) && (instance.args = object);
                    break;

                case vocab + 'sequence':

                    if (isBlankNode(subject)) {
                        event.get(subject).N = object;
                        break;
                    }

                    event.get(object).F = true;
                    break;

                case vocab + 'instance':
                    event.set(subject);
                    Load.Instance(scope, object, (err, inst) => event.set(subject, err, inst));
                    break;

                case vocab + 'onceHandler':
                    let seq = event.get(subject)
                    seq.D = object.split('#')[1];
                    seq.once = 1;
                    break;

                case vocab + 'dataHandler':
                    event.get(subject).D = object.split('#')[1];
                    break;

                case vocab + 'streamHandler':
                    event.get(subject).S = object.split('#')[1];
                    break;

                case vocab + 'emit':
                    event.get(subject).E = object;
                    break;

                default:
                    parser.emit('error', new Error('[Parser] Unknown triple: ' + predicate));
            }

            done();
        }
    });

    parser.on('finish', () => event.fin());

    return parser;
};
<commit_msg>use strict<commit_after>'use strict'

const Writable = require('stream').Writable;
const Load = require('./Load');
const vocab = 'http://schema.jillix.net/vocab/';

function isBlankNode (string) {
    return string.indexOf('_:') === 0;
}

module.exports = (scope, event, session) => {

    const parser = new Writable({
        objectMode: true,
        write: (triple, enc, done) => {

            let subject = triple[0] || triple.subject;
            let predicate = triple[1] || triple.predicate;
            let object = triple[2] || triple.object;
            let instance;

            switch (predicate) {

                case vocab + 'onEnd':
                    event.end = object;
                    break;

                case vocab + 'onError':
                    event.err = object;
                    break;

                case vocab + 'module':
                    (instance = Load.Instance(scope, subject)) && Load.Module(scope, object, session, instance.done);
                    break;

                case vocab + 'roles':
                    (instance = Load.Instance(scope, subject)) && ((instance.roles = instance.roles || {})[object] = true);
                    break;

                case vocab + 'args':
                    object = object.slice(1, -1);

                    if (isBlankNode(subject)) {
                        event.get(subject).A = object;
                        break;
                    }

                    (instance = Load.Instance(scope, subject)) && (instance.args = object);
                    break;

                case vocab + 'sequence':

                    if (isBlankNode(subject)) {
                        event.get(subject).N = object;
                        break;
                    }

                    event.get(object).F = true;
                    break;

                case vocab + 'instance':
                    event.set(subject);
                    Load.Instance(scope, object, (err, inst) => event.set(subject, err, inst));
                    break;

                case vocab + 'onceHandler':
                    let seq = event.get(subject)
                    seq.D = object.split('#')[1];
                    seq.once = 1;
                    break;

                case vocab + 'dataHandler':
                    event.get(subject).D = object.split('#')[1];
                    break;

                case vocab + 'streamHandler':
                    event.get(subject).S = object.split('#')[1];
                    break;

                case vocab + 'emit':
                    event.get(subject).E = object;
                    break;

                default:
                    parser.emit('error', new Error('[Parser] Unknown triple: ' + predicate));
            }

            done();
        }
    });

    parser.on('finish', () => event.fin());

    return parser;
};
<|endoftext|>


<commit_before>'use strict';

var Message = Message || require('./Message');

var RootCerts = require('./common/RootCerts');

var PayPro = require('./common/PayPro');

var KJUR = require('jsrsasign');

var asn1 = require('asn1.js');
var rfc3280 = require('asn1.js/rfc/3280');
var Certificate = rfc3280.Certificate;

PayPro.prototype.x509Sign = function(key) {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var pki_data = this.get('pki_data'); // contains one or more x509 certs
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var type = pki_type.split('+')[1].toUpperCase();

  var trusted = pki_data.map(function(cert) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    return RootCerts.getTrusted(pem);
  });

  // XXX Figure out what to do here
  if (!trusted.length) {
    // throw new Error('Unstrusted certificate.');
  } else {
    trusted.forEach(function(name) {
      // console.log('Certificate: %s', name);
    });
  }

  var signature = crypto.createSign('RSA-' + type);
  var buf = this.serializeForSig();
  signature.update(buf);
  var sig = signature.sign(key);
  return sig;
};

PayPro.prototype.x509Verify = function() {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var sig = this.get('signature');
  var pki_data = this.get('pki_data');
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var buf = this.serializeForSig();
  var type = pki_type.split('+')[1].toUpperCase();

  var verifier = crypto.createVerify('RSA-' + type);
  verifier.update(buf);

  var signedCert = pki_data[0];
  var der = signedCert.toString('hex');
  var pem = this._DERtoPEM(der, 'CERTIFICATE');
  var verified = verifier.verify(pem, sig);

  var chain = pki_data;

  // Verifying the cert chain:
  // 1. Extract public key from next certificate.
  // 2. Extract signature from current certificate.
  // 3. If current cert is not trusted, verify that the current cert is signed
  //    by NEXT by the certificate.
  // 4. XXX What to do when the certificate is revoked?

  var blen = +type.replace(/[^\d]+/g, '');
  if (blen === 1) blen = 20;
  if (blen === 256) blen = 32;

  chain.forEach(function(cert, i) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    var name = RootCerts.getTrusted(pem);

    var ncert = chain[i + 1];
    // The root cert, check if it's trusted:
    if (!ncert || name) {
      return;
    }
    var nder = ncert.toString('hex');
    var npem = self._DERtoPEM(nder, 'CERTIFICATE');

    // Get public key from next certificate.
    var data = new Buffer(nder, 'hex');
    var nc = Certificate.decode(data, 'der');
    var npubKey = nc.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
    npubKey = self._DERtoPEM(npubKey, 'RSA PUBLIC KEY');

    // Get signature from current certificate.
    var data = new Buffer(der, 'hex');
    var c = Certificate.decode(data, 'der');
    var sig = c.signature.data;

    var verifier = crypto.createVerify('RSA-' + type);

    // Create a To-Be-Signed Certificate using asn1.js:
    // Fails at Issuer:
    var tbs = rfc3280.TBSCertificate.encode(c.tbsCertificate, 'der');
    verifier.update(tbs);

    var v = verifier.verify(npubKey, sig);
    if (!v) {
      verified = false;
    }
  });

  return verified;
};

module.exports = PayPro;
<commit_msg>paypro: verify chain refactor.<commit_after>'use strict';

var Message = Message || require('./Message');

var RootCerts = require('./common/RootCerts');

var PayPro = require('./common/PayPro');

var KJUR = require('jsrsasign');

var asn1 = require('asn1.js');
var rfc3280 = require('asn1.js/rfc/3280');
var Certificate = rfc3280.Certificate;

PayPro.prototype.x509Sign = function(key) {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var pki_data = this.get('pki_data'); // contains one or more x509 certs
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var type = pki_type.split('+')[1].toUpperCase();

  var trusted = pki_data.map(function(cert) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    return RootCerts.getTrusted(pem);
  });

  // XXX Figure out what to do here
  if (!trusted.length) {
    // throw new Error('Unstrusted certificate.');
  } else {
    trusted.forEach(function(name) {
      // console.log('Certificate: %s', name);
    });
  }

  var signature = crypto.createSign('RSA-' + type);
  var buf = this.serializeForSig();
  signature.update(buf);
  var sig = signature.sign(key);
  return sig;
};

PayPro.prototype.x509Verify = function() {
  var self = this;
  var crypto = require('crypto');
  var pki_type = this.get('pki_type');
  var sig = this.get('signature');
  var pki_data = this.get('pki_data');
  pki_data = PayPro.X509Certificates.decode(pki_data);
  pki_data = pki_data.certificate;
  var details = this.get('serialized_payment_details');
  var buf = this.serializeForSig();
  var type = pki_type.split('+')[1].toUpperCase();

  var verifier = crypto.createVerify('RSA-' + type);
  verifier.update(buf);

  var signedCert = pki_data[0];
  var der = signedCert.toString('hex');
  var pem = this._DERtoPEM(der, 'CERTIFICATE');
  var verified = verifier.verify(pem, sig);

  var chain = pki_data;

  // Verifying the cert chain:
  // 1. Extract public key from next certificate.
  // 2. Extract signature from current certificate.
  // 3. If current cert is not trusted, verify that the current cert is signed
  //    by NEXT by the certificate.
  // NOTE: XXX What to do when the certificate is revoked?

  var chainVerified = chain.every(function(cert, i) {
    var der = cert.toString('hex');
    var pem = self._DERtoPEM(der, 'CERTIFICATE');
    var name = RootCerts.getTrusted(pem);

    var ncert = chain[i + 1];
    // The root cert, check if it's trusted:
    if (!ncert || name) {
      chain.length = 0;
      return true;
    }
    var nder = ncert.toString('hex');
    var npem = self._DERtoPEM(nder, 'CERTIFICATE');

    // Get public key from next certificate:
    var data = new Buffer(nder, 'hex');
    var nc = Certificate.decode(data, 'der');
    var npubKey = nc.tbsCertificate.subjectPublicKeyInfo.subjectPublicKey.data;
    npubKey = self._DERtoPEM(npubKey, 'RSA PUBLIC KEY');

    // Get signature from current certificate:
    var data = new Buffer(der, 'hex');
    var c = Certificate.decode(data, 'der');
    var sig = c.signature.data;

    var verifier = crypto.createVerify('RSA-' + type);

    // Create a To-Be-Signed Certificate to verify using asn1.js:
    // Fails at Issuer:
    var tbs = rfc3280.TBSCertificate.encode(c.tbsCertificate, 'der');
    verifier.update(tbs);

    return verifier.verify(npubKey, sig);
  });

  return verified && chainVerified;
};

module.exports = PayPro;
<|endoftext|>