<commit_before>(function(d) {
  "use strict";

  var SpotifyRemoteClient = function(host) {
    this.host                  = host || window.location.hostname;
    this.elements              = [];
    this._canTouchThis         = 'ontouchstart' in window || 'createTouch' in d;
    this._volumeRangeBlocked   = false;
    this._positionRangeBlocked = false;
  };

  SpotifyRemoteClient.prototype.init = function(io, container) {
    this.socket    = io.connect(this.host);
    this.container = container;

    this.socket.on('currentTrack', this.showCurrentTrack.bind(this));
    this.socket.on('currentState', this.showCurrentState.bind(this));
    this.socket.on('currentArtwork', this.showCurrentArtwork.bind(this));

    var body = d.getElementsByTagName('body')[0];

    body.addEventListener(
      'click',
      function(event) {
        var command = {
          'previous': 'previous',
          'next': 'next',
          'current-play-state': 'playPause'
        }[event.target.id];

        if (command) this._emit(command);

        event.preventDefault();
      }.bind(this)
    );

    body.addEventListener(
      'keyup',
      function(event) {
        var command = {
          32: 'playPause',   // space
          78: 'next',        // n
          80: 'previous',    // p
          107: 'volumeUp',   // + on numpad
          109: 'volumeDown', // - on numpad
          187: 'volumeUp',   // +
          189: 'volumeDown'  // -
        }[event.keyCode];

        if (command) this._emit(command);
      }.bind(this)
    );

    // volume control
    this.$('current-volume').addEventListener(
      'change',
      function(event) {
        this.socket.emit('setVolume', event.target.value);
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._volumeRangeBlocked = true;
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function() {
        this._volumeRangeBlocked = false;
      }.bind(this)
    );

    // position control
    this.$('position').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._positionRangeBlocked = true;
      }.bind(this)
    );

    this.$('position').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function(event) {
        this.socket.emit('jumpTo', event.target.value);
        this._positionRangeBlocked = false;
      }.bind(this)
    );
  };

  SpotifyRemoteClient.prototype.showCurrentTrack = function(track) {
    // don't rerender stuff when nothing has changed
    if (this.currentTrack && this.currentTrack.id == track.id) {
      return;
    }

    this.$('artist').textContent   = track.artist;
    this.$('name').textContent     = track.name;
    this.$('duration').textContent = formatTime(track.duration);
    this.$('position').setAttribute('max', track.duration);

    this.currentTrack = track;
  };

  SpotifyRemoteClient.prototype.showCurrentState = function(state) {
    if (!this.currentState || this.currentState.position !== state.position) {
      this.$('played-time').textContent = formatTime(parseInt(state.position, 10));

      if (!this._positionRangeBlocked) {
        this.$('position').value = state.position.replace(',', '.');
      }
    }

    if (!this.currentState || this.currentState.state !== state.state) {
      this.$('current-play-state').textContent = state.state == 'paused' ? 'Play' : 'Pause';
    }

    if (!this._volumeRangeBlocked && (!this.currentState || this.currentState.volume !== state.volume)) {
      this.$('current-volume').value = state.volume;
    }

    this.currentState = state;
  };

  SpotifyRemoteClient.prototype.showCurrentArtwork = function(artwork) {
    this.$('artwork').src = 'data:image/png;base64,' + artwork;
  };

  SpotifyRemoteClient.prototype._emit = function(command) {
    this.socket.emit(command);
  };

  // jQuery.
  SpotifyRemoteClient.prototype.$ = function(id) {
    this.elements[id] = this.elements[id] || d.getElementById(id);

    return this.elements[id];
  };

  function formatTime(totalSeconds) {
    var minutes = Math.floor(totalSeconds / 60);
    var seconds = totalSeconds % 60;

    minutes = minutes < 10 ? '0' + minutes : minutes;
    seconds = seconds < 10 ? '0' + seconds : seconds;

    return minutes + ":" + seconds;
  };

  var client = new SpotifyRemoteClient();
  client.init(io, d.getElementById('remote-control'));
})(document);
<commit_msg>Remove _emit on client, wasn't much of a use anyway<commit_after>(function(d) {
  "use strict";

  var SpotifyRemoteClient = function(host) {
    this.host                  = host || window.location.hostname;
    this.elements              = [];
    this._canTouchThis         = 'ontouchstart' in window || 'createTouch' in d;
    this._volumeRangeBlocked   = false;
    this._positionRangeBlocked = false;
  };

  SpotifyRemoteClient.prototype.init = function(io, container) {
    this.socket    = io.connect(this.host);
    this.container = container;

    this.socket.on('currentTrack', this.showCurrentTrack.bind(this));
    this.socket.on('currentState', this.showCurrentState.bind(this));
    this.socket.on('currentArtwork', this.showCurrentArtwork.bind(this));

    var body = d.getElementsByTagName('body')[0];

    body.addEventListener(
      'click',
      function(event) {
        var command = {
          'previous': 'previous',
          'next': 'next',
          'current-play-state': 'playPause'
        }[event.target.id];

        if (command) this.socket.emit(command);

        event.preventDefault();
      }.bind(this)
    );

    body.addEventListener(
      'keyup',
      function(event) {
        var command = {
          32: 'playPause',   // space
          78: 'next',        // n
          80: 'previous',    // p
          107: 'volumeUp',   // + on numpad
          109: 'volumeDown', // - on numpad
          187: 'volumeUp',   // +
          189: 'volumeDown'  // -
        }[event.keyCode];

        if (command) this.socket.emit(command);
      }.bind(this)
    );

    // volume control
    this.$('current-volume').addEventListener(
      'change',
      function(event) {
        this.socket.emit('setVolume', event.target.value);
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._volumeRangeBlocked = true;
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function() {
        this._volumeRangeBlocked = false;
      }.bind(this)
    );

    // position control
    this.$('position').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._positionRangeBlocked = true;
      }.bind(this)
    );

    this.$('position').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function(event) {
        this.socket.emit('jumpTo', event.target.value);
        this._positionRangeBlocked = false;
      }.bind(this)
    );
  };

  SpotifyRemoteClient.prototype.showCurrentTrack = function(track) {
    // don't rerender stuff when nothing has changed
    if (this.currentTrack && this.currentTrack.id == track.id) {
      return;
    }

    this.$('artist').textContent   = track.artist;
    this.$('name').textContent     = track.name;
    this.$('duration').textContent = formatTime(track.duration);
    this.$('position').setAttribute('max', track.duration);

    this.currentTrack = track;
  };

  SpotifyRemoteClient.prototype.showCurrentState = function(state) {
    if (!this.currentState || this.currentState.position !== state.position) {
      this.$('played-time').textContent = formatTime(parseInt(state.position, 10));

      if (!this._positionRangeBlocked) {
        this.$('position').value = state.position.replace(',', '.');
      }
    }

    if (!this.currentState || this.currentState.state !== state.state) {
      this.$('current-play-state').textContent = state.state == 'paused' ? 'Play' : 'Pause';
    }

    if (!this._volumeRangeBlocked && (!this.currentState || this.currentState.volume !== state.volume)) {
      this.$('current-volume').value = state.volume;
    }

    this.currentState = state;
  };

  SpotifyRemoteClient.prototype.showCurrentArtwork = function(artwork) {
    this.$('artwork').src = 'data:image/png;base64,' + artwork;
  };

  // jQuery.
  SpotifyRemoteClient.prototype.$ = function(id) {
    this.elements[id] = this.elements[id] || d.getElementById(id);

    return this.elements[id];
  };

  function formatTime(totalSeconds) {
    var minutes = Math.floor(totalSeconds / 60);
    var seconds = totalSeconds % 60;

    minutes = minutes < 10 ? '0' + minutes : minutes;
    seconds = seconds < 10 ? '0' + seconds : seconds;

    return minutes + ":" + seconds;
  };

  var client = new SpotifyRemoteClient();
  client.init(io, d.getElementById('remote-control'));
})(document);
<|endoftext|>


<commit_before>(function(d) {
  "use strict";

  var SpotifyRemoteClient = function(host) {
    this.host                  = host || window.location.hostname;
    this.elements              = [];
    this._canTouchThis         = 'ontouchstart' in window || 'createTouch' in d;
    this._volumeRangeBlocked   = false;
    this._positionRangeBlocked = false;
  };

  SpotifyRemoteClient.prototype.init = function(io, container) {
    this.socket    = io.connect(this.host);
    this.container = container;

    this.socket.on('currentTrack', this.showCurrentTrack.bind(this));
    this.socket.on('currentState', this.showCurrentState.bind(this));
    this.socket.on('currentArtwork', this.showCurrentArtwork.bind(this));

    var body = d.getElementsByTagName('body')[0];

    body.addEventListener(
      'click',
      function(event) {
        var command = {
          'previous': 'previous',
          'next': 'next',
          'current-play-state': 'playPause'
        }[event.target.id];

        if (command) this.socket.emit(command);

        event.preventDefault();
      }.bind(this)
    );

    body.addEventListener(
      'keyup',
      function(event) {
        var command = {
          32: 'playPause',   // space
          78: 'next',        // n
          80: 'previous',    // p
          107: 'volumeUp',   // + on numpad
          109: 'volumeDown', // - on numpad
          187: 'volumeUp',   // +
          189: 'volumeDown'  // -
        }[event.keyCode];

        if (command) this.socket.emit(command);
      }.bind(this)
    );

    // volume control
    this.$('current-volume').addEventListener(
      'change',
      function(event) {
        this.socket.emit('setVolume', event.target.value);
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._volumeRangeBlocked = true;
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function() {
        this._volumeRangeBlocked = false;
      }.bind(this)
    );

    // position control
    this.$('position').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._positionRangeBlocked = true;
      }.bind(this)
    );

    this.$('position').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function(event) {
        this.socket.emit('jumpTo', event.target.value);
        this._positionRangeBlocked = false;
      }.bind(this)
    );
  };

  SpotifyRemoteClient.prototype.showCurrentTrack = function(track) {
    // don't rerender stuff when nothing has changed
    if (this.currentTrack && this.currentTrack.id == track.id) {
      return;
    }

    this.$('artist').textContent   = track.artist;
    this.$('name').textContent     = track.name;
    this.$('duration').textContent = formatTime(track.duration);
    this.$('position').setAttribute('max', track.duration);

    this.currentTrack = track;
  };

  SpotifyRemoteClient.prototype.showCurrentState = function(state) {
    if (!this.currentState || this.currentState.position !== state.position) {
      this.$('played-time').textContent = formatTime(parseInt(state.position, 10));

      if (!this._positionRangeBlocked) {
        this.$('position').value = state.position.replace(',', '.');
      }
    }

    if (!this.currentState || this.currentState.state !== state.state) {
      this.$('current-play-state').textContent = state.state == 'paused' ? 'Play' : 'Pause';
    }

    if (!this._volumeRangeBlocked && (!this.currentState || this.currentState.volume !== state.volume)) {
      this.$('current-volume').value = state.volume;
    }

    this.currentState = state;
  };

  SpotifyRemoteClient.prototype.showCurrentArtwork = function(artwork) {
    this.$('artwork').src = 'data:image/png;base64,' + artwork;
  };

  // jQuery.
  SpotifyRemoteClient.prototype.$ = function(id) {
    this.elements[id] = this.elements[id] || d.getElementById(id);

    return this.elements[id];
  };

  function formatTime(totalSeconds) {
    var minutes = Math.floor(totalSeconds / 60);
    var seconds = totalSeconds % 60;

    minutes = minutes < 10 ? '0' + minutes : minutes;
    seconds = seconds < 10 ? '0' + seconds : seconds;

    return minutes + ":" + seconds;
  };

  var client = new SpotifyRemoteClient();
  client.init(io, d.getElementById('remote-control'));
})(document);
<commit_msg>Use touchstart instead of click for touch devices<commit_after>(function(d) {
  "use strict";

  var SpotifyRemoteClient = function(host) {
    this.host                  = host || window.location.hostname;
    this.elements              = [];
    this._canTouchThis         = 'ontouchstart' in window || 'createTouch' in d;
    this._volumeRangeBlocked   = false;
    this._positionRangeBlocked = false;
  };

  SpotifyRemoteClient.prototype.init = function(io, container) {
    this.socket    = io.connect(this.host);
    this.container = container;

    this.socket.on('currentTrack', this.showCurrentTrack.bind(this));
    this.socket.on('currentState', this.showCurrentState.bind(this));
    this.socket.on('currentArtwork', this.showCurrentArtwork.bind(this));

    var body = d.getElementsByTagName('body')[0];

    body.addEventListener(
      this._canTouchThis ? 'touchstart' : 'click',
      function(event) {
        var command = {
          'previous': 'previous',
          'next': 'next',
          'current-play-state': 'playPause'
        }[event.target.id];

        if (command) this.socket.emit(command);

        event.preventDefault();
      }.bind(this)
    );

    body.addEventListener(
      'keyup',
      function(event) {
        var command = {
          32: 'playPause',   // space
          78: 'next',        // n
          80: 'previous',    // p
          107: 'volumeUp',   // + on numpad
          109: 'volumeDown', // - on numpad
          187: 'volumeUp',   // +
          189: 'volumeDown'  // -
        }[event.keyCode];

        if (command) this.socket.emit(command);
      }.bind(this)
    );

    // volume control
    this.$('current-volume').addEventListener(
      'change',
      function(event) {
        this.socket.emit('setVolume', event.target.value);
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._volumeRangeBlocked = true;
      }.bind(this)
    );

    this.$('current-volume').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function() {
        this._volumeRangeBlocked = false;
      }.bind(this)
    );

    // position control
    this.$('position').addEventListener(
      this._canTouchThis ? 'touchstart' : 'mousedown',
      function() {
        this._positionRangeBlocked = true;
      }.bind(this)
    );

    this.$('position').addEventListener(
      this._canTouchThis ? 'touchend' : 'mouseup',
      function(event) {
        this.socket.emit('jumpTo', event.target.value);
        this._positionRangeBlocked = false;
      }.bind(this)
    );
  };

  SpotifyRemoteClient.prototype.showCurrentTrack = function(track) {
    // don't rerender stuff when nothing has changed
    if (this.currentTrack && this.currentTrack.id == track.id) {
      return;
    }

    this.$('artist').textContent   = track.artist;
    this.$('name').textContent     = track.name;
    this.$('duration').textContent = formatTime(track.duration);
    this.$('position').setAttribute('max', track.duration);

    this.currentTrack = track;
  };

  SpotifyRemoteClient.prototype.showCurrentState = function(state) {
    if (!this.currentState || this.currentState.position !== state.position) {
      this.$('played-time').textContent = formatTime(parseInt(state.position, 10));

      if (!this._positionRangeBlocked) {
        this.$('position').value = state.position.replace(',', '.');
      }
    }

    if (!this.currentState || this.currentState.state !== state.state) {
      this.$('current-play-state').textContent = state.state == 'paused' ? 'Play' : 'Pause';
    }

    if (!this._volumeRangeBlocked && (!this.currentState || this.currentState.volume !== state.volume)) {
      this.$('current-volume').value = state.volume;
    }

    this.currentState = state;
  };

  SpotifyRemoteClient.prototype.showCurrentArtwork = function(artwork) {
    this.$('artwork').src = 'data:image/png;base64,' + artwork;
  };

  // jQuery.
  SpotifyRemoteClient.prototype.$ = function(id) {
    this.elements[id] = this.elements[id] || d.getElementById(id);

    return this.elements[id];
  };

  function formatTime(totalSeconds) {
    var minutes = Math.floor(totalSeconds / 60);
    var seconds = totalSeconds % 60;

    minutes = minutes < 10 ? '0' + minutes : minutes;
    seconds = seconds < 10 ? '0' + seconds : seconds;

    return minutes + ":" + seconds;
  };

  var client = new SpotifyRemoteClient();
  client.init(io, d.getElementById('remote-control'));
})(document);
<|endoftext|>


<commit_before>
// var now = new Date();
var now = Date.parse("Thu, 11 May 2017 09:21:00 +0200");

function showTalks(){
    var currentTalks = [];
    var nextTalks = [];

    for(var t in tracks){
        var track = tracks[t];
        for(var i=0;i<track.length;i++){
            var talk = track[i];
            if(talk.start <= now && talk.end >= now){
                currentTalks.push(talk);
            } else if(talk.start > now) {
                if(talk.track == showTrack){
                    nextTalks.push(talk);
                } else {
                    var addIt = true;
                    for(var n = 0; n < nextTalks.length; n++){
                        if(nextTalks[n].track == talk.track){
                            if(nextTalks[n].start > talk.start){
                                nextTalks.splice(n, 1);
                            }else{
                                addIt = false;
                            }
                            break;
                        }
                    }
                    if(addIt) {
                        nextTalks.push(talk);
                    }
                }
            }
        }
    }

    // Display the current date
    $(".js-slides-currentDate").append(formatDate(new Date(now)) + " " + formatTime(new Date(now)));

    var t = jQuery("#target");
    t.empty();

    var markup = "
Currently
";

    // -- Current talks
    if (currentTalks.length > 0) {
        markup += "
";
        //markup += "Currently in other tracks:";
        markup += "
";
        for(var n = 0; n < currentTalks.length; n++) {
            var talk = currentTalks[n];
            markup += "
";
            markup +=     "
";
            markup +=         "
"+talk.track+"
";
            markup +=         talkToString(talk);
            markup +=     "
";
            markup += "
";
        }
        markup += "
";
        markup += "
";
    }

    markup += "
Next
";

    // -- Next talks
    if (nextTalks.length > 0) {
        markup += "
";
        //markup += "Next in other tracks:";
        markup += "
";
        for (var n = 0; n < nextTalks.length; n++) {
            var talk = nextTalks[n];
            markup += "
";
            markup +=     "
";
            markup +=         "
"+talk.track+"
";
            markup +=         talkToString(talk);
            markup +=     "
";
            markup += "
";
        }
        markup += "
";
        markup += "
";
    }

    t.append(markup);
}
var months = [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Decembre",
];
function formatDate(date){
    return pad(date.getDate()) + " " + months[date.getMonth()];
}
function formatTime(date){
    return pad(date.getHours()) + ":" + pad(date.getMinutes());
}
function pad(num) {
    var s = num+"";
    while (s.length < 2) s = "0" + s;
    return s;
}
function duration(time){
    var seconds = Math.floor(time / 1000);
    var minutes = Math.floor(seconds / 60);
    var secondsMod = seconds % 60;
    var hours = Math.floor(minutes / 60);
    var minutesMod = minutes % 60;
    var days = Math.floor(hours / 24);
    var hoursMod = hours % 24;
    var weeks = Math.floor(days / 7);
    var daysMod = days % 7;

    var ret="";
    if(weeks > 0)
        ret += weeks+" weeks ";
    if(daysMod > 0)
        ret += daysMod+" days ";
    if(hoursMod > 0)
        ret += hoursMod+" hours ";
    if(minutesMod > 0)
        ret += minutesMod+" minutes ";
    if(secondsMod > 0)
        ret += secondsMod+" seconds";
    return ret;
}

function talkToString(talk){
    if(talk == null)
        return "";
    var start = new Date(talk.start);
    var end = new Date(talk.end);
    var durationString;
    if(start.getTime() > now){
        durationString = " (in " + duration(start.getTime() - now)+")";
    }else{
        durationString = " (" + duration(end.getTime() - now)+" remaining)";
    }
    var markup = "
";

    // Title
    markup += "
" + talk.title + "
";

    // Slot
    markup += "
"
            + "    "
            +      formatTime(start) + " - " + formatTime(end) + durationString
            + "
";

    // Theme
    if (talk.theme) {
        markup += "" + talk.theme + "";
    }

    // Level
    if (talk.level) {
        markup += "" + talk.level + "";
    }

    //markup += "
"+talk.description+"
";

    // Speakers
    markup += "
";
    for(var n = 0; n < talk.speakers.length; n++) {
        var speaker = talk.speakers[n];
        markup += "
";
            markup += "

";
            markup += "
" + speaker.name + "
";
        markup += "
";
    }
    markup += "
";

    // End of the div .talk
    markup += "
";
    return markup;
}

jQuery(function(){
    showTalks();
});
<commit_msg>Only display single next talk for current track<commit_after>
// var now = new Date();
var now = Date.parse("Thu, 11 May 2017 09:21:00 +0200");

function showTalks(){
    var currentTalks = [];
    var nextTalks = [];

    for(var t in tracks){
        var track = tracks[t];
        for(var i=0;i<track.length;i++){
            var talk = track[i];
            if(talk.start <= now && talk.end >= now){
                currentTalks.push(talk);
            } else if(talk.start > now) {
                var addIt = true;
                for(var n = 0; n < nextTalks.length; n++){
                    if(nextTalks[n].track == talk.track){
                        if(nextTalks[n].start > talk.start){
                            nextTalks.splice(n, 1);
                        }else{
                            addIt = false;
                        }
                        break;
                    }
                }
                if(addIt) {
                    nextTalks.push(talk);
                }
            }
        }
    }

    // Display the current date
    $(".js-slides-currentDate").append(formatDate(new Date(now)) + " " + formatTime(new Date(now)));

    var t = jQuery("#target");
    t.empty();

    var markup = "
Currently
";

    // -- Current talks
    if (currentTalks.length > 0) {
        markup += "
";
        //markup += "Currently in other tracks:";
        markup += "
";
        for(var n = 0; n < currentTalks.length; n++) {
            var talk = currentTalks[n];
            markup += "
";
            markup +=     "
";
            markup +=         "
"+talk.track+"
";
            markup +=         talkToString(talk);
            markup +=     "
";
            markup += "
";
        }
        markup += "
";
        markup += "
";
    }

    markup += "
Next
";

    // -- Next talks
    if (nextTalks.length > 0) {
        markup += "
";
        //markup += "Next in other tracks:";
        markup += "
";
        for (var n = 0; n < nextTalks.length; n++) {
            var talk = nextTalks[n];
            markup += "
";
            markup +=     "
";
            markup +=         "
"+talk.track+"
";
            markup +=         talkToString(talk);
            markup +=     "
";
            markup += "
";
        }
        markup += "
";
        markup += "
";
    }

    t.append(markup);
}
var months = [
"Janvier",
"Février",
"Mars",
"Avril",
"Mai",
"Juin",
"Juillet",
"Août",
"Septembre",
"Octobre",
"Novembre",
"Decembre",
];
function formatDate(date){
    return pad(date.getDate()) + " " + months[date.getMonth()];
}
function formatTime(date){
    return pad(date.getHours()) + ":" + pad(date.getMinutes());
}
function pad(num) {
    var s = num+"";
    while (s.length < 2) s = "0" + s;
    return s;
}
function duration(time){
    var seconds = Math.floor(time / 1000);
    var minutes = Math.floor(seconds / 60);
    var secondsMod = seconds % 60;
    var hours = Math.floor(minutes / 60);
    var minutesMod = minutes % 60;
    var days = Math.floor(hours / 24);
    var hoursMod = hours % 24;
    var weeks = Math.floor(days / 7);
    var daysMod = days % 7;

    var ret="";
    if(weeks > 0)
        ret += weeks+" weeks ";
    if(daysMod > 0)
        ret += daysMod+" days ";
    if(hoursMod > 0)
        ret += hoursMod+" hours ";
    if(minutesMod > 0)
        ret += minutesMod+" minutes ";
    if(secondsMod > 0)
        ret += secondsMod+" seconds";
    return ret;
}

function talkToString(talk){
    if(talk == null)
        return "";
    var start = new Date(talk.start);
    var end = new Date(talk.end);
    var durationString;
    if(start.getTime() > now){
        durationString = " (in " + duration(start.getTime() - now)+")";
    }else{
        durationString = " (" + duration(end.getTime() - now)+" remaining)";
    }
    var markup = "
";

    // Title
    markup += "
" + talk.title + "
";

    // Slot
    markup += "
"
            + "    "
            +      formatTime(start) + " - " + formatTime(end) + durationString
            + "
";

    // Theme
    if (talk.theme) {
        markup += "" + talk.theme + "";
    }

    // Level
    if (talk.level) {
        markup += "" + talk.level + "";
    }

    //markup += "
"+talk.description+"
";

    // Speakers
    markup += "
";
    for(var n = 0; n < talk.speakers.length; n++) {
        var speaker = talk.speakers[n];
        markup += "
";
            markup += "

";
            markup += "
" + speaker.name + "
";
        markup += "
";
    }
    markup += "
";

    // End of the div .talk
    markup += "
";
    return markup;
}

jQuery(function(){
    showTalks();
});
<|endoftext|>


<commit_before>/*   Copyright (c) 2010, Diaspora Inc.  This file is
 *   licensed under the Affero General Public License version 3 or later.  See
 *   the COPYRIGHT file.
 */

var Stream = {
  selector: "#main_stream",

  initialize: function() {
    Diaspora.widgets.timeago.updateTimeAgo();
    Diaspora.widgets.directionDetector.updateBinds();

    $.each(["a.stream_element_delete", "span.post_scope"], function(idx, el){
      $(el).tipsy({
        trigger: "hover",
        gravity: "n"
      });
    });

    //audio links
    Stream.setUpAudioLinks();
    //Stream.setUpImageLinks();

    Diaspora.widgets.subscribe("stream/scrolled", Stream.collapseText);
    Stream.collapseText('eventID', $(Stream.selector)[0]);
  },
  collapseText: function(){
    elements = $(Array.prototype.slice.call(arguments,1));
    // collapse long posts
    $(".content p", elements).expander({
      slicePoint: 400,
      widow: 12,
      expandText: Diaspora.widgets.i18n.t("show_more"),
      userCollapse: false
    });

    // collapse long comments
    $(".comment .content span", elements).expander({
      slicePoint: 200,
      widow: 18,
      expandText: Diaspora.widgets.i18n.t("show_more"),
      userCollapse: false
    });
  },
  initializeLives: function(){
    // reshare button action
    $(".reshare_button", this.selector).live("click", function(evt) {
      evt.preventDefault();
      var button = $(this),
        box = button.siblings(".reshare_box");

      if (box.length > 0) {
        button.toggleClass("active");
        box.toggle();
      }
    });

    this.setUpComments();
  },

  setUpComments: function(){
    $("a.toggle_post_comments:not(.show)", this.selector).live('click', Stream.toggleComments);
    // comment link form focus
    $(".focus_comment_textarea", this.selector).live('click', function(evt) {
      Stream.focusNewComment($(this), evt);
    });

    $(".new_comment", this.selector).live("ajax:failure", function() {
       Diaspora.widgets.alert.alert(Diaspora.widgets.i18n.t("failed_to_post_message"));
    });

    $(".comment .comment_delete", this.selector).live("ajax:success", function() {
      var element = $(this),
        target = element.parents(".comment"),
        post = element.closest(".stream_element"),
        toggler = post.find(".toggle_post_comments");

      target.hide("blind", { direction: "vertical" }, 300, function() {
        $(this).remove();
        toggler.html(
          toggler.html().replace(/\d+/, $(".comments li", post).length - 1)
        );
      });

    });

    $("textarea.comment_box", this.selector).live("focus", function(evt) {
      if (this.value === undefined || this.value ===  ''){
        var commentBox = $(this);
        commentBox
          .parent().parent()
            .addClass("open");
      }
    });
    $("textarea.comment_box", this.selector).live("blur", function(evt) {
      if (this.value === undefined || this.value ===  ''){
        var commentBox = $(this);
        commentBox
          .parent().parent()
            .removeClass("open");
      }
    });

  },

  setUpAudioLinks: function() {
    $(".stream a[target='_blank']").each(function(r){
      var link = $(this);
      if(this.href.match(/\.mp3$|\.ogg$/)) {
        $("<audio/>", {
          preload: "none",
          src: this.href,
          controls: "controls"
        }).appendTo(link.parent());

        link.remove();
      }
    });
  },

  setUpImageLinks: function() {
    $(".stream a[target='_blank']").each(function() {
      var link = $(this);
      if(this.href.match(/\.gif$|\.jpg$|\.png$|\.jpeg$/)) {
        $("", {
          src: this.href
        }).appendTo(link.parent());

        link.remove();
      }
    });
  },

  toggleComments: function(evt) {
    evt.preventDefault();

    var $toggler = $(this),
        comments = $toggler.closest('.stream_element').find('ul.comments');

    if (comments.hasClass('loaded') && !comments.hasClass('hidden')){
      Stream.hideComments.apply($toggler);
    }else {
      Stream.showComments.apply($toggler);
    }
  },
  showComments: function(){
    var commentList = this.closest('.stream_element').find('ul.comments'),
        toggle = this;

    if( commentList.hasClass('loaded') ){
        toggle.html(Diaspora.widgets.i18n.t("comments.hide"));
        commentList.removeClass('hidden');
    }
    else {
      toggle.append("");
      $.ajax({
        url: this.attr('href'),
        success: function(data){
          toggle.html(Diaspora.widgets.i18n.t("comments.hide"));
          commentList.html(data)
                     .addClass('loaded');
          Diaspora.widgets.publish("stream/scrolled", commentList);
        }
      });
    }
  },

  hideComments: function(){
    var commentList = this.closest('.stream_element').find('ul.comments');
    commentList.addClass('hidden');
    this.html(Diaspora.widgets.i18n.t("comments.show"));
  },

  focusNewComment: function(toggle, evt) {
    evt.preventDefault();
    var post = toggle.closest(".stream_element");
    var commentBlock = post.find(".new_comment_form_wrapper");
    var textarea = post.find(".new_comment textarea");

    if(commentBlock.hasClass("hidden")) {
      commentBlock.removeClass("hidden");
      textarea.focus();
    } else {
      if(commentBlock.children().length <= 1) {
        commentBlock.addClass("hidden");
      } else {
        textarea.focus();
      }
    }
  }
};

$(document).ready(function() {
  if( $(Stream.selector).length == 0 ) { return }
  Stream.initializeLives();
  Diaspora.widgets.subscribe("stream/reloaded", Stream.initialize, Stream);
  Diaspora.widgets.publish("stream/reloaded");
});
<commit_msg>Actually add the comment delete link to list of tipsified elements<commit_after>/*   Copyright (c) 2010, Diaspora Inc.  This file is
 *   licensed under the Affero General Public License version 3 or later.  See
 *   the COPYRIGHT file.
 */

var Stream = {
  selector: "#main_stream",

  initialize: function() {
    Diaspora.widgets.timeago.updateTimeAgo();
    Diaspora.widgets.directionDetector.updateBinds();

    $.each(["a.stream_element_delete", "a.comment_delete", "span.post_scope"], function(idx, el){
      $(el).tipsy({
        trigger: "hover",
        gravity: "n"
      });
    });

    //audio links
    Stream.setUpAudioLinks();
    //Stream.setUpImageLinks();

    Diaspora.widgets.subscribe("stream/scrolled", Stream.collapseText);
    Stream.collapseText('eventID', $(Stream.selector)[0]);
  },
  collapseText: function(){
    elements = $(Array.prototype.slice.call(arguments,1));
    // collapse long posts
    $(".content p", elements).expander({
      slicePoint: 400,
      widow: 12,
      expandText: Diaspora.widgets.i18n.t("show_more"),
      userCollapse: false
    });

    // collapse long comments
    $(".comment .content span", elements).expander({
      slicePoint: 200,
      widow: 18,
      expandText: Diaspora.widgets.i18n.t("show_more"),
      userCollapse: false
    });
  },
  initializeLives: function(){
    // reshare button action
    $(".reshare_button", this.selector).live("click", function(evt) {
      evt.preventDefault();
      var button = $(this),
        box = button.siblings(".reshare_box");

      if (box.length > 0) {
        button.toggleClass("active");
        box.toggle();
      }
    });

    this.setUpComments();
  },

  setUpComments: function(){
    $("a.toggle_post_comments:not(.show)", this.selector).live('click', Stream.toggleComments);
    // comment link form focus
    $(".focus_comment_textarea", this.selector).live('click', function(evt) {
      Stream.focusNewComment($(this), evt);
    });

    $(".new_comment", this.selector).live("ajax:failure", function() {
       Diaspora.widgets.alert.alert(Diaspora.widgets.i18n.t("failed_to_post_message"));
    });

    $(".comment .comment_delete", this.selector).live("ajax:success", function() {
      var element = $(this),
        target = element.parents(".comment"),
        post = element.closest(".stream_element"),
        toggler = post.find(".toggle_post_comments");

      target.hide("blind", { direction: "vertical" }, 300, function() {
        $(this).remove();
        toggler.html(
          toggler.html().replace(/\d+/, $(".comments li", post).length - 1)
        );
      });

    });

    $("textarea.comment_box", this.selector).live("focus", function(evt) {
      if (this.value === undefined || this.value ===  ''){
        var commentBox = $(this);
        commentBox
          .parent().parent()
            .addClass("open");
      }
    });
    $("textarea.comment_box", this.selector).live("blur", function(evt) {
      if (this.value === undefined || this.value ===  ''){
        var commentBox = $(this);
        commentBox
          .parent().parent()
            .removeClass("open");
      }
    });

  },

  setUpAudioLinks: function() {
    $(".stream a[target='_blank']").each(function(r){
      var link = $(this);
      if(this.href.match(/\.mp3$|\.ogg$/)) {
        $("<audio/>", {
          preload: "none",
          src: this.href,
          controls: "controls"
        }).appendTo(link.parent());

        link.remove();
      }
    });
  },

  setUpImageLinks: function() {
    $(".stream a[target='_blank']").each(function() {
      var link = $(this);
      if(this.href.match(/\.gif$|\.jpg$|\.png$|\.jpeg$/)) {
        $("", {
          src: this.href
        }).appendTo(link.parent());

        link.remove();
      }
    });
  },

  toggleComments: function(evt) {
    evt.preventDefault();

    var $toggler = $(this),
        comments = $toggler.closest('.stream_element').find('ul.comments');

    if (comments.hasClass('loaded') && !comments.hasClass('hidden')){
      Stream.hideComments.apply($toggler);
    }else {
      Stream.showComments.apply($toggler);
    }
  },
  showComments: function(){
    var commentList = this.closest('.stream_element').find('ul.comments'),
        toggle = this;

    if( commentList.hasClass('loaded') ){
        toggle.html(Diaspora.widgets.i18n.t("comments.hide"));
        commentList.removeClass('hidden');
    }
    else {
      toggle.append("");
      $.ajax({
        url: this.attr('href'),
        success: function(data){
          toggle.html(Diaspora.widgets.i18n.t("comments.hide"));
          commentList.html(data)
                     .addClass('loaded');
          Diaspora.widgets.publish("stream/scrolled", commentList);
        }
      });
    }
  },

  hideComments: function(){
    var commentList = this.closest('.stream_element').find('ul.comments');
    commentList.addClass('hidden');
    this.html(Diaspora.widgets.i18n.t("comments.show"));
  },

  focusNewComment: function(toggle, evt) {
    evt.preventDefault();
    var post = toggle.closest(".stream_element");
    var commentBlock = post.find(".new_comment_form_wrapper");
    var textarea = post.find(".new_comment textarea");

    if(commentBlock.hasClass("hidden")) {
      commentBlock.removeClass("hidden");
      textarea.focus();
    } else {
      if(commentBlock.children().length <= 1) {
        commentBlock.addClass("hidden");
      } else {
        textarea.focus();
      }
    }
  }
};

$(document).ready(function() {
  if( $(Stream.selector).length == 0 ) { return }
  Stream.initializeLives();
  Diaspora.widgets.subscribe("stream/reloaded", Stream.initialize, Stream);
  Diaspora.widgets.publish("stream/reloaded");
});
<|endoftext|>


<commit_before>'use strict';

app.controller('indexController', ['$routeParams', '$mdMedia', '$mdDialog', '$mdToast', "$http", "$interval", "$location", "$timeout", "gamService", function ($routeParams, $mdMedia, $mdDialog, $mdToast, $http, $interval, $location, $timeout, gamService) {

	var index = this;
	index.gamService = gamService;
	index.hello = "Hello World";

	$interval(function () {
		index.gamService = gamService;
		console.log(index.gamService.me);
	}, 5000);
}]);<commit_msg>compiled file<commit_after>'use strict';

app.controller('indexController', ["$scope", '$routeParams', '$mdMedia', '$mdDialog', '$mdToast', "$http", "$interval", "$location", "$timeout", "gamService", function ($scope, $routeParams, $mdMedia, $mdDialog, $mdToast, $http, $interval, $location, $timeout, gamService) {

	// var index = this;
	$scope.gamService = gamService;
	$scope.hello = "Hello World";

	$interval(function () {
		$scope.gamService = gamService;
		// console.log($scope.gamService.me);
	}, 5000);

	$scope.editMode = function (num, pushOrPop) {
		$scope.myArray = [];
		$scope.myArray[pushOrPop](num);
		return $scope.myArray;
	};
}]);<|endoftext|>


<commit_before>/**
 * @fileoverview 场景视图
 * @authors
	Tony.Liang <pillar0514@gmail.com>
 * @description 显示3D场景的界面
 */
define('mods/view/scene',function(require,exports,module){

	var $ = require('lib');
	var $view = require('lib/mvc/view');
	var $sceneModel = require('mods/model/scene');
	var $CoordinateSystem = require('mods/view/coordinateSystem');
	var $House = require('mods/view/house');
	var $personModel = require('mods/model/person');

	var Scene = $view.extend({
		defaults : {
			name : 'scene',
			path : '',
			node : null,
			isSightDevice : true,
			type : 'front'
		},
		build : function(){
			var conf = this.conf;
			this.path = [conf.path, conf.name].join('.');
			this.model = new $sceneModel({
				type : conf.type
			});
			this.personModel = new $personModel();
			this.setPerspective();
			this.buildCoordinateSystem();
			this.buildHouse();
		},
		setEvents : function(action){
			this.delegate(action);
			var model = this.model;
			var proxy = this.proxy();
			model.on('change:perspective', proxy('setPerspective'));
			model.on('change:perspectiveOrigin', proxy('setPerspective'));
		},
		setPerspective : function(){
			var model = this.model;
			this.role('root').css({
				'perspective' : model.get('perspective') + 'px',
				'perspective-origin' : model.get('perspectiveOrigin')
			});
		},
		//构建空间坐标系
		buildCoordinateSystem : function(){
			var conf = this.conf;
			this.coordinateSystem = new $CoordinateSystem({
				path : this.path,
				isSightDevice : conf.isSightDevice,
				personModel : this.personModel,
				parent : this.role('root')
			});
		},
		//构建房间
		buildHouse : function(){
			this.house = new $House({
				path : this.path,
				personModel : this.personModel,
				coordinateSystem : this.coordinateSystem
			});
		},
		update : function(data){
			data = data || {};
			this.personModel.set(data.person);
			this.coordinateSystem.update(data.coordinateSystem);
			this.house.update(data.house);
		},
		toJSON : function(){
			var data = {};
			data.person = this.personModel.toJSON();
			data.coordinateSystem = this.coordinateSystem.toJSON();
			data.house = this.house.toJSON();
			return data;
		}
	});

	module.exports = Scene;

});

<commit_msg>初步实现场景同步<commit_after>/**
 * @fileoverview 场景视图
 * @authors
	Tony.Liang <pillar0514@gmail.com>
 * @description 显示3D场景的界面
 */
define('mods/view/scene',function(require,exports,module){

	var $ = require('lib');
	var $view = require('lib/mvc/view');
	var $sceneModel = require('mods/model/scene');
	var $CoordinateSystem = require('mods/view/coordinateSystem');
	var $House = require('mods/view/house');
	var $personModel = require('mods/model/person');

	var Scene = $view.extend({
		defaults : {
			name : 'scene',
			path : '',
			node : null,
			isSightDevice : true,
			type : 'front'
		},
		build : function(){
			var conf = this.conf;
			this.path = [conf.path, conf.name].join('.');
			this.model = new $sceneModel({
				type : conf.type
			});
			this.personModel = new $personModel();
			this.setPerspective();
			this.buildCoordinateSystem();
			this.buildHouse();
			this.setStyles();
		},
		setEvents : function(action){
			this.delegate(action);
			var model = this.model;
			var proxy = this.proxy();
			model.on('change:perspective', proxy('setPerspective'));
			model.on('change:perspectiveOrigin', proxy('setPerspective'));
		},
		setPerspective : function(){
			var model = this.model;
			this.role('root').css({
				'perspective' : model.get('perspective') + 'px',
				'perspective-origin' : model.get('perspectiveOrigin')
			});
		},
		//构建空间坐标系
		buildCoordinateSystem : function(){
			var conf = this.conf;
			this.coordinateSystem = new $CoordinateSystem({
				path : this.path,
				isSightDevice : conf.isSightDevice,
				personModel : this.personModel,
				parent : this.role('root')
			});
		},
		//构建房间
		buildHouse : function(){
			this.house = new $House({
				path : this.path,
				personModel : this.personModel,
				coordinateSystem : this.coordinateSystem
			});
		},
		setStyles : function(){
			var conf = this.conf;
			if(conf.isSightDevice){return;}
			var root = this.role('root');
			var parent = root.parent();
			var width = root.width();
			var height = root.height();
			var size = Math.min(width, height);
			root.css({
				'position' : 'absolute',
				'top' : 0,
				'left' : 0,
				'bottom' : 0,
				'right' : 0,
				'margin' : 'auto',
				'width' : size + 'px',
				'height' : size + 'px',
				'transform-origin' : '50% 50%',
				'transform' : 'rotateZ(-90deg)'
			});
			parent.css({
				'position' : 'absolute'
			});
		},
		update : function(data){
			data = data || {};
			this.personModel.set(data.person);
			this.coordinateSystem.update(data.coordinateSystem);
			this.house.update(data.house);
		},
		toJSON : function(){
			var data = {};
			data.person = this.personModel.toJSON();
			data.coordinateSystem = this.coordinateSystem.toJSON();
			data.house = this.house.toJSON();
			return data;
		}
	});

	module.exports = Scene;

});

<|endoftext|>


<commit_before>var WO = WO || {};
WO.TrackView = Backbone.View.extend({
  events: {
    'click .delete-track-button' : 'deleteTrack',
    'change .track-volume-slider' : 'setTrackVolume',
    'click .mute-track-button' : 'muteTrack',
    'change .instrument-selector' : 'changeInstrument',
    'click .track-container' : 'setActiveTrack'
  },

  template: _.template(
    '<div class="track-container active-track <%= cid %>">' +
      '
' +
        '
 <%= attributes.title %>
' +
        '<button class="delete-track-button" id="delete"></button>
' +
        '<form action="#">' +
        // '<fieldset>' +
          'Select instrument ' +
          '<select name="instrument-selector" class="instrument-selector">' +
            '<option selected="selected" value="Acoustic Piano">Acoustic Piano</option>'+
            '<option value="Synth">Synth</option>'+
            '<option value="Drums">Drums</option>' +
          '</select>' +
        // '</fieldset>' +
        '</form>
' +
        '<button class="solo-track-button" id="solo">S</button>' +
        '<button class="mute-track-button" id="mute">M</button>' +
        '
' +
          '' +
          '<input class="track-volume-slider" type="range" min="0.00" max="1.00" step="0.01" value="0.75">' +
          '' +
        '
' +
      '
' +
      '

' +
    '
'
  ),
  initialize: function(){
    $(document).ready((function(){
      this.model.set('mRender', new WO.MidiRender(this.model.cid+ ' .track-notes'));
    }).bind(this));
  },

  render: function(){
    this.$el.html( this.template(this.model));
    return this.$el;
  },

  deleteTrack: function(){
    this.model.collection.remove(this.model);
  },

  setTrackVolume: function(){
    var volume = this.$el.find('.track-volume-slider').val();
    this.model.set('volume', volume);
    this.model.get('instrument').setVolume(volume*20);
  },

  muteTrack: function(){
    var volume, color;
    if( this.model.get('isMuted') ){
      volume = 0;
      this.model.set('isMuted', false);
      color = "rgb(255,255,255)";
    }else{
      volume = -50;
      this.model.set('isMuted', true);
      color = "rgb(255,0,0)";
    }
    // console.log(color);
    $('.mute-track-button').toggleClass('muted');
    this.model.set('volume', volume);
    this.model.get('instrument').setVolume(volume);
  },

  changeInstrument : function(e){
    console.log($(e.currentTarget)[0].value);
    this.model.set('instrument');
    //get number of track
    //use that number in variable - "WO.instrumentTrack" + number
    //set the instrument name using the instrument from the dropdown
  },

  setActiveTrack: function(){
    //know current active
    $('.active-track').removeClass('active-track');
    //remove active-track class
    console.log("collection", this.model.collection);
    console.log("model", this.model);
    this.model.collection.settings.activeTrack = this.model;
    //add active-track class
    this.$el.find('.track-container').addClass('active-track');
    console.log(this.$el);
  }

});
<commit_msg>remove mrender event<commit_after>var WO = WO || {};
WO.TrackView = Backbone.View.extend({
  events: {
    'click .delete-track-button' : 'deleteTrack',
    'change .track-volume-slider' : 'setTrackVolume',
    'click .mute-track-button' : 'muteTrack',
    'change .instrument-selector' : 'changeInstrument',
    'click .track-container' : 'setActiveTrack'
  },

  template: _.template(
    '<div class="track-container active-track <%= cid %>">' +
      '
' +
        '
 <%= attributes.title %>
' +
        '<button class="delete-track-button" id="delete"></button>
' +
        '<form action="#">' +
        // '<fieldset>' +
          'Select instrument ' +
          '<select name="instrument-selector" class="instrument-selector">' +
            '<option selected="selected" value="Acoustic Piano">Acoustic Piano</option>'+
            '<option value="Synth">Synth</option>'+
            '<option value="Drums">Drums</option>' +
          '</select>' +
        // '</fieldset>' +
        '</form>
' +
        '<button class="solo-track-button" id="solo">S</button>' +
        '<button class="mute-track-button" id="mute">M</button>' +
        '
' +
          '' +
          '<input class="track-volume-slider" type="range" min="0.00" max="1.00" step="0.01" value="0.75">' +
          '' +
        '
' +
      '
' +
      '

' +
    '
'
  ),
  initialize: function(){
  },

  render: function(){
    this.$el.html( this.template(this.model));
    return this.$el;
  },

  deleteTrack: function(){
    this.model.collection.remove(this.model);
  },

  setTrackVolume: function(){
    var volume = this.$el.find('.track-volume-slider').val();
    this.model.set('volume', volume);
    this.model.get('instrument').setVolume(volume*20);
  },

  muteTrack: function(){
    var volume, color;
    if( this.model.get('isMuted') ){
      volume = 0;
      this.model.set('isMuted', false);
      color = "rgb(255,255,255)";
    }else{
      volume = -50;
      this.model.set('isMuted', true);
      color = "rgb(255,0,0)";
    }
    // console.log(color);
    $('.mute-track-button').toggleClass('muted');
    this.model.set('volume', volume);
    this.model.get('instrument').setVolume(volume);
  },

  changeInstrument : function(e){
    console.log($(e.currentTarget)[0].value);
    this.model.set('instrument');
    //get number of track
    //use that number in variable - "WO.instrumentTrack" + number
    //set the instrument name using the instrument from the dropdown
  },

  setActiveTrack: function(){
    //know current active
    $('.active-track').removeClass('active-track');
    //remove active-track class
    console.log("collection", this.model.collection);
    console.log("model", this.model);
    this.model.collection.settings.activeTrack = this.model;
    //add active-track class
    this.$el.find('.track-container').addClass('active-track');
    console.log(this.$el);
    WO.instrumentKeyHandler(this.model.collection.settings.activeTrack.attributes.instrument);
  }

});
<|endoftext|>


<commit_before>require("ember-data/system/model/model");

DS.Model.reopen({

  /**
    Provides info about the model for debugging purposes
    by grouping the properties into more semantic groups.

    Meant to be used by debugging tools such as the Chrome Ember Extension.

    - Groups all attributes in "Attributes" group.
    - Groups all belongsTo relationships in "Belongs To" group.
    - Groups all hasMany relationships in "Has Many" group.
    - Groups all flags in "Flags" group.
    - Flags relationship CPs as expensive properties.

    @method _debugInfo
    @for DS.Model
    @private
  */
  _debugInfo: function() {
    var attributes = ['id'],
        relationships = { belongsTo: [], hasMany: [] },
        expensiveProperties = [];

    this.eachAttribute(function(name, meta) {
      attributes.push(name);
    }, this);

    this.eachRelationship(function(name, relationship) {
      relationships[relationship.kind].push(name);
      expensiveProperties.push(name);
    });

    var groups = [
      {
        name: 'Attributes',
        properties: attributes,
        expand: true,
      },
      {
        name: 'Belongs To',
        properties: relationships.belongsTo,
        expand: true
      },
      {
        name: 'Has Many',
        properties: relationships.hasMany,
        expand: true
      },
      {
        name: 'Flags',
        properties: ['isLoaded', 'isDirty', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid']
      }
    ];

    return {
      propertyInfo: {
        // include all other mixins / properties (not just the grouped ones)
        includeOtherProperties: true,
        groups: groups,
        // don't pre-calculate unless cached
        expensiveProperties: expensiveProperties
      }
    };
  }

});
<commit_msg>Remove misplaced comma that breaks IE8<commit_after>require("ember-data/system/model/model");

DS.Model.reopen({

  /**
    Provides info about the model for debugging purposes
    by grouping the properties into more semantic groups.

    Meant to be used by debugging tools such as the Chrome Ember Extension.

    - Groups all attributes in "Attributes" group.
    - Groups all belongsTo relationships in "Belongs To" group.
    - Groups all hasMany relationships in "Has Many" group.
    - Groups all flags in "Flags" group.
    - Flags relationship CPs as expensive properties.

    @method _debugInfo
    @for DS.Model
    @private
  */
  _debugInfo: function() {
    var attributes = ['id'],
        relationships = { belongsTo: [], hasMany: [] },
        expensiveProperties = [];

    this.eachAttribute(function(name, meta) {
      attributes.push(name);
    }, this);

    this.eachRelationship(function(name, relationship) {
      relationships[relationship.kind].push(name);
      expensiveProperties.push(name);
    });

    var groups = [
      {
        name: 'Attributes',
        properties: attributes,
        expand: true
      },
      {
        name: 'Belongs To',
        properties: relationships.belongsTo,
        expand: true
      },
      {
        name: 'Has Many',
        properties: relationships.hasMany,
        expand: true
      },
      {
        name: 'Flags',
        properties: ['isLoaded', 'isDirty', 'isSaving', 'isDeleted', 'isError', 'isNew', 'isValid']
      }
    ];

    return {
      propertyInfo: {
        // include all other mixins / properties (not just the grouped ones)
        includeOtherProperties: true,
        groups: groups,
        // don't pre-calculate unless cached
        expensiveProperties: expensiveProperties
      }
    };
  }

});
<|endoftext|>


<commit_before>/**
 * @fileoverview Compare expected errors with those from ESLint.
 */

goog.module('googlejs.configTester.errorCompare');

const googObject = goog.require('goog.object');
const types = goog.require('googlejs.configTester.types');

/**
 * Compares all ESLint results to the expected results for a list of files.
 * @param {!Object<string, !types.ExpectedErrors>} expectedErrorsByFile A map of
 *     an absolute filepath to the expected errors for the file.
 */
function compareEslintToExpected(expectedErrorsByFile) {
  googObject.forEach(expectedErrorsByFile, (expectedErrors, filePath) => {
    compareErrorsForFile(expectedErrors);
  });
}

/**
 * Compares errors between ESLint and the expected errors for one file.
 * @param {!types.ExpectedErrors} expectedErrors A map of an absolute filepath
 *     to the expected errors for the file.
 */
function compareErrorsForFile(expectedErrors) {
  googObject.forEach(expectedErrors.errorsByLineNumber, (lineErrors, line) => {
    verifyExpectedErrors(lineErrors);
    verifyEslintErrors(lineErrors);
  });
}

/**
 * Creates an error string from an ESLint message.
 * @param {!types.LineErrors} lineErrors
 * @param {string} explanation
 * @return {string}
 */
function makeErrorMessage(lineErrors, explanation) {
  return `${lineErrors.filePath}:${lineErrors.line} - ${explanation}`;
}

/**
 * Verifies that all ESLint messages match with an expected error message.
 * @param {!types.LineErrors} lineErrors
 */
function verifyEslintErrors(lineErrors) {
  const {eslintRules, expectedRules} = lineErrors;
  if (eslintRules.isSubsetOf(expectedRules)) {
    return;
  }
  const unmatched = eslintRules.difference(expectedRules);
  const ruleList = unmatched.getValues();
  const message = `These ESLint errors (${ruleList.join(', ')}) ` +
        `did not have a corresponding expected error.`;
  throw new Error(makeErrorMessage(lineErrors, message));
}

/**
 * Verifies that each expected error was also found by ESLint.
 * @param {!types.LineErrors} lineErrors
 */
function verifyExpectedErrors(lineErrors) {
  const {eslintRules, expectedRules} = lineErrors;
  if (expectedRules.isSubsetOf(eslintRules)) {
    return;
  }
  const unmatched = expectedRules.difference(eslintRules);
  const ruleList = unmatched.getValues();
  const message = `These expected errors (${ruleList.join(', ')}) ` +
        `were not found by ESLint.`;
  throw new Error(makeErrorMessage(lineErrors, message));
}

exports = {
  compareEslintToExpected,
  compareErrorsForFile,
  makeErrorMessage,
  verifyEslintErrors,
  verifyExpectedErrors,
};
<commit_msg>tweak error messages<commit_after>/**
 * @fileoverview Compare expected errors with those from ESLint.
 */

goog.module('googlejs.configTester.errorCompare');

const googObject = goog.require('goog.object');
const types = goog.require('googlejs.configTester.types');

/**
 * Compares all ESLint results to the expected results for a list of files.
 * @param {!Object<string, !types.ExpectedErrors>} expectedErrorsByFile A map of
 *     an absolute filepath to the expected errors for the file.
 */
function compareEslintToExpected(expectedErrorsByFile) {
  googObject.forEach(expectedErrorsByFile, (expectedErrors, filePath) => {
    compareErrorsForFile(expectedErrors);
  });
}

/**
 * Compares errors between ESLint and the expected errors for one file.
 * @param {!types.ExpectedErrors} expectedErrors A map of an absolute filepath
 *     to the expected errors for the file.
 */
function compareErrorsForFile(expectedErrors) {
  googObject.forEach(expectedErrors.errorsByLineNumber, (lineErrors, line) => {
    verifyExpectedErrors(lineErrors);
    verifyEslintErrors(lineErrors);
  });
}

/**
 * Creates an error string from an ESLint message.
 * @param {!types.LineErrors} lineErrors
 * @param {string} explanation
 * @return {string}
 */
function makeErrorMessage(lineErrors, explanation) {
  return `${lineErrors.filePath}:${lineErrors.line} - ${explanation}`;
}

/**
 * Verifies that all ESLint messages match with an expected error message.
 * @param {!types.LineErrors} lineErrors
 */
function verifyEslintErrors(lineErrors) {
  const {eslintRules, expectedRules} = lineErrors;
  if (eslintRules.isSubsetOf(expectedRules)) {
    return;
  }
  const unmatched = eslintRules.difference(expectedRules);
  const ruleList = unmatched.getValues();
  const message = `The following ESLint errors (${ruleList.join(', ')}) ` +
        `did not have a corresponding expected error.`;
  throw new Error(makeErrorMessage(lineErrors, message));
}

/**
 * Verifies that each expected error was also found by ESLint.
 * @param {!types.LineErrors} lineErrors
 */
function verifyExpectedErrors(lineErrors) {
  const {eslintRules, expectedRules} = lineErrors;
  if (expectedRules.isSubsetOf(eslintRules)) {
    return;
  }
  const unmatched = expectedRules.difference(eslintRules);
  const ruleList = unmatched.getValues();
  const message = `The following expected errors (${ruleList.join(', ')}) ` +
        `were not found by ESLint.`;
  throw new Error(makeErrorMessage(lineErrors, message));
}

exports = {
  compareEslintToExpected,
  compareErrorsForFile,
  makeErrorMessage,
  verifyEslintErrors,
  verifyExpectedErrors,
};
<|endoftext|>


<commit_before>/**
 * @class Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle
 */
Oskari.clazz.define("Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle", function () {}, {
        /*
         * implementation for protocol 'Oskari.bundle.Bundle'
         */
        "create": function () {
            return null;
        },
        "update": function (manager, bundle, bi, info) {
            manager.alert("RECEIVED update notification " + info);
        }
    },

    /**
     * metadata
     */
    {

        "protocol": ["Oskari.bundle.Bundle", "Oskari.mapframework.bundle.extension.ExtensionBundle"],
        "source": {

            "scripts": [{
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/plugin/DrawFilterPlugin.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StartDrawFilteringRequest.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StartDrawFilteringRequestHandler.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StopDrawFilteringRequest.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StopDrawFilteringRequestHandler.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/event/ActiveDrawFilteringEvent.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/event/FinishedDrawFilteringEvent.js"
            }, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/clipper/clipper.js"
            }, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/jsts/jsts.js"
            }, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/jsts/javascript.util.js"
            }],
            "locales": [{
                "lang": "fi",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/fi.js"
            }, {
                "lang": "sv",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/sv.js"
            }, {
                "lang": "en",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/en.js"
            }]
        },
        "bundle": {
            "manifest": {
                "Bundle-Identifier": "geometryeditor",
                "Bundle-Name": "geometryeditor",
                "Bundle-Tag": {
                    "mapframework": true
                },
                "Bundle-Icon": {
                    "href": "icon.png"
                },
                "Bundle-Author": [{
                    "Name": "jjk",
                    "Organisation": "nls.fi",
                    "Temporal": {
                        "Start": "2009",
                        "End": "2011"
                    },
                    "Copyleft": {
                        "License": {
                            "License-Name": "EUPL",
                            "License-Online-Resource": "http://www.paikkatietoikkuna.fi/license"
                        }
                    }
                }],
                "Bundle-Name-Locale": {
                    "fi": {
                        "Name": "GeometryEditor",
                        "Title": "GeometryEditor"
                    },
                    "en": {}
                },
                "Bundle-Version": "1.0.0",
                "Import-Namespace": ["Oskari"]
            }
        }
    });
Oskari.bundle_manager.installBundleClass("geometryeditor", "Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle");
<commit_msg>[AH-1431] Disabled jsts dependency for the proper Oskari build.<commit_after>/**
 * @class Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle
 */
Oskari.clazz.define("Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle", function () {}, {
        /*
         * implementation for protocol 'Oskari.bundle.Bundle'
         */
        "create": function () {
            return null;
        },
        "update": function (manager, bundle, bi, info) {
            manager.alert("RECEIVED update notification " + info);
        }
    },

    /**
     * metadata
     */
    {

        "protocol": ["Oskari.bundle.Bundle", "Oskari.mapframework.bundle.extension.ExtensionBundle"],
        "source": {

            "scripts": [{
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/plugin/DrawFilterPlugin.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StartDrawFilteringRequest.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StartDrawFilteringRequestHandler.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StopDrawFilteringRequest.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/request/StopDrawFilteringRequestHandler.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/event/ActiveDrawFilteringEvent.js"
            }, {
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/event/FinishedDrawFilteringEvent.js"
            }/*, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/clipper/clipper.js"
            }, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/jsts/jsts.js"
            }, {
                "type" : "text/javascript",
                "src" : "../../../../libraries/jsts/javascript.util.js"
            }*/],
            "locales": [{
                "lang": "fi",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/fi.js"
            }, {
                "lang": "sv",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/sv.js"
            }, {
                "lang": "en",
                "type": "text/javascript",
                "src": "../../../../bundles/framework/bundle/geometryeditor/locale/en.js"
            }]
        },
        "bundle": {
            "manifest": {
                "Bundle-Identifier": "geometryeditor",
                "Bundle-Name": "geometryeditor",
                "Bundle-Tag": {
                    "mapframework": true
                },
                "Bundle-Icon": {
                    "href": "icon.png"
                },
                "Bundle-Author": [{
                    "Name": "jjk",
                    "Organisation": "nls.fi",
                    "Temporal": {
                        "Start": "2009",
                        "End": "2011"
                    },
                    "Copyleft": {
                        "License": {
                            "License-Name": "EUPL",
                            "License-Online-Resource": "http://www.paikkatietoikkuna.fi/license"
                        }
                    }
                }],
                "Bundle-Name-Locale": {
                    "fi": {
                        "Name": "GeometryEditor",
                        "Title": "GeometryEditor"
                    },
                    "en": {}
                },
                "Bundle-Version": "1.0.0",
                "Import-Namespace": ["Oskari"]
            }
        }
    });
Oskari.bundle_manager.installBundleClass("geometryeditor", "Oskari.mapframework.bundle.geometryeditor.GeometryEditorBundle");
<|endoftext|>


<commit_before>const {DatabaseTypes: {JSONARRAYType}} = require('isomorphic-core');

module.exports = (sequelize, Sequelize) => {
  return sequelize.define('transaction', {
    event: Sequelize.STRING,
    object: Sequelize.STRING,
    objectId: Sequelize.STRING,
    changedFields: JSONARRAYType('changedFields'),
  }, {
    instanceMethods: {
      toJSON: function toJSON() {
        return {
          id: `${this.id}`,
          event: this.event,
          object: this.object,
          objectId: this.objectId,
          changedFields: this.changedFields,
        }
      },
    },
  });
}
<commit_msg>[iso-core] Fix dependencyin model<commit_after>const {JSONARRAYType} = require('../database-types');

module.exports = (sequelize, Sequelize) => {
  return sequelize.define('transaction', {
    event: Sequelize.STRING,
    object: Sequelize.STRING,
    objectId: Sequelize.STRING,
    changedFields: JSONARRAYType('changedFields'),
  }, {
    instanceMethods: {
      toJSON: function toJSON() {
        return {
          id: `${this.id}`,
          event: this.event,
          object: this.object,
          objectId: this.objectId,
          changedFields: this.changedFields,
        }
      },
    },
  });
}
<|endoftext|>


<commit_before>var app = angular.module('myApp', []);

app.controller("Ctrl1",function($scope){
  $scope.contents = {
		name : 'Work Experience',
		isDropdown: true,
		dropdownValues: ['HubSpot | June 2016 - Dec 2016', 'HubSpot | May  2015 - Dec 2015', 'Goldman Sachs | July  2014 - Dec 2014']
  };
  $scope.navBarData = [
	  {
			name : 'Work Experience',
			isDropdown: true,
			dropdownValues: ['HubSpot | June 2016 - Dec 2016', 'HubSpot | May  2015 - Dec 2015', 'Goldman Sachs | July  2014 - Dec 2014']
	  },
	  {
	  	name : 'Education',
	  	isDropdown: false,
	  	dropdownValues: []
	  },
	  {
			name : 'Mentorship',
			isDropdown: true,
			dropdownValues: ['Fellow | Jan 2016 - April 2016', 'Tutor  | Jan 2014 - April 2014 Surfing']
	  },
	  {
			name : 'Hobbies',
			isDropdown: true,
			dropdownValues: ['Performing', 'Kite Surfing', 'Running']
	  }
	];
});

app.directive('navbar', function() {

  return {
    restrict: 'AE',
    replace: 'true',
    templateUrl: '/navigation.html',
    scope: false
  };
});

});<commit_msg>remove extra closing bracket<commit_after>var app = angular.module('myApp', []);

app.controller("Ctrl1",function($scope){
  $scope.contents = {
		name : 'Work Experience',
		isDropdown: true,
		dropdownValues: ['HubSpot | June 2016 - Dec 2016', 'HubSpot | May  2015 - Dec 2015', 'Goldman Sachs | July  2014 - Dec 2014']
  };
  $scope.navBarData = [
	  {
			name : 'Work Experience',
			isDropdown: true,
			dropdownValues: ['HubSpot | June 2016 - Dec 2016', 'HubSpot | May  2015 - Dec 2015', 'Goldman Sachs | July  2014 - Dec 2014']
	  },
	  {
	  	name : 'Education',
	  	isDropdown: false,
	  	dropdownValues: []
	  },
	  {
			name : 'Mentorship',
			isDropdown: true,
			dropdownValues: ['Fellow | Jan 2016 - April 2016', 'Tutor  | Jan 2014 - April 2014 Surfing']
	  },
	  {
			name : 'Hobbies',
			isDropdown: true,
			dropdownValues: ['Performing', 'Kite Surfing', 'Running']
	  }
	];
});

app.directive('navbar', function() {

  return {
    restrict: 'AE',
    replace: 'true',
    templateUrl: '/navigation.html',
    scope: false
  };

});<|endoftext|>


<commit_before>define(["Tone/core/Tone", "Tone/shim/AudioContext", "Tone/core/Context", "Tone/core/Gain"], function(Tone){

	if (Tone.supported && !AudioContext.prototype.createConstantSource){

		var ConstantSourceNode = function(context){
			this.context = context;

			// eslint-disable-next-line no-console
			console.log(context.sampleRate);

			var buffer = context.createBuffer(1, 128, context.sampleRate);
			var arr = buffer.getChannelData(0);
			for (var i = 0; i < arr.length; i++){
				arr[i] = 1;
			}

			this._bufferSource = context.createBufferSource();
			this._bufferSource.channelCount = 1;
			this._bufferSource.channelCountMode = "explicit";
			this._bufferSource.buffer = buffer;
			this._bufferSource.loop = true;

			var gainNode = this._output = context.createGain();
			this.offset = gainNode.gain;

			this._bufferSource.connect(gainNode);
		};

		ConstantSourceNode.prototype.start = function(time){
			this._bufferSource.start(time);
			return this;
		};

		ConstantSourceNode.prototype.stop = function(time){
			this._bufferSource.stop(time);
			return this;
		};

		ConstantSourceNode.prototype.connect = function(){
			this._output.connect.apply(this._output, arguments);
			return this;
		};

		ConstantSourceNode.prototype.disconnect = function(){
			this._output.disconnect.apply(this._output, arguments);
			return this;
		};

		AudioContext.prototype.createConstantSource = function(){
			return new ConstantSourceNode(this);
		};

		Tone.Context.prototype.createConstantSource = function(){
			return new ConstantSourceNode(this);
		};
	}
});
<commit_msg>no sampleRate logging<commit_after>define(["Tone/core/Tone", "Tone/shim/AudioContext", "Tone/core/Context", "Tone/core/Gain"], function(Tone){

	if (Tone.supported && !AudioContext.prototype.createConstantSource){

		var ConstantSourceNode = function(context){
			this.context = context;

			var buffer = context.createBuffer(1, 128, context.sampleRate);
			var arr = buffer.getChannelData(0);
			for (var i = 0; i < arr.length; i++){
				arr[i] = 1;
			}

			this._bufferSource = context.createBufferSource();
			this._bufferSource.channelCount = 1;
			this._bufferSource.channelCountMode = "explicit";
			this._bufferSource.buffer = buffer;
			this._bufferSource.loop = true;

			var gainNode = this._output = context.createGain();
			this.offset = gainNode.gain;

			this._bufferSource.connect(gainNode);
		};

		ConstantSourceNode.prototype.start = function(time){
			this._bufferSource.start(time);
			return this;
		};

		ConstantSourceNode.prototype.stop = function(time){
			this._bufferSource.stop(time);
			return this;
		};

		ConstantSourceNode.prototype.connect = function(){
			this._output.connect.apply(this._output, arguments);
			return this;
		};

		ConstantSourceNode.prototype.disconnect = function(){
			this._output.disconnect.apply(this._output, arguments);
			return this;
		};

		AudioContext.prototype.createConstantSource = function(){
			return new ConstantSourceNode(this);
		};

		Tone.Context.prototype.createConstantSource = function(){
			return new ConstantSourceNode(this);
		};
	}
});
<|endoftext|>


<commit_before>const r = require('request')
const rp = require('request-promise')
const fs = require('fs')
const haversine = require('./haversine')

const verbose = false

class FlaneurGeocoder {
  constructor(opts) {
    this.apiKey = (opts && opts.apiKey) || process.env.GOOGLE_PLACES_FLANEUR_API_KEY
    this.verbose = (opts && opts.verbose) || false
    this.aroundRadiusFn = (opts && opts.aroundRadiusFn) || FlaneurGeocoder._timesTwo
    this.aroundPrecisionFn = (opts && opts.aroundPrecisionFn) || FlaneurGeocoder._dividesByFour

    if (!this.apiKey) {
      throw new Error('Missing API key.')
    }
  }

  findWhereIs(...args) {
    if (args.length === 2) {
      const latitude = args[0]
      const longitude = args[1]
      return this._findFromCoordinate(latitude, longitude)
    } else if (args.length === 1) {
      const googlePlaceID = args[0]
      return this._findFromGooglePlaceID(googlePlaceID)
    }
    throw new Error('Invalid args')
  }

  findPhoto(photoRef, outputName = 'photo') {
    r
      .get(`https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${photoRef}&key=${this.apiKey}`)
      .on('error', (err) => {
        console.error(err)
      })
      .pipe(fs.createWriteStream(`${outputName}.jpg`))
  }

  _findPlaceDetails(placeID) {
    return rp(`https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeID}&language=en&key=${this.apiKey}`)
      .then((bodyString) => {
        return JSON.parse(bodyString)
      })
      .catch((e) => {
        console.error('findPlaceDetails:', e)
        return {}
      })
  }

  _findFromGooglePlaceID(placeID) {
    return this._findPlaceDetails(placeID)
      .then((placeDetails) => {
        if (placeDetails.result) {
          return this._outputFromSingleGooglePlaceResult(placeDetails.result, { placeID: placeID })
        } else {
          if (placeDetails.error_message) {
            throw new Error(`Couldn't fetch details for place ${placeID}: ${placeDetails.error_message}`)
          } else {
            throw new Error(`Couldn't fetch details for place ${placeID}: ${placeDetails}`)
          }
        }
      })
  }

  _findFromCoordinate(lat, lng) {
    return rp(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${this.apiKey}`)
      .then(bodyString => JSON.parse(bodyString))
      .then((responseObject) => {
        if (responseObject.results) {
          const localities = responseObject.results.filter(result => result.types && result.types.includes('locality'))

          if (localities.length === 1) {
            return this._outputFromSingleGooglePlaceResult(localities[0], {
              lat: Number(lat),
              lng: Number(lng)
            })
          }
          throw new Error(`Couldn't find locality for coordainte ${lat}, ${lng}`)
        } else {
          throw new Error(`Couldn't fetch details for coordainte ${lat}, ${lng}`)
        }
      })
  }

  _findFromCoordinateLegacy(lat, lng) {
    return rp(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${this.apiKey}`)
      .then((bodyString) => {
        console.log(bodyString)
        return JSON.parse(bodyString)
      })
      .then((responseObject) => {
        if (responseObject.results) {
          const allPoliticalAddressComponents = responseObject.results
            .map(this._extractPoliticalComponents)
            .reduce(this._mergeObjects)
          return allPoliticalAddressComponents
        }
        console.error(`Empty response for ${lat}, ${lng}`)
        return {}
      })
      .catch((e) => {
        console.error('_findFromCoordinate:', e)
        return {}
      })
  }

  static _extractPoliticalComponents(objWithAddressComponents) {
    const result = {}
    objWithAddressComponents.address_components.forEach((addressComponent) => {
      if (addressComponent.types.includes('political')) {
        const filteredTypes = addressComponent.types.filter(elt => elt !== 'political')
        if (filteredTypes.length === 1) {
          const politicalType = filteredTypes[0]
          result[politicalType] = addressComponent.long_name
        } else if (filteredTypes.length === 0) {
          if (verbose) {
            console.warn('Skipping political type with unique entity', addressComponent)
          }
        } else {
          if (verbose) {
            console.warn('Splitting type into multiple political components', addressComponent)
          }
          filteredTypes.forEach((subElt) => {
            result[subElt] = addressComponent.long_name
          })
        }
      }
    })
    return result
  }

  static _mergeObjects(accumulator, currentValue) {
    const newRes = accumulator
    Object.keys(currentValue).forEach((key) => {
      if (newRes[key] && newRes[key] !== currentValue[key]) {
        if (verbose) {
          console.warn(`Conflict for key ${key}: ${newRes[key]} != ${currentValue[key]}`)
        }
        if (newRes[key].length > currentValue[key].length) {
          newRes[key] = currentValue[key]
        }
      } else {
        newRes[key] = currentValue[key]
      }
    })
    return newRes
  }

  _outputFromSingleGooglePlaceResult(gpResult, query = null) {
    const res = {}

    res.types = gpResult.types
    res.enPoliticalComponents = FlaneurGeocoder._extractPoliticalComponents(gpResult)

    res.placeID = gpResult.place_id
    res.name = gpResult.name || res.enPoliticalComponents.locality

    // We need more information: location and size of the viewport
    if (gpResult.geometry && gpResult.geometry.location) {
      res.location = gpResult.geometry.location
    }

    if (gpResult.geometry && gpResult.geometry.viewport) {
      res.viewport = gpResult.geometry.viewport
    }

    // Now let's build the search recommendations
    const searchSettings = {}
    if (res.types.includes('country')) {
      searchSettings.coordinate = null
      searchSettings.tag = `country-${res.enPoliticalComponents.country}`
      searchSettings.aroundPrecision = null
      searchSettings.aroundRadius = null
    } else {
      searchSettings.coordinate = res.location
      searchSettings.tag = null
      if (res.viewport) {
        const p1 = res.viewport.northeast
        const p2 = res.viewport.southwest
        const viewportSizeInMeters = haversine(p1.lat, p1.lng, p2.lat, p2.lng) * 1000.0
        searchSettings.aroundPrecision = this.aroundPrecisionFn(viewportSizeInMeters)
        searchSettings.aroundRadius = this.aroundRadiusFn(viewportSizeInMeters)
      } else {
        searchSettings.aroundPrecision = null
        searchSettings.aroundRadius = null
      }
    }
    res.searchSettings = searchSettings

    // Include the query as is if present
    if (query) {
      res.query = query
    }

    return res
  }

  static _mapsCenteredOnLocation(latitude, longitude) {
    return `https://www.google.com/maps/@?api=1&map_action=map&center=${latitude},${longitude}&zoom=5`
  }

  // This is the default for `aroundRadiusFn`
  static _timesTwo(viewportDiagonal) {
    return viewportDiagonal * 2.0
  }

  // This is the default for `aroundPrecisionFn`
  static _dividesByFour(viewportDiagonal) {
    return viewportDiagonal / 4.0
  }
}

module.exports = FlaneurGeocoder
<commit_msg>Show error for NOT_FOUND instances<commit_after>const r = require('request')
const rp = require('request-promise')
const fs = require('fs')
const haversine = require('./haversine')

const verbose = false

class FlaneurGeocoder {
  constructor(opts) {
    this.apiKey = (opts && opts.apiKey) || process.env.GOOGLE_PLACES_FLANEUR_API_KEY
    this.verbose = (opts && opts.verbose) || false
    this.aroundRadiusFn = (opts && opts.aroundRadiusFn) || FlaneurGeocoder._timesTwo
    this.aroundPrecisionFn = (opts && opts.aroundPrecisionFn) || FlaneurGeocoder._dividesByFour

    if (!this.apiKey) {
      throw new Error('Missing API key.')
    }
  }

  findWhereIs(...args) {
    if (args.length === 2) {
      const latitude = args[0]
      const longitude = args[1]
      return this._findFromCoordinate(latitude, longitude)
    } else if (args.length === 1) {
      const googlePlaceID = args[0]
      return this._findFromGooglePlaceID(googlePlaceID)
    }
    throw new Error('Invalid args')
  }

  findPhoto(photoRef, outputName = 'photo') {
    r
      .get(`https://maps.googleapis.com/maps/api/place/photo?maxwidth=400&photoreference=${photoRef}&key=${this.apiKey}`)
      .on('error', (err) => {
        console.error(err)
      })
      .pipe(fs.createWriteStream(`${outputName}.jpg`))
  }

  _findPlaceDetails(placeID) {
    return rp(`https://maps.googleapis.com/maps/api/place/details/json?placeid=${placeID}&language=en&key=${this.apiKey}`)
      .then((bodyString) => {
        return JSON.parse(bodyString)
      })
      .catch((e) => {
        console.error('findPlaceDetails:', e)
        return {}
      })
  }

  _findFromGooglePlaceID(placeID) {
    return this._findPlaceDetails(placeID)
      .then((placeDetails) => {
        if (placeDetails.result) {
          return this._outputFromSingleGooglePlaceResult(placeDetails.result, { placeID: placeID })
        } else {
          if (placeDetails.error_message) {
            throw new Error(`Couldn't fetch details for place ${placeID}: ${placeDetails.error_message}`)
          } else {
            throw new Error(`Couldn't fetch details for place ${placeID}: ${placeDetails.status}`)
          }
        }
      })
  }

  _findFromCoordinate(lat, lng) {
    return rp(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${this.apiKey}`)
      .then(bodyString => JSON.parse(bodyString))
      .then((responseObject) => {
        if (responseObject.results) {
          const localities = responseObject.results.filter(result => result.types && result.types.includes('locality'))

          if (localities.length === 1) {
            return this._outputFromSingleGooglePlaceResult(localities[0], {
              lat: Number(lat),
              lng: Number(lng)
            })
          }
          throw new Error(`Couldn't find locality for coordainte ${lat}, ${lng}`)
        } else {
          throw new Error(`Couldn't fetch details for coordainte ${lat}, ${lng}`)
        }
      })
  }

  _findFromCoordinateLegacy(lat, lng) {
    return rp(`https://maps.googleapis.com/maps/api/geocode/json?latlng=${lat},${lng}&key=${this.apiKey}`)
      .then((bodyString) => {
        console.log(bodyString)
        return JSON.parse(bodyString)
      })
      .then((responseObject) => {
        if (responseObject.results) {
          const allPoliticalAddressComponents = responseObject.results
            .map(this._extractPoliticalComponents)
            .reduce(this._mergeObjects)
          return allPoliticalAddressComponents
        }
        console.error(`Empty response for ${lat}, ${lng}`)
        return {}
      })
      .catch((e) => {
        console.error('_findFromCoordinate:', e)
        return {}
      })
  }

  static _extractPoliticalComponents(objWithAddressComponents) {
    const result = {}
    objWithAddressComponents.address_components.forEach((addressComponent) => {
      if (addressComponent.types.includes('political')) {
        const filteredTypes = addressComponent.types.filter(elt => elt !== 'political')
        if (filteredTypes.length === 1) {
          const politicalType = filteredTypes[0]
          result[politicalType] = addressComponent.long_name
        } else if (filteredTypes.length === 0) {
          if (verbose) {
            console.warn('Skipping political type with unique entity', addressComponent)
          }
        } else {
          if (verbose) {
            console.warn('Splitting type into multiple political components', addressComponent)
          }
          filteredTypes.forEach((subElt) => {
            result[subElt] = addressComponent.long_name
          })
        }
      }
    })
    return result
  }

  static _mergeObjects(accumulator, currentValue) {
    const newRes = accumulator
    Object.keys(currentValue).forEach((key) => {
      if (newRes[key] && newRes[key] !== currentValue[key]) {
        if (verbose) {
          console.warn(`Conflict for key ${key}: ${newRes[key]} != ${currentValue[key]}`)
        }
        if (newRes[key].length > currentValue[key].length) {
          newRes[key] = currentValue[key]
        }
      } else {
        newRes[key] = currentValue[key]
      }
    })
    return newRes
  }

  _outputFromSingleGooglePlaceResult(gpResult, query = null) {
    const res = {}

    res.types = gpResult.types
    res.enPoliticalComponents = FlaneurGeocoder._extractPoliticalComponents(gpResult)

    res.placeID = gpResult.place_id
    res.name = gpResult.name || res.enPoliticalComponents.locality

    // We need more information: location and size of the viewport
    if (gpResult.geometry && gpResult.geometry.location) {
      res.location = gpResult.geometry.location
    }

    if (gpResult.geometry && gpResult.geometry.viewport) {
      res.viewport = gpResult.geometry.viewport
    }

    // Now let's build the search recommendations
    const searchSettings = {}
    if (res.types.includes('country')) {
      searchSettings.coordinate = null
      searchSettings.tag = `country-${res.enPoliticalComponents.country}`
      searchSettings.aroundPrecision = null
      searchSettings.aroundRadius = null
    } else {
      searchSettings.coordinate = res.location
      searchSettings.tag = null
      if (res.viewport) {
        const p1 = res.viewport.northeast
        const p2 = res.viewport.southwest
        const viewportSizeInMeters = haversine(p1.lat, p1.lng, p2.lat, p2.lng) * 1000.0
        searchSettings.aroundPrecision = this.aroundPrecisionFn(viewportSizeInMeters)
        searchSettings.aroundRadius = this.aroundRadiusFn(viewportSizeInMeters)
      } else {
        searchSettings.aroundPrecision = null
        searchSettings.aroundRadius = null
      }
    }
    res.searchSettings = searchSettings

    // Include the query as is if present
    if (query) {
      res.query = query
    }

    return res
  }

  static _mapsCenteredOnLocation(latitude, longitude) {
    return `https://www.google.com/maps/@?api=1&map_action=map&center=${latitude},${longitude}&zoom=5`
  }

  // This is the default for `aroundRadiusFn`
  static _timesTwo(viewportDiagonal) {
    return viewportDiagonal * 2.0
  }

  // This is the default for `aroundPrecisionFn`
  static _dividesByFour(viewportDiagonal) {
    return viewportDiagonal / 4.0
  }
}

module.exports = FlaneurGeocoder
<|endoftext|>