<commit_before>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(["./d3", "./Mark", "./utils"], function(d3, MarkViewModule, utils) {
    "use strict";

    var Hist = MarkViewModule.Mark.extend({
        render: function() {
            var base_creation_promise = Hist.__super__.render.apply(this);
            this.sel_indices = [-1];
            this.bar_index_sel = [];

            var self = this;
            return base_creation_promise.then(function() {
                self.create_listeners();
                self.draw();
            });
        },
        set_ranges: function() {
            var x_scale = this.scales["sample"];
            if(x_scale) {
                x_scale.set_range(this.parent.padded_range("x", x_scale.model));
            }
            var y_scale = this.scales["counts"];
            if(y_scale) {
                y_scale.set_range(this.parent.padded_range("y", y_scale.model));
            }
        },
        set_positional_scales: function() {
            // In the case of Hist, a change in the "sample" scale triggers
            // a full "update_data" instead of a simple redraw.
            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
            this.listenTo(x_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.model.update_data(); }
            });
            this.listenTo(y_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
        },
        create_listeners: function() {
            Hist.__super__.create_listeners.apply(this);
            this.model.on("data_updated", this.draw, this);
            this.model.on("change:colors",this.update_colors,this);
            this.model.on_some_change(["stroke", "opacity"], this.update_stroke_and_opacity, this);
        },
        reset_selections: function() {
            if(!(this.selector_model)) {
                return;
            }
            var that = this;
            var colors = this.model.get("colors");
            this.bar_index_sel.forEach(function(d) {
                that.el.selectAll("#rect" + d).attr("fill", colors[0]);
            });
            this.bar_index_sel = [];
            this.sel_indices = [];
            this.selector_model.set("selected", []);
            this.selector.touch();
        },
        update_colors: function(model, colors) {
            this.el.selectAll(".bar").selectAll("rect")
              .attr("fill", this.get_colors(0));
            if (model.get("labels") && colors.length > 1) {
                this.el.selectAll(".bar").selectAll("text")
                  .attr("fill", this.get_colors(1));
            }
            if (this.legend_el) {
                this.legend_el.selectAll("rect")
                  .style("fill", this.get_colors(0));
                this.legend_el.selectAll("text")
                  .style("fill", this.get_colors(0));
            }
        },
        update_stroke_and_opacity: function() {
            var stroke = this.model.get("stroke");
            var opacity = this.model.get("opacity");
            this.el.selectAll(".rect")
              .style("stroke", (stroke === null || stroke === undefined) ? "none" : stroke)
              .style("opacity", opacity);
        },
        calculate_bar_width: function() {
            var x_scale = this.scales["sample"];
            var bar_width = (x_scale.scale(this.model.max_x) - x_scale.scale(this.model.min_x)) / this.model.num_bins;
            if (bar_width >= 10) {
                bar_width -= 2;
            }
            return bar_width;
        },
        relayout: function() {
            this.set_ranges();

            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
			this.el.selectAll(".bar")
			  .attr("transform", function(d) {
                  return "translate(" + x_scale.scale(d.x) +
                                  "," + y_scale.scale(d.y) + ")";
              });
            var bar_width = this.calculate_bar_width();
            this.el.selectAll(".bar").select("rect")
              .transition().duration(300)
		      .attr("x", 2)
              .attr("width", bar_width)
		      .attr("height", function(d) {
                  return y_scale.scale(0) - y_scale.scale(d.y);
              });
        },
        draw: function() {
            this.set_ranges();
            var colors = this.model.get("colors");
            var fill_color = colors[0];
            var select_color = (colors.length > 1) ? colors[1] : "red";

            var indices = [];
            this.model.mark_data.forEach(function(d, i) {
                indices.push(i);
            });

            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
            var that = this;
            this.el.selectAll(".bar").remove();
            var bar_width = this.calculate_bar_width();
	        var bar = this.el.selectAll(".bar")
			  .data(this.model.mark_data)
		      .enter().append("g")
			  .attr("class","bar")
			  .attr("transform", function(d) {
                  return "translate(" + x_scale.scale(d.x) + "," +
                                        y_scale.scale(d.y) + ")";
              });

		    bar.append("rect")
              .attr("class", "rect")
              .attr("id", function(d, i) { return "rect"+i; })
		      .attr("x", 2)
              .attr("width", bar_width)
		      .attr("height", function(d) {
                  return y_scale.scale(0) - y_scale.scale(d.y);
              })
              .attr("fill", fill_color)
              .on("click", function(d, i) {
                  if(!(that.selector_model)) {
                     return;
                  }
                  var buffer_index = [];
                  var elem_index = that.bar_index_sel.indexOf(i);
                  if( elem_index > -1 && d3.event.ctrlKey) {
                      that.bar_index_sel.splice(elem_index, 1);
                      d.forEach(function(elem) {
                          var remove_index = that.sel_indices.indexOf(elem.index);
                          if(remove_index !== -1) {
                              that.sel_indices.splice(remove_index, 1);
                          }
                      });
                      that.el.selectAll("#rect" + i).attr("fill", fill_color);
                  }
                  else {
                      if(that.sel_indices[0] === -1) {
                          that.sel_indices.splice(0,1);
                      }
                      if(d3.event.ctrlKey) {
                          that.sel_indices.forEach(function(elem) {
                              buffer_index.push(elem);
                          });
                      } else if(d3.event.shiftKey) {
                          if(elem_index > -1) {
                              return;
                          }
                          that.sel_indices.forEach(function(elem) {
                              buffer_index.push(elem);
                          });
                          var min_index = (that.bar_index_sel.length !== 0) ?
                              d3.min(that.bar_index_sel) : -1;
                          var max_index = (that.bar_index_sel.length !== 0) ?
                              d3.max(that.bar_index_sel) : (that.mark_data).length;
                          if(i > max_index){
                              that.model.mark_data.slice(max_index + 1, i).forEach(function(data_elem ) {
                                  data_elem.map(function(elem) {
                                      buffer_index.push(elem.index);
                                  });
                              });
                              indices.slice(max_index + 1, i).forEach(function(data_elem ) {
                                  that.bar_index_sel.push(data_elem);
                              });
                          } else if(i < min_index){
                              that.model.mark_data.slice(i + 1, min_index).forEach(function(data_elem) {
                                  data_elem.map(function(elem) {
                                      buffer_index.push(elem.index);
                                  });
                              });
                              indices.slice(i+1, min_index).forEach(function(data_elem) {
                                  that.bar_index_sel.push(data_elem);
                              });
                          }
                      } else {
                          that.bar_index_sel.forEach(function(index) {
                              that.el.selectAll("#rect" + index).attr("fill", fill_color);
                          });
                          that.bar_index_sel = [];
                      }
                      that.sel_indices = (d.map(function(elem) {
                          return elem.index;
                      }));
                      that.bar_index_sel.push(i);
                      that.bar_index_sel.forEach(function(data_elem) {
                          _.bind(that.reset_colors(data_elem, select_color), that);
                      });
                  }
                  buffer_index.forEach(function(data_elem) {
                      that.sel_indices.push(data_elem);
                  });
                  that.selector_model.set("selected", utils.deepCopy(that.sel_indices));
                  that.selector.touch();
                  if (!d3.event) {
                      d3.event = window.event;
                  }
                  var e = d3.event;
                  if (e.cancelBubble !== undefined) { // IE
                      e.cancelBubble = true;
                  }
                  if (e.stopPropagation) {
                      e.stopPropagation();
                  }
                  e.preventDefault();
              });
            this.update_stroke_and_opacity();
        },
        draw_legend: function(elem, x_disp, y_disp, inter_x_disp, inter_y_disp) {
            this.legend_el = elem.selectAll(".legend" + this.uuid)
                .data([this.model.mark_data[0]]);

            var that = this;
            var rect_dim = inter_y_disp * 0.8;
            this.legend_el.enter()
              .append("g")
              .attr("class", "legend" + this.uuid)
              .attr("transform", function(d, i) {
                  return "translate(0, " + (i * inter_y_disp + y_disp)  + ")";
              })
              .on("mouseover", _.bind(this.highlight_axes, this))
              .on("mouseout", _.bind(this.unhighlight_axes, this))
              .append("rect")
              .style("fill", function(d,i) { return that.get_colors(i); })
              .attr({x: 0, y: 0, width: rect_dim, height: rect_dim});

            this.legend_el.append("text")
              .attr("class","legendtext")
              .attr("x", rect_dim * 1.2)
              .attr("y", rect_dim / 2)
              .attr("dy", "0.35em")
              .text(function(d, i) {
                  return that.model.get("labels")[i];
              })
              .style("fill", function(d,i) {
                  return that.get_colors(i);
              });

            var max_length = d3.max(this.model.get("labels"), function(d) {
                return d.length;
            });

            this.legend_el.exit().remove();
            return [1, max_length];
        },
        reset_colors: function(index, color) {
            var rects = this.el.selectAll("#rect"+index);
            rects.attr("fill", color);
        },
        update_selected_colors: function(idx_start, idx_end) {
            // listen to changes of idx_selected and draw itself
            var colors = this.model.get("colors");
            var select_color = colors.length > 1 ? colors[1] : "red";
            var fill_color = colors[0];
            var bars_sel = this.el.selectAll(".bar");
            var current_range = _.range(idx_start, idx_end);
            if(current_range.length == this.model.num_bins) {
                current_range = [];
            }
            var self = this;
            _.range(0, this.model.num_bins).forEach(function(d) {
                self.el.selectAll("#rect" + d).attr("fill", fill_color);
            });
            current_range.forEach(function(d) {
                self.el.selectAll("#rect" + d).attr("fill", select_color);
            });
        },
        invert_range: function(start_pxl, end_pxl) {
            if( start_pxl === undefined && end_pxl === undefined ) {
                this.update_selected_colors(-1,-1);
                idx_selected = [];
                this.model.set("idx_selected", idx_selected);
                this.touch();
                return idx_selected;
            }
            var x_scale = this.scales["sample"];
            var data = [start_pxl, end_pxl].map(function(elem) {
                return x_scale.scale.invert(elem);
            });
            var idx_start = d3.max([0, d3.bisectLeft(this.model.x_bins, data[0]) - 1]);
            var idx_end = d3.min([this.model.num_bins, d3.bisectRight(this.model.x_bins, data[1])]);
            this.update_selected_colors(idx_start, idx_end);

            var x_data = this.model.get_typed_field("sample");
            var indices = _.range(x_data.length);
            var selected_data = [this.model.x_bins[idx_start], this.model.x_bins[idx_end]];
            var idx_selected = _.filter(indices, function(index) {
                var elem = x_data[index];
                return (elem <= selected_data[1] && elem >= selected_data[0]);
            });
            this.model.set("idx_selected", idx_selected);
            this.touch();
            return idx_selected;
        },
    });

    return {
        Hist: Hist,
    };
});
<commit_msg>changes to hist<commit_after>/* Copyright 2015 Bloomberg Finance L.P.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

define(["./d3", "./Mark", "./utils"], function(d3, MarkViewModule, utils) {
    "use strict";

    var Hist = MarkViewModule.Mark.extend({
        render: function() {
            var base_creation_promise = Hist.__super__.render.apply(this);
            this.sel_indices = [-1];
            this.bar_index_sel = [];

            var self = this;
            return base_creation_promise.then(function() {
                self.create_listeners();
                self.draw();
            });
        },
        set_ranges: function() {
            var x_scale = this.scales["sample"];
            if(x_scale) {
                x_scale.set_range(this.parent.padded_range("x", x_scale.model));
            }
            var y_scale = this.scales["counts"];
            if(y_scale) {
                y_scale.set_range(this.parent.padded_range("y", y_scale.model));
            }
        },
        set_positional_scales: function() {
            // In the case of Hist, a change in the "sample" scale triggers
            // a full "update_data" instead of a simple redraw.
            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
            this.listenTo(x_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.model.update_data(); }
            });
            this.listenTo(y_scale, "domain_changed", function() {
                if (!this.model.dirty) { this.draw(); }
            });
        },
        create_listeners: function() {
            Hist.__super__.create_listeners.apply(this);
            this.model.on("data_updated", this.draw, this);
            this.model.on("change:colors",this.update_colors,this);
            this.model.on_some_change(["stroke", "opacity"], this.update_stroke_and_opacity, this);
            this.model.on("change:idx_selected", this.update_idx_selected, this);
        },
        reset_selections: function() {
            if(!(this.selector_model)) {
                return;
            }
            var that = this;
            var colors = this.model.get("colors");
            this.bar_index_sel.forEach(function(d) {
                that.el.selectAll("#rect" + d).style("fill", colors[0]);
            });
            this.bar_index_sel = [];
            this.sel_indices = [];
            this.selector_model.set("selected", []);
            this.selector.touch();
        },
        update_colors: function(model, colors) {
            this.el.selectAll(".bar").selectAll("rect")
              .style("fill", this.get_colors(0));
            if (model.get("labels") && colors.length > 1) {
                this.el.selectAll(".bar").selectAll("text")
                  .style("fill", this.get_colors(1));
            }
            if (this.legend_el) {
                this.legend_el.selectAll("rect")
                  .style("fill", this.get_colors(0));
                this.legend_el.selectAll("text")
                  .style("fill", this.get_colors(0));
            }
        },
        update_stroke_and_opacity: function() {
            var stroke = this.model.get("stroke");
            var opacity = this.model.get("opacity");
            this.el.selectAll(".rect")
              .style("stroke", (stroke === null || stroke === undefined) ? "none" : stroke)
              .style("opacity", opacity);
        },
        calculate_bar_width: function() {
            var x_scale = this.scales["sample"];
            var bar_width = (x_scale.scale(this.model.max_x) - x_scale.scale(this.model.min_x)) / this.model.num_bins;
            if (bar_width >= 10) {
                bar_width -= 2;
            }
            return bar_width;
        },
        relayout: function() {
            this.set_ranges();

            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
			this.el.selectAll(".bar")
			  .attr("transform", function(d) {
                  return "translate(" + x_scale.scale(d.x) +
                                  "," + y_scale.scale(d.y) + ")";
              });
            var bar_width = this.calculate_bar_width();
            this.el.selectAll(".bar").select("rect")
              .transition().duration(300)
		      .attr("x", 2)
              .attr("width", bar_width)
		      .attr("height", function(d) {
                  return y_scale.scale(0) - y_scale.scale(d.y);
              });
        },
        draw: function() {
            this.set_ranges();
            var colors = this.model.get("colors");
            var fill_color = colors[0];
            var select_color = (colors.length > 1) ? colors[1] : "red";

            var indices = [];
            this.model.mark_data.forEach(function(d, i) {
                indices.push(i);
            });

            var x_scale = this.scales["sample"],
                y_scale = this.scales["counts"];
            var that = this;
            this.el.selectAll(".bar").remove();
            var bar_width = this.calculate_bar_width();
	        var bar = this.el.selectAll(".bar")
			  .data(this.model.mark_data)
		      .enter().append("g")
			  .attr("class","bar")
			  .attr("transform", function(d) {
                  return "translate(" + x_scale.scale(d.x) + "," +
                                        y_scale.scale(d.y) + ")";
              });

		    bar.append("rect")
              .attr("class", "rect")
              .attr("id", function(d, i) { return "rect"+i; })
		      .attr("x", 2)
              .attr("width", bar_width)
		      .attr("height", function(d) {
                  return y_scale.scale(0) - y_scale.scale(d.y);
              })
              .style("fill", fill_color)
              .on("click", function(d, i) {
                  if(!(that.selector_model)) {
                     return;
                  }
                  var buffer_index = [];
                  var elem_index = that.bar_index_sel.indexOf(i);
                  if( elem_index > -1 && d3.event.ctrlKey) {
                      that.bar_index_sel.splice(elem_index, 1);
                      d.forEach(function(elem) {
                          var remove_index = that.sel_indices.indexOf(elem.index);
                          if(remove_index !== -1) {
                              that.sel_indices.splice(remove_index, 1);
                          }
                      });
                      that.el.selectAll("#rect" + i).style("fill", fill_color);
                  }
                  else {
                      if(that.sel_indices[0] === -1) {
                          that.sel_indices.splice(0,1);
                      }
                      if(d3.event.ctrlKey) {
                          that.sel_indices.forEach(function(elem) {
                              buffer_index.push(elem);
                          });
                      } else if(d3.event.shiftKey) {
                          if(elem_index > -1) {
                              return;
                          }
                          that.sel_indices.forEach(function(elem) {
                              buffer_index.push(elem);
                          });
                          var min_index = (that.bar_index_sel.length !== 0) ?
                              d3.min(that.bar_index_sel) : -1;
                          var max_index = (that.bar_index_sel.length !== 0) ?
                              d3.max(that.bar_index_sel) : (that.mark_data).length;
                          if(i > max_index){
                              that.model.mark_data.slice(max_index + 1, i).forEach(function(data_elem ) {
                                  data_elem.map(function(elem) {
                                      buffer_index.push(elem.index);
                                  });
                              });
                              indices.slice(max_index + 1, i).forEach(function(data_elem ) {
                                  that.bar_index_sel.push(data_elem);
                              });
                          } else if(i < min_index){
                              that.model.mark_data.slice(i + 1, min_index).forEach(function(data_elem) {
                                  data_elem.map(function(elem) {
                                      buffer_index.push(elem.index);
                                  });
                              });
                              indices.slice(i+1, min_index).forEach(function(data_elem) {
                                  that.bar_index_sel.push(data_elem);
                              });
                          }
                      } else {
                          that.bar_index_sel.forEach(function(index) {
                              that.el.selectAll("#rect" + index).style("fill", fill_color);
                          });
                          that.bar_index_sel = [];
                      }
                      that.sel_indices = (d.map(function(elem) {
                          return elem.index;
                      }));
                      that.bar_index_sel.push(i);
                      that.bar_index_sel.forEach(function(data_elem) {
                          _.bind(that.reset_colors(data_elem, select_color), that);
                      });
                  }
                  buffer_index.forEach(function(data_elem) {
                      that.sel_indices.push(data_elem);
                  });
                  that.selector_model.set("selected", utils.deepCopy(that.sel_indices));
                  that.selector.touch();
                  if (!d3.event) {
                      d3.event = window.event;
                  }
                  var e = d3.event;
                  if (e.cancelBubble !== undefined) { // IE
                      e.cancelBubble = true;
                  }
                  if (e.stopPropagation) {
                      e.stopPropagation();
                  }
                  e.preventDefault();
              });
            this.update_stroke_and_opacity();
        },
        draw_legend: function(elem, x_disp, y_disp, inter_x_disp, inter_y_disp) {
            this.legend_el = elem.selectAll(".legend" + this.uuid)
                .data([this.model.mark_data[0]]);

            var that = this;
            var rect_dim = inter_y_disp * 0.8;
            this.legend_el.enter()
              .append("g")
              .attr("class", "legend" + this.uuid)
              .attr("transform", function(d, i) {
                  return "translate(0, " + (i * inter_y_disp + y_disp)  + ")";
              })
              .on("mouseover", _.bind(this.highlight_axes, this))
              .on("mouseout", _.bind(this.unhighlight_axes, this))
              .append("rect")
              .style("fill", function(d,i) { return that.get_colors(i); })
              .attr({x: 0, y: 0, width: rect_dim, height: rect_dim});

            this.legend_el.append("text")
              .attr("class","legendtext")
              .attr("x", rect_dim * 1.2)
              .attr("y", rect_dim / 2)
              .attr("dy", "0.35em")
              .text(function(d, i) {
                  return that.model.get("labels")[i];
              })
              .style("fill", function(d,i) {
                  return that.get_colors(i);
              });

            var max_length = d3.max(this.model.get("labels"), function(d) {
                return d.length;
            });

            this.legend_el.exit().remove();
            return [1, max_length];
        },
        reset_colors: function(index, color) {
            var rects = this.el.selectAll("#rect"+index);
            rects.style("fill", color);
        },
        update_idx_selected: function(model, value) {
            if(value === undefined || value === null || value.length === 0) {
                //reset the color of everything if idx_selected is blank
                this.update_selected_colors(-1, -1);
                return;
            }
            else {
                var x_data = this.model.get_typed_field("sample");
                var min_data = d3.min(value, function(ind) { return x_data[ind]; });
                var max_data = d3.max(value, function(ind) { return x_data[ind]; });
                var indexes = this.calculate_bar_indices(min_data, max_data);

                this.update_selected_colors(indexes[0], indexes[indexes.length - 1]);
            }
        },
        update_selected_colors: function(idx_start, idx_end) {
            // listen to changes of idx_selected and draw itself
            var colors = this.model.get("colors");
            var select_color = colors.length > 1 ? colors[1] : "red";
            var fill_color = colors[0];
            var bars_sel = this.el.selectAll(".bar");
            var current_range = _.range(idx_start, idx_end);
            if(current_range.length == this.model.num_bins) {
                current_range = [];
            }
            var self = this;
            _.difference(_.range(0, this.model.num_bins), current_range)
                    .forEach(function(d) {
                        self.el.selectAll("#rect" + d).style("fill", fill_color);
                    });
            current_range.forEach(function(d) {
                    self.el.selectAll("#rect" + d).style("fill", select_color);
            });
        },
        invert_range: function(start_pxl, end_pxl) {
            if( start_pxl === undefined && end_pxl === undefined ) {
                this.update_selected_colors(-1,-1);
                idx_selected = [];
                this.model.set("idx_selected", idx_selected);
                this.touch();
                return idx_selected;
            }
            var x_scale = this.scales["sample"];
            var data = [start_pxl, end_pxl].map(function(elem) {
                return x_scale.scale.invert(elem);
            });
            var bar_indices = this.calculate_bar_indices(data[0], data[1]);
            var idx_start = bar_indices[0],
                idx_end = bar_indices[bar_indices.length - 1];
            this.update_selected_colors(idx_start, idx_end);

            var x_data = this.model.get_typed_field("sample");
            var selected_data = [this.model.x_bins[idx_start], this.model.x_bins[bar_indices[idx_end]]];

            var indices = _.range(x_data.length);
            var idx_selected = _.filter(indices, function(index) {
                var elem = x_data[index];
                return (elem <= selected_data[1] && elem >= selected_data[0]);
            });
            this.model.set("idx_selected", idx_selected);
            this.touch();
            return idx_selected;
        },
        calculate_bar_indices: function(data_min, data_max, include) {
            //function to calculate bar indices for a given range of data
            //the attribute include if the data is to be included or
            //excluded.
            var idx_start = d3.max([0, d3.bisectLeft(this.model.x_bins, data_min) - 1]);
            var idx_end = d3.min([this.model.num_bins, d3.bisectRight(this.model.x_bins, data_max)]);
            if(include === undefined || !(include)) {
                return _.range(idx_start, idx_end+1);
            }
            var all_indices = _.range(this.model.mark_data.length);
            return _.difference(all_indices, _.range(idx_start, idx_end+1));
        },
    });

    return {
        Hist: Hist,
    };
});
<|endoftext|>


<commit_before>var exec = require('cordova/exec'),
  channel = require('cordova/channel'),

  // Reference name for the plugin
  PLUGIN_NAME = 'HotCodePush',

  // Plugin methods on the native side that can be called from JavaScript
  pluginNativeMethod = {
    INITIALIZE: 'jsInitPlugin',
    FETCH_UPDATE: 'jsFetchUpdate',
    INSTALL_UPDATE: 'jsInstallUpdate',
    CONFIGURE: 'jsConfigure',
    REQUEST_APP_UPDATE: 'jsRequestAppUpdate'
  },

  // List of events, received from native side.
  // Normally you just don't subscribe for unwanted events,
  // but if you want to ignore them on module level - set flag to false.
  pluginEvents = {
    'chcp_assetsInstallationError': true,
    'chcp_assetsInstalledOnExternalStorage': true,
    'chcp_updateLoadFailed': true,
    'chcp_nothingToUpdate': true,
    'chcp_updateIsReadyToInstall': true,
    'chcp_updateInstallFailed': true,
    'chcp_updateInstalled': true,
    'chcp_nothingToInstall': true
  };

// Called when Cordova is ready for work.
// Here we will send default callback to the native side through which it will send to us different events.
channel.onCordovaReady.subscribe(function() {
  ensureCustomEventExists();
  exec(nativeCallback, null, PLUGIN_NAME, pluginNativeMethod.INITIALIZE, []);
});

/**
 * Method is called when native side sends us different events.
 * Those events can be about update download/installation process.
 *
 * @param {String} msg - JSON formatted string with call arguments
 */
function nativeCallback(msg) {
  // parse call arguments
  var resultObj = processMessageFromNative(msg);
  if (resultObj.action == null) {
    console.log('Action is not provided, skipping');
    return;
  }

  var eventIsEnabled = pluginEvents[resultObj.action];

  // if event is not supported - ignore it
  if (eventIsEnabled == undefined || eventIsEnabled == null) {
    console.warn('Unsupported action: ' + resultObj.action);
    return;
  }

  // if event is enabled - broadcast it
  if (eventIsEnabled) {
    broadcastEventFromNative(resultObj);
  }
}

/**
 * Parse arguments that were sent from the native side.
 * Arguments are a JSON string of type:
 * { action: "action identifier", error: {...error data...}, data: {...some additional data..} }
 * Some parameters may not exist, but the resulting object will have them all.
 *
 * @param {String} msg - arguments as JSON string
 * @return {Object} parsed string
 */
function processMessageFromNative(msg) {
  var errorContent = null;
  var dataContent = null;
  var actionId = null;

  try {
    var resultObj = JSON.parse(msg);
    if (resultObj.hasOwnProperty('error')) {
      errorContent = resultObj.error;
    }
    if (resultObj.hasOwnProperty('data')) {
      dataContent = resultObj.data;
    }
    if (resultObj.hasOwnProperty('action')) {
      actionId = resultObj.action;
    }
  } catch (err) {}

  return {
    action: actionId,
    error: errorContent,
    data: dataContent
  };
}

// region Update/Install events

/*
 * Polyfill for adding CustomEvent which may not exist on older versions of Android.
 * See https://developer.mozilla.org/fr/docs/Web/API/CustomEvent for more details.
 */
function ensureCustomEventExists() {
  // Create only if it doesn't exist
  if (window.CustomEvent) {
    return;
  }

  var CustomEvent = function(event, params) {
    params = params || {
      bubbles: false,
      cancelable: false,
      detail: undefined
    };
    var evt = document.createEvent('CustomEvent');
    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
    return evt;
  };

  CustomEvent.prototype = window.Event.prototype;
  window.CustomEvent = CustomEvent;
}

/**
 * Broadcast event that was received from the native side.
 *
 * @param {Object} arguments, received from the native side
 */
function broadcastEventFromNative(nativeMessage) {
  var params = {};
  if (nativeMessage.error != null) {
    params.error = nativeMessage.error;
  }

  var chcpEvent = new CustomEvent(nativeMessage.action, {
    'detail': params
  });
  document.dispatchEvent(chcpEvent);
}

// endregion

/**
 * Public module of the plugin.
 * May be used by developers to send commands to the plugin.
 */
var chcp = {

  /**
   * Set plugin options.
   * Options are send to the native side.
   * As soon as they are processed - callback is called.
   *
   * @param {Object} options - options to set
   * @param {Callback(error)} callback - callback to call when options are set
   */
  configure: function(options, callback) {
    if (options === undefined || options == null) {
      return;
    }

    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback !== undefined && callback != null) {
        callback(resultObj.error);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.CONFIGURE, [options]);
  },

  /**
   * Show dialog with the request to update application through the Store (App Store or Google Play).
   * For that purpose you can use any other cordova library, this is just a small helper method.
   *
   * @param {String} message - message to show in the dialog
   * @param {Callback()} onStoreOpenCallback - called when user redirects to the Store
   * @param {Callback()} onUserDismissedDialogCallback - called when user declines to go to the Store
   */
  requestApplicationUpdate: function(message, onStoreOpenCallback, onUserDismissedDialogCallback) {
    if (message == undefined || message.length == 0) {
      return;
    }

    var onSuccessInnerCallback = function(msg) {
      if (onStoreOpenCallback) {
        onStoreOpenCallback();
      }
    };

    var onFailureInnerCallback = function(msg) {
      if (onUserDismissedDialogCallback) {
        onUserDismissedDialogCallback();
      }
    };

    exec(onSuccessInnerCallback, onFailureInnerCallback, PLUGIN_NAME, pluginNativeMethod.REQUEST_APP_UPDATE, [message]);
  },

  /**
   * Check if any new content is available on the server and download it.
   * Usually this is done automatically by the plugin, but can be triggered at any time from the web page.
   *
   * @param {Callback(error, data)} callback - called when native side finished update process
   */
  fetchUpdate: function(callback) {
    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback !== undefined && callback != null) {
        callback(resultObj.error, resultObj.data);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.FETCH_UPDATE, []);
  },

  /**
   * Install update if there is anything to install.
   *
   * @param (Callback(error)) callback - called when native side finishes installation process
   */
  installUpdate: function(callback) {
    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback != undefined && callback != null) {
        callback(resultObj.error);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.INSTALL_UPDATE, []);
  }
};

module.exports = chcp;
<commit_msg>Added error codes in JS module. Developers can use them for code readability.<commit_after>
var exec = require('cordova/exec'),
  channel = require('cordova/channel'),

  // Reference name for the plugin
  PLUGIN_NAME = 'HotCodePush',

  // Plugin methods on the native side that can be called from JavaScript
  pluginNativeMethod = {
    INITIALIZE: 'jsInitPlugin',
    FETCH_UPDATE: 'jsFetchUpdate',
    INSTALL_UPDATE: 'jsInstallUpdate',
    CONFIGURE: 'jsConfigure',
    REQUEST_APP_UPDATE: 'jsRequestAppUpdate'
  },

  // List of events, received from native side.
  // Normally you just don't subscribe for unwanted events,
  // but if you want to ignore them on module level - set flag to false.
  pluginEvents = {
    'chcp_assetsInstallationError': true,
    'chcp_assetsInstalledOnExternalStorage': true,
    'chcp_updateLoadFailed': true,
    'chcp_nothingToUpdate': true,
    'chcp_updateIsReadyToInstall': true,
    'chcp_updateInstallFailed': true,
    'chcp_updateInstalled': true,
    'chcp_nothingToInstall': true
  };

// Called when Cordova is ready for work.
// Here we will send default callback to the native side through which it will send to us different events.
channel.onCordovaReady.subscribe(function() {
  ensureCustomEventExists();
  exec(nativeCallback, null, PLUGIN_NAME, pluginNativeMethod.INITIALIZE, []);
});

/**
 * Method is called when native side sends us different events.
 * Those events can be about update download/installation process.
 *
 * @param {String} msg - JSON formatted string with call arguments
 */
function nativeCallback(msg) {
  // parse call arguments
  var resultObj = processMessageFromNative(msg);
  if (resultObj.action == null) {
    console.log('Action is not provided, skipping');
    return;
  }

  var eventIsEnabled = pluginEvents[resultObj.action];

  // if event is not supported - ignore it
  if (eventIsEnabled == undefined || eventIsEnabled == null) {
    console.warn('Unsupported action: ' + resultObj.action);
    return;
  }

  // if event is enabled - broadcast it
  if (eventIsEnabled) {
    broadcastEventFromNative(resultObj);
  }
}

/**
 * Parse arguments that were sent from the native side.
 * Arguments are a JSON string of type:
 * { action: "action identifier", error: {...error data...}, data: {...some additional data..} }
 * Some parameters may not exist, but the resulting object will have them all.
 *
 * @param {String} msg - arguments as JSON string
 * @return {Object} parsed string
 */
function processMessageFromNative(msg) {
  var errorContent = null;
  var dataContent = null;
  var actionId = null;

  try {
    var resultObj = JSON.parse(msg);
    if (resultObj.hasOwnProperty('error')) {
      errorContent = resultObj.error;
    }
    if (resultObj.hasOwnProperty('data')) {
      dataContent = resultObj.data;
    }
    if (resultObj.hasOwnProperty('action')) {
      actionId = resultObj.action;
    }
  } catch (err) {}

  return {
    action: actionId,
    error: errorContent,
    data: dataContent
  };
}

// region Update/Install events

/*
 * Polyfill for adding CustomEvent which may not exist on older versions of Android.
 * See https://developer.mozilla.org/fr/docs/Web/API/CustomEvent for more details.
 */
function ensureCustomEventExists() {
  // Create only if it doesn't exist
  if (window.CustomEvent) {
    return;
  }

  var CustomEvent = function(event, params) {
    params = params || {
      bubbles: false,
      cancelable: false,
      detail: undefined
    };
    var evt = document.createEvent('CustomEvent');
    evt.initCustomEvent(event, params.bubbles, params.cancelable, params.detail);
    return evt;
  };

  CustomEvent.prototype = window.Event.prototype;
  window.CustomEvent = CustomEvent;
}

/**
 * Broadcast event that was received from the native side.
 *
 * @param {Object} arguments, received from the native side
 */
function broadcastEventFromNative(nativeMessage) {
  var params = {};
  if (nativeMessage.error != null) {
    params.error = nativeMessage.error;
  }

  var chcpEvent = new CustomEvent(nativeMessage.action, {
    'detail': params
  });
  document.dispatchEvent(chcpEvent);
}

// endregion

/**
 * Public module of the plugin.
 * May be used by developers to send commands to the plugin.
 */
var chcp = {

  // Plugin error codes
  error: {
    FAILED_TO_DOWNLOAD_APPLICATION_CONFIG: -1,
    APPLICATION_BUILD_VERSION_TOO_LOW: -2,
    FAILED_TO_DOWNLOAD_CONTENT_MANIFEST: -3,
    FAILED_TO_DOWNLOAD_UPDATE_FILES: -4,
    FAILED_TO_MOVE_LOADED_FILES_TO_INSTALLATION_FOLDER: -5,
    UPDATE_IS_INVALID: -6,
    FAILED_TO_COPY_FILES_FROM_PREVIOUS_RELEASE: -7,
    FAILED_TO_COPY_NEW_CONTENT_FILES: -8,
    LOCAL_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND: -9,
    LOCAL_VERSION_OF_MANIFEST_NOT_FOUND: -10,
    LOADED_VERSION_OF_APPLICATION_CONFIG_NOT_FOUND: -11,
    LOADED_VERSION_OF_MANIFEST_NOT_FOUND: -12,
    FAILED_TO_INSTALL_ASSETS_ON_EXTERNAL_STORAGE: -13,
    CANT_INSTALL_WHILE_DOWNLOAD_IN_PROGRESS: -14,
    CANT_DOWNLOAD_UPDATE_WHILE_INSTALLATION_IN_PROGRESS: -15,
    INSTALLATION_ALREADY_IN_PROGRESS: -16,
    DOWNLOAD_ALREADY_IN_PROGRESS: -17,
    ASSETS_FOLDER_IN_NOT_YET_INSTALLED: -18
  },

  /**
   * Set plugin options.
   * Options are send to the native side.
   * As soon as they are processed - callback is called.
   *
   * @param {Object} options - options to set
   * @param {Callback(error)} callback - callback to call when options are set
   */
  configure: function(options, callback) {
    if (options === undefined || options == null) {
      return;
    }

    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback !== undefined && callback != null) {
        callback(resultObj.error);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.CONFIGURE, [options]);
  },

  /**
   * Show dialog with the request to update application through the Store (App Store or Google Play).
   * For that purpose you can use any other cordova library, this is just a small helper method.
   *
   * @param {String} message - message to show in the dialog
   * @param {Callback()} onStoreOpenCallback - called when user redirects to the Store
   * @param {Callback()} onUserDismissedDialogCallback - called when user declines to go to the Store
   */
  requestApplicationUpdate: function(message, onStoreOpenCallback, onUserDismissedDialogCallback) {
    if (message == undefined || message.length == 0) {
      return;
    }

    var onSuccessInnerCallback = function(msg) {
      if (onStoreOpenCallback) {
        onStoreOpenCallback();
      }
    };

    var onFailureInnerCallback = function(msg) {
      if (onUserDismissedDialogCallback) {
        onUserDismissedDialogCallback();
      }
    };

    exec(onSuccessInnerCallback, onFailureInnerCallback, PLUGIN_NAME, pluginNativeMethod.REQUEST_APP_UPDATE, [message]);
  },

  /**
   * Check if any new content is available on the server and download it.
   * Usually this is done automatically by the plugin, but can be triggered at any time from the web page.
   *
   * @param {Callback(error, data)} callback - called when native side finished update process
   */
  fetchUpdate: function(callback) {
    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback !== undefined && callback != null) {
        callback(resultObj.error, resultObj.data);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.FETCH_UPDATE, []);
  },

  /**
   * Install update if there is anything to install.
   *
   * @param (Callback(error)) callback - called when native side finishes installation process
   */
  installUpdate: function(callback) {
    var innerCallback = function(msg) {
      var resultObj = processMessageFromNative(msg);
      if (callback != undefined && callback != null) {
        callback(resultObj.error);
      }
    };

    exec(innerCallback, null, PLUGIN_NAME, pluginNativeMethod.INSTALL_UPDATE, []);
  }
};

module.exports = chcp;
<|endoftext|>


<commit_before><commit_msg>server-mod<commit_after><|endoftext|>


<commit_before>'use strict';

import path from 'path';
import fs from 'fs-extra';

import DevstudioAutoInstallGenerator from './devstudio-autoinstall';
import InstallableItem from './installable-item';
import Installer from './helpers/installer';
import Logger from '../services/logger';
import JdkInstall from './jdk-install';
import Platform from '../services/platform';

class DevstudioInstall extends InstallableItem {
  constructor(keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload) {
    super(keyName, downloadUrl, fileName, targetFolderName, installerDataSvc, true);

    this.sha256 = sha256sum;
    this.installConfigFile = path.join(this.installerDataSvc.tempDir(), 'devstudio-autoinstall.xml');
    this.addOption('install', this.version, '', true);
    this.additionalLocations = additionalLocations;
    this.additionalIus = additionalIus;
    this.useDownload = useDownload;
  }

  static get KEY() {
    return 'devstudio';
  }

  installAfterRequirements(progress, success, failure) {
    progress.setStatus('Installing');
    this.installGenerator = new DevstudioAutoInstallGenerator(this.installerDataSvc.devstudioDir(), this.installerDataSvc.jdkDir(), this.version, this.additionalLocations, this.additionalIus);
    let installer = new Installer(this.keyName, progress, success, failure);
    Logger.info(this.keyName + ' - Generate devstudio auto install file content');
    let data = this.installGenerator.fileContent();
    Logger.info(this.keyName + ' - Generate devstudio auto install file content SUCCESS');

    return installer.writeFile(this.installConfigFile, data)
      .then((result) => {
        return this.headlessInstall(installer, result);
      })
      .then(() => {
        installer.succeed(true);
      })
      .catch((error) => {
        installer.fail(error);
      });
  }

  headlessInstall(installer) {
    Logger.info(this.keyName + ' - headlessInstall() called');
    let javaOpts = [
      '-DTRACE=true',
      '-jar',
      this.downloadedFile,
      this.installConfigFile
    ];
    let res = installer.execFile(
      path.join(this.installerDataSvc.jdkDir(), 'bin', 'java'), javaOpts
    );

    return res;
  }

  isConfigurationValid() {
    let jdk = this.installerDataSvc.getInstallable('jdk');
    return jdk.isConfigured()
      && this.isConfigured()
      || this.isSkipped();
  }

  configureRuntimeDetection(name, location) {
    let runtimeproperties =  Platform.OS === 'win32'
      ? path.join(this.installerDataSvc.devstudioDir(), 'studio', 'runtime_locations.properties')
      : path.join(this.installerDataSvc.devstudioDir(), 'studio/devstudio.app/Contents/Eclipse', 'runtime_locations.properties');
    let escapedLocation = location.replace(/\\/g, '\\\\').replace(/:/g, '\\:');
    let result = Promise.resolve();
    if(fs.existsSync(runtimeproperties)) {
      result = fs.appendFile(runtimeproperties, `\n${name}=${escapedLocation},true`).catch((error)=>{
        Logger.error(this.keyName + ' - error occured during runtime detection configuration in DevStudio');
        Logger.error(this.keyName + ` -  ${error}`);
      });
    }
    return result;
  }
}

function fromJson({keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload}) {
  return new DevstudioInstall(keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload);
}

DevstudioInstall.convertor = {fromJson};

export default DevstudioInstall;
<commit_msg>JBDS-4506 Fuse TOoling fails to install from bundled installer<commit_after>'use strict';

import path from 'path';
import fs from 'fs-extra';

import DevstudioAutoInstallGenerator from './devstudio-autoinstall';
import InstallableItem from './installable-item';
import Installer from './helpers/installer';
import Logger from '../services/logger';
import JdkInstall from './jdk-install';
import Platform from '../services/platform';

class DevstudioInstall extends InstallableItem {
  constructor(keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload) {
    super(keyName, downloadUrl, fileName, targetFolderName, installerDataSvc, true);

    this.sha256 = sha256sum;
    this.installConfigFile = path.join(this.installerDataSvc.tempDir(), 'devstudio-autoinstall.xml');
    this.addOption('install', this.version, '', true);
    this.additionalLocations = additionalLocations;
    this.additionalIus = additionalIus;
    this.useDownload = useDownload;
  }

  static get KEY() {
    return 'devstudio';
  }

  installAfterRequirements(progress, success, failure) {
    progress.setStatus('Installing');
    //this workaround for fuse tooling install problems
    if(fs.existsSync(this.bundledFile)) {
      this.downloadedFile = this.bundledFile;
    }
    this.installGenerator = new DevstudioAutoInstallGenerator(this.installerDataSvc.devstudioDir(), this.installerDataSvc.jdkDir(), this.version, this.additionalLocations, this.additionalIus);
    let installer = new Installer(this.keyName, progress, success, failure);
    Logger.info(this.keyName + ' - Generate devstudio auto install file content');
    let data = this.installGenerator.fileContent();
    Logger.info(this.keyName + ' - Generate devstudio auto install file content SUCCESS');

    return installer.writeFile(this.installConfigFile, data)
      .then((result) => {
        return this.headlessInstall(installer, result);
      })
      .then(() => {
        installer.succeed(true);
      })
      .catch((error) => {
        installer.fail(error);
      });
  }

  headlessInstall(installer) {
    Logger.info(this.keyName + ' - headlessInstall() called');
    let javaOpts = [
      '-DTRACE=true',
      '-jar',
      this.downloadedFile,
      this.installConfigFile
    ];
    let res = installer.execFile(
      path.join(this.installerDataSvc.jdkDir(), 'bin', 'java'), javaOpts
    );

    return res;
  }

  isConfigurationValid() {
    let jdk = this.installerDataSvc.getInstallable('jdk');
    return jdk.isConfigured()
      && this.isConfigured()
      || this.isSkipped();
  }

  configureRuntimeDetection(name, location) {
    let runtimeproperties =  Platform.OS === 'win32'
      ? path.join(this.installerDataSvc.devstudioDir(), 'studio', 'runtime_locations.properties')
      : path.join(this.installerDataSvc.devstudioDir(), 'studio/devstudio.app/Contents/Eclipse', 'runtime_locations.properties');
    let escapedLocation = location.replace(/\\/g, '\\\\').replace(/:/g, '\\:');
    let result = Promise.resolve();
    if(fs.existsSync(runtimeproperties)) {
      result = fs.appendFile(runtimeproperties, `\n${name}=${escapedLocation},true`).catch((error)=>{
        Logger.error(this.keyName + ' - error occured during runtime detection configuration in DevStudio');
        Logger.error(this.keyName + ` -  ${error}`);
      });
    }
    return result;
  }
}

function fromJson({keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload}) {
  return new DevstudioInstall(keyName, installerDataSvc, targetFolderName, downloadUrl, fileName, sha256sum, additionalLocations, additionalIus, useDownload);
}

DevstudioInstall.convertor = {fromJson};

export default DevstudioInstall;
<|endoftext|>


<commit_before>'use strict';

var gameWidth = window.innerWidth * window.devicePixelRatio;
var gameHeight = window.innerHeight * window.devicePixelRatio;

var game = new Phaser.Game(gameWidth, gameHeight, Phaser.AUTO, 'gameDiv');
var game_state = {};

game_state.main = function ()
{
var self = this;
self.player;
//self.players = {}
//self.playerGroup;

self.preload = () =>
  {
  self.id = getParameter('id');
  if (!self.id) self.id = 1;

  gameClient.connect("localhost", 8082, self.id, self.clientConnected);

  game.load.image('sky', 'assets/bg/sky.png');
  game.load.image('player', 'assets/player_classes/knight.png');
  }

self.create = () =>
  {
  game.stage.disableVisibilityChange = true;
  self.bg = game.add.sprite(0, 0, 'sky');
  self.bg.height = gameHeight;
  self.bg.width = gameWidth;
  self.bg.smoothed = false;

  game.physics.startSystem(Phaser.Physics.ARCADE);

  //playerGroup = game.add.group();
  }

self.setPlayerInput = (id, input) =>
  {
  if (self.player != undefined)
  {
    console.log("setting player input X: " + input.X);
    self.player.setInput(input);
  }
  };

self.update = () =>
  {
  if (self.player != undefined)
  {
    self.player.update();
  }
  };

self.render = () => {};

self.onControllerConnected = (id) =>
  {
  self.player = new Player(game, game.world.width/2, game.world.height/2);
  //players[id] = new Player(game, game.world.width/2, game.world.height/2);
  //playerGroup.add(players[id]);
  };

self.onControllerDisconnected = (id) =>
  {
  //playerGroup.remove(players[id]);
  //players[id].kill();
  if (self.player != undefined)
  {
  self.player.kill();
  self.player = undefined;
  }
  };

self.onScreenConnected = (id) =>
  {
  console.log("OwnScreen::onScreenConnected() "+ id);
  console.log("Currently connected screens: " + gameClient.getConnectedScreenIds());
  //gameClient.callServerRpc(1, "method", ["hello server"],  self, null);
  };

self.onScreenDisconnected = (id) =>
  {
  console.log("OwnScreen::onScreenDisconnected() "+id);
  console.log("Currently connected screens: " + gameClient.getConnectedScreenIds());
  };

self.clientConnected = () =>
  {
  console.log("DemoScreen::screenConnected()");

  gameClient.setClientConnectionListener(self, self.onControllerConnected);
  gameClient.setClientDisconnectionListener(self, self.onControllerDisconnected);
  gameClient.setScreenConnectionListener(self, self.onScreenConnected);
  gameClient.setScreenDisconnectionListener(self, self.onScreenDisconnected);

  gameClient.exposeRpcMethod("setPlayerInput", self, self.setPlayerInput);

  gameClient.callClientRpc(1, "setStickPosition", [211,100],  self, null);
  gameClient.callClientRpc(1, "getStickPosition", [],  self, function(err, data)
  {
  console.log("Stick position received: "+data);
  });

  };
};

game.state.add('main', game_state.main);
game.state.start('main');
<commit_msg>Supports multiple players<commit_after>'use strict';

var gameWidth = window.innerWidth * window.devicePixelRatio;
var gameHeight = window.innerHeight * window.devicePixelRatio;

var game = new Phaser.Game(gameWidth, gameHeight, Phaser.AUTO, 'gameDiv');
var game_state = {};

game_state.main = function ()
{
var self = this;
//self.player;

self.players = {}
//self.playerGroup;

self.preload = () =>
  {
  self.id = getParameter('id');
  if (!self.id) self.id = 1;

  gameClient.connect("localhost", 8082, self.id, self.clientConnected);

  game.load.image('sky', 'assets/bg/sky.png');
  game.load.image('player', 'assets/player_classes/knight.png');
  }

self.create = () =>
  {
  game.stage.disableVisibilityChange = true;
  self.bg = game.add.sprite(0, 0, 'sky');
  self.bg.height = gameHeight;
  self.bg.width = gameWidth;
  self.bg.smoothed = false;

  game.physics.startSystem(Phaser.Physics.ARCADE);

  //playerGroup = game.add.group();
  }

self.setPlayerInput = (id, input) =>
  {
  if (self.players[id] != undefined)
  {
    console.log("setting player input X: " + input.X);
    self.players[id].setInput(input);
  }
  };

self.update = () =>
  {
  for (var id in self.players)
  {
  if (self.players[id] != undefined)
  {
    self.players[id].update();
  }
  }
  };

self.render = () => {};

self.onControllerConnected = (id) =>
  {
  //self.player = new Player(game, game.world.width/2, game.world.height/2);
  self.players[id] = new Player(game, game.world.width/2, game.world.height/2);
  //playerGroup.add(players[id]);
  };

self.onControllerDisconnected = (id) =>
  {
  //playerGroup.remove(players[id]);
  //players[id].kill();
  if (self.players[id] != undefined)
  {
  self.players[id].kill();
  self.players[id] = undefined;
  //playerGroup.remove(players[id]);
  }
  };

self.onScreenConnected = (id) =>
  {
  console.log("OwnScreen::onScreenConnected() "+ id);
  console.log("Currently connected screens: " + gameClient.getConnectedScreenIds());
  //gameClient.callServerRpc(1, "method", ["hello server"],  self, null);
  };

self.onScreenDisconnected = (id) =>
  {
  console.log("OwnScreen::onScreenDisconnected() "+id);
  console.log("Currently connected screens: " + gameClient.getConnectedScreenIds());
  };

self.clientConnected = () =>
  {
  console.log("DemoScreen::screenConnected()");

  gameClient.setClientConnectionListener(self, self.onControllerConnected);
  gameClient.setClientDisconnectionListener(self, self.onControllerDisconnected);
  gameClient.setScreenConnectionListener(self, self.onScreenConnected);
  gameClient.setScreenDisconnectionListener(self, self.onScreenDisconnected);

  gameClient.exposeRpcMethod("setPlayerInput", self, self.setPlayerInput);

  gameClient.callClientRpc(1, "setStickPosition", [211,100],  self, null);
  gameClient.callClientRpc(1, "getStickPosition", [],  self, function(err, data)
  {
  console.log("Stick position received: "+data);
  });

  };
};

game.state.add('main', game_state.main);
game.state.start('main');
<|endoftext|>


<commit_before>(function() {
  'use strict';

  module.exports = function(key) {
    require('terminal-colors');

    var DEBUG = true;
    var raw = require('raw-socket'),
        crypto = require('./encryption.js'),
        socket = raw.createSocket({
          protocol: raw.Protocol.ICMP
        });

    var message = '',
        count = 0,
        offset,
        type,
        length,
        hex;

    socket.on('message', listen);
    function listen(buffer, source) {
      // convert buffer to hex string
      buffer = buffer.toString('hex', 20, buffer.length);
      type = parseInt(buffer.substring(0, 2), 16);
      length = parseInt(buffer.substring(8, 9), 16);

      // get message
      offset = 9;
      hex = buffer.substring(offset, offset + length);

      if(DEBUG) {
        console.log('\nping #' + count);
        console.log('buffer:', buffer);
        console.log('type:', type === 0 ? 'ICMP Echo reply' : 'ICMP Echo request');
        console.log('message length:', length);
        console.log('message content:', hex);
      }

      // return if type is ICMP Echo reply
      if(type === 0)
        return;

      // end ping
      if(hex === 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') {
        process.stdout.write(source.green + ' ');
        process.stdout.write('[' + count + ']: ');
        process.stdout.write(message.bold + '\n');

        count = 0;
        message = '';

        return;
      }

      message += crypto.decrypt(hex, key);
      count++;
    }
  };
}());
<commit_msg>bugfixes<commit_after>(function() {
  'use strict';

  module.exports = function(key) {
    require('terminal-colors');

    var DEBUG = true;
    var raw = require('raw-socket'),
        crypto = require('./encryption.js'),
        socket = raw.createSocket({
          protocol: raw.Protocol.ICMP
        });

    var message = '',
        count = 0,
        offset,
        type,
        length,
        hex;

    socket.on('message', listen);
    function listen(buffer, source) {
      // convert buffer to hex string
      buffer = buffer.toString('hex', 20, buffer.length);
      type = parseInt(buffer.substring(0, 2), 16);
      length = parseInt(buffer.substring(16, 18), 16);

      // get message
      offset = 18;
      hex = buffer.substring(offset, offset + length);

      if(DEBUG) {
        console.log('\nping #' + count);
        console.log('buffer:', buffer);
        console.log('type:', type === 0 ? 'ICMP Echo reply' : 'ICMP Echo request');
        console.log('message length:', length);
        console.log('message content:', hex);
      }

      // return if type is ICMP Echo reply
      if(type === 0)
        return;

      // end ping
      if(hex === 'ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff') {
        process.stdout.write(source.green + ' ');
        process.stdout.write('[' + count + ']: ');
        process.stdout.write(message.bold + '\n');

        count = 0;
        message = '';

        return;
      }

      message += crypto.decrypt(hex, key);
      count++;
    }
  };
}());
<|endoftext|>


<commit_before>var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');
var mongoose   = require('mongoose');
var morgan = require('morgan');

var logger = morgan('combined')

//User Models
var User       = require('./models/user');
mongoose.connect('mongodb://10.132.126.169/battle-api');
// mongoose.connect('mongodb://localhost/battle-api');

// ADD MIDDLEWARE
app.use(morgan('combined'))
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

var port = '8080';
var private_ip = '10.132.125.55';

// ROUTES FOR OUR API
// =============================================================================
var router = express.Router();              // get an instance of the express Router

router.get('/', function(req, res, next) {
  console.log('hitting home')

    res.end("Hello, World!!!");
});

router.route('/users')
    .post(function(req, res) {
        var user = new User();
        user.name = req.body.name;

        user.save(function(err) {
            if (err) res.send(err);

            res.json({ message: 'User created!' });
        })
    })
    .get(function(req,res) {
        User.find(function(err,users) {
          if(err) req.send(err);
          res.send(users);
        })
      });

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use(router);

// START THE SERVER
// =============================================================================
app.listen(port,private_ip);
console.log('Server started on port ' + port);
<commit_msg>logging2<commit_after>var express    = require('express');        // call express
var app        = express();                 // define our app using express
var bodyParser = require('body-parser');
var mongoose   = require('mongoose');
var morgan = require('morgan');

var logger = morgan('combined')

//User Models
var User       = require('./models/user');
mongoose.connect('mongodb://10.132.126.169/battle-api');
// mongoose.connect('mongodb://localhost/battle-api');

// ADD MIDDLEWARE
app.use(morgan('combined'))
app.use(bodyParser.urlencoded({ extended: true }));
app.use(bodyParser.json());

var port = '8080';
var private_ip = '10.132.125.55';

// ROUTES FOR OUR API
// =============================================================================
var router = express.Router();              // get an instance of the express Router

router.get('/', function(req, res, next) {
  console.log('hitting home')
    res.end("Hello, World!!!");
});

router.route('/users')
    .post(function(req, res) {
        var user = new User();
        user.name = req.body.name;

        user.save(function(err) {
            if (err) res.send(err);

            res.json({ message: 'User created!' });
        })
    })
    .get(function(req,res) {
        User.find(function(err,users) {
          if(err) req.send(err);
          res.send(users);
        })
      });

// REGISTER OUR ROUTES -------------------------------
// all of our routes will be prefixed with /api
app.use('api',router);

// START THE SERVER
// =============================================================================
app.listen(port,private_ip);
console.log('Server started on port ' + port);
<|endoftext|>


<commit_before>(function (DISPLAY_TIMEOUT, ANSWER_TIMEOUT, SHORT_DISPLAY_TIMEOUT, HTTP_PORT, NUMBER_QUESTION) {
    var games = [];
    var players = [];
    var playerIdGenerator = 0;
    var lies = undefined;

    require('./array.js');

    var express = require('express');
    var app = express();
    var server = null;

    try {
        app.use(express.static(__dirname + '/client'));
        app.get('/', function (req, res) {
            res.sendfile(__dirname + '/client/index.html');
        });
        server = app.listen(HTTP_PORT);
        console.log("Ready & listening to requests. Ctrl-C to stop.")
    } catch (e) {
        console.log("Error in server: " + e);
    }

    try {
        var io = require('socket.io').listen(server);
        console.log("WSServer lancé");
    } catch (e) {
        console.log("Problème WSServer" + e);
    }

    console.log("Listening to port: " + HTTP_PORT);

    io.sockets.on('connection', function (socket) {
        socket.on('iam:presenter', function (data) {
            var game = new Game(socket);
            games.push(game);

            game.presenterSocket.emit('display:code', game.code);
            console.log("New Game: Presenter: " + game.code);
        });

        socket.on('iam:player', function (data) {
            var game = getGameByCode(data.code);
            if (game == undefined) {
                socket.emit('wrong:code');
            } else {
                var player = game.getPlayerByName(data.name);
                if (player !== undefined) {
                    player.disconnected = false;
                    player.socket = socket;
                } else {
                    game.createPlayer(data.name, socket);
                    game.presenterSocket.emit('display:player', {"name": data.name, "id": getPlayerBySocket(socket).id});
                    console.log("[Game" + game.code + "] New Player: " + data.name);
                }
            }

        });

        socket.on('start', function (data) {
            var game = getGameByCode(data.code).start();
            console.log("[Game" + game.code + "] Game Start !");
        });

        socket.on('play:lie', function (data) {
            var player = getPlayerById(data.id);
            if (player != undefined) {
                if (data.lie.trim() === player.game.questions[0].truth) {
                    socket.emit('lie:truth');
                    console.log("[Game" + player.game.code + "] Player found truth !");
                } else {
                    player.actualLie = data.lie.toUpperCase().trim();
                    player.socket.emit('lie:ok');
                    player.game.presenterSocket.emit('song:player', player.id);
                    console.log("[Game" + player.game.code + "] Player " + player.name + " lied [" + player.actualLie + "]");

                    player.game.presenterSocket.emit('player:lied', player.name);

                    if (player.game.allLiesEntered()) {
                        player.game.endLie();
                        console.log("[Game" + player.game.code + "] All players lied !");
                    }
                }
            } else {
                console.log("Wrong lier " + JSON.stringify(data));
            }
        });

        socket.on('play:answer', function (data) {
            var player = getPlayerById(data.id);
            if (player != undefined) {
                player.actualAnswer = data.answer.toUpperCase().trim();
                console.log("[Game" + player.game.code + "] Player " + player.name + " answered [" + player.actualAnswer + "]");
                player.game.presenterSocket.emit('song:player', player.id);

                if (player.game.allAnswersEntered()) {
                    console.log("[Game" + player.game.code + "] All players Answered !");
                    player.game.endAnswer();
                }
            } else {
                console.log("Wrong answerer " + JSON.stringify(data));
            }
        });

        socket.on('disconnect', function () {
            socket.emit('disconnected');
            var player = getPlayerBySocket(socket);
            if (player != undefined) {
                player.disconnected = true;
            }
        });
    });

    function Game(socket) {
        this.code = this.generateCode();
        this.presenterSocket = socket;
        this.players = [];
        this.questions = randomQuestions(NUMBER_QUESTION);
    }

    var fs = require('fs');

    function randomQuestions(nb) {
        var buffer = fs.readFileSync('./questions.json', "utf8");
        var possibleQuestions = JSON.parse(buffer);
        return possibleQuestions.shuffle().splice(0, nb);
    }

    function randomLies() {
        if (lies === undefined) {
            var buffer = fs.readFileSync('./questions.json', "utf8");
            lies = JSON.parse(buffer)
                .filter(function (obj) {
                    return obj !== undefined;
                })
                .map(function (obj) {
                    return obj.truth;
                })
                .unique();
        }
        return lies;
    }

    function getGameByCode(code) {
        return games.filter(function (game) {
            return game.code === code;
        })[0];
    }

    Game.prototype.generateCode = function () {
        var valid = false;
        while (!valid) {
            var candidate = randomString(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
            valid = games.filter(function (game) {
                    return game.code === candidate;
                }).length === 0;
        }
        return candidate;
    };

    function randomString(length, chars) {
        var result = '';
        for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
        return result;
    }

    Game.prototype.createPlayer = function (name, socket) {
        var player = new Player(name, socket, this);
        this.players.push(player);
        players.push(player);
        socket.emit('identify', {"id": player.id});
    };

    Game.prototype.getPlayerByName = function (name) {
        return this.players.filter(function (player) {
            return name === player.name;
        })[0];
    };

    Game.prototype.start = function () {
        this.state = "lying";
        this.players.forEach(function (player) {
            player.actualLie = undefined;
            player.actualAnswer = undefined;
        });
        var game = this;
        if (this.questions.length > 0) {
            console.log("[Game" + this.code + "] Question n°" + ( NUMBER_QUESTION - this.questions.length) + " started");
            this.broadcast('display:lie', this.questions[0]);
            this.endLieTimeout = setTimeout(function () {
                game.endLie();
            }, ANSWER_TIMEOUT);
        } else {
            console.log("[Game" + this.code + "] Game terminated !");
            this.end = Date.now();
            this.questions = randomQuestions(NUMBER_QUESTION);
            this.broadcast('end');
        }
        return this;
    };

    Game.prototype.endLie = function () {
        var game = this;
        clearTimeout(this.endLieTimeout);
        if (this.state == "lying") {
            console.log("[Game" + game.code + "] Starting choosing answers");
            this.state = "answering";

            this.broadcast("display:answer", {
                question: this.questions[0],
                lies    : this.players
                    .filter(function (player) {
                        return player.actualLie != undefined && player.actualLie != null;
                    })
                    .map(function (player) {
                        return player.actualLie;
                    })
                    .concat(this.questions[0].truth.toUpperCase())
                    .unique()
                    .completeWith(randomLies(), this.players.length + 1 > 4 ? this.players.length + 1 : 4)
                    .shuffle()
            });

            this.endAnswerTimeout = setTimeout(function () {
                game.endAnswer();
            }, ANSWER_TIMEOUT);
        }
    };

    Game.prototype.broadcast = function (evt, obj) {
        this.presenterSocket.emit(evt, obj);
        this.players.forEach(function (player) {
            player.socket.emit(evt, obj);
        });
    };

    Game.prototype.allLiesEntered = function () {
        var allLied = true;
        this.players.forEach(function (player) {
            allLied = allLied && (player.actualLie !== undefined);
        });
        return allLied;
    };

    Game.prototype.allAnswersEntered = function () {
        var allAnswers = true;
        this.players.forEach(function (player) {
            allAnswers = allAnswers && (player.actualAnswer !== undefined);
        });
        return allAnswers;
    };

    Game.prototype.endAnswer = function () {
        var game = this;
        clearTimeout(this.endAnswerTimeout);
        if (this.state == "answering") {
            console.log("[Game" + game.code + "] Starting displaying results");
            this.state = "calculating";
            this.presenterSocket.emit("clear:message", {});
            this.resultMessages = [];

            var points = 500;
            if ((NUMBER_QUESTION / 2) > this.questions.length) {
                points = 1000;
            }
            if (this.questions.length == 1) {
                points = 1500;
            }

            /* L'ordi a menti */
            randomLies()
                .filter(function (lie) {
                    /* Un utilisateur a entré ce même mensonge */
                    var entered = false;
                    game.players.forEach(function (player, idx, arr) {
                        if (lie.toUpperCase() === player.actualLie) {
                            entered = true;
                        }
                    });
                    return !entered;
                })
                .filter(function (lie) {
                    /* On ignore la vérité */
                    return lie.toUpperCase() !== game.questions[0].truth.toUpperCase();
                })
                .forEach(function (lie) {
                    var liedWorkedOn = "";
                    game.players.forEach(function (player, idx, arr) {
                        if (lie.toUpperCase() === player.actualAnswer) {
                            liedWorkedOn += player.name + " ";
                            player.score -= points;
                        }
                    });
                    if (liedWorkedOn.length > 0) {
                        game.resultMessages.push({msg: "La réponse " + lie, time: SHORT_DISPLAY_TIMEOUT});
                        game.resultMessages.push({msg: "Etait un MENSONGE de la MATRICE !!!", time: SHORT_DISPLAY_TIMEOUT * 2});
                        game.resultMessages.push({msg: "qui a trompé " + liedWorkedOn, time: SHORT_DISPLAY_TIMEOUT * 2});
                    }
                });

            /* A menti */
            this.players
                .filter(function(player){
                    return player.actualLie !== undefined;
                })
                .forEach(function (player, idx, arr) {
                var liedTo = "";
                arr.forEach(function (potentialLiedTo) {
                    if (potentialLiedTo.actualAnswer !== undefined && potentialLiedTo.actualAnswer === player.actualLie) {
                        liedTo += potentialLiedTo.name + " ";
                        player.score += points;
                    }
                });
                if (liedTo.length > 0) {
                    game.resultMessages.push({msg: "La réponse " + player.actualLie, time: SHORT_DISPLAY_TIMEOUT});
                    game.resultMessages.push({msg: "Etait un MENSONGE de " + player.name, time: SHORT_DISPLAY_TIMEOUT * 2});
                    game.resultMessages.push({msg: "qui a trompé " + liedTo, time: SHORT_DISPLAY_TIMEOUT * 2});
                }
            });

            /* A trouvé la vérité */
            this.resultMessages.push({msg: "La réponse " + game.questions[0].truth.toUpperCase(), time: SHORT_DISPLAY_TIMEOUT});
            this.resultMessages.push({msg: "Etait la VERITE", time: SHORT_DISPLAY_TIMEOUT});
            var haveFoundTruth = "";
            this.players.forEach(function (player, idx, arr) {
                if (player.actualAnswer === game.questions[0].truth.toUpperCase()) {
                    player.score += points * 2;
                    haveFoundTruth += player.name + " ";
                }
            });
            if (haveFoundTruth.length > 0) {
                this.resultMessages.push({msg: "qui a été trouvée par " + haveFoundTruth, time: SHORT_DISPLAY_TIMEOUT});
            } else {
                this.resultMessages.push({msg: "qui n'a été trouvée par PERSONNE !", time: SHORT_DISPLAY_TIMEOUT});
            }
            game.presenterSocket.emit('song:result');
            game.displayNextMessage();
        }
    };

    Game.prototype.displayNextMessage = function () {
        var game = this;
        if (this.resultMessages.length > 0) {
            var result = this.resultMessages.shift();
            this.presenterSocket.emit("display:message", {question: this.questions[0].question, msg: result});
            setTimeout(function () {
                game.displayNextMessage();
            }, DISPLAY_TIMEOUT);
        } else {
            this.presenterSocket.emit("display:score", {question: this.questions[0].question, scoreTab: game.getScoreTab()});
            setTimeout(function () {
                console.log("[Game" + game.code + "] Next Question !");
                game.questions.shift();
                game.start();
            }, DISPLAY_TIMEOUT);
        }
    };

    Game.prototype.getScoreTab = function () {
        return this.players.map(function (player) {
            return {name: player.name, score: player.score}
        }).sort(function (a, b) {
            return a.score - b.score;
        });
    };

    function Player(name, socket, game) {
        this.name = name.toUpperCase();
        this.socket = socket;
        this.id = playerIdGenerator++;
        this.game = game;
        this.score = 0;
    }

    function getPlayerById(id) {
        return players.filter(function (player) {
            return player.id === id;
        })[0];
    }

    function getPlayerBySocket(socket) {
        return players.filter(function (player) {
            return player.socket === socket;
        })[0];
    }

})(5000, 30000, 1000, 8000, 7);<commit_msg>Correction d'un bug de réponse/mensonge undefined<commit_after>(function (DISPLAY_TIMEOUT, ANSWER_TIMEOUT, SHORT_DISPLAY_TIMEOUT, HTTP_PORT, NUMBER_QUESTION) {
    var games = [];
    var players = [];
    var playerIdGenerator = 0;
    var lies = undefined;

    require('./array.js');

    var express = require('express');
    var app = express();
    var server = null;

    try {
        app.use(express.static(__dirname + '/client'));
        app.get('/', function (req, res) {
            res.sendfile(__dirname + '/client/index.html');
        });
        server = app.listen(HTTP_PORT);
        console.log("Ready & listening to requests. Ctrl-C to stop.")
    } catch (e) {
        console.log("Error in server: " + e);
    }

    try {
        var io = require('socket.io').listen(server);
        console.log("WSServer lancé");
    } catch (e) {
        console.log("Problème WSServer" + e);
    }

    console.log("Listening to port: " + HTTP_PORT);

    io.sockets.on('connection', function (socket) {
        socket.on('iam:presenter', function (data) {
            var game = new Game(socket);
            games.push(game);

            game.presenterSocket.emit('display:code', game.code);
            console.log("New Game: Presenter: " + game.code);
        });

        socket.on('iam:player', function (data) {
            var game = getGameByCode(data.code);
            if (game == undefined) {
                socket.emit('wrong:code');
            } else {
                var player = game.getPlayerByName(data.name);
                if (player !== undefined) {
                    player.disconnected = false;
                    player.socket = socket;
                } else {
                    game.createPlayer(data.name, socket);
                    game.presenterSocket.emit('display:player', {"name": data.name, "id": getPlayerBySocket(socket).id});
                    console.log("[Game" + game.code + "] New Player: " + data.name);
                }
            }

        });

        socket.on('start', function (data) {
            var game = getGameByCode(data.code).start();
            console.log("[Game" + game.code + "] Game Start !");
        });

        socket.on('play:lie', function (data) {
            var player = getPlayerById(data.id);
            if (player != undefined) {
                if (data.lie.trim() === player.game.questions[0].truth) {
                    socket.emit('lie:truth');
                    console.log("[Game" + player.game.code + "] Player found truth !");
                } else {
                    player.actualLie = data.lie.toUpperCase().trim();
                    player.socket.emit('lie:ok');
                    player.game.presenterSocket.emit('song:player', player.id);
                    console.log("[Game" + player.game.code + "] Player " + player.name + " lied [" + player.actualLie + "]");

                    player.game.presenterSocket.emit('player:lied', player.name);

                    if (player.game.allLiesEntered()) {
                        player.game.endLie();
                        console.log("[Game" + player.game.code + "] All players lied !");
                    }
                }
            } else {
                console.log("Wrong lier " + JSON.stringify(data));
            }
        });

        socket.on('play:answer', function (data) {
            var player = getPlayerById(data.id);
            if (player != undefined) {
                player.actualAnswer = data.answer.toUpperCase().trim();
                console.log("[Game" + player.game.code + "] Player " + player.name + " answered [" + player.actualAnswer + "]");
                player.game.presenterSocket.emit('song:player', player.id);

                if (player.game.allAnswersEntered()) {
                    console.log("[Game" + player.game.code + "] All players Answered !");
                    player.game.endAnswer();
                }
            } else {
                console.log("Wrong answerer " + JSON.stringify(data));
            }
        });

        socket.on('disconnect', function () {
            socket.emit('disconnected');
            var player = getPlayerBySocket(socket);
            if (player != undefined) {
                player.disconnected = true;
            }
        });
    });

    function Game(socket) {
        this.code = this.generateCode();
        this.presenterSocket = socket;
        this.players = [];
        this.questions = randomQuestions(NUMBER_QUESTION);
    }

    var fs = require('fs');

    function randomQuestions(nb) {
        var buffer = fs.readFileSync('./questions.json', "utf8");
        var possibleQuestions = JSON.parse(buffer);
        return possibleQuestions.shuffle().splice(0, nb);
    }

    function randomLies() {
        if (lies === undefined) {
            var buffer = fs.readFileSync('./questions.json', "utf8");
            lies = JSON.parse(buffer)
                .filter(function (obj) {
                    return obj !== undefined;
                })
                .map(function (obj) {
                    return obj.truth;
                })
                .unique();
        }
        return lies;
    }

    function getGameByCode(code) {
        return games.filter(function (game) {
            return game.code === code;
        })[0];
    }

    Game.prototype.generateCode = function () {
        var valid = false;
        while (!valid) {
            var candidate = randomString(5, 'ABCDEFGHIJKLMNOPQRSTUVWXYZ');
            valid = games.filter(function (game) {
                    return game.code === candidate;
                }).length === 0;
        }
        return candidate;
    };

    function randomString(length, chars) {
        var result = '';
        for (var i = length; i > 0; --i) result += chars[Math.floor(Math.random() * chars.length)];
        return result;
    }

    Game.prototype.createPlayer = function (name, socket) {
        var player = new Player(name, socket, this);
        this.players.push(player);
        players.push(player);
        socket.emit('identify', {"id": player.id});
    };

    Game.prototype.getPlayerByName = function (name) {
        return this.players.filter(function (player) {
            return name === player.name;
        })[0];
    };

    Game.prototype.start = function () {
        this.state = "lying";
        this.players.forEach(function (player) {
            player.actualLie = undefined;
            player.actualAnswer = undefined;
        });
        var game = this;
        if (this.questions.length > 0) {
            console.log("[Game" + this.code + "] Question n°" + ( NUMBER_QUESTION - this.questions.length) + " started");
            this.broadcast('display:lie', this.questions[0]);
            this.endLieTimeout = setTimeout(function () {
                game.endLie();
            }, ANSWER_TIMEOUT);
        } else {
            console.log("[Game" + this.code + "] Game terminated !");
            this.end = Date.now();
            this.questions = randomQuestions(NUMBER_QUESTION);
            this.broadcast('end');
        }
        return this;
    };

    Game.prototype.endLie = function () {
        var game = this;
        clearTimeout(this.endLieTimeout);
        if (this.state == "lying") {
            console.log("[Game" + game.code + "] Starting choosing answers");
            this.state = "answering";

            this.broadcast("display:answer", {
                question: this.questions[0],
                lies    : this.players
                    .filter(function (player) {
                        return player.actualLie != undefined && player.actualLie != null;
                    })
                    .map(function (player) {
                        return player.actualLie;
                    })
                    .concat(this.questions[0].truth.toUpperCase())
                    .unique()
                    .completeWith(randomLies(), this.players.length + 1 > 4 ? this.players.length + 1 : 4)
                    .shuffle()
            });

            this.endAnswerTimeout = setTimeout(function () {
                game.endAnswer();
            }, ANSWER_TIMEOUT);
        }
    };

    Game.prototype.broadcast = function (evt, obj) {
        this.presenterSocket.emit(evt, obj);
        this.players.forEach(function (player) {
            player.socket.emit(evt, obj);
        });
    };

    Game.prototype.allLiesEntered = function () {
        var allLied = true;
        this.players.forEach(function (player) {
            allLied = allLied && (player.actualLie !== undefined);
        });
        return allLied;
    };

    Game.prototype.allAnswersEntered = function () {
        var allAnswers = true;
        this.players.forEach(function (player) {
            allAnswers = allAnswers && (player.actualAnswer !== undefined);
        });
        return allAnswers;
    };

    Game.prototype.endAnswer = function () {
        var game = this;
        clearTimeout(this.endAnswerTimeout);
        if (this.state == "answering") {
            console.log("[Game" + game.code + "] Starting displaying results");
            this.state = "calculating";
            this.broadcast('results');
            this.presenterSocket.emit("clear:message", {});
            this.resultMessages = [];

            var points = 500;
            if ((NUMBER_QUESTION / 2) > this.questions.length) {
                points = 1000;
            }
            if (this.questions.length == 1) {
                points = 1500;
            }

            /* L'ordi a menti */
            randomLies()
                .filter(function (lie) {
                    /* Un utilisateur a entré ce même mensonge */
                    var entered = false;
                    game.players.forEach(function (player, idx, arr) {
                        if (lie.toUpperCase() === player.actualLie) {
                            entered = true;
                        }
                    });
                    return !entered;
                })
                .filter(function (lie) {
                    /* On ignore la vérité */
                    return lie.toUpperCase() !== game.questions[0].truth.toUpperCase();
                })
                .forEach(function (lie) {
                    var liedWorkedOn = "";
                    game.players.forEach(function (player, idx, arr) {
                        if (lie.toUpperCase() === player.actualAnswer) {
                            liedWorkedOn += player.name + " ";
                            player.score -= points;
                        }
                    });
                    if (liedWorkedOn.length > 0) {
                        game.resultMessages.push({msg: "La réponse " + lie, time: SHORT_DISPLAY_TIMEOUT});
                        game.resultMessages.push({msg: "Etait un MENSONGE de la MATRICE !!!", time: SHORT_DISPLAY_TIMEOUT * 2});
                        game.resultMessages.push({msg: "qui a trompé " + liedWorkedOn, time: SHORT_DISPLAY_TIMEOUT * 2});
                    }
                });

            /* A menti */
            this.players
                .filter(function(player){
                    return player.actualLie !== undefined;
                })
                .forEach(function (player, idx, arr) {
                var liedTo = "";
                arr.forEach(function (potentialLiedTo) {
                    if (potentialLiedTo.actualAnswer !== undefined && potentialLiedTo.actualAnswer === player.actualLie) {
                        liedTo += potentialLiedTo.name + " ";
                        player.score += points;
                    }
                });
                if (liedTo.length > 0) {
                    game.resultMessages.push({msg: "La réponse " + player.actualLie, time: SHORT_DISPLAY_TIMEOUT});
                    game.resultMessages.push({msg: "Etait un MENSONGE de " + player.name, time: SHORT_DISPLAY_TIMEOUT * 2});
                    game.resultMessages.push({msg: "qui a trompé " + liedTo, time: SHORT_DISPLAY_TIMEOUT * 2});
                }
            });

            /* A trouvé la vérité */
            this.resultMessages.push({msg: "La réponse " + game.questions[0].truth.toUpperCase(), time: SHORT_DISPLAY_TIMEOUT});
            this.resultMessages.push({msg: "Etait la VERITE", time: SHORT_DISPLAY_TIMEOUT});
            var haveFoundTruth = "";
            this.players.forEach(function (player, idx, arr) {
                if (player.actualAnswer === game.questions[0].truth.toUpperCase()) {
                    player.score += points * 2;
                    haveFoundTruth += player.name + " ";
                }
            });
            if (haveFoundTruth.length > 0) {
                this.resultMessages.push({msg: "qui a été trouvée par " + haveFoundTruth, time: SHORT_DISPLAY_TIMEOUT});
            } else {
                this.resultMessages.push({msg: "qui n'a été trouvée par PERSONNE !", time: SHORT_DISPLAY_TIMEOUT});
            }
            game.presenterSocket.emit('song:result');
            game.displayNextMessage();
        }
    };

    Game.prototype.displayNextMessage = function () {
        var game = this;
        if (this.resultMessages.length > 0) {
            var result = this.resultMessages.shift();
            this.presenterSocket.emit("display:message", {question: this.questions[0].question, msg: result});
            setTimeout(function () {
                game.displayNextMessage();
            }, DISPLAY_TIMEOUT);
        } else {
            this.presenterSocket.emit("display:score", {question: this.questions[0].question, scoreTab: game.getScoreTab()});
            setTimeout(function () {
                console.log("[Game" + game.code + "] Next Question !");
                game.questions.shift();
                game.start();
            }, DISPLAY_TIMEOUT);
        }
    };

    Game.prototype.getScoreTab = function () {
        return this.players.map(function (player) {
            return {name: player.name, score: player.score}
        }).sort(function (a, b) {
            return a.score - b.score;
        });
    };

    function Player(name, socket, game) {
        this.name = name.toUpperCase();
        this.socket = socket;
        this.id = playerIdGenerator++;
        this.game = game;
        this.score = 0;
    }

    function getPlayerById(id) {
        return players.filter(function (player) {
            return player.id === id;
        })[0];
    }

    function getPlayerBySocket(socket) {
        return players.filter(function (player) {
            return player.socket === socket;
        })[0];
    }

})(5000, 30000, 1000, 8000, 7);<|endoftext|>