<commit_before>import React from 'react';
import AceEditor from 'react-ace';

import 'brace';
import 'brace/mode/javascript';
import 'brace/theme/chaos';
import 'brace/ext/language_tools';

import {getDefaultCode} from '../lib/coding';

export default class CodeEditor extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      code: getDefaultCode(this.props.index + 1)
    };

    this.handleKeyPress = this.handleKeyPress.bind(this);
  }

  onChange(code) {
    this.setState({code, dirty: true});
  }

  exit() {
    if (!this.state.dirty || confirm('Are you sure you want to discard your changes?')) {
      this.props.exit();
    }
  }

  save() {
    this.setState({dirty: false});
    this.props.save(this.state.code);
  }

  handleKeyPress(e) {
    if (e.key === 'Escape') {
      this.exit();
    } else if (e.key === 's' && e.ctrlKey) {
      this.save();
      e.preventDefault();
    }
  }

  componentDidMount() {
    document.addEventListener('keydown', this.handleKeyPress, false);
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this.handleKeyPress, false);
  }

  render() {
    return (

          editing script at position {this.props.index + 1} {this.state.dirty ? '*' : ''}
           | press control+s to save, esc to go back to scene

        <AceEditor
          style={{
            position: 'absolute',
            top: '25px',
            left: 0,
            opacity: 0.95
          }}
          width="100%"
          height="calc(100% - 25px)"
          focus={true}
          fontSize={16}
          mode="javascript"
          theme="chaos"
          onChange={this.onChange.bind(this)}
          showPrintMargin={false}
          editorProps={{
            $blockScrolling: true
          }}
          setOptions={{
            enableBasicAutocompletion: true,
            enableLiveAutocompletion: true,
            enableSnippets: false,
            showLineNumbers: true,
            tabSize: 2
          }}
          value={this.state.code}
        />

    );
  }
}
<commit_msg>make buttons clickable<commit_after>import React from 'react';
import AceEditor from 'react-ace';

import 'brace';
import 'brace/mode/javascript';
import 'brace/theme/chaos';
import 'brace/ext/language_tools';

import {getDefaultCode} from '../lib/coding';

export default class CodeEditor extends React.Component {
  constructor(props) {
    super(props);

    this.state = {
      code: getDefaultCode(this.props.index + 1)
    };

    this.handleKeyPress = this.handleKeyPress.bind(this);
    this.onChange = this.onChange.bind(this);
    this.exit = this.exit.bind(this);
    this.save = this.save.bind(this);
  }

  onChange(code) {
    this.setState({code, dirty: true});
  }

  exit() {
    if (!this.state.dirty || confirm('Are you sure you want to discard your changes?')) {
      this.props.exit();
    }
  }

  save() {
    this.setState({dirty: false});
    this.props.save(this.state.code);
  }

  handleKeyPress(e) {
    if (e.key === 'Escape') {
      this.exit();
    } else if (e.key === 's' && e.ctrlKey) {
      this.save();
      e.preventDefault();
    }
  }

  componentDidMount() {
    document.addEventListener('keydown', this.handleKeyPress, false);
  }

  componentWillUnmount() {
    document.removeEventListener('keydown', this.handleKeyPress, false);
  }

  render() {
    return (

          editing script at position {this.props.index + 1} {this.state.dirty ? '*' : ''}
           | press control+s to save, esc to go back to scene

        <AceEditor
          style={{
            position: 'absolute',
            top: '25px',
            left: 0,
            opacity: 0.95
          }}
          width="100%"
          height="calc(100% - 25px)"
          focus={true}
          fontSize={16}
          mode="javascript"
          theme="chaos"
          onChange={this.onChange}
          showPrintMargin={false}
          editorProps={{
            $blockScrolling: true
          }}
          setOptions={{
            enableBasicAutocompletion: true,
            enableLiveAutocompletion: true,
            enableSnippets: false,
            showLineNumbers: true,
            tabSize: 2
          }}
          value={this.state.code}
        />

    );
  }
}
<|endoftext|>


<commit_before>var app = angular.module('BlueCube.defaults', [])

app.constant('appDefaults', {
	autoConnect: "true",
	liveAllColourChanges: "true",

	// Minimum and Maximum allowable history items (I recommend keeping this between 20 and 200)
	minAllowedHistoryItems: 20,
	maxAllowedHistoryItems: 200,

	// Maximum number of items to keep in the history (it should be between minAllowedHistoryItems
	// and maxAllowedHistoryItems set above)
	maxHistoryItems: 100,
});

app.constant('colourDefaults', {
	defaultColour: '00d1ff',
	otherColour: 'f80ed1',
	favouriteColours:	[
							{
								id: 1,
								hex: '000000',	// Black
							},
							{
								id: 2,
								hex: '0000FF',	// Blue
							},
							{
								id: 3,
								hex: '00ff00',	// Green
							},
							{
								id: 4,
								hex: 'ff4500',	// Orange
							},
							{
								id: 5,
								hex: 'ff1444',	// Pink
							},
							{
								id: 6,
								hex: 'ff00ff',	// Purple
							},
							{
								id: 7,
								hex: 'ff0000',	// Red
							},
							{
								id: 8,
								hex: 'ffffff',	// White
							},
							{
								id: 9,
								hex: 'ffff00',	// Yellow
							}
						],
	favouriteColoursNextIndex: 10,
});

app.constant('axisDefaults', {
	axis: 'X',
	fromOffset: '0',
	toOffset: '1',
});

app.constant('staticFavouritesDefaults', {
	staticFavourites: 	[
							{
								id: 0,
								name: "Rainbow",
								cmds:	[
											{"id":1,"cmd":"set 000 180064;"},
											{"id":2,"cmd":"set 001 0C0032;"},
											{"id":3,"cmd":"set 002 060019;"},
											{"id":4,"cmd":"set 003 03000C;"},
											{"id":5,"cmd":"set 010 380044;"},
											{"id":6,"cmd":"set 011 1C0022;"},
											{"id":7,"cmd":"set 012 0E0011;"},
											{"id":8,"cmd":"set 013 070008;"},
											{"id":9,"cmd":"set 020 580024;"},
											{"id":10,"cmd":"set 021 2C0012;"},
											{"id":11,"cmd":"set 022 160009;"},
											{"id":12,"cmd":"set 023 0B0004;"},
											{"id":13,"cmd":"set 030 780004;"},
											{"id":14,"cmd":"set 031 3C0002;"},
											{"id":15,"cmd":"set 032 1E0001;"},
											{"id":16,"cmd":"set 033 0F0000;"},
											{"id":17,"cmd":"set 130 641800;"},
											{"id":18,"cmd":"set 131 320C00;"},
											{"id":19,"cmd":"set 132 190600;"},
											{"id":20,"cmd":"set 133 0C0300;"},
											{"id":21,"cmd":"set 230 443800;"},
											{"id":22,"cmd":"set 231 221C00;"},
											{"id":23,"cmd":"set 232 110E00;"},
											{"id":24,"cmd":"set 233 080700;"},
											{"id":25,"cmd":"set 330 245800;"},
											{"id":26,"cmd":"set 331 122C00;"},
											{"id":27,"cmd":"set 332 091600;"},
											{"id":28,"cmd":"set 333 040B00;"},
											{"id":29,"cmd":"set 320 047800;"},
											{"id":30,"cmd":"set 321 023C00;"},
											{"id":31,"cmd":"set 322 011E00;"},
											{"id":32,"cmd":"set 323 000F00;"},
											{"id":33,"cmd":"set 310 006418;"},
											{"id":34,"cmd":"set 311 00320C;"},
											{"id":35,"cmd":"set 312 001906;"},
											{"id":36,"cmd":"set 313 000C03;"},
											{"id":37,"cmd":"set 300 004438;"},
											{"id":38,"cmd":"set 301 00221C;"},
											{"id":39,"cmd":"set 302 00110E;"},
											{"id":40,"cmd":"set 303 000807;"},
											{"id":41,"cmd":"set 200 002458;"},
											{"id":42,"cmd":"set 201 00122C;"},
											{"id":43,"cmd":"set 202 000916;"},
											{"id":44,"cmd":"set 203 00040B;"},
											{"id":45,"cmd":"set 100 000478;"},
											{"id":46,"cmd":"set 101 00023C;"},
											{"id":47,"cmd":"set 102 00011E;"},
											{"id":48,"cmd":"set 103 00000F;"},
											{"id":49,"cmd":"set 110 180064;"},
											{"id":50,"cmd":"set 111 0C0032;"},
											{"id":51,"cmd":"set 112 060019;"},
											{"id":52,"cmd":"set 113 03000C;"},
											{"id":53,"cmd":"set 120 780004;"},
											{"id":54,"cmd":"set 121 3C0002;"},
											{"id":55,"cmd":"set 122 1E0001;"},
											{"id":56,"cmd":"set 123 0F0000;"},
											{"id":57,"cmd":"set 220 245800;"},
											{"id":58,"cmd":"set 221 122C00;"},
											{"id":59,"cmd":"set 222 091600;"},
											{"id":60,"cmd":"set 223 040B00;"},
											{"id":61,"cmd":"set 210 004438;"},
											{"id":62,"cmd":"set 211 00221C;"},
											{"id":63,"cmd":"set 212 00110E;"},
											{"id":64,"cmd":"set 213 000807;"}
										]
							},
						{
							id: 1,
							name: "All Black",
							cmds:	[
										{"id":1,"cmd":"all 000000;"}
									]
						},
						{
							id: 2,
							name: "Crossed Planes",
							cmds:	[
										{"id":1,"cmd":"setplane X 2 0000ff;"},
										{"id":2,"cmd":"setplane Y 1 3DF400;"}
									]
						},
						{
							id: 3,
							name: "Filled Sphere",
							cmds:	[
										{"id":1,"cmd":"sphere 111 ff0000 00ff00;"},
										{"id":2,"cmd":"box 000 333 0000ff 2;"}
									]
						}
					],
	staticFavouritesNextIndex: 4,
});

app.constant('userDefinedFunctionsDefaults', {
	userDefinedFunctions:	[
								{
									id: 0,
									name: "ZigZag Blue",
									number: 1,
									colourRequired: true,
									colour: "0000ff",
								},
								{
									id: 1,
									name: "ZigZag Green",
									number: 1,
									colourRequired: true,
									colour: "00ff00",
								},
								{
									id: 2,
									name: "Random Pastels",
									number: 2,
									colourRequired: false,
									colour: "",
								},
								{
									id: 3,
									name: "Random Colours",
									number: 3,
									colourRequired: false,
									colour: "",
								},
								{
									id: 4,
									name: "Random Primary Colours",
									number: 4,
									colourRequired: false,
									colour: "",
								},
								{
									id: 5,
									name: "Face Sweep",
									number: 5,
									colourRequired: false,
									colour: "",
								}
							],
	userDefinedFunctionsNextIndex: 6,
});

// Define the defaults for the Box and Sphere views
app.constant('graphicsDefaults', {
	/* boxStyle:	0 = Solid
					1 = Walls Only
					2 = Edges Only
					3 = Walls Filled
					4 = Edges Filled */
	boxStyle: '0',

	/* sphereStyle:	0: Walls Only
					1: Solid */
	sphereStyle: '0',

	// sphereSize:	3 or 4
	sphereSize: '3',
});
<commit_msg>Document the defaults, and do a minor code reorg.<commit_after>var app = angular.module('BlueCube.defaults', [])

// Default settings for key parts of the app
app.constant('appDefaults', {
	// Whether to attempt to auto connect to the cube ("true" | "false")
	autoConnect: "true",

	// Whether to send colour changes automatically in the All view ("true" | "false")
	liveAllColourChanges: "true",

	// Minimum and Maximum allowable history items (I recommend keeping this between 20 and 200)
	minAllowedHistoryItems: 20,
	maxAllowedHistoryItems: 200,

	// Maximum number of items to keep in the history (it should be between minAllowedHistoryItems
	// and maxAllowedHistoryItems set above)
	maxHistoryItems: 100,
});

// Default settings for Colours within the app
app.constant('colourDefaults', {
	// The default colour used for the colour picker if the user hasn't previously selected a
	// colour
	defaultColour: '00d1ff',

	// The default colour used for the second colour picker (if required) if the user hasn't
	// previously selected a colour
	otherColour: 'f80ed1',

	// The default favourite colours. These match the defined colours in the Cube Library, but there
	// is no reason that they can't be changed
	favouriteColours:	[
							{
								id: 1,
								hex: '000000',	// Black
							},
							{
								id: 2,
								hex: '0000FF',	// Blue
							},
							{
								id: 3,
								hex: '00ff00',	// Green
							},
							{
								id: 4,
								hex: 'ff4500',	// Orange
							},
							{
								id: 5,
								hex: 'ff1444',	// Pink
							},
							{
								id: 6,
								hex: 'ff00ff',	// Purple
							},
							{
								id: 7,
								hex: 'ff0000',	// Red
							},
							{
								id: 8,
								hex: 'ffffff',	// White
							},
							{
								id: 9,
								hex: 'ffff00',	// Yellow
							}
						],

	// To ensure that each favourite colour has a unique ID, we store the next ID that should
	// be used. It's 10 because we have 9 favourites above already defined.
	favouriteColoursNextIndex: 10,
});

// Default settings for the Set, Copy and Move Plane Views
app.constant('axisDefaults', {
	// Default axis to select ('X' | 'Y' | 'Z')
	axis: 'X',

	// The first or only offset to use ('0' | '1' | '2' | '3')
	fromOffset: '0',

	// The second offset to use ('0' | '1' | '2' | '3')
	toOffset: '1',
});

// Define the defaults for the Box and Sphere views
app.constant('graphicsDefaults', {
	/* boxStyle:	0 = Solid
					1 = Walls Only
					2 = Edges Only
					3 = Walls Filled
					4 = Edges Filled */
	boxStyle: '0',

	/* sphereStyle:	0: Walls Only
					1: Solid */
	sphereStyle: '0',

	// sphereSize:	3 or 4
	sphereSize: '3',
});

// Initially provided static favourites
app.constant('staticFavouritesDefaults', {
	// A sample set of static favourites to get the user started
	staticFavourites: 	[
							{
								id: 0,
								name: "Rainbow",
								cmds:	[
											{"id":1,"cmd":"set 000 180064;"},
											{"id":2,"cmd":"set 001 0C0032;"},
											{"id":3,"cmd":"set 002 060019;"},
											{"id":4,"cmd":"set 003 03000C;"},
											{"id":5,"cmd":"set 010 380044;"},
											{"id":6,"cmd":"set 011 1C0022;"},
											{"id":7,"cmd":"set 012 0E0011;"},
											{"id":8,"cmd":"set 013 070008;"},
											{"id":9,"cmd":"set 020 580024;"},
											{"id":10,"cmd":"set 021 2C0012;"},
											{"id":11,"cmd":"set 022 160009;"},
											{"id":12,"cmd":"set 023 0B0004;"},
											{"id":13,"cmd":"set 030 780004;"},
											{"id":14,"cmd":"set 031 3C0002;"},
											{"id":15,"cmd":"set 032 1E0001;"},
											{"id":16,"cmd":"set 033 0F0000;"},
											{"id":17,"cmd":"set 130 641800;"},
											{"id":18,"cmd":"set 131 320C00;"},
											{"id":19,"cmd":"set 132 190600;"},
											{"id":20,"cmd":"set 133 0C0300;"},
											{"id":21,"cmd":"set 230 443800;"},
											{"id":22,"cmd":"set 231 221C00;"},
											{"id":23,"cmd":"set 232 110E00;"},
											{"id":24,"cmd":"set 233 080700;"},
											{"id":25,"cmd":"set 330 245800;"},
											{"id":26,"cmd":"set 331 122C00;"},
											{"id":27,"cmd":"set 332 091600;"},
											{"id":28,"cmd":"set 333 040B00;"},
											{"id":29,"cmd":"set 320 047800;"},
											{"id":30,"cmd":"set 321 023C00;"},
											{"id":31,"cmd":"set 322 011E00;"},
											{"id":32,"cmd":"set 323 000F00;"},
											{"id":33,"cmd":"set 310 006418;"},
											{"id":34,"cmd":"set 311 00320C;"},
											{"id":35,"cmd":"set 312 001906;"},
											{"id":36,"cmd":"set 313 000C03;"},
											{"id":37,"cmd":"set 300 004438;"},
											{"id":38,"cmd":"set 301 00221C;"},
											{"id":39,"cmd":"set 302 00110E;"},
											{"id":40,"cmd":"set 303 000807;"},
											{"id":41,"cmd":"set 200 002458;"},
											{"id":42,"cmd":"set 201 00122C;"},
											{"id":43,"cmd":"set 202 000916;"},
											{"id":44,"cmd":"set 203 00040B;"},
											{"id":45,"cmd":"set 100 000478;"},
											{"id":46,"cmd":"set 101 00023C;"},
											{"id":47,"cmd":"set 102 00011E;"},
											{"id":48,"cmd":"set 103 00000F;"},
											{"id":49,"cmd":"set 110 180064;"},
											{"id":50,"cmd":"set 111 0C0032;"},
											{"id":51,"cmd":"set 112 060019;"},
											{"id":52,"cmd":"set 113 03000C;"},
											{"id":53,"cmd":"set 120 780004;"},
											{"id":54,"cmd":"set 121 3C0002;"},
											{"id":55,"cmd":"set 122 1E0001;"},
											{"id":56,"cmd":"set 123 0F0000;"},
											{"id":57,"cmd":"set 220 245800;"},
											{"id":58,"cmd":"set 221 122C00;"},
											{"id":59,"cmd":"set 222 091600;"},
											{"id":60,"cmd":"set 223 040B00;"},
											{"id":61,"cmd":"set 210 004438;"},
											{"id":62,"cmd":"set 211 00221C;"},
											{"id":63,"cmd":"set 212 00110E;"},
											{"id":64,"cmd":"set 213 000807;"}
										]
							},
						{
							id: 1,
							name: "All Black",
							cmds:	[
										{"id":1,"cmd":"all 000000;"}
									]
						},
						{
							id: 2,
							name: "Crossed Planes",
							cmds:	[
										{"id":1,"cmd":"setplane X 2 0000ff;"},
										{"id":2,"cmd":"setplane Y 1 3DF400;"}
									]
						},
						{
							id: 3,
							name: "Filled Sphere",
							cmds:	[
										{"id":1,"cmd":"sphere 111 ff0000 00ff00;"},
										{"id":2,"cmd":"box 000 333 0000ff 2;"}
									]
						}
					],

	// To ensure that each static favourite has a unique ID, we store the next ID that should
	// be used. It's 4 because we have 3 static favourites above already defined.
	staticFavouritesNextIndex: 4,
});

// Initially provided user defined functions
app.constant('userDefinedFunctionsDefaults', {
	// Provide a sample set of user defined functions to match those that ship with the included
	// Arduino sketch
	userDefinedFunctions:	[
								{
									id: 0,
									name: "ZigZag Blue",
									number: 1,
									colourRequired: true,
									colour: "0000ff",
								},
								{
									id: 1,
									name: "ZigZag Green",
									number: 1,
									colourRequired: true,
									colour: "00ff00",
								},
								{
									id: 2,
									name: "Random Pastels",
									number: 2,
									colourRequired: false,
									colour: "",
								},
								{
									id: 3,
									name: "Random Colours",
									number: 3,
									colourRequired: false,
									colour: "",
								},
								{
									id: 4,
									name: "Random Primary Colours",
									number: 4,
									colourRequired: false,
									colour: "",
								},
								{
									id: 5,
									name: "Face Sweep",
									number: 5,
									colourRequired: false,
									colour: "",
								}
							],

	// To ensure that each user defined function has a unique ID, we store the next ID that should
	// be used. It's 6 because we have 5 user defined functions above already defined.
	userDefinedFunctionsNextIndex: 6,
});
<|endoftext|>


<commit_before>
var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 860 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

var tooltip = d3.select("div#chart")
    .append("div")
    .attr("class", "remove")
    .style("position", "absolute")
    .style("z-index", "20")
    .style("visibility", "hidden")
    .style("top", "30px")
    .style("left", "225px");

var datearray = [];

var x = d3.scale.linear()
    .range([0, width]);

var y = d3.scale.linear()
    .range([height, 0]);

var color = d3.scale.category20();

var xAxis = d3.svg.axis()
    .scale(x)
    .tickFormat(d3.format('d'))
    .orient("bottom");

var yAxis = d3.svg.axis()
    .scale(y)
    .orient("left");

var stack = d3.layout.stack()
  .offset('zero')
  .values(function(d){ return d.values; })
  .x(function(d){ return d.yearCol; })
  .y(function(d){ return d.countCol; });

var area = d3.svg.area()
    .interpolate('basis')
    .x(function(d) { return x(d.yearCol); })
    .y0(function(d) { return y(d.y0); })
    .y1(function(d) { return y(d.y0 + d.y); });

var svg = d3.select("div#chart").append("svg")
    .attr("width", width + margin.left + margin.right)
    .attr("height", height + margin.top + margin.bottom)
  .append("g")
    .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

d3.csv('Words_allyears_26oct.csv', function(error, data){

  console.log(data);

  data.forEach(function(d){
    d.countCol = +d.countCol;
    d.yearCol = +d.yearCol;
  });

  var summed_data = d3.nest()
                      .key(function(d){ return d.wordCol; })
                      .rollup(function(leaves){
                          return {"total": d3.sum(
                            leaves, function(d){ return d.countCol; })}})
                      .entries(data);
  summed_data.sort(function(a,b){ return b.values.total - a.values.total; });
  console.log(summed_data);

  //var list = ['war', 'bomb', 'blast'];
  var list = [];
  for (i=0; i<20; i++){
    list.push(summed_data[i].key);
  }

  var data = $.map(data, function(element){
    return ($.inArray(element.wordCol,list)>-1?element:null)
  });

  function complete(x, key){
    for (i=0; i<key.length; i++){
      tempdata = x.filter(function(d){ return d.wordCol == key[i]; });
      yearsPresent = []
      years = [];

      for (year=1955; year<2010; year++){
        years.push(year)
        for (row=0; row<tempdata.length; row++){
          if (tempdata[row].yearCol === year){
            yearsPresent.push(year);
          }
        }
      }

      for (year=0; year<years.length; year++){
        if (yearsPresent.indexOf(years[year]) < 0){
          dict = {}
          dict['countCol'] = 0;
          dict['wordCol'] = tempdata[0].wordCol;
          dict['yearCol'] = years[year];
          data.push(dict);
        }
      }
    }

  };
  complete(data, list);

  data.sort(function(a,b){ return a.yearCol - b.yearCol; });

  var nest = d3.nest()
    .key(function(d){ return d.wordCol; })
    .entries(data);

  var layers = stack(nest);

  x.domain(d3.extent(data, function(d){ return d.yearCol; }));
  y.domain([0, d3.max(data, function(d){ return d.y0 + d.y; })]);

  svg.selectAll(".layer")
      .data(layers)
    .enter().append("path")
      .attr("class", "layer")
      .attr("d", function(d) { return area(d.values); })
      .style("fill", function(d, i) { return color(i); });

  svg.append("g")
      .attr("class", "x axis")
      .attr("transform", "translate(0," + height + ")")
      .call(xAxis);

  svg.append("g")
      .attr("class", "y axis")
      .call(yAxis);

  svg.selectAll(".layer")
    .attr("opacity", 1)
    .on("mouseover", function(d, i) {
      svg.selectAll(".layer").transition()
      .duration(250)
      .attr("opacity", function(d, j) {
        return j != i ? 0.6 : 1;
    })})
    .on("mousemove", function(d, i) {
      mousex = d3.mouse(this);
      mousex = mousex[0];
      var invertedx = x.invert(mousex);
      console.log(invertedx);
      //invertedx = invertedx.getMonth() + invertedx.getDate();
      var selected = (d.values);
      for (var k = 0; k < selected.length; k++) {
        datearray[k] = selected[k].yearCol;
      }

      mousedate = datearray.indexOf(Math.round(invertedx));
      pro = d.values[mousedate].countCol;
      tip_year = d.values[mousedate].yearCol;

      d3.select(this)
      .classed("hover", true)
      .attr("stroke", color[0])
      .attr("stroke-width", "0.5px"),
      tooltip.html( "
" + d.key + " | " + tip_year + ": " + pro + "
" ).style("visibility", "visible");

    })
    .on("mouseout", function(d, i) {
     svg.selectAll(".layer")
      .transition()
      .duration(250)
      .attr("opacity", "1");
      d3.select(this)
      .classed("hover", false)
      .attr("stroke-width", "0px"), tooltip.html( "
" + d.key + "
" + pro + "
" ).style("visibility", "hidden");
  });

});

  <commit_msg>update data<commit_after>
stacked_chart(10);

function stacked_chart(word_num){

  var margin = {top: 20, right: 20, bottom: 30, left: 50},
    width = 860 - margin.left - margin.right,
    height = 500 - margin.top - margin.bottom;

  var tooltip = d3.select("div#chart")
      .append("div")
      .attr("class", "remove")
      .style("position", "absolute")
      .style("z-index", "20")
      .style("visibility", "hidden")
      .style("top", "30px")
      .style("left", "225px");

  var datearray = [];

  var x = d3.scale.linear()
      .range([0, width]);

  var y = d3.scale.linear()
      .range([height, 0]);

  var color = d3.scale.category20();

  var xAxis = d3.svg.axis()
      .scale(x)
      .tickFormat(d3.format('d'))
      .orient("bottom");

  var yAxis = d3.svg.axis()
      .scale(y)
      .orient("left");

  var stack = d3.layout.stack()
    .offset('zero')
    .values(function(d){ return d.values; })
    .x(function(d){ return d.yearCol; })
    .y(function(d){ return d.countCol; });

  var area = d3.svg.area()
      .interpolate('basis')
      .x(function(d) { return x(d.yearCol); })
      .y0(function(d) { return y(d.y0); })
      .y1(function(d) { return y(d.y0 + d.y); });

  var svg = d3.select("div#chart").append("svg")
      .attr("width", width + margin.left + margin.right)
      .attr("height", height + margin.top + margin.bottom)
    .append("g")
      .attr("transform", "translate(" + margin.left + "," + margin.top + ")");

  d3.csv('Words_allyears_26oct.csv', function(error, data){

    console.log(data);

    data.forEach(function(d){
      d.countCol = +d.countCol;
      d.yearCol = +d.yearCol;
    });

    var summed_data = d3.nest()
                        .key(function(d){ return d.wordCol; })
                        .rollup(function(leaves){
                            return {"total": d3.sum(
                              leaves, function(d){ return d.countCol; })}})
                        .entries(data);
    summed_data.sort(function(a,b){ return b.values.total - a.values.total; });
    console.log(summed_data);

    //var list = ['war', 'bomb', 'blast'];
    var list = [];
    for (i=0; i<word_num; i++){
      list.push(summed_data[i].key);
    }

    var data = $.map(data, function(element){
      return ($.inArray(element.wordCol,list)>-1?element:null)
    });

    function complete(x, key){
      for (i=0; i<key.length; i++){
        tempdata = x.filter(function(d){ return d.wordCol == key[i]; });
        yearsPresent = []
        years = [];

        for (year=1955; year<2010; year++){
          years.push(year)
          for (row=0; row<tempdata.length; row++){
            if (tempdata[row].yearCol === year){
              yearsPresent.push(year);
            }
          }
        }

        for (year=0; year<years.length; year++){
          if (yearsPresent.indexOf(years[year]) < 0){
            dict = {}
            dict['countCol'] = 0;
            dict['wordCol'] = tempdata[0].wordCol;
            dict['yearCol'] = years[year];
            data.push(dict);
          }
        }
      }

    };
    complete(data, list);

    data.sort(function(a,b){ return a.yearCol - b.yearCol; });

    var nest = d3.nest()
      .key(function(d){ return d.wordCol; })
      .entries(data);

    var layers = stack(nest);

    x.domain(d3.extent(data, function(d){ return d.yearCol; }));
    y.domain([0, d3.max(data, function(d){ return d.y0 + d.y; })]);

    svg.selectAll(".layer")
        .data(layers)
      .enter().append("path")
        .attr("class", "layer")
        .attr("d", function(d) { return area(d.values); })
        .style("fill", function(d, i) { return color(i); });

    svg.append("g")
        .attr("class", "x axis")
        .attr("transform", "translate(0," + height + ")")
        .call(xAxis);

    svg.append("g")
        .attr("class", "y axis")
        .call(yAxis);

    svg.selectAll(".layer")
      .attr("opacity", 1)
      .on("mouseover", function(d, i) {
        svg.selectAll(".layer").transition()
        .duration(250)
        .attr("opacity", function(d, j) {
          return j != i ? 0.6 : 1;
      })})
      .on("mousemove", function(d, i) {
        mousex = d3.mouse(this);
        mousex = mousex[0];
        var invertedx = x.invert(mousex);
        console.log(invertedx);
        //invertedx = invertedx.getMonth() + invertedx.getDate();
        var selected = (d.values);
        for (var k = 0; k < selected.length; k++) {
          datearray[k] = selected[k].yearCol;
        }

        mousedate = datearray.indexOf(Math.round(invertedx));
        pro = d.values[mousedate].countCol;
        tip_year = d.values[mousedate].yearCol;

        d3.select(this)
        .classed("hover", true)
        .attr("stroke", color[0])
        .attr("stroke-width", "0.5px"),
        tooltip.html( "
" + d.key + " | " + tip_year + ": " + pro + "
" ).style("visibility", "visible");

      })
      .on("mouseout", function(d, i) {
       svg.selectAll(".layer")
        .transition()
        .duration(250)
        .attr("opacity", "1");
        d3.select(this)
        .classed("hover", false)
        .attr("stroke-width", "0px"), tooltip.html( "
" + d.key + "
" + pro + "
" ).style("visibility", "hidden");
    });

  });
}

  <|endoftext|>


<commit_before>'use strict';

// This Iterator is used to simplify the consolidate() method. It works by
// gathering a list of the nodes in the list in the constructor since the
// nodes can change during consolidation.
var NodeListIterator = function (start) {
  if (!start) {
    return;
  }

  this.items = [];
  var current = start;
  do {
    this.items.push(current);
    current = current.next;
  } while (start !== current);
};

NodeListIterator.prototype.hasNext = function () {
  return this.items.length > 0;
};

NodeListIterator.prototype.next = function () {
  return this.items.shift();
};

/**
 * Creates a Fibonacci heap.
 *
 * @constructor
 * @param {function} customCompare An optional custom node comparison
 * function.
 */
var FibonacciHeap = function (customCompare) {
  this.minNode = undefined;
  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

/**
 * Clears the heap's data, making it an empty heap.
 */
FibonacciHeap.prototype.clear = function () {
  this.minNode = undefined;
  this.nodeCount = 0;
};

FibonacciHeap.prototype.decreaseKey = function (node, newKey) {
  if (typeof node === 'undefined') {
    throw new Error('Cannot decrease key of non-existent node');
  }
  if (this.compare({key: newKey}, {key: node.key}) > 0) {
    throw new Error('New key is larger than old key');
  }

  node.key = newKey;
  var parent = node.parent;
  if (parent && this.compare(node, parent) < 0) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  if (this.compare(node, this.minNode) < 0) {
    this.minNode = node;
  }
};

FibonacciHeap.prototype.delete = function (node) {
  // This is a special implementation of decreaseKey that sets the
  // argument to the minimum value. This is necessary to make generic keys
  // work, since there is no MIN_VALUE constant for generic types.
  node.isMinimum = true;
  var parent = node.parent;
  if (parent) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  this.minNode = node;

  this.extractMinimum();
};

FibonacciHeap.prototype.extractMinimum = function () {
  var extractedMin = this.minNode;
  if (extractedMin) {
    // Set parent to undefined for the minimum's children
    if (extractedMin.child) {
      var child = extractedMin.child;
      do {
        child.parent = undefined;
        child = child.next;
      } while (child !== extractedMin.child);
    }

    var nextInRootList;
    if (this.minNode.next !== this.minNode) {
      nextInRootList = this.minNode.next;
    }
    // Remove min from root list
    removeNodeFromList(extractedMin);
    this.nodeCount--;

    // Merge the children of the minimum node with the root list
    this.minNode = mergeLists(nextInRootList, extractedMin.child,
        this.compare);
    if (nextInRootList) {
      this.minNode = nextInRootList;
      this.minNode = consolidate(this.minNode, this.compare);
    }
  }
  return extractedMin;
};

FibonacciHeap.prototype.findMinimum = function () {
  return this.minNode;
};

/**
 * Inserts a new key-value pair into the heap.
 *
 * @param {Object} key The key to insert.
 * @param {Object} value The value to insert.
 * @return {Node} node The inserted node.
 */
FibonacciHeap.prototype.insert = function (key, value) {
  var node = new Node(key, value);
  this.minNode = mergeLists(this.minNode, node, this.compare);
  this.nodeCount++;
  return node;
};

FibonacciHeap.prototype.isEmpty = function () {
  return this.minNode === undefined;
};

FibonacciHeap.prototype.size = function () {
  if (this.isEmpty()) {
    return 0;
  }
  return getNodeListSize(this.minNode);
};

// Union another fibonacci heap with this one
FibonacciHeap.prototype.union = function (other) {
  this.minNode = mergeLists(this.minNode, other.minNode, this.compare);
  this.nodeCount += other.nodeCount;
};

FibonacciHeap.prototype.compare = function (a, b) {
  if (a.key > b.key) {
    return 1;
  }
  if (a.key < b.key) {
    return -1;
  }
  return 0;
};

function cut(node, parent, minNode, compare) {
  removeNodeFromList(node);
  parent.degree--;
  if (node.next === node) {
    parent.child = undefined;
  } else {
    parent.child = node.next;
  }
  minNode = mergeLists(minNode, node, compare);
  node.isMarked = false;
  return minNode;
}

function cascadingCut(node, minNode, compare) {
  var parent = node.parent;
  if (parent) {
    if (node.isMarked) {
      minNode = cut(node, parent, minNode, compare);
      minNode = cascadingCut(parent, minNode, compare);
    } else {
      node.isMarked = true;
    }
  }
  return minNode;
}

function consolidate(minNode, compare) {
  var aux = [];
  var it = new NodeListIterator(minNode);
  while (it.hasNext()) {
    var current = it.next();

    // If there exists another node with the same degree, merge them
    while (aux[current.degree]) {
      if (compare(current, aux[current.degree]) > 0) {
        var temp = current;
        current = aux[current.degree];
        aux[current.degree] = temp;
      }
      linkHeaps(aux[current.degree], current, compare);
      aux[current.degree] = undefined;
      current.degree++;
    }

    aux[current.degree] = current;
  }

  minNode = undefined;
  for (var i = 0; i < aux.length; i++) {
    if (aux[i]) {
      // Remove siblings before merging
      aux[i].next = aux[i];
      aux[i].prev = aux[i];
      minNode = mergeLists(minNode, aux[i], compare);
    }
  }
  return minNode;
}

function removeNodeFromList(node) {
  var prev = node.prev;
  var next = node.next;
  prev.next = next;
  next.prev = prev;

  node.next = node;
  node.prev = node;
}

function linkHeaps(max, min, compare) {
  removeNodeFromList(max);
  min.child = mergeLists(max, min.child, compare);
  max.parent = min;
  max.isMarked = false;
}

// Merges two lists and returns the minimum node
function mergeLists(a, b, compare) {
  if (!a && !b) {
    return undefined;
  }
  if (!a) {
    return b;
  }
  if (!b) {
    return a;
  }

  var temp = a.next;
  a.next = b.next;
  a.next.prev = a;
  b.next = temp;
  b.next.prev = b;

  return compare(a, b) < 0 ? a : b;
}

function getNodeListSize(node) {
  var count = 0;
  var current = node;

  do {
    count++;
    if (current.child) {
      count += getNodeListSize(current.child);
    }
    current = current.next;
  } while (current !== node);

  return count;
}

function Node(key, value) {
  this.key = key;
  this.value = value;
  this.prev = this;
  this.next = this;
  this.degree = 0;

  this.parent = undefined;
  this.child = undefined;
  this.isMarked = undefined;
  this.isMinimum = undefined;
}

module.exports = FibonacciHeap;
<commit_msg>Add jsdoc for some functions<commit_after>'use strict';

// This Iterator is used to simplify the consolidate() method. It works by
// gathering a list of the nodes in the list in the constructor since the
// nodes can change during consolidation.
var NodeListIterator = function (start) {
  if (!start) {
    return;
  }

  this.items = [];
  var current = start;
  do {
    this.items.push(current);
    current = current.next;
  } while (start !== current);
};

NodeListIterator.prototype.hasNext = function () {
  return this.items.length > 0;
};

NodeListIterator.prototype.next = function () {
  return this.items.shift();
};

/**
 * Creates a Fibonacci heap.
 *
 * @constructor
 * @param {function} customCompare An optional custom node comparison
 * function.
 */
var FibonacciHeap = function (customCompare) {
  this.minNode = undefined;
  this.nodeCount = 0;

  if (customCompare) {
    this.compare = customCompare;
  }
};

/**
 * Clears the heap's data, making it an empty heap.
 */
FibonacciHeap.prototype.clear = function () {
  this.minNode = undefined;
  this.nodeCount = 0;
};

FibonacciHeap.prototype.decreaseKey = function (node, newKey) {
  if (typeof node === 'undefined') {
    throw new Error('Cannot decrease key of non-existent node');
  }
  if (this.compare({key: newKey}, {key: node.key}) > 0) {
    throw new Error('New key is larger than old key');
  }

  node.key = newKey;
  var parent = node.parent;
  if (parent && this.compare(node, parent) < 0) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  if (this.compare(node, this.minNode) < 0) {
    this.minNode = node;
  }
};

FibonacciHeap.prototype.delete = function (node) {
  // This is a special implementation of decreaseKey that sets the
  // argument to the minimum value. This is necessary to make generic keys
  // work, since there is no MIN_VALUE constant for generic types.
  node.isMinimum = true;
  var parent = node.parent;
  if (parent) {
    cut(node, parent, this.minNode, this.compare);
    cascadingCut(parent, this.minNode, this.compare);
  }
  this.minNode = node;

  this.extractMinimum();
};

/**
 * Extracts and returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.extractMinimum = function () {
  var extractedMin = this.minNode;
  if (extractedMin) {
    // Set parent to undefined for the minimum's children
    if (extractedMin.child) {
      var child = extractedMin.child;
      do {
        child.parent = undefined;
        child = child.next;
      } while (child !== extractedMin.child);
    }

    var nextInRootList;
    if (this.minNode.next !== this.minNode) {
      nextInRootList = this.minNode.next;
    }
    // Remove min from root list
    removeNodeFromList(extractedMin);
    this.nodeCount--;

    // Merge the children of the minimum node with the root list
    this.minNode = mergeLists(nextInRootList, extractedMin.child,
        this.compare);
    if (nextInRootList) {
      this.minNode = nextInRootList;
      this.minNode = consolidate(this.minNode, this.compare);
    }
  }
  return extractedMin;
};

/**
 * Returns the minimum node from the heap.
 *
 * @return {Node} node The heap's minimum node or undefined if the heap is
 * empty.
 */
FibonacciHeap.prototype.findMinimum = function () {
  return this.minNode;
};

/**
 * Inserts a new key-value pair into the heap.
 *
 * @param {Object} key The key to insert.
 * @param {Object} value The value to insert.
 * @return {Node} node The inserted node.
 */
FibonacciHeap.prototype.insert = function (key, value) {
  var node = new Node(key, value);
  this.minNode = mergeLists(this.minNode, node, this.compare);
  this.nodeCount++;
  return node;
};

/**
 * @return {boolean} Whether the heap is empty.
 */
FibonacciHeap.prototype.isEmpty = function () {
  return this.minNode === undefined;
};

/**
 * @return {number} The size of the heap.
 */
FibonacciHeap.prototype.size = function () {
  if (this.isEmpty()) {
    return 0;
  }
  return getNodeListSize(this.minNode);
};

/**
 * Joins another heap to this heap.
 *
 * @param {BinaryHeap} otherHeap The other heap.
 */
FibonacciHeap.prototype.union = function (other) {
  this.minNode = mergeLists(this.minNode, other.minNode, this.compare);
  this.nodeCount += other.nodeCount;
};

/**
 * Compares two nodes with each other.
 *
 * @param {Object} a The first key to compare.
 * @param {Object} b The second key to compare.
 * @return -1, 0 or 1 if a < b, a == b or a > b respectively.
 */
FibonacciHeap.prototype.compare = function (a, b) {
  if (a.key > b.key) {
    return 1;
  }
  if (a.key < b.key) {
    return -1;
  }
  return 0;
};

function cut(node, parent, minNode, compare) {
  removeNodeFromList(node);
  parent.degree--;
  if (node.next === node) {
    parent.child = undefined;
  } else {
    parent.child = node.next;
  }
  minNode = mergeLists(minNode, node, compare);
  node.isMarked = false;
  return minNode;
}

function cascadingCut(node, minNode, compare) {
  var parent = node.parent;
  if (parent) {
    if (node.isMarked) {
      minNode = cut(node, parent, minNode, compare);
      minNode = cascadingCut(parent, minNode, compare);
    } else {
      node.isMarked = true;
    }
  }
  return minNode;
}

function consolidate(minNode, compare) {
  var aux = [];
  var it = new NodeListIterator(minNode);
  while (it.hasNext()) {
    var current = it.next();

    // If there exists another node with the same degree, merge them
    while (aux[current.degree]) {
      if (compare(current, aux[current.degree]) > 0) {
        var temp = current;
        current = aux[current.degree];
        aux[current.degree] = temp;
      }
      linkHeaps(aux[current.degree], current, compare);
      aux[current.degree] = undefined;
      current.degree++;
    }

    aux[current.degree] = current;
  }

  minNode = undefined;
  for (var i = 0; i < aux.length; i++) {
    if (aux[i]) {
      // Remove siblings before merging
      aux[i].next = aux[i];
      aux[i].prev = aux[i];
      minNode = mergeLists(minNode, aux[i], compare);
    }
  }
  return minNode;
}

function removeNodeFromList(node) {
  var prev = node.prev;
  var next = node.next;
  prev.next = next;
  next.prev = prev;

  node.next = node;
  node.prev = node;
}

function linkHeaps(max, min, compare) {
  removeNodeFromList(max);
  min.child = mergeLists(max, min.child, compare);
  max.parent = min;
  max.isMarked = false;
}

// Merges two lists and returns the minimum node
function mergeLists(a, b, compare) {
  if (!a && !b) {
    return undefined;
  }
  if (!a) {
    return b;
  }
  if (!b) {
    return a;
  }

  var temp = a.next;
  a.next = b.next;
  a.next.prev = a;
  b.next = temp;
  b.next.prev = b;

  return compare(a, b) < 0 ? a : b;
}

function getNodeListSize(node) {
  var count = 0;
  var current = node;

  do {
    count++;
    if (current.child) {
      count += getNodeListSize(current.child);
    }
    current = current.next;
  } while (current !== node);

  return count;
}

function Node(key, value) {
  this.key = key;
  this.value = value;
  this.prev = this;
  this.next = this;
  this.degree = 0;

  this.parent = undefined;
  this.child = undefined;
  this.isMarked = undefined;
  this.isMinimum = undefined;
}

module.exports = FibonacciHeap;
<|endoftext|>


<commit_before>'use strict';

const isFirefoxAndroid = require('./lib/is-firefox-android')();
const tabs = require('sdk/tabs');

function handleClick() {
  const worker = tabs.activeTab.attach({
    contentScriptFile: './content-script.js',
  });
  worker.port.on('copyToClipboard', (request) => {
    if (isFirefoxAndroid) {
      const { Cc, Ci } = require('chrome');
      const prompts = Cc['@mozilla.org/embedcomp/prompt-service;1']
        .getService(Ci.nsIPromptService);
      prompts.prompt(
        null,
        'Build Link Plain',
        'Built link',
        { value: request },
        null,
        { value: false }
      );
    } else {
      const clipboard = require('sdk/clipboard');
      clipboard.set(request);
    }
  });
  worker.port.emit('buildLinkPlain');
}

if (isFirefoxAndroid) {
  const getWindow = require('./lib/get-window');
  let menuId = 0;
  exports.main = (options, callback) => {// eslint-disable-line no-unused-vars
    menuId = getWindow().NativeWindow.menu.add({
      name: 'Build Link Plain',
      callback: handleClick,
    });
  };
  exports.onUnload = (reason) => {// eslint-disable-line no-unused-vars
    getWindow().NativeWindow.menu.remove(menuId);
  };
} else {
  const { ActionButton } = require('sdk/ui/button/action');
  ActionButton({ // eslint-disable-line new-cap
    id: 'build-link-plain',
    label: 'Plain',
    icon: {
      16: './filter3-16.png',
      32: './filter3-32.png',
      64: './filter3-64.png',
    },
    onClick: handleClick,
  });
}

// tabs.on("ready", (tab) => {
//   tab.attach({
//     contentScript: "console.log(document.body.innerHTML);"
//   });
// });
<commit_msg>chore(debug): remove debug code<commit_after>'use strict';

const isFirefoxAndroid = require('./lib/is-firefox-android')();
const tabs = require('sdk/tabs');

function handleClick() {
  const worker = tabs.activeTab.attach({
    contentScriptFile: './content-script.js',
  });
  worker.port.on('copyToClipboard', (request) => {
    if (isFirefoxAndroid) {
      const { Cc, Ci } = require('chrome');
      const prompts = Cc['@mozilla.org/embedcomp/prompt-service;1']
        .getService(Ci.nsIPromptService);
      prompts.prompt(
        null,
        'Build Link Plain',
        'Built link',
        { value: request },
        null,
        { value: false }
      );
    } else {
      const clipboard = require('sdk/clipboard');
      clipboard.set(request);
    }
  });
  worker.port.emit('buildLinkPlain');
}

if (isFirefoxAndroid) {
  const getWindow = require('./lib/get-window');
  let menuId = 0;
  exports.main = (options, callback) => {// eslint-disable-line no-unused-vars
    menuId = getWindow().NativeWindow.menu.add({
      name: 'Build Link Plain',
      callback: handleClick,
    });
  };
  exports.onUnload = (reason) => {// eslint-disable-line no-unused-vars
    getWindow().NativeWindow.menu.remove(menuId);
  };
} else {
  const { ActionButton } = require('sdk/ui/button/action');
  ActionButton({ // eslint-disable-line new-cap
    id: 'build-link-plain',
    label: 'Plain',
    icon: {
      16: './filter3-16.png',
      32: './filter3-32.png',
      64: './filter3-64.png',
    },
    onClick: handleClick,
  });
}
<|endoftext|>


<commit_before>/*
 *Author: Teo Jin Cheng
 *
 *When user clicks on the remove item link on the shopping cart page,
 *make the table row of that toy disappear to simulate
 *removing from cart.
 */

/**
 * AJAX call to delete one item in the cart of the user.
 * @param {type} cartId id of the entry in the cart datastore
 * @returns {undefined}
 */
function asyncDelete(cartId) {
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            alert(this.responseText);
        }
    }
    xmlhttp.open("GET", "updateCart.php?d=" + cartId, true);
    xmlhttp.send();
}

function asyncUpdate(cartId, arrOfId) {
    var qtyNode = document.getElementById("itemQty" + cartId);
    var priceNode = document.getElementById("unitPrice" + cartId);
    var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
    var price = parseFloat(priceNode.innerHTML);
    var itemTotal = qty * price;

    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            calculateTotal(arrOfId);
            alert(this.responseText);
        }
    }
    xmlhttp.open("GET", "updateCart.php?u=" + cartId + "&q=" + qty, true);
    xmlhttp.send();
}

function calculateTotal(arrOfIds) {
    var cartTotal = 0;
    for (var i = 0; i < arrOfIds.length; i++) {
        var idToStr = arrOfIds[i].toString();

        var qtyNode = document.getElementById("itemQty" + idToStr);
        var priceNode = document.getElementById("unitPrice" + idToStr);

        var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
        var price = parseFloat(priceNode.innerHTML);
        var itemTotal = qty * price;

        cartTotal = cartTotal + itemTotal;
    }
    document.getElementById("cartTotalBottom").innerHTML = cartTotal.toString();
    document.getElementById("cartTotalSide").innerHTML = cartTotal.toString();
}

/*
 * Calculate the total price of the items in the shopping cart after the person remove a item.
 * Sets the new total price in the html element
 *
 */
function calculateNewTotal(num, arrOfIds) {
    var cartTotal = 0;
    var toRemoveIndex = arrOfIds.indexOf(num);
    arrOfIds.splice(toRemoveIndex, 1);
    for (var i = 0; i < arrOfIds.length; i++) {

        var idToStr = arrOfIds[i].toString();

        var qtyNode = document.getElementById("itemQty" + idToStr);
        var priceNode = document.getElementById("unitPrice" + idToStr);

        var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
        var price = parseFloat(priceNode.innerHTML);
        var itemTotal = qty * price;

        cartTotal = cartTotal + itemTotal;

    }

    document.getElementById("cartTotalBottom").innerHTML = cartTotal.toString();
    document.getElementById("cartTotalSide").innerHTML = cartTotal.toString();

    /*
     var cartTotal = 0;
     var qtyList = document.getElementsByClassName("itemQty");
     var priceList = document.getElementsByClassName("unitPrice");

     for (var j = 0; j < qtyList.length; j++) {
     var qty = parseInt(qtyList[j].options[qtyList[j].selectedIndex].value);
     var price = parseFloat(priceList[j].innerHTML);
     var itemTotal = qty * price;

     cartTotal = cartTotal + itemTotal;

     }
     document.getElementById("cartTotalBottom").innerHTML = cartTotal.toString();
     document.getElementById("cartTotalSide").innerHTML = cartTotal.toString();
     */
}

/**
 * Make a tr element visually disappear from the html page. Then remove the node
 * from DOM.
 * Call the AJAX function to update datastore
 * @param {type} num unique id of the tr we want to make disappear
 *
 */

function fadeFunction(num, arrOfId) {

    var o = num.toString();

    $("#tr" + o).fadeOut("slow");

    var child = document.getElementById("tr" + o);
    child.parentElement.removeChild(child);
    setTimeout(function () {
        calculateNewTotal(num, arrOfId);
    }, 650);
    asyncDelete(o);

}

/**
 * Register element to event listener.
 * @param {type} num unique id of the link element that the user clicks to
 * reomove cart iem.
 *
 */

function addClickListener(num, arrOfId) {
    var n = "del" + num.toString();
    document.getElementById(n).addEventListener("click", function () {
        fadeFunction(num, arrOfId);
    });
}

function addChangeListener(num, arrOfId) {

    var p = "itemQty" + num.toString();
    document.getElementById(p).addEventListener("change", function () {
        asyncUpdate(num.toString(), arrOfId);

    });

}

var cartIdsToReg = arrOfId;

/*
 * For every 'remove item link' in the shopping cart, register the click listener.
 * */

for (var i = 0; i < cartIdsToReg.length; i++) {
    addClickListener(cartIdsToReg[i], cartIdsToReg);
    addChangeListener(cartIdsToReg[i], cartIdsToReg);
}

<commit_msg>update cart total round to 2 decimal place and commenting<commit_after>/*
 *Author: Teo Jin Cheng
 *
 *When user removes a cart item or change the qty of an item in the cart, update the datastore
 *and refresh the page.
 *
 */

/**
 * AJAX call to delete one item in the cart of the user.
 * @param {type} cartId id of the entry in the cart datastore
 * @returns {undefined}
 */
function asyncDelete(cartId) {
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            alert(this.responseText);
        }
    }
    xmlhttp.open("GET", "updateCart.php?d=" + cartId, true);
    xmlhttp.send();
}

/**
 * AJAX call to update the qty of one cart item in the datastore
 * @param {type} cartId id of the entry of one item in the cart datastore
 * @param {type} arrOfId an array which contains id of the cart items in the datastore
 * @returns {undefined}
 */
function asyncUpdate(cartId, arrOfId) {
    var qtyNode = document.getElementById("itemQty" + cartId);
    var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
    if (window.XMLHttpRequest) {
        // code for IE7+, Firefox, Chrome, Opera, Safari
        xmlhttp = new XMLHttpRequest();
    } else { // code for IE6, IE5
        xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
    }
    xmlhttp.onreadystatechange = function () {
        if (this.readyState == 4 && this.status == 200) {
            calculateTotal(arrOfId);
            alert(this.responseText);
        }
    }
    xmlhttp.open("GET", "updateCart.php?u=" + cartId + "&q=" + qty, true);
    xmlhttp.send();
}

/**
 * Caculate the total cost of the items in the cart based on the html markup.
 * Used when user only changes the qty of a cart item.
 *
 * @param {type} arrOfIds an array which contains id of the cart items in the datastore

 */
function calculateTotal(arrOfIds) {
    var cartTotal = 0;
    for (var i = 0; i < arrOfIds.length; i++) {
        var idToStr = arrOfIds[i].toString();

        var qtyNode = document.getElementById("itemQty" + idToStr);
        var priceNode = document.getElementById("unitPrice" + idToStr);

        var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
        var price = parseFloat(priceNode.innerHTML);
        var itemTotal = qty * price;

        cartTotal = cartTotal + itemTotal;
    }
    document.getElementById("cartTotalBottom").innerHTML = cartTotal.toFixed(2);
    document.getElementById("cartTotalSide").innerHTML = cartTotal.toFixed(2);
}

/**
 *
 * Calculate the total price of the items in the shopping cart after the person remove a item.
 * Sets the new total price in the html element
 *
 * @param {type} num id of the cart item in the datastore
 * @param {type} arrOfIds an array which contains id of the cart items in the datastore
 */
function calculateNewTotal(num, arrOfIds) {
    var cartTotal = 0;
    var toRemoveIndex = arrOfIds.indexOf(num);
    arrOfIds.splice(toRemoveIndex, 1);
    for (var i = 0; i < arrOfIds.length; i++) {

        var idToStr = arrOfIds[i].toString();

        var qtyNode = document.getElementById("itemQty" + idToStr);
        var priceNode = document.getElementById("unitPrice" + idToStr);

        var qty = parseInt(qtyNode.options[qtyNode.selectedIndex].value);
        var price = parseFloat(priceNode.innerHTML);
        var itemTotal = qty * price;

        cartTotal = cartTotal + itemTotal;

    }

    document.getElementById("cartTotalBottom").innerHTML = cartTotal.toFixed(2);
    document.getElementById("cartTotalSide").innerHTML = cartTotal.toFixed(2);

}

/**
 * Make a tr element visually disappear from the html page. Then remove the node
 * from DOM.
 * Call the AJAX function to update datastore
 * @param {type} num unique id of the tr we want to make disappear
 *
 */

function fadeFunction(num, arrOfId) {

    var o = num.toString();

    $("#tr" + o).fadeOut("slow");

    var child = document.getElementById("tr" + o);
    child.parentElement.removeChild(child);
    setTimeout(function () {
        calculateNewTotal(num, arrOfId);
    }, 650);
    asyncDelete(o);

}

/**
 * Register the click listener for a remove cart item link
 *
 * @param {type} num id of the cart item in the datastore
 * @param {type} arrOfId an array which contains id of the cart items in the datastore
 */

function addClickListener(num, arrOfId) {
    var n = "del" + num.toString();
    document.getElementById(n).addEventListener("click", function () {
        fadeFunction(num, arrOfId);
    });
}

/**
 * Register the change listener for the item qty dropdown
 *
 * @param {type} num id of the cart item in the datastore
 * @param {type} arrOfId arrOfId an array which contains id of the cart items in the datastore
 */

function addChangeListener(num, arrOfId) {

    var p = "itemQty" + num.toString();
    document.getElementById(p).addEventListener("change", function () {
        asyncUpdate(num.toString(), arrOfId);

    });

}

var cartIdsToReg = arrOfId;

/*
 * For every item in the shopping cart, register the event listener.
 * */

for (var i = 0; i < cartIdsToReg.length; i++) {
    addClickListener(cartIdsToReg[i], cartIdsToReg);
    addChangeListener(cartIdsToReg[i], cartIdsToReg);
}

<|endoftext|>


<commit_before>angular.module('app.utils', [])
  .controller('MessageModalCtrl', function($scope, $modalInstance, modalOpts) {
    $scope.title = modalOpts.title || 'Voxxel';
    $scope.icon = modalOpts.icon;
    $scope.message = modalOpts.message;

    $scope.ok = function() {
      $modalInstance.close();
    }
  })

  .service('messageModal', function($modal) {
    this.open = function(modalOpts) {
      var modalInstance = $modal.open({
        templateUrl: 'modals/message-modal.html',
        controller: 'MessageModalCtrl',
        resolve: {
          modalOpts: function() { return modalOpts; }
        }
      });
    };
  });<commit_msg>added show-errors directive to highlight inputs with errors<commit_after>angular.module('app.utils', [])
  .directive('showErrors', function() {
    return {
      restrict: 'A',
      require: '^form', //require a parent form element
      link: function(scope, el, attrs, formCtrl) {
        var inputEl = el[0].querySelector("[name]"); //find the textbox element within the form-group
        var inputNgEl = angular.element(inputEl); //convert native textbox to an angular element
        var inputName = inputNgEl.attr('name'); //get the name on the text box, so we know the property to check for on the model

        inputNgEl.bind('blur', function() {
          el.toggleClass('has-error', formCtrl[inputName].$invalid);
        })
      }
    }
  })

  .controller('MessageModalCtrl', function($scope, $modalInstance, modalOpts) {
    $scope.title = modalOpts.title || 'Voxxel';
    $scope.icon = modalOpts.icon;
    $scope.message = modalOpts.message;

    $scope.ok = function() {
      $modalInstance.close();
    }
  })

  .service('messageModal', function($modal) {
    this.open = function(modalOpts) {
      var modalInstance = $modal.open({
        templateUrl: 'modals/message-modal.html',
        controller: 'MessageModalCtrl',
        resolve: {
          modalOpts: function() { return modalOpts; }
        }
      });
    };
  });<|endoftext|>


<commit_before>require('./global');

global.target = {};

// This ensures we only execute the script targets after the entire script has
// been evaluated
var args = process.argv.slice(2);
setTimeout(function() {

  if (args.length === 1 && args[0] === '--help') {
    console.log('Available targets:');
    for (t in target)
      console.log('  ' + t);
    return;
  }

  // Wrap targets to prevent duplicate execution
  for (t in target) {
    (function(t, oldTarget){

      // Wrap it
      target[t] = function(force) {
        if (oldTarget.done && !force)
          return;
        oldTarget.done = true;
        return oldTarget(arguments);
      }

    })(t, target[t]);
  }

  // Execute desired targets
  if (args.length > 0) {
    args.forEach(function(arg) {
      if (arg in target)
        target[arg]();
      else {
        console.log('no such target: ' + arg);
        exit(1);
      }
    });
  } else if ('all' in target) {
    target.all();
  }

}, 0);
<commit_msg>fixing make.js function arguments<commit_after>require('./global');

global.target = {};

// This ensures we only execute the script targets after the entire script has
// been evaluated
var args = process.argv.slice(2);
setTimeout(function() {

  if (args.length === 1 && args[0] === '--help') {
    console.log('Available targets:');
    for (t in target)
      console.log('  ' + t);
    return;
  }

  // Wrap targets to prevent duplicate execution
  for (t in target) {
    (function(t, oldTarget){

      // Wrap it
      target[t] = function(force) {
        if (oldTarget.done && !force)
          return;
        oldTarget.done = true;
        return oldTarget.apply(oldTarget, arguments);
      }

    })(t, target[t]);
  }

  // Execute desired targets
  if (args.length > 0) {
    args.forEach(function(arg) {
      if (arg in target)
        target[arg]();
      else {
        console.log('no such target: ' + arg);
        exit(1);
      }
    });
  } else if ('all' in target) {
    target.all();
  }

}, 0);
<|endoftext|>


<commit_before>//i18n
//
function _t(s) {
  return s;
}

var i18n = {
  // format('hello, {0}', 'rambo') -> "hello, rambo"
  format: function (str) {
    for(var i = 1; i < arguments.length; ++i) {
      var attrs = arguments[i];
      for(var attr in attrs) {
        str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
      }
    }
    return str;
  }
};

cdb.config.isOrganizationUrl = function() {
  return window.location.pathname.search(this.organizationUrl()) !== -1;
}

// returns true if the current url is a organization one
cdb.config.organizationUrl = function() {
  var username = this.get('user_name');
  return '/u/' + username;
}

// return prefixUrl for all the queries to the rest api
cdb.config.prefixUrl = function() {
  return this.get('url_prefix') || '';
};

(function() {

  // helper functions needed frmo backbone (they are not exported)
  var getValue = function(object, prop) {
    if (!(object && object[prop])) return null;
    return _.isFunction(object[prop]) ? object[prop]() : object[prop];
  };

  // Throw an error when a URL is needed, and none is supplied.
  var urlError = function() {
    throw new Error('A "url" property or function must be specified');
  };

  // backbone.sync replacement to control url prefix
  Backbone.originalSync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    var url = options.url || getValue(model, 'url') || urlError();
    // prefix if http is not present
    var absoluteUrl = url.indexOf('http') === 0 || url.indexOf("//") === 0;
    if (!absoluteUrl) {
      options.url = cdb.config.prefixUrl() + url;
    } else {
      options.url = url;
    }
    return Backbone.originalSync(method, model, options);
  };

  // this method returns a cached version of backbone sync
  // take a look at https://github.com/teambox/backbone.memoized_sync/blob/master/backbone.memoized_sync.js
  // this is the same concept but implemented as a wrapper for ``Backbone.sync``
  // usage:
  // initialize: function() {
  //    this.sync = Backbone.cachedSync(this.user_name);
  // }
  Backbone.cachedSync = function(namespace) {

    if (!namespace) {
      throw new Error("cachedSync needs a namespace as argument");
    }

    var namespaceKey = "cdb-cache/" + namespace;

    var index = {

      _keys: function() {
        return JSON.parse(localStorage.getItem(namespaceKey) || '{}');
      },

      add: function(key) {
        var keys = this._keys();
        keys[key] = +new Date();
        localStorage.setItem(namespaceKey, JSON.stringify(keys));
      },

      invalidate: function() {
        var keys = this._keys();
        _.each(keys, function(v, k) {
          localStorage.removeItem(k);
        });
        localStorage.removeItem(namespaceKey);
      }

    }

    var cache = {

      setItem: function(key, value) {
        localStorage.setItem(key, value);
        index.add(key);
        return this;
      },

      getItem: function(key, callback) {
        var val = localStorage.getItem(key);
        _.defer(function() {
          callback(val);
        });
      },

      removeItem: function(key) {
        localStorage.removeItem(key);
        index.invalidate();
      }
    }

    var cached = function(method, model, options) {
      var url = options.url || getValue(model, 'url') || urlError();
      var key = namespaceKey + "/" + url;

      if (method === 'read') {
        var success = options.success;
        var cachedValue = null;

        options.success = function(resp, status, xhr) {
           // if cached value is ok
           if (cachedValue && xhr.responseText === cachedValue) {
             return;
           }
           success(resp, status, xhr);
           cache.setItem(key, xhr.responseText);
        }

        cache.getItem(key, function(val) {
          cachedValue = val;
          if (val) {
            success(JSON.parse(val), "success");
          }
        });
      } else {
        cache.removeItem(key);
      }
      return Backbone.sync(method, model, options);
    }

    cached.invalidate = function() {
      index.invalidate();
    }

    cached.cache = cache;

    return cached;
  }

})();

Backbone.syncAbort = function() {
  var self = arguments[1];
  if (self._xhr) {
    self._xhr.abort();
  }
  self._xhr = Backbone.sync.apply(this, arguments);
  self._xhr.always(function() { self._xhr = null; });
  return self._xhr;
};

Backbone.delayedSaveSync = function(sync, delay) {
  var dsync = _.debounce(sync, delay);
  return function(method, model, options) {
    if (method === 'create' || method === 'update') {
      return dsync(method, model, options);
    } else {
      return sync(method, model, options);
    }
  }
}

Backbone.saveAbort = function() {
  var self = this;
  if (this._saving && this._xhr) {
    this._xhr.abort();
  }
  this._saving = true;
  var xhr = Backbone.Model.prototype.save.apply(this, arguments);
  this._xhr = xhr;
  xhr.always(function() { self._saving = false; });
  return xhr;
};

cdb.admin = {};
cdb.common = {};
cdb.admin.dashboard = {};
cdb.forms = {};
cdb.open = {};

/**
 * track changes and sync on every model
 */
function instrumentBackbone() {
  var events = [];
  var eventMap = {}
  instrumentBackbone.events = events;

  EVENT_SET = "SET";
  EVENT_SYNC = "SYNC";
  EVENT_SAVE = "SAVE";
  EVENT_SAVE_SUCCESS = "SAVE_SUCESS";
  EVENT_FETCH = "FETCH";
  EVENT_FETCH_SUCCESS = "FETCH_SUCESS";
  EVENT_FETCH_COLLECTION = "FETCH_COLLECTION";
  EVENT_FETCH_COLLECTION_SUCCESS = "FETCH_COLLECTION_SUCCESS";
  EVENT_SYNC_COLL = "SYNC_COLL";

  function track(obj, ev, data, parentId) {
    var t, o;
    events.push(o = {
      id: events.length,
      time: Date.now(),
      ev: ev,
      obj: obj,
      data: _.clone(data),
      parentId: parentId
    });
    eventMap[o.id] = o;
    return o.id;
  }

  var coll = 0;
  // sync
  var sync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    if (model) {
      if (!model.cid) {
        model.cid = "col_" + coll;
        ++coll;
      }
      track(model.cid, model.cid.indexOf('col') != -1 ? EVENT_SYNC_COLL: EVENT_SYNC);
    }
    return sync.apply(Backbone, arguments);
  }

  // set
  var set = Backbone.Model.prototype.set;
  Backbone.Model.prototype.set = function(key, value, options) {
    var attrs, attr, val;
    if (_.isObject(key) || key == null) {
      attrs = key;
      options = value;
    } else {
      attrs = {};
      attrs[key] = value;
    }
    track(this.cid, EVENT_SET, attrs);
    return set.apply(this, arguments)
  }

  // save
  var save = Backbone.Model.prototype.save;
  Backbone.Model.prototype.save = function(key, value, options) {
      var attrs, current;

      // Handle both `("key", value)` and `({key: value})` -style calls.
      if (_.isObject(key) || key == null) {
        attrs = key;
        options = value;
      } else {
        attrs = {};
        attrs[key] = value;
      }
      options = options ? _.clone(options) : {};

      var i = track(this.cid, EVENT_SAVE, attrs);

      // If we're "wait"-ing to set changed attributes, validate early.
      if (options.wait) {
        if (!this._validate(attrs, options)) return false;
        current = _.clone(this.attributes);
      }

      // Regular saves `set` attributes before persisting to the server.
      var silentOptions = _.extend({}, options, {silent: true});
      if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) {
        return false;
      }

      // After a successful server-side save, the client is (optionally)
      // updated with the server-side state.
      var model = this;
      var success = options.success;
      var self = this;
      options.success = function(resp, status, xhr) {
        track(self.cid, EVENT_SAVE_SUCCESS, resp, i);
        var serverAttrs = model.parse(resp, xhr);
        if (options.wait) {
          delete options.wait;
          serverAttrs = _.extend(attrs || {}, serverAttrs);
        }
        if (!model.set(serverAttrs, options)) return false;
        if (success) {
          success(model, resp);
        } else {
          model.trigger('sync', model, resp, options);
        }
      };

      // Finish configuring and sending the Ajax request.
      options.error = Backbone.wrapError(options.error, model, options);
      var method = this.isNew() ? 'create' : 'update';
      var xhr = (this.sync || Backbone.sync).call(this, method, this, options);
      if (options.wait) this.set(current, silentOptions);
      return xhr;
  };

  Backbone.Model.prototype.fetch = function(options) {
    options = options ? _.clone(options) : {};
    var model = this;
    var success = options.success;
    var i = track(this.cid, EVENT_FETCH);
    var self = this;
    options.success = function(resp, status, xhr) {
      track(self.cid, EVENT_FETCH_SUCCESS, resp, i);
      if (!model.set(model.parse(resp, xhr), options)) return false;
      if (success) success(model, resp);
    };
    options.error = Backbone.wrapError(options.error, model, options);
    return (this.sync || Backbone.sync).call(this, 'read', this, options);
  }

   Backbone.Collection.fetch = function(options) {
      options = options ? _.clone(options) : {};
      if (options.parse === undefined) options.parse = true;
      var collection = this;
      var success = options.success;
      var i = track(this, EVENT_FETCH_COLLECTION);
      options.success = function(resp, status, xhr) {
        track(this, EVENT_FETCH_COLLECTION_SUCCESS, resp, i);
        collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
        if (success) success(collection, resp);
      };
      options.error = Backbone.wrapError(options.error, collection, options);
      return (this.sync || Backbone.sync).call(this, 'read', this, options);
   }

  instrumentBackbone.show = function(cid) {
    var padding = 100;
    var div = d3.select(document.body)
      .append('div')
      .style('position', 'absolute')
      .style('top', 0)
      .style('left', 0)
      .style('right', 0)
      .style('bottom', 0)
      .style('z-index', 1000)
      .style('background', 'rgba(0, 0, 0, 0.85)');

  var tooltip = div.append("div")
    .style('width', 100)
    .style('height', 100)
    .style('position', 'absolute')
    .style('background', 'rgba(255, 255, 255, 0.85)')
    .style('color', 'black')
    .style("opacity", 0);

  var width = div.node().clientWidth;
  var height = div.node().clientHeight;

    var svg = div.append("svg:svg")
        .attr('width', width)
        .attr('height', height);

    var zx = d3.scale.linear()
      .domain([-width / 2, width / 2])
      .range([0, width]);

    var zy = d3.scale.linear()
      .domain([-height / 2, height / 2])
      .range([height, 0]);

    var zoom = d3.behavior.zoom()
      .x(zx)
      .y(zy)
      .scaleExtent([1, 10])

    var xAxis = d3.svg.axis()
      .scale(zx)
      .orient("bottom")
      .tickSize(-height);

    var yAxis = d3.svg.axis()
      .scale(zy)
      .orient("left")
      .ticks(5)
      .tickSize(-width);

    var ev = svg.append("g").attr("transform", 'translate(0, 0)').call(zoom);

    svg.append("g")
    .style('fill', 'none')
    .style('stoke', '#FFF')
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

     svg.append("g")
      .style('fill', 'none')
      .style('stoke', '#FFF')
          .call(yAxis);

    objEvents = events;
    if (cid) {
      var objEvents = events.filter(function(e) {
        return cid.indexOf(e.obj) !== -1
      });
    } else {
      cid = events.map(function(e) { return e.obj; });
    }

    var e =  {
      "FETCH": 0,
      "FETCH_SUCESS": 1,
      "FETCH_COLLECTION": 2,
      "FETCH_COLLECTION_SUCCESS": 3,
      "SET": 4,
      "SAVE": 5,
      "SAVE_SUCESS": 6,
      "SYNC": 7,
      "SYNC_COLL": 8
    };
    var colors = d3.scale.category10()

    var catx = d3.scale.linear()
      .domain([0, cid.length])
      .range([0, width/Object.keys(e).length])

    function x(d) {
      return catx(cid.indexOf(d.obj)) + padding*2 + e[d.ev]*100;
    }

    function _time(d) { return +d.time; };
    var y = d3.scale.linear()
      .domain([d3.min(objEvents, _time), d3.max(objEvents, _time)])
      .range([padding, div.node().clientHeight - padding ]);

    // lines
    var line = d3.svg.line()
        .x(function(d) { return d.x; })
        .y(function(d) { return d.y; })
        .interpolate("basis");

    var lines = objEvents.filter(function(e) {
      return !!e.parentId;
    });

    ev.selectAll('.line')
      .data(lines)
      .enter()
        .append("path")
        .attr("fill", "none")
        .attr("stroke", '#FFF')
        .attr("stroke-width", 0.2)
        .attr('d', function(d, i) {
          var p = eventMap[d.parentId];
          return line([
            {x: x(d), y: y(+d.time) },
            {x: x(p), y: y(+p.time) }
          ]);
        })

    ev.selectAll('.event')
      .data(objEvents)
      .enter()
        .append("svg:circle")
          .attr("fill", function(d) {
            console.log(d.ev);
            return colors(e[d.ev]);
          })
          .attr("r", 3)
          .attr('cx', function(d, i) {
            return x(d);
          })
          .attr('cy', function(d, i) {
            return y(d.time);
          })
          .on("mouseover", function(d) {
            tooltip.transition()
                .duration(200)
                .style("opacity", .9);
            tooltip.html("<h1>" + d.ev  + " (" + d.obj + ")<br>" + (d.time - objEvents[0].time))
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 48) + "px");
           })
          .on("mouseout", function(d) {
            tooltip.transition()
                .duration(500)
                .style("opacity", 0);
        });

  }
}

//instrumentBackbone();

cdb.dashboard = {};
<commit_msg>added some comments<commit_after>//i18n
//
function _t(s) {
  return s;
}

var i18n = {
  // format('hello, {0}', 'rambo') -> "hello, rambo"
  format: function (str) {
    for(var i = 1; i < arguments.length; ++i) {
      var attrs = arguments[i];
      for(var attr in attrs) {
        str = str.replace(RegExp('\\{' + attr + '\\}', 'g'), attrs[attr]);
      }
    }
    return str;
  }
};

cdb.config.isOrganizationUrl = function() {
  return window.location.pathname.search(this.organizationUrl()) !== -1;
}

// returns true if the current url is a organization one
cdb.config.organizationUrl = function() {
  var username = this.get('user_name');
  return '/u/' + username;
}

// return prefixUrl for all the queries to the rest api
cdb.config.prefixUrl = function() {
  return this.get('url_prefix') || '';
};

(function() {

  // helper functions needed frmo backbone (they are not exported)
  var getValue = function(object, prop) {
    if (!(object && object[prop])) return null;
    return _.isFunction(object[prop]) ? object[prop]() : object[prop];
  };

  // Throw an error when a URL is needed, and none is supplied.
  var urlError = function() {
    throw new Error('A "url" property or function must be specified');
  };

  // backbone.sync replacement to control url prefix
  Backbone.originalSync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    var url = options.url || getValue(model, 'url') || urlError();
    // prefix if http is not present
    var absoluteUrl = url.indexOf('http') === 0 || url.indexOf("//") === 0;
    if (!absoluteUrl) {
      options.url = cdb.config.prefixUrl() + url;
    } else {
      options.url = url;
    }
    return Backbone.originalSync(method, model, options);
  };

  // this method returns a cached version of backbone sync
  // take a look at https://github.com/teambox/backbone.memoized_sync/blob/master/backbone.memoized_sync.js
  // this is the same concept but implemented as a wrapper for ``Backbone.sync``
  // usage:
  // initialize: function() {
  //    this.sync = Backbone.cachedSync(this.user_name);
  // }
  Backbone.cachedSync = function(namespace) {

    if (!namespace) {
      throw new Error("cachedSync needs a namespace as argument");
    }

    var namespaceKey = "cdb-cache/" + namespace;

    // saves all the localstore references to the namespace
    // inside localstore. It allows to remove all the references
    // at a time
    var index = {

      // return a list of references for the namespace
      _keys: function() {
        return JSON.parse(localStorage.getItem(namespaceKey) || '{}');
      },

      // add a new reference for the namespace
      add: function(key) {
        var keys = this._keys();
        keys[key] = +new Date();
        localStorage.setItem(namespaceKey, JSON.stringify(keys));
      },

      // remove all the references for the namespace
      invalidate: function() {
        var keys = this._keys();
        _.each(keys, function(v, k) {
          localStorage.removeItem(k);
        });
        localStorage.removeItem(namespaceKey);
      }

    }

    // localstore-like cache wrapper
    var cache = {

      setItem: function(key, value) {
        localStorage.setItem(key, value);
        index.add(key);
        return this;
      },

      // this is async in case the data needs to be compressed
      getItem: function(key, callback) {
        var val = localStorage.getItem(key);
        _.defer(function() {
          callback(val);
        });
      },

      removeItem: function(key) {
        localStorage.removeItem(key);
        index.invalidate();
      }
    }

    var cached = function(method, model, options) {
      var url = options.url || getValue(model, 'url') || urlError();
      var key = namespaceKey + "/" + url;

      if (method === 'read') {
        var success = options.success;
        var cachedValue = null;

        options.success = function(resp, status, xhr) {
           // if cached value is ok
           if (cachedValue && xhr.responseText === cachedValue) {
             return;
           }
           success(resp, status, xhr);
           cache.setItem(key, xhr.responseText);
        }

        cache.getItem(key, function(val) {
          cachedValue = val;
          if (val) {
            success(JSON.parse(val), "success");
          }
        });
      } else {
        cache.removeItem(key);
      }
      return Backbone.sync(method, model, options);
    }

    // create a public function to invalidate all the namespace
    // items
    cached.invalidate = function() {
      index.invalidate();
    }

    // for testing and debugging porpuposes
    cached.cache = cache;

    return cached;
  }

})();

Backbone.syncAbort = function() {
  var self = arguments[1];
  if (self._xhr) {
    self._xhr.abort();
  }
  self._xhr = Backbone.sync.apply(this, arguments);
  self._xhr.always(function() { self._xhr = null; });
  return self._xhr;
};

Backbone.delayedSaveSync = function(sync, delay) {
  var dsync = _.debounce(sync, delay);
  return function(method, model, options) {
    if (method === 'create' || method === 'update') {
      return dsync(method, model, options);
    } else {
      return sync(method, model, options);
    }
  }
}

Backbone.saveAbort = function() {
  var self = this;
  if (this._saving && this._xhr) {
    this._xhr.abort();
  }
  this._saving = true;
  var xhr = Backbone.Model.prototype.save.apply(this, arguments);
  this._xhr = xhr;
  xhr.always(function() { self._saving = false; });
  return xhr;
};

cdb.admin = {};
cdb.common = {};
cdb.admin.dashboard = {};
cdb.forms = {};
cdb.open = {};

/**
 * track changes and sync on every model
 */
function instrumentBackbone() {
  var events = [];
  var eventMap = {}
  instrumentBackbone.events = events;

  EVENT_SET = "SET";
  EVENT_SYNC = "SYNC";
  EVENT_SAVE = "SAVE";
  EVENT_SAVE_SUCCESS = "SAVE_SUCESS";
  EVENT_FETCH = "FETCH";
  EVENT_FETCH_SUCCESS = "FETCH_SUCESS";
  EVENT_FETCH_COLLECTION = "FETCH_COLLECTION";
  EVENT_FETCH_COLLECTION_SUCCESS = "FETCH_COLLECTION_SUCCESS";
  EVENT_SYNC_COLL = "SYNC_COLL";

  function track(obj, ev, data, parentId) {
    var t, o;
    events.push(o = {
      id: events.length,
      time: Date.now(),
      ev: ev,
      obj: obj,
      data: _.clone(data),
      parentId: parentId
    });
    eventMap[o.id] = o;
    return o.id;
  }

  var coll = 0;
  // sync
  var sync = Backbone.sync;
  Backbone.sync = function(method, model, options) {
    if (model) {
      if (!model.cid) {
        model.cid = "col_" + coll;
        ++coll;
      }
      track(model.cid, model.cid.indexOf('col') != -1 ? EVENT_SYNC_COLL: EVENT_SYNC);
    }
    return sync.apply(Backbone, arguments);
  }

  // set
  var set = Backbone.Model.prototype.set;
  Backbone.Model.prototype.set = function(key, value, options) {
    var attrs, attr, val;
    if (_.isObject(key) || key == null) {
      attrs = key;
      options = value;
    } else {
      attrs = {};
      attrs[key] = value;
    }
    track(this.cid, EVENT_SET, attrs);
    return set.apply(this, arguments)
  }

  // save
  var save = Backbone.Model.prototype.save;
  Backbone.Model.prototype.save = function(key, value, options) {
      var attrs, current;

      // Handle both `("key", value)` and `({key: value})` -style calls.
      if (_.isObject(key) || key == null) {
        attrs = key;
        options = value;
      } else {
        attrs = {};
        attrs[key] = value;
      }
      options = options ? _.clone(options) : {};

      var i = track(this.cid, EVENT_SAVE, attrs);

      // If we're "wait"-ing to set changed attributes, validate early.
      if (options.wait) {
        if (!this._validate(attrs, options)) return false;
        current = _.clone(this.attributes);
      }

      // Regular saves `set` attributes before persisting to the server.
      var silentOptions = _.extend({}, options, {silent: true});
      if (attrs && !this.set(attrs, options.wait ? silentOptions : options)) {
        return false;
      }

      // After a successful server-side save, the client is (optionally)
      // updated with the server-side state.
      var model = this;
      var success = options.success;
      var self = this;
      options.success = function(resp, status, xhr) {
        track(self.cid, EVENT_SAVE_SUCCESS, resp, i);
        var serverAttrs = model.parse(resp, xhr);
        if (options.wait) {
          delete options.wait;
          serverAttrs = _.extend(attrs || {}, serverAttrs);
        }
        if (!model.set(serverAttrs, options)) return false;
        if (success) {
          success(model, resp);
        } else {
          model.trigger('sync', model, resp, options);
        }
      };

      // Finish configuring and sending the Ajax request.
      options.error = Backbone.wrapError(options.error, model, options);
      var method = this.isNew() ? 'create' : 'update';
      var xhr = (this.sync || Backbone.sync).call(this, method, this, options);
      if (options.wait) this.set(current, silentOptions);
      return xhr;
  };

  Backbone.Model.prototype.fetch = function(options) {
    options = options ? _.clone(options) : {};
    var model = this;
    var success = options.success;
    var i = track(this.cid, EVENT_FETCH);
    var self = this;
    options.success = function(resp, status, xhr) {
      track(self.cid, EVENT_FETCH_SUCCESS, resp, i);
      if (!model.set(model.parse(resp, xhr), options)) return false;
      if (success) success(model, resp);
    };
    options.error = Backbone.wrapError(options.error, model, options);
    return (this.sync || Backbone.sync).call(this, 'read', this, options);
  }

   Backbone.Collection.fetch = function(options) {
      options = options ? _.clone(options) : {};
      if (options.parse === undefined) options.parse = true;
      var collection = this;
      var success = options.success;
      var i = track(this, EVENT_FETCH_COLLECTION);
      options.success = function(resp, status, xhr) {
        track(this, EVENT_FETCH_COLLECTION_SUCCESS, resp, i);
        collection[options.add ? 'add' : 'reset'](collection.parse(resp, xhr), options);
        if (success) success(collection, resp);
      };
      options.error = Backbone.wrapError(options.error, collection, options);
      return (this.sync || Backbone.sync).call(this, 'read', this, options);
   }

  instrumentBackbone.show = function(cid) {
    var padding = 100;
    var div = d3.select(document.body)
      .append('div')
      .style('position', 'absolute')
      .style('top', 0)
      .style('left', 0)
      .style('right', 0)
      .style('bottom', 0)
      .style('z-index', 1000)
      .style('background', 'rgba(0, 0, 0, 0.85)');

  var tooltip = div.append("div")
    .style('width', 100)
    .style('height', 100)
    .style('position', 'absolute')
    .style('background', 'rgba(255, 255, 255, 0.85)')
    .style('color', 'black')
    .style("opacity", 0);

  var width = div.node().clientWidth;
  var height = div.node().clientHeight;

    var svg = div.append("svg:svg")
        .attr('width', width)
        .attr('height', height);

    var zx = d3.scale.linear()
      .domain([-width / 2, width / 2])
      .range([0, width]);

    var zy = d3.scale.linear()
      .domain([-height / 2, height / 2])
      .range([height, 0]);

    var zoom = d3.behavior.zoom()
      .x(zx)
      .y(zy)
      .scaleExtent([1, 10])

    var xAxis = d3.svg.axis()
      .scale(zx)
      .orient("bottom")
      .tickSize(-height);

    var yAxis = d3.svg.axis()
      .scale(zy)
      .orient("left")
      .ticks(5)
      .tickSize(-width);

    var ev = svg.append("g").attr("transform", 'translate(0, 0)').call(zoom);

    svg.append("g")
    .style('fill', 'none')
    .style('stoke', '#FFF')
    .attr("transform", "translate(0," + height + ")")
    .call(xAxis);

     svg.append("g")
      .style('fill', 'none')
      .style('stoke', '#FFF')
          .call(yAxis);

    objEvents = events;
    if (cid) {
      var objEvents = events.filter(function(e) {
        return cid.indexOf(e.obj) !== -1
      });
    } else {
      cid = events.map(function(e) { return e.obj; });
    }

    var e =  {
      "FETCH": 0,
      "FETCH_SUCESS": 1,
      "FETCH_COLLECTION": 2,
      "FETCH_COLLECTION_SUCCESS": 3,
      "SET": 4,
      "SAVE": 5,
      "SAVE_SUCESS": 6,
      "SYNC": 7,
      "SYNC_COLL": 8
    };
    var colors = d3.scale.category10()

    var catx = d3.scale.linear()
      .domain([0, cid.length])
      .range([0, width/Object.keys(e).length])

    function x(d) {
      return catx(cid.indexOf(d.obj)) + padding*2 + e[d.ev]*100;
    }

    function _time(d) { return +d.time; };
    var y = d3.scale.linear()
      .domain([d3.min(objEvents, _time), d3.max(objEvents, _time)])
      .range([padding, div.node().clientHeight - padding ]);

    // lines
    var line = d3.svg.line()
        .x(function(d) { return d.x; })
        .y(function(d) { return d.y; })
        .interpolate("basis");

    var lines = objEvents.filter(function(e) {
      return !!e.parentId;
    });

    ev.selectAll('.line')
      .data(lines)
      .enter()
        .append("path")
        .attr("fill", "none")
        .attr("stroke", '#FFF')
        .attr("stroke-width", 0.2)
        .attr('d', function(d, i) {
          var p = eventMap[d.parentId];
          return line([
            {x: x(d), y: y(+d.time) },
            {x: x(p), y: y(+p.time) }
          ]);
        })

    ev.selectAll('.event')
      .data(objEvents)
      .enter()
        .append("svg:circle")
          .attr("fill", function(d) {
            console.log(d.ev);
            return colors(e[d.ev]);
          })
          .attr("r", 3)
          .attr('cx', function(d, i) {
            return x(d);
          })
          .attr('cy', function(d, i) {
            return y(d.time);
          })
          .on("mouseover", function(d) {
            tooltip.transition()
                .duration(200)
                .style("opacity", .9);
            tooltip.html("<h1>" + d.ev  + " (" + d.obj + ")<br>" + (d.time - objEvents[0].time))
                .style("left", (d3.event.pageX) + "px")
                .style("top", (d3.event.pageY - 48) + "px");
           })
          .on("mouseout", function(d) {
            tooltip.transition()
                .duration(500)
                .style("opacity", 0);
        });

  }
}

//instrumentBackbone();

cdb.dashboard = {};
<|endoftext|>


<commit_before>// Copyright (C) 2016 ncph Authors
// This file is free software: You can redistribute it and/or modify it under
// the terms of the GNU AGPLv3 or later. See COPYING for details.

// Implementation of the Fischer-Yates-Durstenfeld O(n) shuffle algorithm. This
// variant is non-destructive (does not modify the input array), and takes the
// random number generator as a parameter, for deterministic operation.
//
//   https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
//
function shuffle(orig, rng) {
  arr = orig.slice(0);
  for (var i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(rng.gen() * (i + 1));
    var tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  return arr;
}

// Implementation of a simple linear congruential generator, using the
// parameters from Teukolsky-Vetterling-Flannery's Numerical Recipes.
//
//   https://en.wikipedia.org/wiki/Linear_congruential_generator
//
function Lcg32(seed) {
  this.state = (seed + 0xad2158e3) % 0x100000000;
  this.advance(); this.advance(); this.advance(); this.advance();
}
Lcg32.prototype.advance = function() {
  this.state = (this.state * 1664525 + 1013904223) % 0x100000000;
};
Lcg32.prototype.gen = function() {
  this.advance();
  return this.state / 0x100000000;
};

var vid = document.getElementById('vid');
var vidCounter = 0;
var clipDuration = 5000;
var clips = [
  {name: 'wicker-notthebees'},
  {name: 'zandalee-inevitable'},
  {name: 'firebirds-kiss'},
  {name: 'therock-gottago'},
  {name: 'driveangry-disrobe'},
  {name: 'faceoff-hallelujah'},
  {name: 'wildheart-sing'},
  {name: 'corelli-sing'},
  {name: 'leavinglas-meet'},
  {name: 'gone60s-letsride'},
  {name: '8mm-becausehecould'},
  {name: 'adaptation-narcissistic'},
];

// Get the permutation of clips for a given run.
//
// This computes a sequence such that the clips are always played in an order
// that appears random to humans, which very rarely should show a clip more than
// once in a single sitting.
//
// The sequence is first permuted using the runblock (blocks of 100 runs) as the
// seed, then split into groups of 6, and each group is permuted again using
// the run as the seed.
//
// By maintaing distinct groups within a runblock, seeing the same clip twice in
// a single sitting is only possible when straddling runblocks. Permuting groups
// as well adds variation between sequential runs. Within a runblock, the
// minimum spacing between two screenings of the same clip is N-6, where N is
// the total number of clips.
//
function getSequence(run) {
  var runBlock = Math.floor(run / 100);
  var permuted = shuffle(clips, new Lcg32(runBlock));

  var rng2 = new Lcg32(run);
  var permuted2 = [];
  for (var i = 0; i < permuted.length; i += 6) {
    var group = permuted.slice(i, i + 6);
    var shuffled = shuffle(group, rng2);
    permuted2 = permuted2.concat(shuffled);
  }
  return permuted2;
}

// Get the current clip from a timestamp.
function getClip(ts) {
  var total = Math.floor(ts / clipDuration);
  var run = Math.floor(total / clips.length);
  var clip = total % clips.length;

  var seq = getSequence(run);
  return seq[clip];
}

function playVid(clip) {
  if (clip.cached !== undefined) {
    vid.src = clip.cached;
  } else {
    vid.src = 'clips/' + clip.name + '.mp4';
  }
  vid.play();
  ++vidCounter;
}

function preloadClip(clip) {
  if (clip.cached === undefined) {
    var req = new XMLHttpRequest();
    req.open('GET', 'clips/' + clip.name + '.mp4', true);
    req.responseType = 'blob';
    req.onload = function() {
      if (this.status === 200) {
        clip.cached = URL.createObjectURL(this.response);
      }
    }
    req.send();
  }
}

function scheduleVid(state) {
  var nextTimestamp = state.timestamp + clipDuration;
  var firstClip = getClip(state.timestamp);
  playVid(firstClip);
  var secondClip = getClip(nextTimestamp);
  preloadClip(secondClip);
  state.timestamp = nextTimestamp;
}

window.onload = function() {
  // Wrapped in an object to pass by reference between invocations.
  var state = {timestamp: Date.now()};
  window.setInterval(scheduleVid, clipDuration, state);
  scheduleVid(state);
}

window.addEventListener("keydown", function (event) {
  switch (event.key) {
  case "ArrowDown":
    vid.volume = Math.max(0.0, vid.volume - 0.05);
    break;
  case "ArrowUp":
    vid.volume = Math.min(1.0, vid.volume + 0.05);
    break;
  default:
    return;
  }
});
<commit_msg>ncph: Change clip to prototyped object.<commit_after>// Copyright (C) 2016 ncph Authors
// This file is free software: You can redistribute it and/or modify it under
// the terms of the GNU AGPLv3 or later. See COPYING for details.

// Implementation of the Fischer-Yates-Durstenfeld O(n) shuffle algorithm. This
// variant is non-destructive (does not modify the input array), and takes the
// random number generator as a parameter, for deterministic operation.
//
//   https://en.wikipedia.org/wiki/Fisher-Yates_shuffle
//
function shuffle(orig, rng) {
  arr = orig.slice(0);
  for (var i = arr.length - 1; i > 0; i--) {
    var j = Math.floor(rng.gen() * (i + 1));
    var tmp = arr[i];
    arr[i] = arr[j];
    arr[j] = tmp;
  }
  return arr;
}

// Implementation of a simple linear congruential generator, using the
// parameters from Teukolsky-Vetterling-Flannery's Numerical Recipes.
//
//   https://en.wikipedia.org/wiki/Linear_congruential_generator
//
function Lcg32(seed) {
  this.state = (seed + 0xad2158e3) % 0x100000000;
  this.advance(); this.advance(); this.advance(); this.advance();
}
Lcg32.prototype.advance = function() {
  this.state = (this.state * 1664525 + 1013904223) % 0x100000000;
};
Lcg32.prototype.gen = function() {
  this.advance();
  return this.state / 0x100000000;
};

var vid = document.getElementById('vid');
var vidCounter = 0;
var clipDuration = 5000;

function Clip(name) {
  this.name = name;
}
Clip.prototype.path = function() {
  return 'clips/' + this.name + '.mp4';
};
Clip.prototype.play = function() {
  if (this.cached !== undefined) {
    vid.src = this.cached;
  } else {
    vid.src = this.path();
  }
  vid.play();
  ++vidCounter;
};
Clip.prototype.preload = function() {
  if (this.cached === undefined) {
    var req = new XMLHttpRequest();
    req.open('GET', this.path(), true);
    req.responseType = 'blob';
    req.onload = function() {
      if (this.status === 200) {
        this.cached = URL.createObjectURL(this.response);
      }
    };
    req.send();
  }
};

var clips = [
  new Clip('wicker-notthebees'),
  new Clip('zandalee-inevitable'),
  new Clip('firebirds-kiss'),
  new Clip('therock-gottago'),
  new Clip('driveangry-disrobe'),
  new Clip('faceoff-hallelujah'),
  new Clip('wildheart-sing'),
  new Clip('corelli-sing'),
  new Clip('leavinglas-meet'),
  new Clip('gone60s-letsride'),
  new Clip('8mm-becausehecould'),
  new Clip('adaptation-narcissistic'),
];

// Get the permutation of clips for a given run.
//
// This computes a sequence such that the clips are always played in an order
// that appears random to humans, which very rarely should show a clip more than
// once in a single sitting.
//
// The sequence is first permuted using the runblock (blocks of 100 runs) as the
// seed, then split into groups of 6, and each group is permuted again using
// the run as the seed.
//
// By maintaing distinct groups within a runblock, seeing the same clip twice in
// a single sitting is only possible when straddling runblocks. Permuting groups
// as well adds variation between sequential runs. Within a runblock, the
// minimum spacing between two screenings of the same clip is N-6, where N is
// the total number of clips.
//
function getSequence(run) {
  var runBlock = Math.floor(run / 100);
  var permuted = shuffle(clips, new Lcg32(runBlock));

  var rng2 = new Lcg32(run);
  var permuted2 = [];
  for (var i = 0; i < permuted.length; i += 6) {
    var group = permuted.slice(i, i + 6);
    var shuffled = shuffle(group, rng2);
    permuted2 = permuted2.concat(shuffled);
  }
  return permuted2;
}

// Get the current clip from a timestamp.
function getClip(ts) {
  var total = Math.floor(ts / clipDuration);
  var run = Math.floor(total / clips.length);
  var clip = total % clips.length;
  var seq = getSequence(run);
  return seq[clip];
}

// Scheduler to be run every clipDuration milliseconds.
function scheduleVid(state) {
  var nextTimestamp = state.timestamp + clipDuration;
  getClip(state.timestamp).play();
  getClip(nextTimestamp).preload();
  state.timestamp = nextTimestamp;
}

// Run this event at startup.
window.onload = function() {
  // Wrapped in an object to pass by reference between invocations.
  var state = {timestamp: Date.now()};
  window.setInterval(scheduleVid, clipDuration, state);
  scheduleVid(state);
};

// Register keyboard event handler.
window.addEventListener('keydown', function(event) {
  switch (event.key) {
  case 'ArrowDown':
    vid.volume = Math.max(0.0, vid.volume - 0.05);
    break;
  case 'ArrowUp':
    vid.volume = Math.min(1.0, vid.volume + 0.05);
    break;
  default:
    return;
  }
});
<|endoftext|>