<commit_before>var ui = (function () {

var exports = {};

// What, if anything, obscures the home tab?

exports.replace_emoji_with_text = function (element) {
    element.find(".emoji").replaceWith(function () {
        if ($(this).is("img")) {
            return $(this).attr("alt");
        }
        return $(this).text();
    });
};

exports.set_up_scrollbar = function (element) {
    var perfectScrollbar = new PerfectScrollbar(element[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
        minScrollbarLength: 40,
    });
    element[0].perfectScrollbar = perfectScrollbar;
};

exports.update_scrollbar = function (element) {
    element.scrollTop = 0;
    if (element[0].perfectScrollbar !== undefined) {
        element[0].perfectScrollbar.update();
    }
};

exports.destroy_scrollbar = function (element) {
    element[0].perfectScrollbar.destroy();
};

function update_message_in_all_views(message_id, callback) {
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) {
        if (list === undefined) {
            return;
        }
        var row = list.get_row(message_id);
        if (row === undefined) {
            // The row may not exist, e.g. if you do an action on a message in
            // a narrowed view
            return;
        }
        callback(row);
    });
}

exports.show_error_for_unsupported_platform = function () {
    // Check if the user is using old desktop app
    if (typeof(bridge) !== 'undefined') {
        // We don't internationalize this string because it is long,
        // and few users will have both the old desktop app and an
        // internationalized version of Zulip anyway.
        var error = "Hello! You're using the unsupported old Zulip desktop app," +
            " which is no longer developed. We recommend switching to the new, " +
            "modern desktop app, which you can download at " +
            "zulipchat.com/apps.";

        ui_report.generic_embed_error(error);
    }
};

exports.find_message = function (message_id) {
    // Try to find the message object. It might be in the narrow list
    // (if it was loaded when narrowed), or only in the message_list.all
    // (if received from the server while in a different narrow)
    var message;
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (msg_list) {
        if (msg_list !== undefined && message === undefined) {
            message = msg_list.get(message_id);
        }
    });
    return message;
};

exports.update_starred = function (message) {
    var starred = message.starred;

    // Avoid a full re-render, but update the star in each message
    // table in which it is visible.
    update_message_in_all_views(message.id, function update_row(row) {
        var elt = row.find(".star");
        if (starred) {
            elt.addClass("icon-vector-star").removeClass("icon-vector-star-empty").removeClass("empty-star");
        } else {
            elt.removeClass("icon-vector-star").addClass("icon-vector-star-empty").addClass("empty-star");
        }
        var title_state = starred ? i18n.t("Unstar") : i18n.t("Star");
        elt.attr("title", i18n.t("__starred_status__ this message", {starred_status: title_state}));
    });
};

exports.show_message_failed = function (message_id, failed_msg) {
    // Failed to send message, so display inline retry/cancel
    update_message_in_all_views(message_id, function update_row(row) {
        var failed_div = row.find('.message_failed');
        failed_div.toggleClass('notvisible', false);
        failed_div.find('.failed_text').attr('title', failed_msg);
    });
};

exports.remove_message = function (message_id) {
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) {
        if (list === undefined) {
            return;
        }
        var row = list.get_row(message_id);
        if (row !== undefined) {
            list.remove_and_rerender([{id: message_id}]);
        }
    });
};

exports.show_failed_message_success = function (message_id) {
    // Previously failed message succeeded
    update_message_in_all_views(message_id, function update_row(row) {
        row.find('.message_failed').toggleClass('notvisible', true);
    });
};

var shown_deprecation_notices = [];
exports.maybe_show_deprecation_notice = function (key) {
    var message;
    if (key === 'C') {
        message = i18n.t('We\'ve replaced the "C" hotkey with "x" to make this common shortcut easier to trigger.');
    } else {
        blueslip.error("Unexpected deprecation notice for hotkey:", key);
        return;
    }

    // Here we handle the tracking for showing deprecation notices,
    // whether or not local storage is available.
    if (localstorage.supported()) {
        var notices_from_storage = JSON.parse(localStorage.getItem('shown_deprecation_notices'));
        if (notices_from_storage !== null) {
            shown_deprecation_notices = notices_from_storage;
        } else {
            shown_deprecation_notices = [];
        }
    }

    if (shown_deprecation_notices.indexOf(key) === -1) {
        $('#deprecation-notice-modal').modal('show');
        $('#deprecation-notice-message').text(message);
        shown_deprecation_notices.push(key);
        if (localstorage.supported()) {
            localStorage.setItem('shown_deprecation_notices', JSON.stringify(shown_deprecation_notices));
        }
    }
};

/* EXPERIMENTS */

/* This method allows an advanced user to use the console
 * to switch the application to span full width of the browser.
 */
exports.switchToFullWidth = function () {
    $("#full-width-style").remove();
    $('head').append('');
    return ("Switched to full width");
};

/* END OF EXPERIMENTS */

// Save the compose content cursor position and restore when we
// shift-tab back in (see hotkey.js).
var saved_compose_cursor = 0;

exports.set_compose_textarea_handlers = function () {
    $('#compose-textarea').blur(function () {
        saved_compose_cursor = $(this).caret();
    });

    // on the end of the modified-message fade in, remove the fade-in-message class.
    var animationEnd = "webkitAnimationEnd oanimationend msAnimationEnd animationend";
    $("body").on(animationEnd, ".fade-in-message", function () {
        $(this).removeClass("fade-in-message");
    });
};

exports.restore_compose_cursor = function () {
    $('#compose-textarea')
        .focus()
        .caret(saved_compose_cursor);
};

exports.initialize = function () {
    exports.set_compose_textarea_handlers();

    exports.do_stuff_for_desktop_app();

    exports.show_error_for_unsupported_platform();

    if (page_params.night_mode) {
        night_mode.enable();
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = ui;
}
<commit_msg>ui: Remove do_stuff_for_desktop_app call.<commit_after>var ui = (function () {

var exports = {};

// What, if anything, obscures the home tab?

exports.replace_emoji_with_text = function (element) {
    element.find(".emoji").replaceWith(function () {
        if ($(this).is("img")) {
            return $(this).attr("alt");
        }
        return $(this).text();
    });
};

exports.set_up_scrollbar = function (element) {
    var perfectScrollbar = new PerfectScrollbar(element[0], {
        suppressScrollX: true,
        useKeyboard: false,
        wheelSpeed: 0.68,
        scrollingThreshold: 50,
        minScrollbarLength: 40,
    });
    element[0].perfectScrollbar = perfectScrollbar;
};

exports.update_scrollbar = function (element) {
    element.scrollTop = 0;
    if (element[0].perfectScrollbar !== undefined) {
        element[0].perfectScrollbar.update();
    }
};

exports.destroy_scrollbar = function (element) {
    element[0].perfectScrollbar.destroy();
};

function update_message_in_all_views(message_id, callback) {
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) {
        if (list === undefined) {
            return;
        }
        var row = list.get_row(message_id);
        if (row === undefined) {
            // The row may not exist, e.g. if you do an action on a message in
            // a narrowed view
            return;
        }
        callback(row);
    });
}

exports.show_error_for_unsupported_platform = function () {
    // Check if the user is using old desktop app
    if (typeof(bridge) !== 'undefined') {
        // We don't internationalize this string because it is long,
        // and few users will have both the old desktop app and an
        // internationalized version of Zulip anyway.
        var error = "Hello! You're using the unsupported old Zulip desktop app," +
            " which is no longer developed. We recommend switching to the new, " +
            "modern desktop app, which you can download at " +
            "zulipchat.com/apps.";

        ui_report.generic_embed_error(error);
    }
};

exports.find_message = function (message_id) {
    // Try to find the message object. It might be in the narrow list
    // (if it was loaded when narrowed), or only in the message_list.all
    // (if received from the server while in a different narrow)
    var message;
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (msg_list) {
        if (msg_list !== undefined && message === undefined) {
            message = msg_list.get(message_id);
        }
    });
    return message;
};

exports.update_starred = function (message) {
    var starred = message.starred;

    // Avoid a full re-render, but update the star in each message
    // table in which it is visible.
    update_message_in_all_views(message.id, function update_row(row) {
        var elt = row.find(".star");
        if (starred) {
            elt.addClass("icon-vector-star").removeClass("icon-vector-star-empty").removeClass("empty-star");
        } else {
            elt.removeClass("icon-vector-star").addClass("icon-vector-star-empty").addClass("empty-star");
        }
        var title_state = starred ? i18n.t("Unstar") : i18n.t("Star");
        elt.attr("title", i18n.t("__starred_status__ this message", {starred_status: title_state}));
    });
};

exports.show_message_failed = function (message_id, failed_msg) {
    // Failed to send message, so display inline retry/cancel
    update_message_in_all_views(message_id, function update_row(row) {
        var failed_div = row.find('.message_failed');
        failed_div.toggleClass('notvisible', false);
        failed_div.find('.failed_text').attr('title', failed_msg);
    });
};

exports.remove_message = function (message_id) {
    _.each([message_list.all, home_msg_list, message_list.narrowed], function (list) {
        if (list === undefined) {
            return;
        }
        var row = list.get_row(message_id);
        if (row !== undefined) {
            list.remove_and_rerender([{id: message_id}]);
        }
    });
};

exports.show_failed_message_success = function (message_id) {
    // Previously failed message succeeded
    update_message_in_all_views(message_id, function update_row(row) {
        row.find('.message_failed').toggleClass('notvisible', true);
    });
};

var shown_deprecation_notices = [];
exports.maybe_show_deprecation_notice = function (key) {
    var message;
    if (key === 'C') {
        message = i18n.t('We\'ve replaced the "C" hotkey with "x" to make this common shortcut easier to trigger.');
    } else {
        blueslip.error("Unexpected deprecation notice for hotkey:", key);
        return;
    }

    // Here we handle the tracking for showing deprecation notices,
    // whether or not local storage is available.
    if (localstorage.supported()) {
        var notices_from_storage = JSON.parse(localStorage.getItem('shown_deprecation_notices'));
        if (notices_from_storage !== null) {
            shown_deprecation_notices = notices_from_storage;
        } else {
            shown_deprecation_notices = [];
        }
    }

    if (shown_deprecation_notices.indexOf(key) === -1) {
        $('#deprecation-notice-modal').modal('show');
        $('#deprecation-notice-message').text(message);
        shown_deprecation_notices.push(key);
        if (localstorage.supported()) {
            localStorage.setItem('shown_deprecation_notices', JSON.stringify(shown_deprecation_notices));
        }
    }
};

/* EXPERIMENTS */

/* This method allows an advanced user to use the console
 * to switch the application to span full width of the browser.
 */
exports.switchToFullWidth = function () {
    $("#full-width-style").remove();
    $('head').append('');
    return ("Switched to full width");
};

/* END OF EXPERIMENTS */

// Save the compose content cursor position and restore when we
// shift-tab back in (see hotkey.js).
var saved_compose_cursor = 0;

exports.set_compose_textarea_handlers = function () {
    $('#compose-textarea').blur(function () {
        saved_compose_cursor = $(this).caret();
    });

    // on the end of the modified-message fade in, remove the fade-in-message class.
    var animationEnd = "webkitAnimationEnd oanimationend msAnimationEnd animationend";
    $("body").on(animationEnd, ".fade-in-message", function () {
        $(this).removeClass("fade-in-message");
    });
};

exports.restore_compose_cursor = function () {
    $('#compose-textarea')
        .focus()
        .caret(saved_compose_cursor);
};

exports.initialize = function () {
    exports.set_compose_textarea_handlers();
    exports.show_error_for_unsupported_platform();

    if (page_params.night_mode) {
        night_mode.enable();
    }
};

return exports;
}());

if (typeof module !== 'undefined') {
    module.exports = ui;
}
<|endoftext|>


<commit_before>//
// Copyright (c) 2017 DrSmugleaf
//

"use strict"
const commando = require("discord.js-commando")
const oneLine = require("common-tags").oneLine

module.exports = class Skip extends commando.Command {
  constructor(client) {
    super(client, {
      name: "skip",
      aliases: ["skip"],
      group: "youtube",
      memberName: "skip",
      description: "Skips the currently playing video in this server",
      examples: ["skip"],
      guildOnly: true
    })

    this.votes = {}
  }

  isSameVoiceChannel(msg) {
    return msg.member.voiceChannel &&
      msg.member.voiceChannel == msg.guild.voiceConnection
  }

  async run(msg) {
    if(this.isSameVoiceChannel(msg)) {
      return msg.reply("You arent in the voice channel")
    }

    const voiceConnection = msg.guild.voiceConnection
    const id = msg.guild.id

    if(voiceConnection) {
      this.votes[id] = this.votes[id] ? +1 : 1

      if(this.votes[id] > (voiceConnection.channel.members.size - 1) / 2) {
        var dispatcher = voiceConnection.player.dispatcher
        var repeatList = this.client.registry.resolveCommand("youtube:repeat").repeatList

        if(repeatList[id]) repeatList.delete(msg.guild)
        dispatcher.end()

        return msg.send(oneLine`
          ${this.votes[id]} members voted to skip,
          skipped the current video
        `)
      } else {
        return msg.reply(oneLine`
          ${this.votes[id]} members want to skip
          the current video
        `)
      }
    }
  }
}
<commit_msg>Maybe this time with the proper check<commit_after>//
// Copyright (c) 2017 DrSmugleaf
//

"use strict"
const commando = require("discord.js-commando")
const constants = require("../../util/constants")
const oneLine = require("common-tags").oneLine

module.exports = class Skip extends commando.Command {
  constructor(client) {
    super(client, {
      name: "skip",
      aliases: ["skip"],
      group: "youtube",
      memberName: "skip",
      description: "Skips the currently playing video in this server",
      examples: ["skip"],
      guildOnly: true
    })

    this.votes = {}
  }

  isSameVoiceChannel(msg) {
    return msg.member.voiceChannel &&
      msg.member.voiceChannel.connection &&
      msg.member.voiceChannel.connection == msg.guild.voiceConnection
  }

  async run(msg) {
    if(!msg.member.voiceChannel) {
      return msg.reply(constants.responses.NOT_A_VOICE_CHANNEL["english"])
    }

    if(!this.isSameVoiceChannel(msg)) {
      return msg.reply("You arent in the voice channel")
    }

    const voiceConnection = msg.guild.voiceConnection
    const id = msg.guild.id

    if(voiceConnection) {
      this.votes[id] = this.votes[id] ? +1 : 1

      if(this.votes[id] > (voiceConnection.channel.members.size - 1) / 2) {
        var dispatcher = voiceConnection.player.dispatcher
        var repeatList = this.client.registry.resolveCommand("youtube:repeat").repeatList

        if(repeatList[id]) repeatList.delete(msg.guild)
        dispatcher.end()

        return msg.channel.send(oneLine`
          ${this.votes[id]} out of ${voiceConnection.channel.members.size - 1}
          members voted to skip, skipped the current video
        `)
      } else {
        return msg.reply(oneLine`
          ${this.votes[id]} out of ${voiceConnection.channel.members.size - 1}
          members want to skip the current video
        `)
      }
    }
  }
}
<|endoftext|>


<commit_before>HTMLWidgets.widget({

  name: 'sunburst',

  type: 'output',

  initialize: function(el, width, height) {

    d3.select(el).select(".sunburst-chart").append("svg")
      .attr("width", width)
      .attr("height", height);

    return {};

  },

  renderValue: function(el, x, instance) {

    // Dimensions of sunburst.
    var width = el.getBoundingClientRect().width;
    var height = el.getBoundingClientRect().height - 70;
    var radius = Math.min(width, height) / 2;

    // Breadcrumb dimensions: width, height, spacing, width of tip/tail.
    var b = {
      w: 75, h: 30, s: 3, t: 10
    };
/*
    // Mapping of step names to colors.
    var colors = {
      "home": "#5687d1",
      "product": "#7b615c",
      "search": "#de783b",
      "account": "#6ab975",
      "other": "#a173d1",
      "end": "#bbbbbb"
    };
*/

    var colors = d3.scale.category20();

    if(x.options.colors !== null){
      try{
        colors.range(x.options.colors)
      } catch(e) {

      }
    }
    // Total size of all segments; we set this later, after loading the data.
    var totalSize = 0;

    var vis = d3.select(el).select(".sunburst-chart").select("svg")
        .append("g")
        .attr("id", el.id + "-container")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    var partition = d3.layout.partition()
        .size([2 * Math.PI, radius * radius])
        .value(function(d) { return d.size; });

    var arc = d3.svg.arc()
        .startAngle(function(d) { return d.x; })
        .endAngle(function(d) { return d.x + d.dx; })
        .innerRadius(function(d) { return Math.sqrt(d.y); })
        .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });

    // x.data should be a data.frame in R so an Javascript Object of Objects
    //     but buildHierarchy expects an Array of Arrays
    //     so use d3.zip and apply to do this
    var json = [];
    if(x.csvdata !== null){
      json = buildHierarchy(
        d3.zip.apply(
          null,
          Object.keys(x.csvdata).map(function(ky){return x.csvdata[ky]})
        )
      );
    } else {
      json = x.jsondata
    }
    createVisualization(json);

    // Main function to draw and set up the visualization, once we have the data.
    function createVisualization(json) {

      // Basic setup of page elements.
      initializeBreadcrumbTrail();

      // Bounding circle underneath the sunburst, to make it easier to detect
      // when the mouse leaves the parent g.
      vis.append("circle")
          .attr("r", radius)
          .style("opacity", 0);

      // For efficiency, filter nodes to keep only those large enough to see.
      var nodes = partition.nodes(json)
          .filter(function(d) {
          return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
          });

      var path = vis.data([json]).selectAll("path")
          .data(nodes)
          .enter().append("path")
          .attr("display", function(d) { return d.depth ? null : "none"; })
          .attr("d", arc)
          .attr("fill-rule", "evenodd")
          .style("fill", function(d) { return colors(d.name); })
          .style("opacity", 1)
          .on("mouseover", mouseover);

      // Add the mouseleave handler to the bounding circle.
      d3.select(el).select("#"+ el.id + "-container").on("mouseleave", mouseleave);

      // Get total size of the tree = value of root node from partition.
      totalSize = path.node().__data__.value;

      drawLegend();
      d3.select(el).select(".sunburst-togglelegend").on("click", toggleLegend);

     };

    // Fade all but the current sequence, and show it in the breadcrumb trail.
    function mouseover(d) {

      var percentage = (100 * d.value / totalSize).toPrecision(3);
      var percentageString = percentage + "%";
      if (percentage < 0.1) {
        percentageString = "< 0.1%";
      }

      var countString = [
          '',
          d3.format("1.2s")(d.value) + ' of ' + d3.format("1.2s")(totalSize),
          ''
        ].join('')

      var explanationString = "";
      if(x.options.percent && x.options.count){
        explanationString = percentageString + '
' + countString;
      } else if(x.options.percent){
        explanationString = percentageString;
      } else if(x.options.count){
        explanationString = countString;
      }

      //if explanation defined in R then use this instead
      if(x.options.explanation !== null){
        explanationString = x.options.explanation(d);
      }

      //d3.select(el).select(".sunburst-percentage")
      //    .text(percentageString);
      var svgBound = d3.select(el).select("svg").node().getBoundingClientRect();
      var circleBound = d3.select(el).select("circle").node().getBoundingClientRect()

      d3.select(el).selectAll(".sunburst-explanation")
          .style("visibility", "")
          .style("top",(circleBound.height/2 + 10) + "px")
          .style("width",svgBound.width + "px")
          .html(explanationString);

      var sequenceArray = getAncestors(d);
      updateBreadcrumbs(sequenceArray, percentageString);

      // Fade all the segments.
      d3.select(el).selectAll("path")
          .style("opacity", 0.3);

      // Then highlight only those that are an ancestor of the current segment.
      vis.selectAll("path")
          .filter(function(node) {
                    return (sequenceArray.indexOf(node) >= 0);
                  })
          .style("opacity", 1);
    }

    // Restore everything to full opacity when moving off the visualization.
    function mouseleave(d) {

      // Hide the breadcrumb trail
      d3.select(el).select("#" + el.id + "-trail")
          .style("visibility", "hidden");

      // Deactivate all segments during transition.
      d3.select(el).selectAll("path").on("mouseover", null);

      // Transition each segment to full opacity and then reactivate it.
      d3.select(el).selectAll("path")
          .transition()
          .duration(1000)
          .style("opacity", 1)
          .each("end", function() {
                  d3.select(this).on("mouseover", mouseover);
                });

      d3.select(el).selectAll(".sunburst-explanation")
          .style("visibility", "hidden");
    }

    // Given a node in a partition layout, return an array of all of its ancestor
    // nodes, highest first, but excluding the root.
    function getAncestors(node) {
      var path = [];
      var current = node;
      while (current.parent) {
        path.unshift(current);
        current = current.parent;
      }
      return path;
    }

    function initializeBreadcrumbTrail() {
      // Add the svg area.
      var trail = d3.select(el).select(".sunburst-sequence").append("svg")
          .attr("width", width)
          .attr("height", 50)
          .attr("id", el.id + "-trail");
      // Add the label at the end, for the percentage.
      trail.append("text")
        .attr("id", el.id + "-endlabel")
        .style("fill", "#000");
    }

    // Generate a string that describes the points of a breadcrumb polygon.
    function breadcrumbPoints(d, i) {
      var points = [];
      points.push("0,0");
      points.push(b.w + ",0");
      points.push(b.w + b.t + "," + (b.h / 2));
      points.push(b.w + "," + b.h);
      points.push("0," + b.h);
      if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
        points.push(b.t + "," + (b.h / 2));
      }
      return points.join(" ");
    }

    // Update the breadcrumb trail to show the current sequence and percentage.
    function updateBreadcrumbs(nodeArray, percentageString) {

      // Data join; key function combines name and depth (= position in sequence).
      var g = d3.select(el).select("#" + el.id + "-trail")
          .selectAll("g")
          .data(nodeArray, function(d) { return d.name + d.depth; });

      // Add breadcrumb and label for entering nodes.
      var entering = g.enter().append("g");

      entering.append("polygon")
          .attr("points", breadcrumbPoints)
          .style("fill", function(d) { return colors(d.name); });

      entering.append("text")
          .attr("x", (b.w + b.t) / 2)
          .attr("y", b.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(function(d) { return d.name; });

      // Set position for entering and updating nodes.
      g.attr("transform", function(d, i) {
        return "translate(" + i * (b.w + b.s) + ", 0)";
      });

      // Remove exiting nodes.
      g.exit().remove();

      // Now move and update the percentage at the end.
      d3.select(el).select("#" + el.id + "-trail").select("#" + el.id + "-endlabel")
          .attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
          .attr("y", b.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(percentageString);

      // Make the breadcrumb trail visible, if it's hidden.
      d3.select(el).select("#" + el.id + "-trail")
          .style("visibility", "");

    }

    function drawLegend() {

      // Dimensions of legend item: width, height, spacing, radius of rounded rect.
      var li = {
        w: 75, h: 30, s: 3, r: 3
      };

      var legend = d3.select(el).select(".sunburst-legend").append("svg")
          .attr("width", li.w)
          .attr("height", colors.domain().length * (li.h + li.s));

      var g = legend.selectAll("g")
          .data( function(){
            if(x.options.legendOrder !== null){
              return x.options.legendOrder;
            } else {
              // get sorted by top level
              sortedname = d3.set(Object.keys(d3.nest().key(function(d){return d.name}).rollup(function(d){return d[0].value}).map(json.children) ))
              // add any other missing
              colors.domain()
                .filter(function(d){
                  return d !== json.name;
                })
                .forEach(function(d){
                  sortedname.add(d)
                })
              return sortedname.values();
            }
          })
          .enter().append("g")
          .attr("transform", function(d, i) {
                  return "translate(0," + i * (li.h + li.s) + ")";
               });

      g.append("rect")
          .attr("rx", li.r)
          .attr("ry", li.r)
          .attr("width", li.w)
          .attr("height", li.h)
          .style("fill", function(d) { return colors(d); });

      g.append("text")
          .attr("x", li.w / 2)
          .attr("y", li.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(function(d) { return d; });
    }

    function toggleLegend() {
      var legend = d3.select(el).select(".sunburst-legend")
      if (legend.style("visibility") == "hidden") {
        legend.style("visibility", "");
      } else {
        legend.style("visibility", "hidden");
      }
    }

    // Take a 2-column CSV and transform it into a hierarchical structure suitable
    // for a partition layout. The first column is a sequence of step names, from
    // root to leaf, separated by hyphens. The second column is a count of how
    // often that sequence occurred.
    function buildHierarchy(csv) {
      var root = {"name": "root", "children": []};
      for (var i = 0; i < csv.length; i++) {
        var sequence = csv[i][0];
        var size = +csv[i][1];
        if (isNaN(size)) { // e.g. if this is a header row
          continue;
        }
        var parts = sequence.split("-");
        var currentNode = root;
        for (var j = 0; j < parts.length; j++) {
          var children = currentNode["children"];
          var nodeName = parts[j];
          var childNode;
          if (j + 1 < parts.length) {
       // Not yet at the end of the sequence; move down the tree.
     	var foundChild = false;
     	for (var k = 0; k < children.length; k++) {
     	  if (children[k]["name"] == nodeName) {
     	    childNode = children[k];
     	    foundChild = true;
     	    break;
     	  }
     	}
      // If we don't already have a child node for this branch, create it.
     	if (!foundChild) {
     	  childNode = {"name": nodeName, "children": []};
     	  children.push(childNode);
     	}
     	currentNode = childNode;
          } else {
     	// Reached the end of the sequence; create a leaf node.
     	childNode = {"name": nodeName, "size": size};
     	children.push(childNode);
          }
        }
      }
      return root;
    };

  },

  resize: function(el, width, height, instance) {

  }

});
<commit_msg>remove contents for shiny/dynamic<commit_after>HTMLWidgets.widget({

  name: 'sunburst',

  type: 'output',

  initialize: function(el, width, height) {

    d3.select(el).select(".sunburst-chart").append("svg")
      .attr("width", width)
      .attr("height", height);

    return {};

  },

  renderValue: function(el, x, instance) {

    // remove previous in case of Shiny/dynamic
    el.innerHTML = "";

    // Dimensions of sunburst.
    var width = el.getBoundingClientRect().width;
    var height = el.getBoundingClientRect().height - 70;
    var radius = Math.min(width, height) / 2;

    // Breadcrumb dimensions: width, height, spacing, width of tip/tail.
    var b = {
      w: 75, h: 30, s: 3, t: 10
    };
/*
    // Mapping of step names to colors.
    var colors = {
      "home": "#5687d1",
      "product": "#7b615c",
      "search": "#de783b",
      "account": "#6ab975",
      "other": "#a173d1",
      "end": "#bbbbbb"
    };
*/

    var colors = d3.scale.category20();

    if(x.options.colors !== null){
      try{
        colors.range(x.options.colors)
      } catch(e) {

      }
    }
    // Total size of all segments; we set this later, after loading the data.
    var totalSize = 0;

    var vis = d3.select(el).select(".sunburst-chart").select("svg")
        .append("g")
        .attr("id", el.id + "-container")
        .attr("transform", "translate(" + width / 2 + "," + height / 2 + ")");

    var partition = d3.layout.partition()
        .size([2 * Math.PI, radius * radius])
        .value(function(d) { return d.size; });

    var arc = d3.svg.arc()
        .startAngle(function(d) { return d.x; })
        .endAngle(function(d) { return d.x + d.dx; })
        .innerRadius(function(d) { return Math.sqrt(d.y); })
        .outerRadius(function(d) { return Math.sqrt(d.y + d.dy); });

    // x.data should be a data.frame in R so an Javascript Object of Objects
    //     but buildHierarchy expects an Array of Arrays
    //     so use d3.zip and apply to do this
    var json = [];
    if(x.csvdata !== null){
      json = buildHierarchy(
        d3.zip.apply(
          null,
          Object.keys(x.csvdata).map(function(ky){return x.csvdata[ky]})
        )
      );
    } else {
      json = x.jsondata
    }
    createVisualization(json);

    // Main function to draw and set up the visualization, once we have the data.
    function createVisualization(json) {

      // Basic setup of page elements.
      initializeBreadcrumbTrail();

      // Bounding circle underneath the sunburst, to make it easier to detect
      // when the mouse leaves the parent g.
      vis.append("circle")
          .attr("r", radius)
          .style("opacity", 0);

      // For efficiency, filter nodes to keep only those large enough to see.
      var nodes = partition.nodes(json)
          .filter(function(d) {
          return (d.dx > 0.005); // 0.005 radians = 0.29 degrees
          });

      var path = vis.data([json]).selectAll("path")
          .data(nodes)
          .enter().append("path")
          .attr("display", function(d) { return d.depth ? null : "none"; })
          .attr("d", arc)
          .attr("fill-rule", "evenodd")
          .style("fill", function(d) { return colors(d.name); })
          .style("opacity", 1)
          .on("mouseover", mouseover);

      // Add the mouseleave handler to the bounding circle.
      d3.select(el).select("#"+ el.id + "-container").on("mouseleave", mouseleave);

      // Get total size of the tree = value of root node from partition.
      totalSize = path.node().__data__.value;

      drawLegend();
      d3.select(el).select(".sunburst-togglelegend").on("click", toggleLegend);

     };

    // Fade all but the current sequence, and show it in the breadcrumb trail.
    function mouseover(d) {

      var percentage = (100 * d.value / totalSize).toPrecision(3);
      var percentageString = percentage + "%";
      if (percentage < 0.1) {
        percentageString = "< 0.1%";
      }

      var countString = [
          '',
          d3.format("1.2s")(d.value) + ' of ' + d3.format("1.2s")(totalSize),
          ''
        ].join('')

      var explanationString = "";
      if(x.options.percent && x.options.count){
        explanationString = percentageString + '
' + countString;
      } else if(x.options.percent){
        explanationString = percentageString;
      } else if(x.options.count){
        explanationString = countString;
      }

      //if explanation defined in R then use this instead
      if(x.options.explanation !== null){
        explanationString = x.options.explanation(d);
      }

      //d3.select(el).select(".sunburst-percentage")
      //    .text(percentageString);
      var svgBound = d3.select(el).select("svg").node().getBoundingClientRect();
      var circleBound = d3.select(el).select("circle").node().getBoundingClientRect()

      d3.select(el).selectAll(".sunburst-explanation")
          .style("visibility", "")
          .style("top",(circleBound.height/2 + 10) + "px")
          .style("width",svgBound.width + "px")
          .html(explanationString);

      var sequenceArray = getAncestors(d);
      updateBreadcrumbs(sequenceArray, percentageString);

      // Fade all the segments.
      d3.select(el).selectAll("path")
          .style("opacity", 0.3);

      // Then highlight only those that are an ancestor of the current segment.
      vis.selectAll("path")
          .filter(function(node) {
                    return (sequenceArray.indexOf(node) >= 0);
                  })
          .style("opacity", 1);
    }

    // Restore everything to full opacity when moving off the visualization.
    function mouseleave(d) {

      // Hide the breadcrumb trail
      d3.select(el).select("#" + el.id + "-trail")
          .style("visibility", "hidden");

      // Deactivate all segments during transition.
      d3.select(el).selectAll("path").on("mouseover", null);

      // Transition each segment to full opacity and then reactivate it.
      d3.select(el).selectAll("path")
          .transition()
          .duration(1000)
          .style("opacity", 1)
          .each("end", function() {
                  d3.select(this).on("mouseover", mouseover);
                });

      d3.select(el).selectAll(".sunburst-explanation")
          .style("visibility", "hidden");
    }

    // Given a node in a partition layout, return an array of all of its ancestor
    // nodes, highest first, but excluding the root.
    function getAncestors(node) {
      var path = [];
      var current = node;
      while (current.parent) {
        path.unshift(current);
        current = current.parent;
      }
      return path;
    }

    function initializeBreadcrumbTrail() {
      // Add the svg area.
      var trail = d3.select(el).select(".sunburst-sequence").append("svg")
          .attr("width", width)
          .attr("height", 50)
          .attr("id", el.id + "-trail");
      // Add the label at the end, for the percentage.
      trail.append("text")
        .attr("id", el.id + "-endlabel")
        .style("fill", "#000");
    }

    // Generate a string that describes the points of a breadcrumb polygon.
    function breadcrumbPoints(d, i) {
      var points = [];
      points.push("0,0");
      points.push(b.w + ",0");
      points.push(b.w + b.t + "," + (b.h / 2));
      points.push(b.w + "," + b.h);
      points.push("0," + b.h);
      if (i > 0) { // Leftmost breadcrumb; don't include 6th vertex.
        points.push(b.t + "," + (b.h / 2));
      }
      return points.join(" ");
    }

    // Update the breadcrumb trail to show the current sequence and percentage.
    function updateBreadcrumbs(nodeArray, percentageString) {

      // Data join; key function combines name and depth (= position in sequence).
      var g = d3.select(el).select("#" + el.id + "-trail")
          .selectAll("g")
          .data(nodeArray, function(d) { return d.name + d.depth; });

      // Add breadcrumb and label for entering nodes.
      var entering = g.enter().append("g");

      entering.append("polygon")
          .attr("points", breadcrumbPoints)
          .style("fill", function(d) { return colors(d.name); });

      entering.append("text")
          .attr("x", (b.w + b.t) / 2)
          .attr("y", b.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(function(d) { return d.name; });

      // Set position for entering and updating nodes.
      g.attr("transform", function(d, i) {
        return "translate(" + i * (b.w + b.s) + ", 0)";
      });

      // Remove exiting nodes.
      g.exit().remove();

      // Now move and update the percentage at the end.
      d3.select(el).select("#" + el.id + "-trail").select("#" + el.id + "-endlabel")
          .attr("x", (nodeArray.length + 0.5) * (b.w + b.s))
          .attr("y", b.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(percentageString);

      // Make the breadcrumb trail visible, if it's hidden.
      d3.select(el).select("#" + el.id + "-trail")
          .style("visibility", "");

    }

    function drawLegend() {

      // Dimensions of legend item: width, height, spacing, radius of rounded rect.
      var li = {
        w: 75, h: 30, s: 3, r: 3
      };

      var legend = d3.select(el).select(".sunburst-legend").append("svg")
          .attr("width", li.w)
          .attr("height", colors.domain().length * (li.h + li.s));

      var g = legend.selectAll("g")
          .data( function(){
            if(x.options.legendOrder !== null){
              return x.options.legendOrder;
            } else {
              // get sorted by top level
              sortedname = d3.set(Object.keys(d3.nest().key(function(d){return d.name}).rollup(function(d){return d[0].value}).map(json.children) ))
              // add any other missing
              colors.domain()
                .filter(function(d){
                  return d !== json.name;
                })
                .forEach(function(d){
                  sortedname.add(d)
                })
              return sortedname.values();
            }
          })
          .enter().append("g")
          .attr("transform", function(d, i) {
                  return "translate(0," + i * (li.h + li.s) + ")";
               });

      g.append("rect")
          .attr("rx", li.r)
          .attr("ry", li.r)
          .attr("width", li.w)
          .attr("height", li.h)
          .style("fill", function(d) { return colors(d); });

      g.append("text")
          .attr("x", li.w / 2)
          .attr("y", li.h / 2)
          .attr("dy", "0.35em")
          .attr("text-anchor", "middle")
          .text(function(d) { return d; });
    }

    function toggleLegend() {
      var legend = d3.select(el).select(".sunburst-legend")
      if (legend.style("visibility") == "hidden") {
        legend.style("visibility", "");
      } else {
        legend.style("visibility", "hidden");
      }
    }

    // Take a 2-column CSV and transform it into a hierarchical structure suitable
    // for a partition layout. The first column is a sequence of step names, from
    // root to leaf, separated by hyphens. The second column is a count of how
    // often that sequence occurred.
    function buildHierarchy(csv) {
      var root = {"name": "root", "children": []};
      for (var i = 0; i < csv.length; i++) {
        var sequence = csv[i][0];
        var size = +csv[i][1];
        if (isNaN(size)) { // e.g. if this is a header row
          continue;
        }
        var parts = sequence.split("-");
        var currentNode = root;
        for (var j = 0; j < parts.length; j++) {
          var children = currentNode["children"];
          var nodeName = parts[j];
          var childNode;
          if (j + 1 < parts.length) {
       // Not yet at the end of the sequence; move down the tree.
     	var foundChild = false;
     	for (var k = 0; k < children.length; k++) {
     	  if (children[k]["name"] == nodeName) {
     	    childNode = children[k];
     	    foundChild = true;
     	    break;
     	  }
     	}
      // If we don't already have a child node for this branch, create it.
     	if (!foundChild) {
     	  childNode = {"name": nodeName, "children": []};
     	  children.push(childNode);
     	}
     	currentNode = childNode;
          } else {
     	// Reached the end of the sequence; create a leaf node.
     	childNode = {"name": nodeName, "size": size};
     	children.push(childNode);
          }
        }
      }
      return root;
    };

  },

  resize: function(el, width, height, instance) {

  }

});
<|endoftext|>


<commit_before>import { obj, num } from "lively.lang";
import { pt, Color, Rectangle } from "lively.graphics";
import { Morph, Button, List, Text } from "./index.js";
import { Icon } from "./icons.js";
import { signal, connect } from "lively.bindings";
import { Tooltip } from "./tooltips.js";
import config from "./config.js";

export class ValueScrubber extends Text {

  constructor(props) {
      super({
        fill: Color.transparent, draggable: true,
        textString: obj.safeToString(this.scrubbedValue),
        min: -Infinity,
        max: Infinity,
        ...obj.dissoc(props, ["value"])
      });

      this.value = props.value || 0;
  }

  onDragStart(evt) {
     this.execCommand("toggle active mark");
     this.initPos = evt.position;
     this.factorLabel = new Tooltip({
          position: evt.hand.position.addXY(10,10),
          description: "1x"}).openInWorld();
  }

  onKeyDown(evt) {
    super.onKeyDown(evt);
    if ("Enter" == evt.keyCombo) {
      const [v, unit] = this.textString.split(" ");
      if (v) {
         this.value = parseFloat(v);
         signal(this, "scrub", this.scrubbedValue);
      }
      evt.stop();
    }
  }

  onDrag(evt) {
      // x delta is the offset to the original value
      // y is the scale
      const {x, y} = evt.position.subPt(this.initPos),
            scaleFactor = num.roundTo(Math.exp(-y / this.world().height * 4), 0.01),
            v = this.getCurrentValue(x, scaleFactor);
      signal(this, "scrub", v);
      this.textString = obj.safeToString(v);
      if (this.unit) this.textString += " " + this.unit;
      this.factorLabel.description = scaleFactor + "x";
      this.factorLabel.position = evt.hand.position.addXY(10,10);
  }

  getCurrentValue(delta, s) {
      const v = this.scrubbedValue + Math.round(delta * s);
      return Math.max(this.min, Math.min(this.max, v));
  }

  onDragEnd(evt) {
      const {x, y} = this.initPos.subPt(evt.position),
            scaleFactor = num.roundTo(Math.exp(-y / this.world().height * 4), 0.01);
      this.scrubbedValue = this.getCurrentValue(x, scaleFactor);
      this.factorLabel.softRemove();
  }

  set value(v) {
      v = Math.max(this.min, Math.min(this.max, v));
      this.scrubbedValue = v;
      this.textString = obj.safeToString(v) || "";
      if (this.unit) this.textString += " " + this.unit;
  }

}

export class CheckBox extends Morph {

  constructor(props) {
    super({
      draggable: false,
      extent: pt(18, 18),
      borderWidth: 0,
      active: true,
      checked: false,
      fill: Color.transparent,
      ...props,
    });
  }

  get checked() { return this.getProperty("checked"); }
  set checked(value) { this.addValueChange("checked", value); }
  get active() { return this.getProperty("active"); }
  set active(value) { this.addValueChange("active", value); }

  trigger() {
    try {
      this.checked = !this.checked;
      signal(this, "toggle", this.checked);
    } catch (err) {
      var w = this.world();
      if (w) w.logError(err);
      else console.error(err);
    }
  }

  onMouseDown(evt) {
    if (this.active) this.trigger();
  }

  render(renderer) {
    return renderer.renderCheckBox(this);
  }

}
<commit_msg>widgets: add mode selector widget<commit_after>import { obj, num, arr } from "lively.lang";
import { pt, Color, Rectangle } from "lively.graphics";
import { Morph, Button, List, Text, GridLayout } from "./index.js";
import { Icon } from "./icons.js";
import { signal, connect } from "lively.bindings";
import { Tooltip } from "./tooltips.js";
import config from "./config.js";

export class ValueScrubber extends Text {

  constructor(props) {
      super({
        fill: Color.transparent, draggable: true,
        textString: obj.safeToString(this.scrubbedValue),
        min: -Infinity,
        max: Infinity,
        ...obj.dissoc(props, ["value"])
      });

      this.value = props.value || 0;
  }

  onDragStart(evt) {
     this.execCommand("toggle active mark");
     this.initPos = evt.position;
     this.factorLabel = new Tooltip({
          position: evt.hand.position.addXY(10,10),
          description: "1x"}).openInWorld();
  }

  onKeyDown(evt) {
    super.onKeyDown(evt);
    if ("Enter" == evt.keyCombo) {
      const [v, unit] = this.textString.split(" ");
      if (v) {
         this.value = parseFloat(v);
         signal(this, "scrub", this.scrubbedValue);
      }
      evt.stop();
    }
  }

  onDrag(evt) {
      // x delta is the offset to the original value
      // y is the scale
      const {x, y} = evt.position.subPt(this.initPos),
            scaleFactor = num.roundTo(Math.exp(-y / this.world().height * 4), 0.01),
            v = this.getCurrentValue(x, scaleFactor);
      signal(this, "scrub", v);
      this.textString = obj.safeToString(v);
      if (this.unit) this.textString += " " + this.unit;
      this.factorLabel.description = scaleFactor + "x";
      this.factorLabel.position = evt.hand.position.addXY(10,10);
  }

  getCurrentValue(delta, s) {
      const v = this.scrubbedValue + Math.round(delta * s);
      return Math.max(this.min, Math.min(this.max, v));
  }

  onDragEnd(evt) {
      const {x, y} = this.initPos.subPt(evt.position),
            scaleFactor = num.roundTo(Math.exp(-y / this.world().height * 4), 0.01);
      this.scrubbedValue = this.getCurrentValue(x, scaleFactor);
      this.factorLabel.softRemove();
  }

  set value(v) {
      v = Math.max(this.min, Math.min(this.max, v));
      this.scrubbedValue = v;
      this.textString = obj.safeToString(v) || "";
      if (this.unit) this.textString += " " + this.unit;
  }

}

export class CheckBox extends Morph {

  constructor(props) {
    super({
      draggable: false,
      extent: pt(18, 18),
      borderWidth: 0,
      active: true,
      checked: false,
      fill: Color.transparent,
      ...props,
    });
  }

  get checked() { return this.getProperty("checked"); }
  set checked(value) { this.addValueChange("checked", value); }
  get active() { return this.getProperty("active"); }
  set active(value) { this.addValueChange("active", value); }

  trigger() {
    try {
      this.checked = !this.checked;
      signal(this, "toggle", this.checked);
    } catch (err) {
      var w = this.world();
      if (w) w.logError(err);
      else console.error(err);
    }
  }

  onMouseDown(evt) {
    if (this.active) this.trigger();
  }

  render(renderer) {
    return renderer.renderCheckBox(this);
  }

}

export class ModeSelector extends Morph {

   constructor(props) {
     var {items, initLabel, tooltips = {}} = props, keys, values;
     if (obj.isArray(items)) {
         keys = values = items;
     } else {
         keys = obj.keys(items);
         values = obj.values(items);
     }
     super({
         keys, values, tooltips,
         morphClasses: ['root'],
         layout: new GridLayout({
             grid: [[null, ...arr.interpose(keys.map(k => k + "Label"), null), null]],
             autoAssign: false, fitToCell: false,
         }),
         ...props
      })
      this.build();
      this.switchLabel(initLabel ? initLabel : keys[0]);
      connect(this, "extent", this, "relayout");
    }

    build() {
       this.submorphs = [
            {name: "typeMarker"},
            ...this.createLabels(this.keys, this.values, this.tooltips)
         ]
       this.applyStyler();
    }

    applyStyler() {
       this.withAllSubmorphsDo(m => {
         var styleProps;
         if (styleProps = this.styler[m.name]) {
            Object.assign(m, styleProps);
         } else if (m.morphClasses) {
            styleProps = obj.merge(arr.compact(m.morphClasses.map(c => this.styler[c])));
            Object.assign(m, styleProps);
         }
      })
    }

    get styler() {
       return {
          root: {fill: Color.transparent,
                 height: 30, origin: pt(0,5)},
          typeMarker: {fill: Color.gray.darker(), borderRadius: 3},
          label: {fontWeight: 'bold', nativeCursor: "pointer", padding: 4}
       }
    }

    createLabels(keys, values, tooltips = {}) {
       return arr.zip(keys, values)
                 .map(([name, value]) => {
                   const tooltip = tooltips[name];
                   return {
                      name: name + "Label", morphClasses: ['label'],
                      type: "label", value: name,
                      ...tooltip && {tooltip},
                      onMouseDown: () => {
                         this.switchLabel(name, value);
                }}});
    }

    async relayout() {
        return this.currentLabel && this.get("typeMarker").animate({bounds: this.currentLabel.bounds(), duration: 200});
    }

    async switchLabel(label, value) {
       const newLabel = this.get(label + "Label"), duration = 200;
       newLabel.animate({fontColor: Color.white, duration});
       this.currentLabel && this.currentLabel.animate({fontColor: Color.black, duration});
       this.currentLabel = newLabel;
       await this.relayout();
       signal(this, label, value)
    }
}
<|endoftext|>


<commit_before>'use strict'

// Imports
const TelegramBot = require('node-telegram-bot-api')
const matchAll = require('match-all')
const db = require('./db')
const remove = require('unordered-array-remove')

// Declarations
const token = process.env.TOKEN
const chatId = process.env.CHATID
let bot = null

if (process.env.NODE_ENV === 'production') {
  bot = new TelegramBot(token)
  bot.setWebHook(process.env.HEROKU_URL + bot.token)
  console.log('Running in production')
} else {
  bot = new TelegramBot(token, { polling: true })
  console.log('Running in development')
}
console.log('Bot started!')
console.log('Token:', token)
console.log('ChatId:', chatId)

// Custom keyboards
const keyboards = {
  howMom: {
    reply_markup: JSON.stringify({
      keyboard: [
        [{ text: 'Bene' }],
        [{ text: 'Male' }]
      ]
    })
  },
  hideKeyboard: {
    reply_to_message_id: null,
    reply_markup: JSON.stringify({
      hide_keyboard: true,
      selective: true
    })
  }
}

// /mom command
bot.onText(/\/mom/, function (message, match) {
  const reg = /@(\w+)/gi
  const users = matchAll(message.text, reg).toArray()
  // If the user sends "/mom@Your_Mom_Bot"
  const botName = users.indexOf('Your_Mom_Bot')
  if (botName !== -1) remove(users, botName)
  if (!users.length) return

  users.forEach((user) => {
    db.get(user.toLowerCase(), (err, value) => {
      if (err) {
        if (err.error === 'Key not found') {
          bot.sendMessage(chatId, 'Non ha ancora risposto!')
        } else {
          console.log(err)
          bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
        }
        return
      }
      bot.sendMessage(chatId, `${user.toLowerCase()} ${value}`)
    })
  })
})

// /allmom command
bot.onText(/\/allmom/, function (message, match) {
  db.all((err, iterator) => {
    if (err) {
      console.log(err)
      bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
    }
    for (let [key, value] of iterator()) {
      bot.sendMessage(chatId, `${key} ${value}`)
    }
  })
})

// /mymom command
bot.onText(/\/mymom/, sendHowMom)

// Sends "How is your mom?" with a custom keyboard response.
function sendHowMom (message, match) {
  bot.sendMessage(chatId, 'Come sta la tua mamma?', keyboards.howMom)
    .then((message) => {
      bot.onReplyToMessage(message.chat.id, message.message_id, (reply) => {
        db.put(reply.from.username.toLowerCase(), reply.text, (err) => {
          if (err) {
            console.log(err)
            bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
          }
          keyboards.hideKeyboard.reply_to_message_id = reply.message_id
          bot.sendMessage(chatId, 'ok!', keyboards.hideKeyboard)
        })
      })
    })
}

sendHowMom()
// setInterval(sendHowMom, 1000 * 60 * 60 * 24)

module.exports = bot
<commit_msg>Added interval<commit_after>'use strict'

// Imports
const TelegramBot = require('node-telegram-bot-api')
const matchAll = require('match-all')
const db = require('./db')
const remove = require('unordered-array-remove')

// Declarations
const token = process.env.TOKEN
const chatId = process.env.CHATID
let bot = null

if (process.env.NODE_ENV === 'production') {
  bot = new TelegramBot(token)
  bot.setWebHook(process.env.HEROKU_URL + bot.token)
  console.log('Running in production')
} else {
  bot = new TelegramBot(token, { polling: true })
  console.log('Running in development')
}
console.log('Bot started!')
console.log('Token:', token)
console.log('ChatId:', chatId)

// Custom keyboards
const keyboards = {
  howMom: {
    reply_markup: JSON.stringify({
      keyboard: [
        [{ text: 'Bene' }],
        [{ text: 'Male' }]
      ]
    })
  },
  hideKeyboard: {
    reply_to_message_id: null,
    reply_markup: JSON.stringify({
      hide_keyboard: true,
      selective: true
    })
  }
}

// /mom command
bot.onText(/\/mom/, function (message, match) {
  const reg = /@(\w+)/gi
  const users = matchAll(message.text, reg).toArray()
  // If the user sends "/mom@Your_Mom_Bot"
  const botName = users.indexOf('Your_Mom_Bot')
  if (botName !== -1) remove(users, botName)
  if (!users.length) return

  users.forEach((user) => {
    db.get(user.toLowerCase(), (err, value) => {
      if (err) {
        if (err.error === 'Key not found') {
          bot.sendMessage(chatId, 'Non ha ancora risposto!')
        } else {
          console.log(err)
          bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
        }
        return
      }
      bot.sendMessage(chatId, `${user.toLowerCase()} ${value}`)
    })
  })
})

// /allmom command
bot.onText(/\/allmom/, function (message, match) {
  db.all((err, iterator) => {
    if (err) {
      console.log(err)
      bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
    }
    for (let [key, value] of iterator()) {
      bot.sendMessage(chatId, `${key} ${value}`)
    }
  })
})

// /mymom command
bot.onText(/\/mymom/, sendHowMom)

// Sends "How is your mom?" with a custom keyboard response.
function sendHowMom (message, match) {
  bot.sendMessage(chatId, 'Come sta la tua mamma?', keyboards.howMom)
    .then((message) => {
      bot.onReplyToMessage(message.chat.id, message.message_id, (reply) => {
        db.put(reply.from.username.toLowerCase(), reply.text, (err) => {
          if (err) {
            console.log(err)
            bot.sendMessage(chatId, 'Ops, è accaduto qualcosa di spiacevole!')
          }
          keyboards.hideKeyboard.reply_to_message_id = reply.message_id
          bot.sendMessage(chatId, 'ok!', keyboards.hideKeyboard)
        })
      })
    })
}

sendHowMom()
setInterval(sendHowMom, 1000 * 60 * 60 * 24)

module.exports = bot
<|endoftext|>


<commit_before>console.log('Load babel config');

module.exports = {
  presets: [
    [
      '@babel/preset-env',
      {
        loose:true,
        modules: false,
      },
    ],
  ],

  // plugins:[["@babel/plugin-transform-runtime",{
  //   helpers:false,
  //
  // }],
  //   ["module-resolver", {
  //     "root": ["./src"],
  //     "alias": {
  //       "@babel/runtime/regenerator": "regenerator-runtime",
  //     }
  //   }]
  // ],
  env: {
    test: {
      presets: [
        [
          '@babel/preset-env',
          {
            targets: {
              node: true,
            },
          },
        ],
      ],
      plugins: ['@babel/plugin-transform-modules-commonjs'],
    },
  },
};
<commit_msg>clean babel<commit_after>console.log('Load babel config');

module.exports = (api) => {
  return ({
    presets: [
      [
        '@babel/preset-env',
        (api.env() !== 'test') ? ({
          loose: true,
          modules: false,
        }) : { targets: { node: true } },
      ],
    ],
  });
};
<|endoftext|>


<commit_before>var util = require('util');
var events = require('events');
var SerialPort = require("serialport").SerialPort;
var fs = require('fs');
var path = require('path');
var glob = require('glob');

function LidarPacket(index, speed, dist1, dist2, dist3, dist4){
    this.index = index;
    this.speed = speed;
    this.dist1 = dist1;
    this.dist2 = dist2;
    this.dist3 = dist3;
    this.dist4 = dist4;
}

/**
 * Computes and returns the checksum as an int.
 * @param {Array} data - The data to compute the checksum for. Must be 20 bytes.
 * @return {Number} The checksum as an integer.
 */
var computeChecksum = function(data) {
    // group the data by word, little-endian
    var dataList = [];
    for (var i = 0; i < 10; i++){
        dataList.push(data[2*i] + (data[2*i+1]<<8));
    }

    // compute the checksum on 32 bits
    var chk32 = 0;
    dataList.forEach(function(item){
        chk32 = (chk32 << 1) + item;
    });

    // return a value wrapped around on 15 bits, and truncated to still fit into 15 bits
    var checksum = (chk32 & 0x7FFF) + (chk32 >> 15); // wrap around to fit into 15 bits
    checksum = checksum & 0x7FFF; // truncate to 15 bits
    return checksum;
};

/**
 * Gets the lidar distance reading from a 4 byte data section.
 * @param {Array} bytes - Buffer with 4 bytes of data.
 * @return {Number} The distance reading as an integer.
 */
var parsePacketDataSection = function(bytes) {
    // if the 8th bit of the byte 1 is set, the data is invalid; the 7th bit of byte 1 is a strength warning (varies with material sometimes) flag, but we are ignoring it for now
    if (bytes[1] & 128 === 128)
        return -1;

    // get distance from byte 0 and byte 1; byte 2 and byte 3 contain signal strength data, which we are ignoring for now
    return bytes[0] + ((bytes[1] & 63) << 8);
};

var parsePacket = function(bytes) {
    // first byte in the packet must be 0xFA
    if (bytes[0] != 0xFA)
        return null;

    // verify data via checksum
    if (computeChecksum(bytes.slice(0, 20)) !== (bytes[20] + (bytes[21] << 8)))
        return null;

    // packet index must be between 0xA0 and 0xF9
    var index = bytes[1];
    if (index < 0xA0 || index > 0xF9)
        return null;

    // adjust index to 0 based index
    index = index - 0xA0;

    // speed unit used by the LIDAR is in 64ths of an RPM; we want the speed in RPMs
    var speed = (bytes[2] + (bytes[3]<<8))/64.0;

    var distances = [];
    for (var i = 1; i < 5; i++)
        distances.push(parsePacketDataSection(bytes.slice(4*i, 4*i+4)));

    return new LidarPacket(index, speed, distances[0], distances[1], distances[2], distances[3]);
};

function Lidar(serialPath, pwmPath) {
    var self = this;
    self._pwmPath = pwmPath;
    self._pwmDuty = 380000;
    self._serialPort = new SerialPort(serialPath, {
        baudrate: 115200
    });

    self._serialPort.on("open", function () {
        console.log('serial port to lidar is open');

        var currentPacketData = [];
        self._serialPort.on('data', function(data) {
            //console.log('data received from lidar: ' + data.toString('hex'));
            self.emit('raw data', data);

            for (var i = 0; i < data.length; i++) {
                var b = data[i];

                // if we're starting a new packet, but the current byte doesn't mark the beginning of the packet, skip it
                if (currentPacketData.length === 0 && b != 0xFA)
                    continue;

                currentPacketData.push(b);

                if (currentPacketData.length === 22) {
                    var packet = parsePacket(currentPacketData);
                    if (packet === null) {
                        // packet was invalid; check for 0xFA packet start marker in the last packet, as sometimes some bytes are dropped and the next packet is already started
                        var nextIndex = currentPacketData.slice(1).indexOf(0xFA) + 1;
                        if (nextIndex > 0)
                            currentPacketData = currentPacketData.slice(nextIndex);
                        else
                            currentPacketData = [];
                    }
                    else {
                        self.emit('packet', packet);

                        // reset currentPacketData
                        currentPacketData = [];
                    }
                }
            }
        });
    });

    var targetRPM = 240;
    var lastRPM = 0
    var rpmAdjustInProgress = false;
    self.on('packet', function(packet) {

        if (packet.index != 0){
            return;
        }

        var rpm = packet.speed;
        var prevRPM = 0;

        if (rpm > 100 && rpm > targetRPM - 5 && rpm < targetRPM + 5 && lastRPM > 0 && Math.abs(rpm - lastRPM) < 3 && !rpmAdjustInProgress) {
            var deltaRPM = targetRPM - rpm;
            var deltaDuty = Math.round((deltaRPM / rpm) * self._pwmDuty * 0.5);

            self._pwmDuty += deltaDuty;

            rpmAdjustInProgress = true;
            setTimeout(function(){ rpmAdjustInProgress = false; }, 3000);

            console.log('Changed pwm duty to: ' + self._pwmDuty);
        }

        lastRPM = rpm;

        if (rpm < 100) {
            lastRPMs = 0;
        }
    });
}

// Inherit the EventEmitter - this line must be before prototype declarations
util.inherits(Lidar, events.EventEmitter);

Lidar.prototype._sendPwmCommand = function (name, value) {
    var self = this;
    glob(path.join(self._pwmPath, name), { cwd: '/' }, function(err, files) {
        if (err || files.length < 1) {
            console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. Could not resolve the pwm path. ' + err);
            return;
        }

        if (files.length > 1) {
            console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. PWM path resolved to more than one location. ' + err);
            return;
        }

        fs.writeFile(files[0], value, function(writeError) {
            if (err) {
                console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. ' + writeError);
            }
        });
    });
};

// turns on the lidar motor
Lidar.prototype.start = function () {
    var self = this;

    console.log('Lidar starting.');

    if (self._pwmDuty > 1000000) {
        self._pwmDuty = 380000;
    }

    self._sendPwmCommand('period', '1000000');
    self._sendPwmCommand('duty', self._pwmDuty.toString());
    self._sendPwmCommand('run', '1');
};

// turns off the lidar motor
Lidar.prototype.stop = function () {
    var self = this;

    console.log('Lidar stopping.');

    self._sendPwmCommand('run', '0');
};

module.exports = Lidar;<commit_msg>Completed lidar rpm adjustment code<commit_after>var util = require('util');
var events = require('events');
var SerialPort = require("serialport").SerialPort;
var fs = require('fs');
var path = require('path');
var glob = require('glob');

function LidarPacket(index, speed, dist1, dist2, dist3, dist4){
    this.index = index;
    this.speed = speed;
    this.dist1 = dist1;
    this.dist2 = dist2;
    this.dist3 = dist3;
    this.dist4 = dist4;
}

/**
 * Computes and returns the checksum as an int.
 * @param {Array} data - The data to compute the checksum for. Must be 20 bytes.
 * @return {Number} The checksum as an integer.
 */
var computeChecksum = function(data) {
    // group the data by word, little-endian
    var dataList = [];
    for (var i = 0; i < 10; i++){
        dataList.push(data[2*i] + (data[2*i+1]<<8));
    }

    // compute the checksum on 32 bits
    var chk32 = 0;
    dataList.forEach(function(item){
        chk32 = (chk32 << 1) + item;
    });

    // return a value wrapped around on 15 bits, and truncated to still fit into 15 bits
    var checksum = (chk32 & 0x7FFF) + (chk32 >> 15); // wrap around to fit into 15 bits
    checksum = checksum & 0x7FFF; // truncate to 15 bits
    return checksum;
};

/**
 * Gets the lidar distance reading from a 4 byte data section.
 * @param {Array} bytes - Buffer with 4 bytes of data.
 * @return {Number} The distance reading as an integer.
 */
var parsePacketDataSection = function(bytes) {
    // if the 8th bit of the byte 1 is set, the data is invalid; the 7th bit of byte 1 is a strength warning (varies with material sometimes) flag, but we are ignoring it for now
    if (bytes[1] & 128 === 128)
        return -1;

    // get distance from byte 0 and byte 1; byte 2 and byte 3 contain signal strength data, which we are ignoring for now
    return bytes[0] + ((bytes[1] & 63) << 8);
};

var parsePacket = function(bytes) {
    // first byte in the packet must be 0xFA
    if (bytes[0] != 0xFA)
        return null;

    // verify data via checksum
    if (computeChecksum(bytes.slice(0, 20)) !== (bytes[20] + (bytes[21] << 8)))
        return null;

    // packet index must be between 0xA0 and 0xF9
    var index = bytes[1];
    if (index < 0xA0 || index > 0xF9)
        return null;

    // adjust index to 0 based index
    index = index - 0xA0;

    // speed unit used by the LIDAR is in 64ths of an RPM; we want the speed in RPMs
    var speed = (bytes[2] + (bytes[3]<<8))/64.0;

    var distances = [];
    for (var i = 1; i < 5; i++)
        distances.push(parsePacketDataSection(bytes.slice(4*i, 4*i+4)));

    return new LidarPacket(index, speed, distances[0], distances[1], distances[2], distances[3]);
};

function Lidar(serialPath, pwmPath) {
    var self = this;
    self._pwmPath = pwmPath;
    self._lidarStopped = true;
    self._pwmDuty = 380000;
    self._serialPort = new SerialPort(serialPath, {
        baudrate: 115200
    });

    self._serialPort.on("open", function () {
        console.log('serial port to lidar is open');

        var currentPacketData = [];
        self._serialPort.on('data', function(data) {
            //console.log('data received from lidar: ' + data.toString('hex'));
            self.emit('raw data', data);

            for (var i = 0; i < data.length; i++) {
                var b = data[i];

                // if we're starting a new packet, but the current byte doesn't mark the beginning of the packet, skip it
                if (currentPacketData.length === 0 && b != 0xFA)
                    continue;

                currentPacketData.push(b);

                if (currentPacketData.length === 22) {
                    var packet = parsePacket(currentPacketData);
                    if (packet === null) {
                        // packet was invalid; check for 0xFA packet start marker in the last packet, as sometimes some bytes are dropped and the next packet is already started
                        var nextIndex = currentPacketData.slice(1).indexOf(0xFA) + 1;
                        if (nextIndex > 0)
                            currentPacketData = currentPacketData.slice(nextIndex);
                        else
                            currentPacketData = [];
                    }
                    else {
                        self.emit('packet', packet);

                        // reset currentPacketData
                        currentPacketData = [];
                    }
                }
            }
        });
    });

    var targetRPM = 240;
    var lastRPM = 0
    var rpmAdjustInProgress = false;
    self.on('packet', function(packet) {

        if (packet.index != 0 || self._lidarStopped){
            return;
        }

        var rpm = packet.speed;
        var prevRPM = 0;

        if (rpm > 100 && (rpm < targetRPM - 5 || rpm > targetRPM + 5) && lastRPM > 0 && Math.abs(rpm - lastRPM) < 3 && !rpmAdjustInProgress) {
            var deltaRPM = targetRPM - rpm;
            var deltaDuty = Math.round((deltaRPM / rpm) * self._pwmDuty * 0.5);

            self._pwmDuty -= deltaDuty;
            self._sendPwmCommand('duty', self._pwmDuty.toString());

            rpmAdjustInProgress = true;
            setTimeout(function(){ rpmAdjustInProgress = false; }, 3000);

            console.log('Changed pwm duty to: ' + self._pwmDuty);
            console.log('Current rpms: ' + rpm);
        }

        lastRPM = rpm;

        if (rpm < 100) {
            lastRPMs = 0;
        }
    });
}

// Inherit the EventEmitter - this line must be before prototype declarations
util.inherits(Lidar, events.EventEmitter);

Lidar.prototype._sendPwmCommand = function (name, value) {
    var self = this;
    glob(path.join(self._pwmPath, name), { cwd: '/' }, function(err, files) {
        if (err || files.length < 1) {
            console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. Could not resolve the pwm path. ' + err);
            return;
        }

        if (files.length > 1) {
            console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. PWM path resolved to more than one location. ' + err);
            return;
        }

        fs.writeFile(files[0], value, function(writeError) {
            if (err) {
                console.log('An error occurred sending pwm command \'' + name + '\' with value \'' + value + '\'. ' + writeError);
            }
        });
    });
};

// turns on the lidar motor
Lidar.prototype.start = function () {
    var self = this;

    console.log('Lidar starting.');

    if (self._pwmDuty > 1000000) {
        self._pwmDuty = 380000;
    }

    self._sendPwmCommand('period', '1000000');
    self._sendPwmCommand('duty', self._pwmDuty.toString());
    self._sendPwmCommand('run', '1');

    self._lidarStopped = false;
};

// turns off the lidar motor
Lidar.prototype.stop = function () {
    var self = this;

    console.log('Lidar stopping.');

    self._sendPwmCommand('run', '0');

    self._lidarStopped = true;
};

module.exports = Lidar;
<|endoftext|>


<commit_before>app.controller('colorPickerController', function($scope) {
  console.log('ColorPickerController');
  var that = this;

  this.resizeVideo = function() {
    // TODO dynamic toolbar height
    $scope.canvas.height = window.innerHeight - 44;
    $scope.canvas.width = window.innerWidth;
  };

  this.stopVideo = function() {
    $scope.video.pause();
    $scope.video.src = '';

    if ($scope.stream) {
      $scope.stream.getVideoTracks()[0].stop();
    }
  };

  this.componentToHex = function(c) {
    var hex = c.toString(16);
    return hex.length === 1 ? '0' + hex : hex;
  };

  this.rgbToHex = function(r, g, b) {
    return '#' + this.componentToHex(r) +
      this.componentToHex(g) + this.componentToHex(b);
  };

  function successCallback(stream) {
    $scope.stream = stream;
    $scope.video.src = window.URL.createObjectURL(stream);
    that.resizeVideo();

    navigatorMain.on('prepush', that.stopVideo);
    navigatorMain.on('postpop', that.stopVideo);

  }

  function errorCallback(error) {
    console.log('navigator.getUserMedia error: ', error);
  }

  this.getShades = function() {
    var ctx = $scope.canvas.getContext('2d');

    var ratio = this.videoWidth / this.videoHeight;
    var height = $scope.canvas.clientHeight;
    var width = height * ratio;
    var right = ($scope.canvas.clientWidth - width) / 2;

    var centerX = $scope.canvas.width / 2;
    var centerY = $scope.canvas.height / 2;
    var radius = 10;
    var r = 0;
    var g = 0;
    var b = 0;
    var l = 0;

    ctx.drawImage(this, right, 0, width, height);
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = 'rgba(0,0,0,0)';
    ctx.fill();
    ctx.lineWidth = 2;
    ctx.stroke();

    var colorDatas = ctx.getImageData(centerX, centerY, 5, 5);
    for (var i = 0;i < colorDatas.data.length; i += 4) {
      r += colorDatas.data[i];
      g += colorDatas.data[i + 1];
      b += colorDatas.data[i + 2];
      l++;
    }
    r = Math.round(r / l);
    g = Math.round(g / l);
    b = Math.round(b / l);
    var hexColor = that.rgbToHex(r, g, b);
    var colorNames = ntc.name(hexColor);
    $scope.currentShade = colorNames[3];
    $scope.currentColor = colorNames[1];
  };

  // Init

  $scope.init = function() {
    $scope.show = function() {
      modalColorPicker.show();
    };
    $scope.currentColor = '';
    $scope.currentShade = '';
    $scope.video = document.querySelector('video');
    $scope.canvas = document.querySelector('canvas');
    var i;

    // Events
    window.addEventListener('resize', that.resizeVideo);
    $scope.video.addEventListener('play', function() {
      var $this = this;
      that.resizeVideo();
      i = window.setInterval(function() {
          that.getShades.bind($this)();
          $scope.$apply();
        }, 1000 / 60);
    }, false);

    $scope.video.addEventListener('pause',function() {
      window.clearInterval(i);
    },false);

    $scope.video.addEventListener('ended',function() {
      clearInterval(i);
    },false);

    // Load media stream
    if (typeof MediaStreamTrack === 'undefined' ||
      typeof MediaStreamTrack.getSources === 'undefined') {

      // TODO onsenUI clean modal
      alert('This browser does not support MediaStreamTrack.\n\nTry Chrome.');
      navigatorMain.popPage();
    } else {
      // Deprecated but supported by android webview
      MediaStreamTrack.getSources(function(sources) {
        var targetSourceId;
        sources.forEach(function(source) {
          if (source.facing === 'environment') {
            targetSourceId = source.id;
          }
        });
        if (!targetSourceId) {
          if (sources[0]) {
            targetSourceId = sources[0].id;
          }
          if (sources[1]) {
            targetSourceId = sources[1].id;
          }
          if (sources[2]) {
            targetSourceId = sources[2].id;
          }
        }

        console.log(targetSourceId);

        navigator.webkitGetUserMedia({
          audio: false,
          video: {
            optional: [{
              sourceId: targetSourceId,
            },],
          },
        }, successCallback, errorCallback);
      });
    }
  };
});
<commit_msg>fix colorPickerTest<commit_after>app.controller('colorPickerController', function($scope) {
  console.log('ColorPickerController');
  var that = this;

  this.resizeVideo = function() {
    // TODO dynamic toolbar height
    $scope.canvas.height = window.innerHeight - 44;
    $scope.canvas.width = window.innerWidth;
  };

  this.stopVideo = function() {
    $scope.video.pause();
    $scope.video.src = '';

    if ($scope.stream) {
      $scope.stream.getVideoTracks()[0].stop();
    }
  };

  this.componentToHex = function(c) {
    var hex = c.toString(16);
    return hex.length === 1 ? '0' + hex : hex;
  };

  this.rgbToHex = function(r, g, b) {
    return '#' + this.componentToHex(r) +
      this.componentToHex(g) + this.componentToHex(b);
  };

  function successCallback(stream) {
    $scope.stream = stream;
    $scope.video.srcObject = stream;
    that.resizeVideo();

    navigatorMain.on('prepush', that.stopVideo);
    navigatorMain.on('postpop', that.stopVideo);

  }

  function errorCallback(error) {
    console.log('navigator.getUserMedia error: ', error);
  }

  this.getShades = function() {
    var ctx = $scope.canvas.getContext('2d');

    var ratio = this.videoWidth / this.videoHeight;
    var height = $scope.canvas.clientHeight;
    var width = height * ratio;
    var right = ($scope.canvas.clientWidth - width) / 2;

    var centerX = $scope.canvas.width / 2;
    var centerY = $scope.canvas.height / 2;
    var radius = 10;
    var r = 0;
    var g = 0;
    var b = 0;
    var l = 0;

    ctx.drawImage(this, right, 0, width, height);
    ctx.beginPath();
    ctx.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
    ctx.fillStyle = 'rgba(0,0,0,0)';
    ctx.fill();
    ctx.lineWidth = 2;
    ctx.stroke();

    var colorDatas = ctx.getImageData(centerX, centerY, 5, 5);
    for (var i = 0;i < colorDatas.data.length; i += 4) {
      r += colorDatas.data[i];
      g += colorDatas.data[i + 1];
      b += colorDatas.data[i + 2];
      l++;
    }
    r = Math.round(r / l);
    g = Math.round(g / l);
    b = Math.round(b / l);
    var hexColor = that.rgbToHex(r, g, b);
    var colorNames = ntc.name(hexColor);
    $scope.currentShade = colorNames[3];
    $scope.currentColor = colorNames[1];
  };

  // Init

  $scope.init = function() {
    $scope.show = function() {
      modalColorPicker.show();
    };
    $scope.currentColor = '';
    $scope.currentShade = '';
    $scope.video = document.querySelector('video');
    $scope.canvas = document.querySelector('canvas');
    var i;

    // Events
    window.addEventListener('resize', that.resizeVideo);
    $scope.video.addEventListener('play', function() {
      var $this = this;
      that.resizeVideo();
      i = window.setInterval(function() {
          that.getShades.bind($this)();
          $scope.$apply();
        }, 1000 / 60);
    }, false);

    $scope.video.addEventListener('pause',function() {
      window.clearInterval(i);
    },false);

    $scope.video.addEventListener('ended',function() {
      clearInterval(i);
    },false);

    // Load media stream
    if (typeof navigator.mediaDevices === 'undefined' ||
      typeof navigator.mediaDevices.enumerateDevices === 'undefined') {

      // TODO onsenUI clean modal
      alert('This browser does not support mediaDevices.\n\nTry Chrome.');
      navigatorMain.popPage();
    } else {
      // Deprecated but supported by android webview
      navigator.mediaDevices.enumerateDevices()
        .then(function(devices) {
          var camera = [];
          var currCameraIndex = 0;
          var videoContraint = false;

          devices.forEach(function(info) {
            if (info.kind == "videoinput") {
              camera.push(info.deviceId);
            }
          });
          currCameraIndex = camera.length - 1;
          if(camera){
            videoContraint = {
              optional: [{
                sourceId: camera[currCameraIndex]
              }]
            };
          }
          setTimeout(function() {
            navigator.getUserMedia({
              audio: false,
              video: videoContraint
            }, function(stream) {
              console.log('ok');
              successCallback(stream)
            },function(error){
              console.log(error);
              errorCallback(error)
            });
          },10);

      });
    }
  };
});
<|endoftext|>


<commit_before>/*! jQuery.transitionHelper, v0.4 | MIT */
/**
 * @fileOverview Micro plugin to help with CSS transitions
 *
 * @copyright Copyright (c) 2013 Urszula Ciaputa (http://urszula.ciaputa.com)
 * @author Urszula Ciaputa <urszula@ciaputa.com>
 *
 * @version 0.4
 * @license http://www.opensource.org/licenses/mit-license.php
 */
/*jslint unparam: true, browser: true */
/*global jQuery, Modernizr */

/**
 * jQuery
 *
 * @name jQuery
 * @namespace
 *
 * This just documents the function and classes that are added to jQuery
 * by this plug-in.
 * @see jQuery Library
 */
/**
 * jQuery.fn
 *
 * @name fn
 * @memberOf jQuery
 * @namespace
 *
 * This just documents the function and classes that are added to jQuery
 * by this plug-in.
 * @see jQuery Library
 */
/**
 * Modernizr
 *
 * @name Modernizr
 * @namespace
 *
 * @see Modernizr Library
 */
/**
 * Modernizr.prefixed
 *
 * @name prefixed
 * @memberOf Modernizr
 * @function
 *
 * @see Modernizr.prefixed() Docs
 */

(function (factory) {
    if ( typeof define === 'function' && define.amd ) {
        // AMD. Register as an anonymous module.
        define(['jquery', 'modernizr'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports = factory;
    } else {
        // Browser globals
        factory(jQuery, Modernizr);
    }
}(function ($, Modernizr) {

	"use strict";

	var EVENTS = {
			transitionend: {
				'WebkitTransition' : 'webkitTransitionEnd',
				'MozTransition'    : 'transitionend',
				'OTransition'      : 'oTransitionEnd otransitionend',
				'msTransition'     : 'MSTransitionEnd',
				'transition'       : 'transitionend'
			}[ Modernizr.prefixed('transition') ],

			animationend: {
				'WebkitAnimation' : 'webkitAnimationEnd',
				'MozAnimation'    : 'animationend',
				'OAnimation'      : 'oAnimationEnd oanimationend',
				'msAnimation'     : 'MSAnimationEnd',
				'animation'       : 'animationend'
			}[ Modernizr.prefixed('animation') ]
		};

	var helper = function (type, callback, off) {
		callback = callback || $.noop;
		var eventName = type + 'end';
		var namespacedEvent = EVENTS[eventName] + '.' + type + 'helper';
		if (EVENTS[eventName]){
			if (off) {
				this.off(namespacedEvent);
			} else {
				this.on(namespacedEvent, function (ev) {
					//ignore events bubbling from descendants
					if (ev.target !== this) {
						return ;
					}
					$(this).off(namespacedEvent).removeClass(type + '-helper');
					callback.call(this, ev);
				});
			}
			return this.toggleClass(type + '-helper', !off);
		} else {
			return this.each(function () {
				callback.call(this);
			});
		}
	};

	$.fn.transitionHelper = function (callback, off) {
		return helper.call(this, 'transition', callback, off);
	};

	$.fn.animationHelper = function (callback, off) {
		return helper.call(this, 'animation', callback, off);
	};

}));
<commit_msg>Passing object instead of parameters list. Callback extended<commit_after>/*! jQuery.transitionHelper, v0.4 | MIT */
/**
 * @fileOverview Micro plugin to help with CSS transitions
 *
 * @copyright Copyright (c) 2013 Urszula Ciaputa (http://urszula.ciaputa.com)
 * @author Urszula Ciaputa <urszula@ciaputa.com>
 *
 * @version 0.4
 * @license http://www.opensource.org/licenses/mit-license.php
 */
/*jslint unparam: true, browser: true */
/*global jQuery, Modernizr */

/**
 * jQuery
 *
 * @name jQuery
 * @namespace
 *
 * This just documents the function and classes that are added to jQuery
 * by this plug-in.
 * @see jQuery Library
 */
/**
 * jQuery.fn
 *
 * @name fn
 * @memberOf jQuery
 * @namespace
 *
 * This just documents the function and classes that are added to jQuery
 * by this plug-in.
 * @see jQuery Library
 */
/**
 * Modernizr
 *
 * @name Modernizr
 * @namespace
 *
 * @see Modernizr Library
 */
/**
 * Modernizr.prefixed
 *
 * @name prefixed
 * @memberOf Modernizr
 * @function
 *
 * @see Modernizr.prefixed() Docs
 */

(function (factory) {
    if ( typeof define === 'function' && define.amd ) {
        // AMD. Register as an anonymous module.
        define(['jquery', 'modernizr'], factory);
    } else if (typeof exports === 'object') {
        // Node/CommonJS style for Browserify
        module.exports = factory;
    } else {
        // Browser globals
        factory(jQuery, Modernizr);
    }
}(function ($, Modernizr) {

	"use strict";

	var EVENTS = {
			transitionend: {
				'WebkitTransition' : 'webkitTransitionEnd',
				'MozTransition'    : 'transitionend',
				'OTransition'      : 'oTransitionEnd otransitionend',
				'msTransition'     : 'MSTransitionEnd',
				'transition'       : 'transitionend'
			}[ Modernizr.prefixed('transition') ],

			animationend: {
				'WebkitAnimation' : 'webkitAnimationEnd',
				'MozAnimation'    : 'animationend',
				'OAnimation'      : 'oAnimationEnd oanimationend',
				'msAnimation'     : 'MSAnimationEnd',
				'animation'       : 'animationend'
			}[ Modernizr.prefixed('animation') ]
		};

	var helper = function (options) {
		var callback = options.callback || $.noop;
		var eventName = options.type + 'end';
		var namespacedEvent = EVENTS[eventName] + '.' + options.type + 'helper';
    var self = this;
    var timeout;

		if (EVENTS[eventName]){
			if (options.off) {
				self.off(namespacedEvent);
			} else {
				self.on(namespacedEvent, function (ev) {
					//ignore events bubbling from descendants
					if (ev.target !== this) {
						return ;
					}

          clearTimeout(timeout);
					$(this).off(namespacedEvent).removeClass(options.type + '-helper');
					callback.call(this, ev);
				});
			}
      if (options.timeout) {
        timeout = setTimeout(function() {
          self.off(namespacedEvent).removeClass(options.type + '-helper');
          self.each(function () {
            callback.call(this, null);
          });
        }, options.timeout);
      }
			return self.toggleClass(options.type + '-helper', !options.off);
		} else {
			return self.each(function () {
				callback.call(this, null);
			});
		}
	};

	$.fn.transitionHelper = function (options) {
    options = options || {};
    options.type = 'transition';
    if (typeof options === 'function') {
      options.callback = arguments[0];
    }
    return helper.call(this, options);
	};

	$.fn.animationHelper = function (options) {
    options = options || {};
    options.type = 'animation';
    if (typeof options === 'function') {
      options.callback = arguments[0];
    }
		return helper.call(this, options);
	};

}));
<|endoftext|>


<commit_before>const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://iot.eclipse.org')

var sys = require('sys')
var exec = require('child_process').exec;

function puts(error, stdout, stderr) { sys.puts(stdout) }

function espeak(phrase) {
  exec("echo " + phrase + " | espeak", puts);
}

var state = 'closed'

client.on('connect', function () {
  client.subscribe('lupe/open')
  client.subscribe('lupe/close')
  client.subscribe('lupe/say')

  client.subscribe('lupe/resetall')
  client.subscribe('lupe/headleft')
  client.subscribe('lupe/headright')

  client.subscribe('lupe/leftup')
  client.subscribe('lupe/leftdown')
  client.subscribe('lupe/leftfold')
  client.subscribe('lupe/leftunfold')

  client.subscribe('lupe/rightup')
  client.subscribe('lupe/rightdown')
  client.subscribe('lupe/rightfold')
  client.subscribe('lupe/rightunfold')

  client.subscribe('lupe/moveleft')
  client.subscribe('lupe/moveright')
  client.subscribe('lupe/moveforward')
  client.subscribe('lupe/movebackward')
  client.subscribe('lupe/movestop')

  client.subscribe('lupe/bienvenida')
  client.subscribe('lupe/agradece')
  client.subscribe('lupe/dance')
  client.subscribe('lupe/creador')
  client.subscribe('lupe/norte')

  client.publish('lupe/connected', 'true')
  sendStateUpdate()
})

client.on('message', function (topic, message) {
  console.log('Received message %s %s', topic, message)
  switch (topic) {
    case 'lupe/open':
      return handleRequestOpen(message)
    case 'lupe/close':
      return handleRequestClose(message)
    case 'lupe/say':
      return handleRequestSay(message)

    case 'lupe/resetall':
      return handleLupe('Resetting Lupe Robot')
    case 'lupe/headleft':
      return handleLupe('Head Left')
    case 'lupe/headright':
      return handleLupe('Head Right')

    case 'lupe/leftup':
      return handleLupe('Left Up')
    case 'lupe/leftdown':
      return handleLupe('Left Down')
    case 'lupe/leftfold':
      return handleLupe('Left Fold')
    case 'lupe/leftunfold':
      return handleLupe('Left Unfold')

    case 'lupe/rightup':
      return handleLupe('Right Up')
    case 'lupe/rightdown':
      return handleLupe('Right Down')
    case 'lupe/rightfold':
      return handleLupe('Right Fold')
    case 'lupe/rightunfold':
      return handleLupe('Right Unfold')

    case 'lupe/moveleft':
      return handleLupe('Move Left')
    case 'lupe/moveright':
      return handleLupe('Move Right')
    case 'lupe/moveforward':
      return handleLupe('Move Forward')
    case 'lupe/movebackward':
      return handleLupe('Move Backward')
    case 'lupe/movestop':
      return handleLupe('Move Stop')

    case 'lupe/bienvenida':
      return handleLupe('Welcome')
    case 'lupe/agradece':
      return handleLupe('Thanks')
    case 'lupe/dance':
      return handleLupe('Dance')
    case 'lupe/creador':
      return handleLupe('Creator')
    case 'lupe/norte':
      return handleLupe('North')

  }
})

function sendStateUpdate () {
  console.log('Sending state %s', state)
  client.publish('lupe/state', state)
}

function handleRequestOpen (message) {
  if (state !== 'open' && state !== 'opening') {
    console.log('Opening Lupe')
    state = 'opening'
    espeak('Opening')
    sendStateUpdate()

    setTimeout(function (){
      state = 'open'
      sendStateUpdate()
    }, 5000)
  }
}

function handleRequestClose (message) {
  if (state !== 'closed' && state !== 'closing') {
    state = 'closing'

    espeak('Closing')
    sendStateUpdate()

    setTimeout(function () {
      state = 'closed'
      sendStateUpdate()
    }, 5000)
  }
}

function handleRequestSay (message) {
    espeak(message)
}

function handleLupe (message) {
  espeak(message)

}

function handleAppExit (options, err) {
  if (err) {
    console.log(err.stack)
  }

  if (options.cleanup) {
    client.publish('lupe/connected', 'false')
  }

  if (options.exit) {
    process.exit()
  }
}

process.on('exit', handleAppExit.bind(null, {
  cleanup: true
}))
process.on('SIGINT', handleAppExit.bind(null, {
  exit: true
}))
process.on('uncaughtException', handleAppExit.bind(null, {
  exit: true
}))
<commit_msg>Update<commit_after>const mqtt = require('mqtt')
const client = mqtt.connect('mqtt://iot.eclipse.org')

var sys = require('sys')
var exec = require('child_process').exec;

function puts(error, stdout, stderr) { sys.puts(stdout) }

function espeak(phrase) {
  exec("echo " + phrase + " | espeak", puts);
}

var state = 'closed'

client.on('connect', function () {
  client.subscribe('lupe/open')
  client.subscribe('lupe/close')
  client.subscribe('lupe/say')

  client.subscribe('lupe/resetall')
  client.subscribe('lupe/headleft')
  client.subscribe('lupe/headright')

  client.subscribe('lupe/leftup')
  client.subscribe('lupe/leftdown')
  client.subscribe('lupe/leftfold')
  client.subscribe('lupe/leftunfold')

  client.subscribe('lupe/rightup')
  client.subscribe('lupe/rightdown')
  client.subscribe('lupe/rightfold')
  client.subscribe('lupe/rightunfold')

  client.subscribe('lupe/moveleft')
  client.subscribe('lupe/moveright')
  client.subscribe('lupe/moveforward')
  client.subscribe('lupe/movebackward')
  client.subscribe('lupe/movestop')

  client.subscribe('lupe/bienvenida')
  client.subscribe('lupe/agradece')
  client.subscribe('lupe/dance')
  client.subscribe('lupe/creador')
  client.subscribe('lupe/norte')

  client.publish('lupe/connected', 'true')
  sendStateUpdate()
})

client.on('message', function (topic, message) {
  console.log('Received message %s %s', topic, message)
  switch (topic) {
    case 'lupe/open':
      return handleRequestOpen(message)
    case 'lupe/close':
      return handleRequestClose(message)
    case 'lupe/say':
      return handleRequestSay(message)

    case 'lupe/resetall':
      return handleLupe('Reset All')
    case 'lupe/headleft':
      return handleLupe('Head Left')
    case 'lupe/headright':
      return handleLupe('Head Right')

    case 'lupe/leftup':
      return handleLupe('Left Up')
    case 'lupe/leftdown':
      return handleLupe('Left Down')
    case 'lupe/leftfold':
      return handleLupe('Left Fold')
    case 'lupe/leftunfold':
      return handleLupe('Left Unfold')

    case 'lupe/rightup':
      return handleLupe('Right Up')
    case 'lupe/rightdown':
      return handleLupe('Right Down')
    case 'lupe/rightfold':
      return handleLupe('Right Fold')
    case 'lupe/rightunfold':
      return handleLupe('Right Unfold')

    case 'lupe/moveleft':
      return handleLupe('Move Left')
    case 'lupe/moveright':
      return handleLupe('Move Right')
    case 'lupe/moveforward':
      return handleLupe('Move Forward')
    case 'lupe/movebackward':
      return handleLupe('Move Backward')
    case 'lupe/movestop':
      return handleLupe('Move Stop')

    case 'lupe/bienvenida':
      return handleLupe('Welcome')
    case 'lupe/agradece':
      return handleLupe('Thanks')
    case 'lupe/dance':
      return handleLupe('Dance')
    case 'lupe/creador':
      return handleLupe('Creator')
    case 'lupe/norte':
      return handleLupe('North')

  }
})

function sendStateUpdate () {
  console.log('Sending state %s', state)
  client.publish('lupe/state', state)
}

function handleRequestOpen (message) {
  if (state !== 'open' && state !== 'opening') {
    console.log('Opening Lupe')
    state = 'opening'
    espeak('Opening')
    sendStateUpdate()

    setTimeout(function (){
      state = 'open'
      sendStateUpdate()
    }, 5000)
  }
}

function handleRequestClose (message) {
  if (state !== 'closed' && state !== 'closing') {
    state = 'closing'

    espeak('Closing')
    sendStateUpdate()

    setTimeout(function () {
      state = 'closed'
      sendStateUpdate()
    }, 5000)
  }
}

function handleRequestSay (message) {
    espeak(message)
}

function handleLupe (message) {
  espeak(message)

}

function handleAppExit (options, err) {
  if (err) {
    console.log(err.stack)
  }

  if (options.cleanup) {
    client.publish('lupe/connected', 'false')
  }

  if (options.exit) {
    process.exit()
  }
}

process.on('exit', handleAppExit.bind(null, {
  cleanup: true
}))
process.on('SIGINT', handleAppExit.bind(null, {
  exit: true
}))
process.on('uncaughtException', handleAppExit.bind(null, {
  exit: true
}))
<|endoftext|>