<commit_before>var dygraphs_data;
var g;
var timer = 1000*60*1;
var cntdown = 1000*REFRESH_INTER;
var offset = -1;
var one_day = -1;
var update_countdown;

$('#cntdown').text(REFRESH_INTER);

if (COUCHDB) {
  var data_checker;
  dygraphs_data = [];

  $('#timemachine').val(DEFAULT_SPAN);
  $('#range-value').text(DEFAULT_SPAN);

  function getDoc(id) {
    $.couch.db('bandwidth').openDoc(id, {
      success: function(data) {
        dygraphs_data.push([
            parseFloat(data['_id']),
            parseFloat(data['latency']),
            parseFloat(data['upload']),
            parseFloat(data['download'])
        ]);
      },
      error: function(e) {
        one_day -= 1;
      }
    });
  }

  $('#timemachine').mousemove(function() {
    val = $('#timemachine').val();
    $('#range-value').text(val);
  });
  $('#timemachine').change(function() {
    dygraphs_data = [];
    $('#timemachine').prop('disabled', true);
    clearInterval(update_countdown);
    $('#progress-bar').attr('aria-valuenow', 0);
    $('#progress-bar').css('width', '0%');
    $('#progress').show();
    $('#loading').show();
    get_data();
  });

  function get_data() {
    $.couch.db("bandwidth").allDocs({
      success: function(data) {
        offset = data['rows'].length;
        docs = [];
        start_time = moment(parseFloat(data['rows'][0]['id']), 's');

        time_span = moment().diff(start_time.unix(), 'hours');
        max_timemachine = Math.ceil(moment.duration(time_span, 's').asHours());
        $('#timemachine').attr('max', max_timemachine);
        $.each(data['rows'], function(index, obj) {
          timestamp = parseFloat(obj['id']);
          if (moment(timestamp).isBetween(moment().subtract($('#timemachine').val(), 'hours').unix(), moment().unix(), null, '[]')) {
            docs.push(obj['id']);
          }
        });
        one_day = docs.length;
        $.each(docs, function(index, id) {
          getDoc(id);
        });
      }
    });
    data_checker = setInterval(function() {
      if (dygraphs_data.length == one_day) {
        clearInterval(data_checker);
        dygraphs_data.sort(function(a, b) {
          var keyA = a[0];
          var keyB = b[0];
          if(keyA < keyB) return -1;
          if(keyA > keyB) return 1;
          return 0;
        });
        draw_graph();
        $('#time-slider').show();
        $('#progress').hide();
        $('#timemachine').prop('disabled', false);
        $('#loading').hide();
      } else {
        percent = Math.round(dygraphs_data.length*100/one_day);
        $('#progress-bar').attr('aria-valuenow', percent);
        $('#progress-bar').css('width', percent+'%');
      }
    }, 200);
  }
  $(document).ready(function() {
    get_data();
  });
} else { // just download the log.csv file
  dygraphs_data = '/log.csv';
  draw_graph();
}
var legend_display = 'always';
if ($(window).width() < 768) {
  legend_display = 'onmouseover';
}

function formatDate(d, short=false) {
  if (short) {
    return moment.unix(d).format('H:mm');
  } else {
    return moment.unix(d).format('D MMM YYYY - H:mm:ss');
  }
}
function get_max_min(cur_max, cur_min, val) {
    if (val > cur_max) {
      cur_max = val;
    }
    if (cur_min < 0 && val > 0) {
      cur_min = val;
    }
    if (val > 0 && val < cur_min) {
      cur_min = val;
    }
    return [cur_max, cur_min];
}
function averages() {
  avg_up = 0;
  avg_down = 0;
  avg_lat = 0;
  down_max_speed = 0;
  down_min_speed = -1;
  up_max_speed = 0;
  up_min_speed = -1;
  lat_max = 0;
  lat_min = -1;
  for (var i=0; i<g.numRows(); i++) {
    up = parseFloat(g.getValue(i,2));
    down = parseFloat(g.getValue(i,3));
    lat = parseFloat(g.getValue(i,1));

    avg_lat  += lat;
    avg_up   += up;
    avg_down += down;

    vals = get_max_min(down_min_speed,down_max_speed, down);
    down_max_speed = vals[0];
    down_min_speed = vals[1];

    vals = get_max_min(up_min_speed,up_max_speed, up);
    up_max_speed = vals[0];
    up_min_speed = vals[1];

    vals = get_max_min(lat_max,lat_min, lat);
    lat_max = vals[0];
    lat_min = vals[1];

  }
  if (SHOW_DOWN_MIN_MAX) {
    $('span[name="down_avg"]').text((avg_down/g.numRows()).toFixed(2)+'Mbit/s ('+down_max_speed+'/'+down_min_speed+'Mbit/s)');
    $('span[name="down_avg"]').attr('title', 'Download (average, max, min)');
  } else {
    $('span[name="down_avg"]').text((avg_down/g.numRows()).toFixed(2)+'Mbit/s');
    $('span[name="down_avg"]').attr('title', 'Download (max: '+down_max_speed+', min: '+down_min_speed+'Mbit/s)');
  }
  if (SHOW_UP_MIN_MAX) {
    $('span[name="up_avg"]').text((avg_up/g.numRows()).toFixed(2)+'Mbit/s ('+up_max_speed+'/'+up_min_speed+'Mbit/s)');
    $('span[name="up_avg"]').attr('title', 'Upload (average, max, min)');
  } else {
    $('span[name="up_avg"]').text((avg_up/g.numRows()).toFixed(2)   +'Mbit/s');
    $('span[name="up_avg"]').attr('title', 'Upload (max: '+up_max_speed+' min: '+up_min_speed+'Mbit/s)');
  }
  if (SHOW_LAT_MIN_MAX) {
    $('span[name="lat_avg"]').text((avg_lat/g.numRows()).toFixed(2)  +'ms ('+lat_min+'/'+lat_max+'s)');
    $('span[name="lat_avg"]').attr('title', 'Latency (average, min, max)');
  } else {
    $('span[name="lat_avg"]').text((avg_lat/g.numRows()).toFixed(2)  +'ms');
    $('span[name="lat_avg"]').attr('title', 'Latency (min: '+lat_min+' max: '+lat_max+'s)');
  }
}

function draw_graph() {
  g = new Dygraph(
      document.getElementById("dygraph"),
      dygraphs_data,
      {
        labels: [ "Date", "Latency", "Upload", "Download" ],
        series: {
          "Upload": { axis: 'y1'},
          "Download": { axis: 'y1', showInRangeSelector: true },
          "Latency": { axis: 'y2' }
        },
        legend: legend_display,
        labelsSeparateLines: true,
        connectSeparatedPoints: true,
        fillGraph: true,
        colors: [
          "purple",
          "blue",
          "green",
        ],
        ylabel: "Bandwidth (Mbit/s)",
        y2label: "Latency (ms)",
        axes: {
          x: {
            valueFormatter: function(timestamp) {
              return formatDate(timestamp);
            },
            axisLabelFormatter: function(timestamp) {
              return formatDate(timestamp, true);
            }
          },
          y: {
            valueRange: [0, MAX_BW+50],
          },
          y2: {
            independentTicks: true,
            valueRange: [0, MAX_BW+50],
            labelsKMB: true,
          }
        },
        underlayCallback: function(canvas, area, g) {
          canvas.strokeStyle = 'red';
          var lines = [(MAX_BW*0.8),MAX_BW];
          var range = g.xAxisRange();
          for (var idy = 0; idy < lines.length; idy++) {
            var canvasy = g.toDomYCoord(lines[idy]);
            canvas.beginPath();
            canvas.moveTo(g.toDomXCoord(range[0]), canvasy);
            canvas.lineTo(g.toDomXCoord(range[1]), canvasy);
            canvas.lineWidth = 2;
            canvas.stroke();
            canvas.closePath();
          }
        },
        showRangeSelector: true,
        rangeSelectorPlotFillColor: 'green',
      }
  );
  g.ready(function() {
    averages();
    update_countdown = setInterval(function() { count_down() }, 1000);
  });
}

function updateGraph() {
  x = g.xAxisRange()[0];
  if (COUCHDB) {
    $('#timemachine').prop('disabled', true);
    $.couch.db('bandwidth').allDocs({
      skip: offset,
      success: function(data) {
        docs = [];
        $.each(data['rows'], function(index, obj) {
          getDoc(obj['id']);
        });

        if (data['rows'].length != 0) {
          data_checker = setInterval(function() {
            if (dygraphs_data.length == (one_day + data['rows'].length)) {
              clearInterval(data_checker);
              dygraphs_data.sort(function(a, b) {
                var keyA = a[0];
                var keyB = b[0];
                if(keyA < keyB) return -1;
                if(keyA > keyB) return 1;
                return 0;
              });
              g.updateOptions({
                file: dygraphs_data,
                dateWindow: [
                  x,
                  moment().unix()
                ]
              });
              offset += data['rows'].length;
              one_day += data['rows'].length;
              $('#timemachine').prop('disabled', false);
            } else {
              console.log('Waiting for dataset');
            }
          }, 500);
        } else {
          console.log('No new data for now');
        }
      }
    });
  } else {
    g.updateOptions({
      file: dygraphs_data,
      dateWindow: [
        x,
        moment().unix()
      ]
    });
  }
  g.ready(averages);
}

function count_down() {
  if (cntdown <= 0) {
    cntdown = timer;
    updateGraph();
  }
  cntdown = cntdown - 1000;
  $('#cntdown').text(cntdown/1000);
}
<commit_msg>code refactoring<commit_after>var dygraphs_data;
var g;
var timer = 1000*60*1;
var cntdown = 1000*REFRESH_INTER;
var offset = -1;
var one_day = -1;
var update_countdown;

var legend_display = 'always';
if ($(window).width() < 768) {
  legend_display = 'onmouseover';
}

$('#cntdown').text(REFRESH_INTER);

function count_down() {
  if (cntdown <= 0) {
    cntdown = timer;
    updateGraph();
  }
  cntdown = cntdown - 1000;
  $('#cntdown').text(cntdown/1000);
}

if (COUCHDB) {
  var data_checker;
  dygraphs_data = [];

  $('#timemachine').val(DEFAULT_SPAN);
  $('#range-value').text(DEFAULT_SPAN);

  function getDoc(id) {
    $.couch.db('bandwidth').openDoc(id, {
      success: function(data) {
        dygraphs_data.push([
            parseFloat(data['_id']),
            parseFloat(data['latency']),
            parseFloat(data['upload']),
            parseFloat(data['download'])
        ]);
      },
      error: function(e) {
        one_day -= 1;
      }
    });
  }

  function sort_data(a,b) {
    var keyA = a[0];
    var keyB = b[0];
    if(keyA < keyB) return -1;
    if(keyA > keyB) return 1;
    return 0;
  }

  $('#timemachine').mousemove(function() {
    val = $('#timemachine').val();
    $('#range-value').text(val);
  });
  $('#timemachine').change(function() {
    dygraphs_data = [];
    $('#timemachine').prop('disabled', true);
    clearInterval(update_countdown);
    $('#progress-bar').attr('aria-valuenow', 0);
    $('#progress-bar').css('width', '0%');
    $('#progress').show();
    $('#loading').show();
    get_data();
  });

  function get_data() {
    $.couch.db("bandwidth").allDocs({
      success: function(data) {
        offset = data['rows'].length;
        docs = [];
        start_time = moment(parseFloat(data['rows'][0]['id']), 's');

        time_span = moment().diff(start_time.unix(), 'hours');
        max_timemachine = Math.ceil(moment.duration(time_span, 's').asHours());
        $('#timemachine').attr('max', max_timemachine);
        $.each(data['rows'], function(index, obj) {
          timestamp = parseFloat(obj['id']);
          if (moment(timestamp).isBetween(moment().subtract($('#timemachine').val(), 'hours').unix(), moment().unix(), null, '[]')) {
            docs.push(obj['id']);
          }
        });
        one_day = docs.length;
        $.each(docs, function(index, id) {
          getDoc(id);
        });
      }
    });
    data_checker = setInterval(function() {
      if (dygraphs_data.length == one_day) {
        clearInterval(data_checker);
        dygraphs_data.sort(sort_data);
        draw_graph();
        $('#time-slider').show();
        $('#progress').hide();
        $('#timemachine').prop('disabled', false);
        $('#loading').hide();
      } else {
        percent = Math.round(dygraphs_data.length*100/one_day);
        $('#progress-bar').attr('aria-valuenow', percent);
        $('#progress-bar').css('width', percent+'%');
      }
    }, 200);
  }
  $(document).ready(function() {
    get_data();
  });
} else { // just download the log.csv file
  dygraphs_data = '/log.csv';
  draw_graph();
}
function formatDate(d, short=false) {
  if (short) {
    return moment.unix(d).format('H:mm');
  } else {
    return moment.unix(d).format('D MMM YYYY - H:mm:ss');
  }
}
function get_max_min(cur_max, cur_min, val) {
    if (val > cur_max) {
      cur_max = val;
    }
    if (cur_min < 0 && val > 0) {
      cur_min = val;
    }
    if (val > 0 && val < cur_min) {
      cur_min = val;
    }
    return [cur_max, cur_min];
}
function averages() {
  avg_up = 0;
  avg_down = 0;
  avg_lat = 0;
  down_max_speed = 0;
  down_min_speed = -1;
  up_max_speed = 0;
  up_min_speed = -1;
  lat_max = 0;
  lat_min = -1;
  for (var i=0; i<g.numRows(); i++) {
    up = parseFloat(g.getValue(i,2));
    down = parseFloat(g.getValue(i,3));
    lat = parseFloat(g.getValue(i,1));

    avg_lat  += lat;
    avg_up   += up;
    avg_down += down;

    vals = get_max_min(down_min_speed,down_max_speed, down);
    down_max_speed = vals[0];
    down_min_speed = vals[1];

    vals = get_max_min(up_min_speed,up_max_speed, up);
    up_max_speed = vals[0];
    up_min_speed = vals[1];

    vals = get_max_min(lat_max,lat_min, lat);
    lat_max = vals[0];
    lat_min = vals[1];

  }
  if (SHOW_DOWN_MIN_MAX) {
    $('span[name="down_avg"]').text((avg_down/g.numRows()).toFixed(2)+'Mbit/s ('+down_max_speed+'/'+down_min_speed+'Mbit/s)');
    $('span[name="down_avg"]').attr('title', 'Download (average, max, min)');
  } else {
    $('span[name="down_avg"]').text((avg_down/g.numRows()).toFixed(2)+'Mbit/s');
    $('span[name="down_avg"]').attr('title', 'Download (max: '+down_max_speed+', min: '+down_min_speed+'Mbit/s)');
  }
  if (SHOW_UP_MIN_MAX) {
    $('span[name="up_avg"]').text((avg_up/g.numRows()).toFixed(2)+'Mbit/s ('+up_max_speed+'/'+up_min_speed+'Mbit/s)');
    $('span[name="up_avg"]').attr('title', 'Upload (average, max, min)');
  } else {
    $('span[name="up_avg"]').text((avg_up/g.numRows()).toFixed(2)   +'Mbit/s');
    $('span[name="up_avg"]').attr('title', 'Upload (max: '+up_max_speed+' min: '+up_min_speed+'Mbit/s)');
  }
  if (SHOW_LAT_MIN_MAX) {
    $('span[name="lat_avg"]').text((avg_lat/g.numRows()).toFixed(2)  +'ms ('+lat_min+'/'+lat_max+'s)');
    $('span[name="lat_avg"]').attr('title', 'Latency (average, min, max)');
  } else {
    $('span[name="lat_avg"]').text((avg_lat/g.numRows()).toFixed(2)  +'ms');
    $('span[name="lat_avg"]').attr('title', 'Latency (min: '+lat_min+' max: '+lat_max+'s)');
  }
}

function draw_graph() {
  g = new Dygraph(
      document.getElementById("dygraph"),
      dygraphs_data,
      {
        labels: [ "Date", "Latency", "Upload", "Download" ],
        series: {
          "Upload": { axis: 'y1'},
          "Download": { axis: 'y1', showInRangeSelector: true },
          "Latency": { axis: 'y2' }
        },
        legend: legend_display,
        labelsSeparateLines: true,
        connectSeparatedPoints: true,
        fillGraph: true,
        colors: [
          "purple",
          "blue",
          "green",
        ],
        ylabel: "Bandwidth (Mbit/s)",
        y2label: "Latency (ms)",
        axes: {
          x: {
            valueFormatter: function(timestamp) {
              return formatDate(timestamp);
            },
            axisLabelFormatter: function(timestamp) {
              return formatDate(timestamp, true);
            }
          },
          y: {
            valueRange: [0, MAX_BW+50],
          },
          y2: {
            independentTicks: true,
            valueRange: [0, MAX_BW+50],
            labelsKMB: true,
          }
        },
        underlayCallback: function(canvas, area, g) {
          canvas.strokeStyle = 'red';
          var lines = [(MAX_BW*0.8),MAX_BW];
          var range = g.xAxisRange();
          for (var idy = 0; idy < lines.length; idy++) {
            var canvasy = g.toDomYCoord(lines[idy]);
            canvas.beginPath();
            canvas.moveTo(g.toDomXCoord(range[0]), canvasy);
            canvas.lineTo(g.toDomXCoord(range[1]), canvasy);
            canvas.lineWidth = 2;
            canvas.stroke();
            canvas.closePath();
          }
        },
        showRangeSelector: true,
        rangeSelectorPlotFillColor: 'green',
      }
  );
  g.ready(function() {
    averages();
    update_countdown = setInterval(function() { count_down() }, 1000);
  });
}

function updateGraph() {
  x = g.xAxisRange()[0];
  if (COUCHDB) {
    $('#timemachine').prop('disabled', true);
    $.couch.db('bandwidth').allDocs({
      skip: offset,
      success: function(data) {
        docs = [];
        $.each(data['rows'], function(index, obj) {
          getDoc(obj['id']);
        });

        if (data['rows'].length != 0) {
          data_checker = setInterval(function() {
            if (dygraphs_data.length == (one_day + data['rows'].length)) {
              clearInterval(data_checker);
              dygraphs_data.sort(sort_data);
              g.updateOptions({
                file: dygraphs_data,
                dateWindow: [
                  x,
                  moment().unix()
                ]
              });
              offset += data['rows'].length;
              one_day += data['rows'].length;
              $('#timemachine').prop('disabled', false);
            } else {
              console.log('Waiting for dataset');
            }
          }, 500);
        } else {
          console.log('No new data for now');
          $('#timemachine').prop('disabled', false);
        }
      }
    });
  } else {
    g.updateOptions({
      file: dygraphs_data,
      dateWindow: [
        x,
        moment().unix()
      ]
    });
  }
  g.ready(averages);
}

<|endoftext|>


<commit_before>import React from 'react'
import PropTypes from 'prop-types'

class Counter2 extends React.Component {
  constructor () {
    super()
    this.state = {
      items: [],
    }
  }
  fetchData (url) {
    this.setState({ isLoading: true })
    fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw Error(response.statusText)
          }
          this.setState({ isLoading: false })
          return response
        })
        .then((response) => response.json())
        .then((items) => this.setState({ items })) // ES6 property value shorthand for { items: items }
        .catch(() => this.setState({ hasErrored: true }))
  }
  componentDidMount () {
    this.fetchData('http://5826ed963900d612000138bd.mockapi.io/items')
  }
  render () {
    if (this.state.hasErrored) {
      return
Sorry! There was an error loading the items

    }
    if (this.state.isLoading) {
      return
Loading…

    }
    return (

        {this.state.items.map((item) => (

            {item.label}

                ))}

    )
  }
}

Counter2.propTypes = {
  counter: PropTypes.number.isRequired,
  increment: PropTypes.func.isRequired,
  doubleAsync: PropTypes.func.isRequired,
}

export default Counter2
<commit_msg>ok for fetch without redux<commit_after>import React from 'react'
import PropTypes from 'prop-types'

class Counter2 extends React.Component {
  constructor () {
    super()
    this.state = {
      items: [],
    }
  }
  fetchData (url) {
    this.setState({ isLoading: true })
    fetch(url)
        .then((response) => {
          if (!response.ok) {
            throw Error(response.statusText)
          }
          this.setState({ isLoading: false })
          return response
        })
        .then((response) => response.json())
        .then((items) => this.setState({ items })) // ES6 property value shorthand for { items: items }
        .catch(() => this.setState({ hasErrored: true }))
  }
  componentDidMount () {
    this.fetchData('http://5826ed963900d612000138bd.mockapi.io/items')
  }
  render () {
    if (this.state.hasErrored) {
      return
Sorry! There was an error loading the items

    }
    if (this.state.isLoading) {
      return
Loading…

    }
    return (

        {this.state.items.map((item) => (

            {item.label}

          ))}

    )
  }
}

Counter2.propTypes = {
  itemsr: PropTypes.object.isRequired,
  isLoadingt: PropTypes.func.isRequired,
  hasErroredc: PropTypes.func.isRequired,
}

export default Counter2
<|endoftext|>


<commit_before>function readURL(input) {
    if (input.files && input.files[0]) {
        var image = new FileReader();
        image.onload = function (e) {
            $('#myImage')
                .attr('src', e.target.result)
                .width(400)
                .height(300);
        };
        image.crossOrigin="";
        image.readAsDataURL(input.files[0]);
    }
}

/* Converts image to canvas
 *
 * Input      Type      Name
 * imageId    String    id of HTML img
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         Object    used for canvas manipulation
 */
function imageToCanvas(imageId, canvasId){
    var image = document.getElementById(imageId);
    var canvas = document.getElementById(canvasId);
    canvas.width = image.naturalWidth;
    canvas.height = image.naturalHeight;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    return ctx;
}

/* Converts canvas to image
 *
 * Input      Type      Name
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         .png      image file
 */
function canvasToImage(canvasId) {
    var image = new Image();
    image.src = canvasId.toDataURL("image/png");
    return image;
}

/* Takes a canvas and image and returns the
 * top ten averaged colors
 *
 * Input      Type      Name
 * imageId    String    id of HTML img
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         Array     10 hex values
 */
function findDominateColors(imageId, canvasId){
    var r, g, b;
    var h, s, l;
    var hsl, rgb, weight;
    var dominateColors = new Array();
    var hslTable = new HashTable();
    var hslHeap = new binaryHeap();

    imageToCanvas(imageId, canvasId);
    var c = document.getElementById(canvasId);
    var ctx = c.getContext("2d");
    var imgData = ctx.getImageData(0,0,c.width,c.height);

    /*convert canvas into hsvtable*/
    for (var i=0;i<imgData.data.length;i+=4)
    {
        /**
         * i   = Red (r) - The color red (from 0-255)
         * i+1 = Green (g) - The color green (from 0-255)
         * i+2 = Blue (b) - The color blue (from 0-255)
         * i+3 = Alpha (a) - The alpha channel (from 0-255; 0 is transparent and 255 is fully visible)
         */
        r = imgData.data[i];
        g = imgData.data[i+1];
        b = imgData.data[i+2];
        /*Alpha is not used*/
        hsl = rgbToHsl(r, g, b);
        h = hsl[0];
        s = hsl[1];
        l = hsl[2];
        /*divide values into 226 different coloured buckets
         * buckets are labelled by
         * 5 white
         * 5 black
         * 216 color
         */
        if( l <= 0.05){
            /*black cylinder*/
            /*divided into 5 slices
             * 0   =< h < 72  key:  Black0
             * 72  =< h < 144 key:  Black1
             * 144 =< h < 216 key:  Black2
             * 216 =< h < 288 key:  Black3
             * 288 =< h < 360 key:  Black4
            **/
            addToBucket  (hslTable, 'Black'+Math.floor(h/72), hsl);
        } else if ( 0.95 <= l){
            /*white bucket*/
            /*divided into 5 slices
             * 0   =< h < 72  key:  White0
             * 72  =< h < 144 key:  White1
             * 144 =< h < 216 key:  White2
             * 216 =< h < 288 key:  White3
             * 288 =< h < 360 key:  White4
            **/
            addToBucket  (hslTable, 'White'+Math.floor(h/72), hsl);
        } else {
            /*coloured bucket*/
             /*divided into 36 slices
             * 0   =< h < 10   key(firstHalf): Color0,
             * 10  =< h < 20   key(firstHalf): Color1,
             * ...
             * 350 =< h < 360  key(firstHalf): Color36,
             *
             * each slice divided into 6 equal volume sections
             * 0    =< s <= 40.8  key(secondHalf): 0
             * 40.8  < s <= 57.7  key(secondHalf): 1
             * 57.7  < s <= 70.7  key(secondHalf): 2
             * 70.7  < s <= 81.6  key(secondHalf): 3
             * 81.6  < s <= 91.3  key(secondHalf): 4
             * 91.3  < s <= 100   key(secondHalf): 5
             *
             * example: h=15;s=30;l=10; key= 'Color1,0'
             */
            addToBucket  (hslTable, 'Color'+Math.floor(h/10)+','+section(s), hsl);
        }
    }
    hslTable.each(function(k, v) {
        hslHeap.push(v);
        //document.write('key is: ' + k + ', value is: ' + v + '
');
    });
    for(var i=0;i<10;i++){
        if(hslHeap.size()==0)
            break;
        hsl = hslHeap.pop()[0];
        rgb = hslToRgb(hsl[0],hsl[1],hsl[2]);
        dominateColors[i] = rgbToHex(rgb[0],rgb[1],rgb[2]);

    }
        displayColors(dominateColors, canvasId);
}

/* helper function for findDominateColors
 * takes the saturation value and returns the
 * bucket value that it should be placed in
 */
function section(s){
    if(s < 40.8)
        return 0;
    else if( s < 57.7)
        return 1;
    else if( s < 70.7)
        return 2;
    else if( s < 81.6)
        return 3;
    else if( s < 91.3)
        return 4;
    else if( s < 100)
        return 5;
}

/* helper function for findDominateColors
 * takes h,s,and l and averages them with
 * the existing bucket value.
 */
function addToBucket  (hTable, key, hsl ){
    var value, oldHsl, weight =1;
    if(hTable.hasItem(key)){
        value = hTable.getItem(key);
        oldHsl = value[0];
        weight = value[1];
        hsl[0] = (hsl[0]+(weight*oldHsl[0]))/(weight+1);
        hsl[1] = (hsl[1]+(weight*oldHsl[1]))/(weight+1);
        hsl[2] = (hsl[2]+(weight*oldHsl[2]))/(weight+1);
        weight++;
    }
    hTable.setItem(key, [hsl, weight]);
}

/* helper function for findDominateColors
 * displays a table of the hex value and it
 * corresponding using the array of 10 hex values
 */
function displayColors(dominateColors, canvasId){
    var table = $('

');
    var row1 = $('

');
    var row2 = $('

');
    var cell1, cell2;

    $('#dominateColors').empty();

    row1.append('Color	');
    row2.append('Hex	');

    for(i=0; i<10; i++)
    {
        cell1 = $('	').text('').css('background-color',''+dominateColors[i]);
        cell2 = $('	').text('' + dominateColors[i]);
        row1.append(cell1);
        row2.append(cell2);
    }

    table.append(row1);
    table.append(row2);

    $('#dominateColors').append(table);
}

<commit_msg>script now finds the closest div to out put color scheme<commit_after>function readURL(input) {
    if (input.files && input.files[0]) {
        var image = new FileReader();
        image.onload = function (e) {
            $('#myImage')
                .attr('src', e.target.result)
                .width(400)
                .height(300);
        };
        image.crossOrigin="";
        image.readAsDataURL(input.files[0]);
    }
}

/* Converts image to canvas
 *
 * Input      Type      Name
 * imageId    String    id of HTML img
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         Object    used for canvas manipulation
 */
function imageToCanvas(imageId, canvasId){
    var image = document.getElementById(imageId);
    var canvas = document.getElementById(canvasId);
    canvas.width = image.naturalWidth;
    canvas.height = image.naturalHeight;
    var ctx = canvas.getContext("2d");
    ctx.drawImage(image, 0, 0);
    return ctx;
}

/* Converts canvas to image
 *
 * Input      Type      Name
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         .png      image file
 */
function canvasToImage(canvasId) {
    var image = new Image();
    image.src = canvasId.toDataURL("image/png");
    return image;
}

/* Takes a canvas and image and returns the
 * top ten averaged colors
 *
 * Input      Type      Name
 * imageId    String    id of HTML img
 * canvasId   String    id of HTML canvas
 *
 * Return  Type      Name
 *         Array     10 hex values
 */
function findDominateColors(imageId, canvasId){
    var r, g, b;
    var h, s, l;
    var hsl, rgb, weight;
    var dominateColors = new Array();
    var hslTable = new HashTable();
    var hslHeap = new binaryHeap();

    imageToCanvas(imageId, canvasId);
    var c = document.getElementById(canvasId);
    var ctx = c.getContext("2d");
    var imgData = ctx.getImageData(0,0,c.width,c.height);

    /*convert canvas into hsvtable*/
    for (var i=0;i<imgData.data.length;i+=4)
    {
        /**
         * i   = Red (r) - The color red (from 0-255)
         * i+1 = Green (g) - The color green (from 0-255)
         * i+2 = Blue (b) - The color blue (from 0-255)
         * i+3 = Alpha (a) - The alpha channel (from 0-255; 0 is transparent and 255 is fully visible)
         */
        r = imgData.data[i];
        g = imgData.data[i+1];
        b = imgData.data[i+2];
        /*Alpha is not used*/
        hsl = rgbToHsl(r, g, b);
        h = hsl[0];
        s = hsl[1];
        l = hsl[2];
        /*divide values into 226 different coloured buckets
         * buckets are labelled by
         * 5 white
         * 5 black
         * 216 color
         */
        if( l <= 0.05){
            /*black cylinder*/
            /*divided into 5 slices
             * 0   =< h < 72  key:  Black0
             * 72  =< h < 144 key:  Black1
             * 144 =< h < 216 key:  Black2
             * 216 =< h < 288 key:  Black3
             * 288 =< h < 360 key:  Black4
            **/
            addToBucket  (hslTable, 'Black'+Math.floor(h/72), hsl);
        } else if ( 0.95 <= l){
            /*white bucket*/
            /*divided into 5 slices
             * 0   =< h < 72  key:  White0
             * 72  =< h < 144 key:  White1
             * 144 =< h < 216 key:  White2
             * 216 =< h < 288 key:  White3
             * 288 =< h < 360 key:  White4
            **/
            addToBucket  (hslTable, 'White'+Math.floor(h/72), hsl);
        } else {
            /*coloured bucket*/
             /*divided into 36 slices
             * 0   =< h < 10   key(firstHalf): Color0,
             * 10  =< h < 20   key(firstHalf): Color1,
             * ...
             * 350 =< h < 360  key(firstHalf): Color36,
             *
             * each slice divided into 6 equal volume sections
             * 0    =< s <= 40.8  key(secondHalf): 0
             * 40.8  < s <= 57.7  key(secondHalf): 1
             * 57.7  < s <= 70.7  key(secondHalf): 2
             * 70.7  < s <= 81.6  key(secondHalf): 3
             * 81.6  < s <= 91.3  key(secondHalf): 4
             * 91.3  < s <= 100   key(secondHalf): 5
             *
             * example: h=15;s=30;l=10; key= 'Color1,0'
             */
            addToBucket  (hslTable, 'Color'+Math.floor(h/10)+','+section(s), hsl);
        }
    }
    hslTable.each(function(k, v) {
        hslHeap.push(v);
        //document.write('key is: ' + k + ', value is: ' + v + '
');
    });
    for(var i=0;i<10;i++){
        if(hslHeap.size()==0)
            break;
        hsl = hslHeap.pop()[0];
        rgb = hslToRgb(hsl[0],hsl[1],hsl[2]);
        dominateColors[i] = rgbToHex(rgb[0],rgb[1],rgb[2]);

    }
        displayColors(dominateColors, canvasId);
}

/* helper function for findDominateColors
 * takes the saturation value and returns the
 * bucket value that it should be placed in
 */
function section(s){
    if(s < 40.8)
        return 0;
    else if( s < 57.7)
        return 1;
    else if( s < 70.7)
        return 2;
    else if( s < 81.6)
        return 3;
    else if( s < 91.3)
        return 4;
    else if( s < 100)
        return 5;
}

/* helper function for findDominateColors
 * takes h,s,and l and averages them with
 * the existing bucket value.
 */
function addToBucket  (hTable, key, hsl ){
    var value, oldHsl, weight =1;
    if(hTable.hasItem(key)){
        value = hTable.getItem(key);
        oldHsl = value[0];
        weight = value[1];
        hsl[0] = (hsl[0]+(weight*oldHsl[0]))/(weight+1);
        hsl[1] = (hsl[1]+(weight*oldHsl[1]))/(weight+1);
        hsl[2] = (hsl[2]+(weight*oldHsl[2]))/(weight+1);
        weight++;
    }
    hTable.setItem(key, [hsl, weight]);
}

/* helper function for findDominateColors
 * displays a table of the hex value and it
 * corresponding using the array of 10 hex values
 */
function displayColors(dominateColors, canvasId){
    var table = $('

');
    var row1 = $('

');
    var row2 = $('

');
    var cell1, cell2;

    $(canvasId).closest('#dominateColors').empty();

    row1.append('Color	');
    row2.append('Hex	');

    for(i=0; i<10; i++)
    {
        cell1 = $('	').text('').css('background-color',''+dominateColors[i]);
        cell2 = $('	').text('' + dominateColors[i]);
        row1.append(cell1);
        row2.append(cell2);
    }

    table.append(row1);
    table.append(row2);

    $(canvasId).closest('#dominateColors').append(table);
}
<|endoftext|>


<commit_before>var primary_canvas = document.getElementById("primary");
var context = primary_canvas.getContext("2d");

context.beginPath();
context.arc(95, 85, 40, 0, 2*Math.PI);
context.closePath();
context.lineWidth = 2;
context.strokeStyle = "#f0e6a3"
context.stroke();<commit_msg>Added calculation for determining sun graphic position for a given angle<commit_after>function getSunset() {

};

function getSunPosition() {
	center_x = 300;
	center_y = 300;
	radius = 200;
	angle = 0;
	x = center_x + radius * Math.cos(angle * (Math.PI / 180));
	y = center_y + radius * Math.sin(angle * (Math.PI / 180));
	return [x,y];
};

//Setup canvas
var primary_canvas = document.getElementById("primary");
var context = primary_canvas.getContext("2d");

//Draw outer circle
context.beginPath();
context.arc(300, 300, 200, 0, 2*Math.PI);
context.closePath();
context.lineWidth = 2;
context.strokeStyle = "#f0e6a3";
context.stroke();

//Draw sun
var sun_position = getSunPosition();
context.beginPath();
context.arc(sun_position[0], sun_position[1], 30, 0, 2*Math.PI);
context.closePath();
context.fillStyle = "#f0e6a3";
context.fill();<|endoftext|>


<commit_before>var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var imageData = context.createImageData(canvas.width, canvas.height);

var Convert = {
  //TODO separate this into module? acts like Math.
  ft_mm : function(ft) {
    //1 ft = 304.8 mm
    return ft * 304.8; }
};

var WallRobot = function(opts) {
  //all working units are in MM! MM is "native".

  // horizontal distance from motors to side of board in mm
  this.MOTOR_SIDE_OFFSET = opts.MOTOR_SIDE_OFFSET;

  // height of motors above top of drawing area in mm
  this.MOTOR_HEIGHT = opts.MOTOR_HEIGHT;

  this.DRAW_AREA_WIDTH = opts.DRAW_AREA_WIDTH;
  this.DRAW_AREA_HEIGHT = opts.DRAW_AREA_HEIGHT;

  this.STRING_LEN_PER_STEP = opts.STRING_LEN_PER_STEP;

  // Right now displacement vectors are named like l_p meaning point L to point P.
  // CONSTANT vectors are uppercase and variable vectors are lowercase.
  //
  // **** VECTOR SYMBOL KEY ****
  // L   Left Stepper Rotor position
  // R   Right Stepper Rotor position
  // O   Origin of drawing area, where (x,y) = (0,0)
  // P   Marker Position

  // this.o_p = new Victor(0, 0);
  this.L_R = new Victor(this.MOTOR_SIDE_OFFSET*2 + this.DRAW_AREA_WIDTH, 0); //horizontal dist btw steppers

  // Assume that both steppers have the same y-axis displacement from
  // their side of the drawing area.
  // IE, they should be horizontally centered.
  this.L_O = new Victor(this.MOTOR_SIDE_OFFSET, this.MOTOR_HEIGHT);

  //The marker starts at (0,0) so L_O = l_p
  this.l_p = this.L_O.clone();

  // TODO SOON use a getter instead, this is an ugly hack!!!
  this.get_r_p = function() { return new Victor(this.l_p.x - this.L_R.x, this.l_p.y);};
  // calculate r_p
  this.r_p = this.get_r_p();

  // TODO SOON same hack ugh
  this.get_o_p = function() { return this.l_p.clone().subtract(this.L_O); };
  this.o_p = this.get_o_p();

  //initialize string lengths
  this.string_len_left = this.l_p.length();
  this.string_len_right = this.r_p.length();

  this.sanityCheck = function () {
    var TOLERANCE_AMT = 0.00000000001; //allow for rounding errors

    //constant scalars that should be > 0
    _.forEach([
      "MOTOR_SIDE_OFFSET",
      "MOTOR_HEIGHT",
      "DRAW_AREA_WIDTH",
      "DRAW_AREA_HEIGHT"],
      function(param) {

      if (this[param] <= 0) {
        throw new Error(
          param + " must be > 0."
        );
      }
    }, this);

    //vectors that should always be positive in both components:
    _.forEach([
      "L_R",
      "L_O",
      "l_p",
      "o_p"],
      function(vect){

      if (this[vect].x < 0 || this[vect].y < 0) {
        throw new Error(vect + " should be positive in both components");
      }

    }, this);

    //r_p is the only vector that should always have a <= 0 x component
    if(this.r_p.x > 0) {
      throw new Error("r_p should not have an x component > 0");
    }

    if(this.L_R.y !== 0) {
      throw new Error("L_R should not have a horizontal component.");
    }

    if(this.l_p.y !== this.r_p.y) {
      throw new Error("l_p and r_p should have the same y value.");
    }

    if(Math.abs(this.l_p.length() - this.string_len_left) > TOLERANCE_AMT) {
      throw new Error("l_p's length should ~equal string_len_left.");
    }

    if(Math.abs(this.r_p.length() - this.string_len_right) > TOLERANCE_AMT) {
    throw new Error("r_p's length should ~equal string_len_right.");
    }

  };

  this.update = function() {
    //Use string length values to update everything else,
    //then do a sanityCheck and lastly drawToBoard.
    this.l_p.x = (( Math.pow(this.string_len_left,2) - Math.pow(this.string_len_right,2) +
       Math.pow(this.L_R.x,2) ) / (2 * this.L_R.x) );

    this.l_p.y = Math.sqrt(Math.pow(this.string_len_left, 2) - Math.pow(this.l_p.x, 2) );

    this.o_p = this.get_o_p();

    //recalculate r_p
    // this.r_p = new Victor(this.l_p.x - this.L_R.x, this.l_p.y);
    this.r_p = this.get_r_p();

    this.sanityCheck();
    drawToBoard(this.o_p.x,this.o_p.y);
  };

  //do a sanity check on init of new WallRobot
  this.sanityCheck();
};

function drawToBoard(x, y) {
  // instead of calling setPixel directly, this is kind of a hook.
  // later I will implement colors etc

  //round off floating point values so you can plot them
  x = Math.round(x);
  y = Math.round(y);
  setPixel(imageData, x, y, 255, 0, 0, 255);
  console.log("drew to board (" + x + "," + y + ").");
  context.putImageData(imageData, 0,0);
}

function setPixel(imageData, x, y, r, g , b, a) {
  var index = (x+y*imageData.width)*4;
  imageData.data[index+0] = r;
  imageData.data[index+1] = g;
  imageData.data[index+2] = b;
  imageData.data[index+3] = a; //255 is opaque, 0 is transparent
}

function randomNoise() {
//just for fun
  for (var i = 0; i < 100000; i++) {
    var x = Math.floor(Math.random()*imageData.width);
    var y = Math.floor(Math.random()*imageData.height);
    setPixel(imageData,
      x, y, 255,0,0,255);
    // console.log(x,y);
  }
  context.putImageData(imageData, 0,0);
}

// start!!!
var robot = new WallRobot({
  MOTOR_SIDE_OFFSET: Convert.ft_mm(2),
  MOTOR_HEIGHT: Convert.ft_mm(2),
  DRAW_AREA_WIDTH: Convert.ft_mm(8),
  DRAW_AREA_HEIGHT: Convert.ft_mm(4),
  STRING_LEN_PER_STEP: 1.5 //??? dunno! TODO measure.
});

//test update and draw!
for(var i = 0; i < 500; i++) {
  robot.string_len_right += robot.STRING_LEN_PER_STEP;
  robot.update();
}
<commit_msg>big refactor, no vectors<commit_after>var canvas = document.getElementById("canvas1");
var context = canvas.getContext("2d");
var imageData = context.createImageData(canvas.width, canvas.height);

var Convert = {
  //TODO separate this into module? acts like Math.
  ft_mm : function(ft) {
    //1 ft = 304.8 mm
    return ft * 304.8; }
};

var WallRobot = function(opts) {
  //all working units are in MM! MM is "native".

  // stepperDelta tracks steps from the origin position.
  // Negative values retract the string, positive values extend the string
  // stepperDelta[0] is left stepper, and stepperDelta[1] is right stepper.
  this.stepperDelta = [0, 0];

  // horizontal distance from motors to side of board in mm
  this.MOTOR_SIDE_OFFSET = opts.MOTOR_SIDE_OFFSET;

  // height of motors above top of drawing area in mm
  this.MOTOR_HEIGHT = opts.MOTOR_HEIGHT;

  this.DRAW_AREA_WIDTH = opts.DRAW_AREA_WIDTH;
  this.DRAW_AREA_HEIGHT = opts.DRAW_AREA_HEIGHT;

  this.STRING_LEN_PER_STEP = opts.STRING_LEN_PER_STEP;

  this.vectorLen = function(x, y) {
    return Math.sqrt( Math.pow(x,2) + Math.pow(y,2) );
  };

  // Derivative values:
  this.INITIAL_STR_LEN_LEFT = this.vectorLen(this.MOTOR_SIDE_OFFSET, this.MOTOR_HEIGHT);
  this.INITIAL_STR_LEN_RIGHT = this.vectorLen(this.MOTOR_SIDE_OFFSET + this.DRAW_AREA_WIDTH, this.MOTOR_HEIGHT);

  this.MOTOR_TO_MOTOR_DIST = this.DRAW_AREA_WIDTH + 2*this.MOTOR_SIDE_OFFSET;

  this.initSanityCheck = function () {
    // Make sure all the constants are sane and consistent.

    //allow for rounding errors and general JS floating point errors
    var TOLERANCE_AMT = 0.00000000001;

    //constant scalars that should be > 0
    _.forEach([
      "MOTOR_SIDE_OFFSET",
      "MOTOR_HEIGHT",
      "DRAW_AREA_WIDTH",
      "DRAW_AREA_HEIGHT",
      "INITIAL_STR_LEN_LEFT",
      "INITIAL_STR_LEN_RIGHT",
      "MOTOR_TO_MOTOR_DIST"
      ],
      function(param) {

      if (this[param] <= 0) {
        throw new Error(
          param + " must be > 0."
        );
      }
    }, this);

  };

  // Call for sanity check upon initialization
  this.initSanityCheck();
};

    // //vectors that should always be positive in both components:
    // _.forEach([
    //   "L_R",
    //   "L_O",
    //   "l_p",
    //   "o_p"],
    //   function(vect){
    //
    //   if (this[vect].x < 0 || this[vect].y < 0) {
    //     throw new Error(vect + " should be positive in both components");
    //   }
    //
    // }, this);

    //r_p is the only vector that should always have a <= 0 x component
  //   if(this.r_p.x > 0) {
  //     throw new Error("r_p should not have an x component > 0");
  //   }
  //
  //   if(this.L_R.y !== 0) {
  //     throw new Error("L_R should not have a horizontal component.");
  //   }
  //
  //   if(this.l_p.y !== this.r_p.y) {
  //     throw new Error("l_p and r_p should have the same y value.");
  //   }
  //
  //   if(Math.abs(this.l_p.length() - this.string_len_left) > TOLERANCE_AMT) {
  //     throw new Error("l_p's length should ~equal string_len_left.");
  //   }
  //
  //   if(Math.abs(this.r_p.length() - this.string_len_right) > TOLERANCE_AMT) {
  //   throw new Error("r_p's length should ~equal string_len_right.");
  //   }
  //

  // this.update = function() {
  //   // //Use string length values to update everything else,
  //   // //then do a sanityCheck and lastly drawToBoard.
  //   // this.l_p.x = (( Math.pow(this.string_len_left,2) - Math.pow(this.string_len_right,2) +
  //   //    Math.pow(this.L_R.x,2) ) / (2 * this.L_R.x) );
  //   //
  //   // this.l_p.y = Math.sqrt(Math.pow(this.string_len_left, 2) - Math.pow(this.l_p.x, 2) );
  //   //
  //   // this.o_p = this.get_o_p();
  //   //
  //   // //recalculate r_p
  //   // // this.r_p = new Victor(this.l_p.x - this.L_R.x, this.l_p.y);
  //   // this.r_p = this.get_r_p();
  //
  //   this.checkPosition();
  //   drawToBoard(this.x, this.y);
  // };

  //do a sanity check on init of new WallRobot

// Getters (and setters, if you make any)
Object.defineProperties(WallRobot.prototype, {

  string_len_left : {
    get: function() {
      return this.stepperDelta[0]*this.STRING_LEN_PER_STEP + this.INITIAL_STR_LEN_LEFT;
    }
  },

  string_len_right : {
    get: function() {
      return this.stepperDelta[1]*this.STRING_LEN_PER_STEP + this.INITIAL_STR_LEN_RIGHT;
    }
  },

  x : {
    get: function() {
      return (( Math.pow(this.string_len_left,2) - Math.pow(this.string_len_right,2) +
        Math.pow(this.MOTOR_TO_MOTOR_DIST,2) ) / (2 * this.MOTOR_TO_MOTOR_DIST) );
    }
  },

  y : {
    get: function() {
      //TODO: this can probably be more efficient (not calling x.get()...)
      return Math.sqrt(Math.pow(this.string_len_left, 2) - Math.pow(this.x, 2) );
    }
  },

});

// Rest of methods
WallRobot.prototype.checkPosition = function(x, y) {
  // You can pass x and y values if you want to test them without changing
  // the stepDelta. If you don't specify, this.x and this.y are used,
  // which are calculated using this.stepDelta
  if (typeof(x)==='undefined') x = this.x;
  if (typeof(y)==='undefined') y = this.y;

  if (x < 0) { throw new Error("x should not be negative"); }
  if (y < 0) { throw new Error("y should not be negative"); }
  if (x > this.DRAW_AREA_WIDTH) { throw new Error("x should not be greater than DRAW_AREA_WIDTH"); }
  if (y > this.DRAW_AREA_HEIGHT) { throw new Error("y should not be greater than DRAW_AREA_HEIGHT"); }

  return true;
};

WallRobot.prototype.setDeltaByCoords = function(x, y) {
  // TODO
};

WallRobot.prototype.setDeltaByLengths = function(left_len, right_len) {
  // TODO
};

// ===============================================

function drawToBoard(x, y) {
  // instead of calling setPixel directly, this is kind of a hook.
  // later I will implement colors etc

  //round off floating point values so you can plot them
  x = Math.round(x);
  y = Math.round(y);
  setPixel(imageData, x, y, 255, 0, 0, 255);
  console.log("drew to board (" + x + "," + y + ").");
  context.putImageData(imageData, 0,0);
}

function setPixel(imageData, x, y, r, g , b, a) {
  var index = (x+y*imageData.width)*4;
  imageData.data[index+0] = r;
  imageData.data[index+1] = g;
  imageData.data[index+2] = b;
  imageData.data[index+3] = a; //255 is opaque, 0 is transparent
}

function randomNoise() {
//just for fun
  for (var i = 0; i < 100000; i++) {
    var x = Math.floor(Math.random()*imageData.width);
    var y = Math.floor(Math.random()*imageData.height);
    setPixel(imageData,
      x, y, 255,0,0,255);
    // console.log(x,y);
  }
  context.putImageData(imageData, 0,0);
}

// start!!!
var robot = new WallRobot({
  MOTOR_SIDE_OFFSET: Convert.ft_mm(2),
  MOTOR_HEIGHT: Convert.ft_mm(2),
  DRAW_AREA_WIDTH: Convert.ft_mm(8),
  DRAW_AREA_HEIGHT: Convert.ft_mm(4),
  STRING_LEN_PER_STEP: 1.5 //??? dunno! TODO measure.
});

//test update and draw!
for(var i = 0; i < 500; i++) {
  robot.string_len_right += robot.STRING_LEN_PER_STEP;
  // robot.update();
}
<|endoftext|>


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

	window.Code = window.Code || {};

	window.Code.Tabs = function(component) {
		'use strict';

		const selectors = {
			buttons: Array.prototype.slice.call(component.querySelectorAll('[data-tabs-button]')),
			panels: Array.prototype.slice.call(component.querySelectorAll('[data-tabs-panel]'))
		};

		const states = {
			buttonActive: 'tabs__button--active',
			panelActive: 'tabs__panel--active'
		};

		const keyboardHandlers = {
			'39': handleArrowRightEvent,
			'37': handleArrowLeftEvent,
			'36': goToFirstTab,
			'35': goToLastTab
		};

		const activeElements = {
			button: component.querySelector(`.${states.buttonActive}`),
			panel: component.querySelector(`.${states.panelActive}`)
		};

		function removeActiveElement() {
			activeElements.button.setAttribute('tabindex', '-1');
			activeElements.button.setAttribute('aria-selected', 'false');
			activeElements.button.classList.remove(states.buttonActive);
			activeElements.panel.classList.remove(states.panelActive);
		}

		function addActiveElement() {
			activeElements.button.setAttribute('tabindex', '0');
			activeElements.button.setAttribute('aria-selected', 'true');
			activeElements.button.classList.add(states.buttonActive);
			activeElements.button.focus();
			activeElements.panel.classList.add(states.panelActive);
		}

		function setActiveElements(button, panel) {
			activeElements.button = button;
			activeElements.panel = panel;
		}

		function getCurrentIndex() {
			return parseInt(activeElements.button.getAttribute('data-tabs-button'));
		}

		function goToFirstTab() {
			removeActiveElement();
			setActiveElements(selectors.buttons[0], selectors.panels[0]);
			addActiveElement();
		}

		function goToLastTab() {
			removeActiveElement();
			setActiveElements(selectors.buttons[selectors.buttons.length - 1], selectors.panels[selectors.panels.length - 1]);
			addActiveElement();
		}

		function handleArrowLeftEvent(element) {
			var currentIndex = getCurrentIndex();

			removeActiveElement();

			if(currentIndex === 0) {
				setActiveElements(selectors.buttons[selectors.buttons.length - 1], selectors.panels[selectors.panels.length - 1]);
			} else {
				currentIndex--;
				setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			}

			addActiveElement();

		}

		function handleArrowRightEvent(element) {
			var currentIndex = getCurrentIndex();

			removeActiveElement();

			if(currentIndex === selectors.buttons.length - 1) {
				setActiveElements(selectors.buttons[0], selectors.panels[0]);
			} else {
				currentIndex++;
				setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			}

			addActiveElement();
		}

		function handleClickEvent(event) {
			const currentIndex = parseInt(event.currentTarget.getAttribute('data-tabs-button'));
			removeActiveElement();
			setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			addActiveElement();
		}

		function keyboardHandler(event) {
			if(keyboardHandlers.hasOwnProperty(event.keyCode)) {
				event.preventDefault();
				keyboardHandlers[event.keyCode](event.currentTarget);
			}
		}

		selectors.buttons.forEach(element => {
			element.addEventListener('keydown', keyboardHandler);
			element.addEventListener('click', handleClickEvent);
		});

		addActiveElement();

		return {
			setActiveElements: setActiveElements
		};

	};

	var tabs = Array.prototype.slice.call(document.querySelectorAll('[data-tabs]'));

	tabs.forEach(element => {
		var newTabs = new window.Code.Tabs(element);
	});
})();

<commit_msg>fix: remove setting active function on load due to it navigating you down the page on load.<commit_after>(function() {
	'use strict';

	window.Code = window.Code || {};

	window.Code.Tabs = function(component) {
		'use strict';

		const selectors = {
			buttons: Array.prototype.slice.call(component.querySelectorAll('[data-tabs-button]')),
			panels: Array.prototype.slice.call(component.querySelectorAll('[data-tabs-panel]'))
		};

		const states = {
			buttonActive: 'tabs__button--active',
			panelActive: 'tabs__panel--active'
		};

		const keyboardHandlers = {
			'39': handleArrowRightEvent,
			'37': handleArrowLeftEvent,
			'36': goToFirstTab,
			'35': goToLastTab
		};

		const activeElements = {
			button: component.querySelector(`.${states.buttonActive}`),
			panel: component.querySelector(`.${states.panelActive}`)
		};

		function removeActiveElement() {
			activeElements.button.setAttribute('tabindex', '-1');
			activeElements.button.setAttribute('aria-selected', 'false');
			activeElements.button.classList.remove(states.buttonActive);
			activeElements.panel.classList.remove(states.panelActive);
		}

		function addActiveElement() {
			activeElements.button.setAttribute('tabindex', '0');
			activeElements.button.setAttribute('aria-selected', 'true');
			activeElements.button.classList.add(states.buttonActive);
			activeElements.button.focus();
			activeElements.panel.classList.add(states.panelActive);
		}

		function setActiveElements(button, panel) {
			activeElements.button = button;
			activeElements.panel = panel;
		}

		function getCurrentIndex() {
			return parseInt(activeElements.button.getAttribute('data-tabs-button'));
		}

		function goToFirstTab() {
			removeActiveElement();
			setActiveElements(selectors.buttons[0], selectors.panels[0]);
			addActiveElement();
		}

		function goToLastTab() {
			removeActiveElement();
			setActiveElements(selectors.buttons[selectors.buttons.length - 1], selectors.panels[selectors.panels.length - 1]);
			addActiveElement();
		}

		function handleArrowLeftEvent(element) {
			var currentIndex = getCurrentIndex();

			removeActiveElement();

			if(currentIndex === 0) {
				setActiveElements(selectors.buttons[selectors.buttons.length - 1], selectors.panels[selectors.panels.length - 1]);
			} else {
				currentIndex--;
				setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			}

			addActiveElement();

		}

		function handleArrowRightEvent(element) {
			var currentIndex = getCurrentIndex();

			removeActiveElement();

			if(currentIndex === selectors.buttons.length - 1) {
				setActiveElements(selectors.buttons[0], selectors.panels[0]);
			} else {
				currentIndex++;
				setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			}

			addActiveElement();
		}

		function handleClickEvent(event) {
			const currentIndex = parseInt(event.currentTarget.getAttribute('data-tabs-button'));
			removeActiveElement();
			setActiveElements(component.querySelector(`[data-tabs-button="${currentIndex}"]`), component.querySelector(`[data-tabs-panel="${currentIndex}"]`));
			addActiveElement();
		}

		function keyboardHandler(event) {
			if(keyboardHandlers.hasOwnProperty(event.keyCode)) {
				event.preventDefault();
				keyboardHandlers[event.keyCode](event.currentTarget);
			}
		}

		selectors.buttons.forEach(element => {
			element.addEventListener('keydown', keyboardHandler);
			element.addEventListener('click', handleClickEvent);
		});

		return {
			setActiveElements: setActiveElements
		};

	};

	var tabs = Array.prototype.slice.call(document.querySelectorAll('[data-tabs]'));

	tabs.forEach(element => {
		var newTabs = new window.Code.Tabs(element);
	});
})();

<|endoftext|>


<commit_before>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Iteration Tracking Board App
     * The Iteration Tracking Board can be used to visualize and manage your User Stories and Defects within an Iteration.
     */
    Ext.define('Rally.apps.iterationtrackingboard.IterationTrackingBoardApp', {
        extend: 'Rally.app.TimeboxScopedApp',
        requires: [
            'Rally.data.ModelFactory',
            'Rally.data.Ranker',
            'Rally.ui.gridboard.GridBoard',
            'Rally.ui.grid.TreeGrid',
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardOwnerFilter',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardArtifactTypeChooser',
            'Rally.ui.gridboard.plugin.GridBoardFieldPicker',
            'Rally.ui.cardboard.plugin.ColumnPolicy',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardFilterControl',
            'Rally.ui.filter.view.ModelFilter',
            'Rally.ui.filter.view.OwnerFilter',
            'Rally.app.Message'
        ],
        mixins: ['Rally.app.CardFieldSelectable'],
        componentCls: 'iterationtrackingboard',
        alias: 'widget.rallyiterationtrackingboard',

        settingsScope: 'project',
        scopeType: 'iteration',

        config: {
            defaultSettings: {
                showCardAge: true,
                cardAgeThreshold: 3,
                cardFields: 'Parent,Tasks,Defects,Discussion,PlanEstimate'
            }
        },

        onScopeChange: function(scope) {
            this.remove('gridBoard');
            this._loadModels();
        },

        getSettingsFields: function () {
            var fields = this.callParent(arguments);

            if (!this.isShowingBlankSlate()) {
                this.appendCardFieldPickerSetting(fields);
                if (this.showGridSettings) {
                    fields.push({settingsType: 'grid', html: 'no grid settings'});
                }
            }

            fields.push({
                type: 'cardage',
                settingsType: 'board',
                config: {
                    margin: '0 0 0 80',
                    width: 300
                }
            });

            return fields;
        },

        launch: function() {
            this.showGridSettings = this.getContext().isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE');
            this.callParent(arguments);
        },

        _addGridBoard: function(compositeModel, treeGridModel) {
            var plugins = ['rallygridboardaddnew'],
                context = this.getContext();

            if (context.isFeatureEnabled('F4359_FILTER')) {
                plugins.push({
                    ptype: 'rallygridboardfiltercontrol',
                    filterControlConfig: {
                        cls: 'small gridboard-filter-control',
                        stateful: true,
                        stateId: context.getScopedStateId('iteration-tracking-filter-button'),
                        items: [
                            {
                                xtype: 'rallyownerfilter',
                                margin: '0 5',
                                project: this.getContext().getProjectRef()
                            },
                            {
                                xtype: 'rallymodelfilter',
                                models: compositeModel.getArtifactComponentModels()
                            }
                        ]
                    }
                });
            }

            plugins = plugins.concat([{
                    ptype: 'rallygridboardfilterinfo',
                    isGloballyScoped: Ext.isEmpty(this.getSetting('project')) ? true : false,
                    stateId: 'iteration-tracking-owner-filter-' + this.getAppId()
                },
                'rallygridboardownerfilter',
                'rallygridboardfieldpicker'
            ]);

            if (context.isFeatureEnabled('SHOW_ARTIFACT_CHOOSER_ON_ITERATION_BOARDS')) {
                plugins.push({
                    ptype: 'rallygridboardartifacttypechooser',
                    artifactTypePreferenceKey: 'artifact-types',
                    showAgreements: true
                });
            }
            this.plugins = plugins;
            this._addGrid(this._getGridConfig(treeGridModel));
        },

        _addGrid: function(gridConfig){
            var context = this.getContext();

            this.gridboard = this.add({
                itemId: 'gridBoard',
                xtype: 'rallygridboard',
                stateId: 'iterationtracking-gridboard',
                context: context,
                enableToggle: context.isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE'),
                plugins: this.plugins,
                modelNames: this.modelNames,
                allModelNames: context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID') ? this.allModelNames : null,
                cardBoardConfig: {
                    serverSideFiltering: context.isFeatureEnabled('F4359_FILTER'),
                    columnConfig: {
                        additionalFetchFields: ['PortfolioItem'],
                        plugins: [{
                            ptype: 'rallycolumnpolicy',
                            app: this
                        }]
                    },
                    cardConfig: {
                        fields: this.getCardFieldNames(),
                        showAge: this.getSetting('showCardAge') ? this.getSetting('cardAgeThreshold') : -1,
                        showBlockedReason: true
                    },
                    listeners: {
                        filter: this._onBoardFilter,
                        filtercomplete: this._onBoardFilterComplete
                    }
                },
                gridConfig: gridConfig,
                addNewPluginConfig: {
                    style: {
                        'float': 'left'
                    }
                },
                listeners: {
                    load: this._onLoad,
                    toggle: this._publishContentUpdated,
                    recordupdate: this._publishContentUpdatedNoDashboardLayout,
                    recordcreate: this._publishContentUpdatedNoDashboardLayout,
                    scope: this
                }
            });
        },

        _getGridConfig: function(treeGridModel, columns) {
            var context = this.getContext();

            var gridConfig = {
                storeConfig: {
                    autoLoad: context.isFeatureEnabled('F4359_FILTER') ? false : true
                },
                columnCfgs: this._getGridColumns(),
                enableBulkEdit: context.isFeatureEnabled('EXT4_GRID_BULK_EDIT'),
                stateId: context.getScopedStateId('iteration-tracking-grid'),
                stateful: context.isFeatureEnabled('ITERATION_TRACKING_PERSISTENT_PREFERENCES')
            };

            if (context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                Ext.apply(gridConfig, {
                    xtype: 'rallytreegrid',
                    model: treeGridModel,
                    storeConfig: {
                        nodeParam: 'Parent',
                        parentFieldNames: ['Requirement', 'WorkProduct', 'DefectSuite'],
                        parentTypes: ['HierarchicalRequirement', 'Defect', 'DefectSuite', 'TestSet'],
                        childTypes: ['Defect', 'Task', 'TestCase'],
                        rootNodeFilters: this.context.getTimeboxScope().getQueryFilter(),
                        sorters: {
                            property: Rally.data.Ranker.getRankField(treeGridModel),
                            direction: 'ASC'
                        },
                        fetch: ['FormattedID', 'Tasks', 'Defects', 'TestCases']
                    },
                    treeColumnRenderer: function(value, metaData, record, rowIdx, colIdx, store, view) {
                        return Rally.ui.renderer.RendererFactory.getRenderTemplate(store.model.getField('FormattedID')).apply(record.data);
                    },
                    rootVisible: false,
                    columnCfgs: columns ? this._getGridColumns(columns) : null,
                    defaultColumnCfgs: this._getGridColumns(),
                    pageResetMessages: [Rally.app.Message.timeboxScopeChange],
                    isLeaf: function(record) {
                        return  (!record.raw.Tasks || record.raw.Tasks.Count === 0) &&
                                (!record.raw.Defects || record.raw.Defects.Count === 0) &&
                                (record.raw._type === 'TestSet' || !record.raw.TestCases || record.raw.TestCases.Count === 0); //remove the type check once TestCases under TestSets can be queried through the artifact endpoint
                    },
                    getIcon: function(record) {
                        return '';
                    }
                });
            }
            return gridConfig;
        },

        _getGridColumns: function(columns) {
            var context = this.getContext(),
                result = ['FormattedID', 'Name', 'ScheduleState', 'Blocked', 'PlanEstimate', 'TaskStatus', 'TaskEstimateTotal', 'TaskRemainingTotal', 'Owner', 'DefectStatus', 'Discussion'];

            if (context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                if (columns) {
                    result = columns;
                }
                _.pull(result, 'FormattedID');
            }

            return result;
        },

        _loadModels: function() {
            var topLevelTypes = ['User Story', 'Defect', 'Defect Suite', 'Test Set'],
                allTypes = topLevelTypes.concat(['Task', 'Test Case']);
            Rally.data.ModelFactory.getModels({
                types: allTypes,
                context: this.getContext().getDataContext(),
                success: function(models) {
                    var topLevelModels = _.filter(models, function(model, key) {
                            return _.contains(topLevelTypes, key);
                        }),
                        compositeModel = Rally.domain.WsapiModelBuilder.buildCompositeArtifact(topLevelModels, this.getContext()),
                        treeGridModel;
                    this.modelNames = topLevelTypes;
                    this.allModelNames = allTypes;
                    if (this.getContext().isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                        treeGridModel = Rally.domain.WsapiModelBuilder.buildCompositeArtifact(_.values(models), this.getContext());
                    }
                    this._addGridBoard(compositeModel, treeGridModel);
                },
                scope: this
            });
        },

        _onLoad: function() {
            this._publishContentUpdated();
            if (Rally.BrowserTest) {
                Rally.BrowserTest.publishComponentReady(this);
            }
        },

        _onBoardFilter: function() {
            this.setLoading(true);
        },

        _onBoardFilterComplete: function() {
            this.setLoading(false);
        },

        _publishContentUpdated: function() {
            this.fireEvent('contentupdated');
        },

        _publishContentUpdatedNoDashboardLayout: function() {
            this.fireEvent('contentupdated', {dashboardLayout: false});
        }
    });
})();
<commit_msg>DE19154 - TreeGrid and RegularGrid share column preferences on IterationTrackingGrid<commit_after>(function() {
    var Ext = window.Ext4 || window.Ext;

    /**
     * Iteration Tracking Board App
     * The Iteration Tracking Board can be used to visualize and manage your User Stories and Defects within an Iteration.
     */
    Ext.define('Rally.apps.iterationtrackingboard.IterationTrackingBoardApp', {
        extend: 'Rally.app.TimeboxScopedApp',
        requires: [
            'Rally.data.ModelFactory',
            'Rally.data.Ranker',
            'Rally.ui.gridboard.GridBoard',
            'Rally.ui.grid.TreeGrid',
            'Rally.ui.gridboard.plugin.GridBoardAddNew',
            'Rally.ui.gridboard.plugin.GridBoardOwnerFilter',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardArtifactTypeChooser',
            'Rally.ui.gridboard.plugin.GridBoardFieldPicker',
            'Rally.ui.cardboard.plugin.ColumnPolicy',
            'Rally.ui.gridboard.plugin.GridBoardFilterInfo',
            'Rally.ui.gridboard.plugin.GridBoardFilterControl',
            'Rally.ui.filter.view.ModelFilter',
            'Rally.ui.filter.view.OwnerFilter',
            'Rally.app.Message'
        ],
        mixins: ['Rally.app.CardFieldSelectable'],
        componentCls: 'iterationtrackingboard',
        alias: 'widget.rallyiterationtrackingboard',

        settingsScope: 'project',
        scopeType: 'iteration',

        config: {
            defaultSettings: {
                showCardAge: true,
                cardAgeThreshold: 3,
                cardFields: 'Parent,Tasks,Defects,Discussion,PlanEstimate'
            }
        },

        onScopeChange: function(scope) {
            this.remove('gridBoard');
            this._loadModels();
        },

        getSettingsFields: function () {
            var fields = this.callParent(arguments);

            if (!this.isShowingBlankSlate()) {
                this.appendCardFieldPickerSetting(fields);
                if (this.showGridSettings) {
                    fields.push({settingsType: 'grid', html: 'no grid settings'});
                }
            }

            fields.push({
                type: 'cardage',
                settingsType: 'board',
                config: {
                    margin: '0 0 0 80',
                    width: 300
                }
            });

            return fields;
        },

        launch: function() {
            this.showGridSettings = this.getContext().isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE');
            this.callParent(arguments);
        },

        _addGridBoard: function(compositeModel, treeGridModel) {
            var plugins = ['rallygridboardaddnew'],
                context = this.getContext();

            if (context.isFeatureEnabled('F4359_FILTER')) {
                plugins.push({
                    ptype: 'rallygridboardfiltercontrol',
                    filterControlConfig: {
                        cls: 'small gridboard-filter-control',
                        stateful: true,
                        stateId: context.getScopedStateId('iteration-tracking-filter-button'),
                        items: [
                            {
                                xtype: 'rallyownerfilter',
                                margin: '0 5',
                                project: this.getContext().getProjectRef()
                            },
                            {
                                xtype: 'rallymodelfilter',
                                models: compositeModel.getArtifactComponentModels()
                            }
                        ]
                    }
                });
            }

            plugins = plugins.concat([{
                    ptype: 'rallygridboardfilterinfo',
                    isGloballyScoped: Ext.isEmpty(this.getSetting('project')) ? true : false,
                    stateId: 'iteration-tracking-owner-filter-' + this.getAppId()
                },
                'rallygridboardownerfilter',
                'rallygridboardfieldpicker'
            ]);

            if (context.isFeatureEnabled('SHOW_ARTIFACT_CHOOSER_ON_ITERATION_BOARDS')) {
                plugins.push({
                    ptype: 'rallygridboardartifacttypechooser',
                    artifactTypePreferenceKey: 'artifact-types',
                    showAgreements: true
                });
            }
            this.plugins = plugins;
            this._addGrid(this._getGridConfig(treeGridModel));
        },

        _addGrid: function(gridConfig){
            var context = this.getContext();

            this.gridboard = this.add({
                itemId: 'gridBoard',
                xtype: 'rallygridboard',
                stateId: 'iterationtracking-gridboard',
                context: context,
                enableToggle: context.isFeatureEnabled('ITERATION_TRACKING_BOARD_GRID_TOGGLE'),
                plugins: this.plugins,
                modelNames: this.modelNames,
                allModelNames: context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID') ? this.allModelNames : null,
                cardBoardConfig: {
                    serverSideFiltering: context.isFeatureEnabled('F4359_FILTER'),
                    columnConfig: {
                        additionalFetchFields: ['PortfolioItem'],
                        plugins: [{
                            ptype: 'rallycolumnpolicy',
                            app: this
                        }]
                    },
                    cardConfig: {
                        fields: this.getCardFieldNames(),
                        showAge: this.getSetting('showCardAge') ? this.getSetting('cardAgeThreshold') : -1,
                        showBlockedReason: true
                    },
                    listeners: {
                        filter: this._onBoardFilter,
                        filtercomplete: this._onBoardFilterComplete
                    }
                },
                gridConfig: gridConfig,
                addNewPluginConfig: {
                    style: {
                        'float': 'left'
                    }
                },
                listeners: {
                    load: this._onLoad,
                    toggle: this._publishContentUpdated,
                    recordupdate: this._publishContentUpdatedNoDashboardLayout,
                    recordcreate: this._publishContentUpdatedNoDashboardLayout,
                    scope: this
                }
            });
        },

        _getGridConfig: function(treeGridModel, columns) {
            var context = this.getContext(),
                stateString = context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID') ? 'iteration-tracking-treegrid' : 'iteration-tracking-grid',
                stateId = context.getScopedStateId(stateString);

            var gridConfig = {
                storeConfig: {
                    autoLoad: context.isFeatureEnabled('F4359_FILTER') ? false : true
                },
                columnCfgs: this._getGridColumns(),
                enableBulkEdit: context.isFeatureEnabled('EXT4_GRID_BULK_EDIT'),
                stateId: stateId,
                stateful: context.isFeatureEnabled('ITERATION_TRACKING_PERSISTENT_PREFERENCES')
            };

            if (context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                Ext.apply(gridConfig, {
                    xtype: 'rallytreegrid',
                    model: treeGridModel,
                    storeConfig: {
                        nodeParam: 'Parent',
                        parentFieldNames: ['Requirement', 'WorkProduct', 'DefectSuite'],
                        parentTypes: ['HierarchicalRequirement', 'Defect', 'DefectSuite', 'TestSet'],
                        childTypes: ['Defect', 'Task', 'TestCase'],
                        rootNodeFilters: this.context.getTimeboxScope().getQueryFilter(),
                        sorters: {
                            property: Rally.data.Ranker.getRankField(treeGridModel),
                            direction: 'ASC'
                        },
                        fetch: ['FormattedID', 'Tasks', 'Defects', 'TestCases']
                    },
                    treeColumnRenderer: function(value, metaData, record, rowIdx, colIdx, store, view) {
                        return Rally.ui.renderer.RendererFactory.getRenderTemplate(store.model.getField('FormattedID')).apply(record.data);
                    },
                    rootVisible: false,
                    columnCfgs: columns ? this._getGridColumns(columns) : null,
                    defaultColumnCfgs: this._getGridColumns(),
                    pageResetMessages: [Rally.app.Message.timeboxScopeChange],
                    isLeaf: function(record) {
                        return  (!record.raw.Tasks || record.raw.Tasks.Count === 0) &&
                                (!record.raw.Defects || record.raw.Defects.Count === 0) &&
                                (record.raw._type === 'TestSet' || !record.raw.TestCases || record.raw.TestCases.Count === 0); //remove the type check once TestCases under TestSets can be queried through the artifact endpoint
                    },
                    getIcon: function(record) {
                        return '';
                    }
                });
            }
            return gridConfig;
        },

        _getGridColumns: function(columns) {
            var context = this.getContext(),
                result = ['FormattedID', 'Name', 'ScheduleState', 'Blocked', 'PlanEstimate', 'TaskStatus', 'TaskEstimateTotal', 'TaskRemainingTotal', 'Owner', 'DefectStatus', 'Discussion'];

            if (context.isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                if (columns) {
                    result = columns;
                }
                _.pull(result, 'FormattedID');
            }

            return result;
        },

        _loadModels: function() {
            var topLevelTypes = ['User Story', 'Defect', 'Defect Suite', 'Test Set'],
                allTypes = topLevelTypes.concat(['Task', 'Test Case']);
            Rally.data.ModelFactory.getModels({
                types: allTypes,
                context: this.getContext().getDataContext(),
                success: function(models) {
                    var topLevelModels = _.filter(models, function(model, key) {
                            return _.contains(topLevelTypes, key);
                        }),
                        compositeModel = Rally.domain.WsapiModelBuilder.buildCompositeArtifact(topLevelModels, this.getContext()),
                        treeGridModel;
                    this.modelNames = topLevelTypes;
                    this.allModelNames = allTypes;
                    if (this.getContext().isFeatureEnabled('F2903_USE_ITERATION_TREE_GRID')) {
                        treeGridModel = Rally.domain.WsapiModelBuilder.buildCompositeArtifact(_.values(models), this.getContext());
                    }
                    this._addGridBoard(compositeModel, treeGridModel);
                },
                scope: this
            });
        },

        _onLoad: function() {
            this._publishContentUpdated();
            if (Rally.BrowserTest) {
                Rally.BrowserTest.publishComponentReady(this);
            }
        },

        _onBoardFilter: function() {
            this.setLoading(true);
        },

        _onBoardFilterComplete: function() {
            this.setLoading(false);
        },

        _publishContentUpdated: function() {
            this.fireEvent('contentupdated');
        },

        _publishContentUpdatedNoDashboardLayout: function() {
            this.fireEvent('contentupdated', {dashboardLayout: false});
        }
    });
})();
<|endoftext|>


<commit_before>/*global document*/

/*eslint-disable no-unused-vars*/
function getRootElsReact15 () {
    /*eslint-enable no-unused-vars*/

    const rootEls      = document.querySelectorAll('[data-reactroot]');
    const checkRootEls = rootEls.length &&
                         Object.keys(rootEls[0]).some(prop => {
                             const rootEl = rootEls[0];

                             //NOTE: server rendering in React 16 also adds data-reactroot attribute
                             return /^__reactInternalInstance/.test(prop) && !!rootEl[prop]._hostContainerInfo;
                         });

    return checkRootEls && rootEls || [];
}<commit_msg>Fix remarks<commit_after>/*global document*/

/*eslint-disable no-unused-vars*/
function getRootElsReact15 () {
    /*eslint-enable no-unused-vars*/

    const rootEls      = document.querySelectorAll('[data-reactroot]');
    const checkRootEls = rootEls.length &&
                         Object.keys(rootEls[0]).some(prop => {
                             const rootEl = rootEls[0];

                             //NOTE: server rendering in React 16 also adds data-reactroot attribute, but
                             //the _hostContainerInfo field doesn't exists in react 16, so need an extra check for it.
                             return /^__reactInternalInstance/.test(prop) && !!rootEl[prop]._hostContainerInfo;
                         });

    return checkRootEls && rootEls || [];
}<|endoftext|>


<commit_before>import React, { Component, PropTypes } from 'react';
import echarts from 'echarts';

class BarCharts extends Component {
    static propTypes = {
        className: PropTypes.string,
        width: PropTypes.number.isRequired,
        height: PropTypes.number.isRequired,
		pieData: PropTypes.object.isRequired
    };

    constructor(props) {
        super(props);
    }

    componentDidMount() {
        // const file = "./data/bus_lines.json";
  //       const reader = new FileReader();
  //       reader.onload = function(data) {

  //       }
  //       reader.readAsText(file);
        this.initalECharts();
    }

	componentDidUpdate () {
		this.initalECharts();
	}

    // 不同群体的特点
    initalECharts = () => {
        const myChart = echarts.init(document.getElementById('pieCharts'));

        // 将统计图表的联动
        myChart.group = 'group1';

		if(this.props.pieData === undefined) return;
        myChart.title = '嵌套环形图';
		const legend = this.props.pieData.legend;   //  series and row of data
		const fields = this.props.pieData.fields;   //  column of  data
		const data = this.props.pieData.data;
		const radiusUnit = legend.length !== 0 ? 56 / legend.length : 20;
		const radiusInterval = radiusUnit * 0.25;
		const seriesData = [];

		const legendData = legend.map( e => ({ name:`人群${e}`,icon:'circle'}));
		for (let i = 0; i < legend.length; i++) {
			if (data[i] instanceof Array) {
				const seriesItemData = data[i].map( (item, index) => { return { value: item, name: fields[index] };});
				seriesItemData.shift();
				seriesData.push(
					{
						name:`人群${i+1}`,
						type:'pie',
						//radius: [`${5 + radiusUnit * i + radiusInterval}%`, `${5 + radiusUnit * (i+1)}%`],
						radius: ['5%','25%'],
						data:seriesItemData,
						label: {
							normal: {
								show: false
							}
						},
						labelLine: {
							normal: {
								show: false
							}
						},
						// center: ['50%', '40%']
						center: [`${33 * (i%3) + 16.5}%`, `${30 * Math.floor(i/3) + 25}%`]
					}
				);
			} else {
				seriesData.push(
					{
						name:legend[i],
						type:'pie',
						radius: [`${35 + radiusUnit * i + radiusInterval}%`, `${35 + radiusUnit * (i+1)}%`],
						data:{ value: data[i], name: fields }
					}
				);
			}
		}

        myChart.setOption({
			toolbox: {
				show: true,
				feature: {
					dataZoom: {
						yAxisIndex: 'none'
					},
					dataView: {readOnly: false},
					restore: {},
					saveAsImage: {}
				}
			},
            tooltip: {
                trigger: 'item',
                formatter: "{a}
{b}: {c} ({d}%)"
            },
            legend: [{
                orient: 'horizontal',
				top:20,
                data:legendData
            },{
				orient:'horizontal',
				bottom: 20,
				data: fields
			}],
			series: seriesData
            // series: [
            //     {
            //         name:'访问来源',
            //         type:'pie',
            //         selectedMode: 'single',
            //         radius: [0, '30%'],
			//
            //         label: {
            //             normal: {
            //                 position: 'inner'
            //             }
            //         },
            //         labelLine: {
            //             normal: {
            //                 show: false
            //             }
            //         },
            //         data:[
            //             {value:335, name:'直达', selected:true},
            //             {value:679, name:'营销广告'},
            //             {value:1548, name:'搜索引擎'}
            //         ]
            //     },
            //     {
            //         name:'访问来源',
            //         type:'pie',
            //         radius: ['40%', '55%'],
			//
            //         data:[
            //             {value:335, name:'直达'},
            //             {value:310, name:'邮件营销'},
            //             {value:234, name:'联盟广告'},
            //             {value:135, name:'视频广告'},
            //             {value:1048, name:'百度'},
            //             {value:251, name:'谷歌'},
            //             {value:147, name:'必应'},
            //             {value:102, name:'其他'}
            //         ]
            //     }
            // ]
        });

    }

    render() {
        const style = {
            width: this.props.width,
            height: this.props.height
        };
        return (

        );
    }
}

export default BarCharts;
<commit_msg>fix warning<commit_after>import React, { Component, PropTypes } from 'react';
import echarts from 'echarts';

class PieCharts extends Component {
    static propTypes = {
        className: PropTypes.string,
        width: PropTypes.number.isRequired,
        height: PropTypes.number.isRequired,
		pieData: PropTypes.object.isRequired
    };

    constructor(props) {
        super(props);
    }

    componentDidMount() {
        // const file = "./data/bus_lines.json";
  //       const reader = new FileReader();
  //       reader.onload = function(data) {

  //       }
  //       reader.readAsText(file);
        this.initalECharts();
    }

	componentDidUpdate () {
		this.initalECharts();
	}

    // 不同群体的特点
    initalECharts = () => {
        if(this.props.pieData === undefined) return;
        const myChart = echarts.init(document.getElementById('pieCharts'));

        // 将统计图表的联动
        myChart.group = 'group1';

		if(this.props.pieData === undefined) return;
        myChart.title = '嵌套环形图';
		const legend = this.props.pieData.legend;   //  series and row of data
		const fields = this.props.pieData.fields;   //  column of  data
		const data = this.props.pieData.data;
		const radiusUnit = legend.length !== 0 ? 56 / legend.length : 20;
		const radiusInterval = radiusUnit * 0.25;
		const seriesData = [];

		const legendData = legend.map( e => ({ name:`人群${e}`,icon:'circle'}));
		for (let i = 0; i < legend.length; i++) {
			if (data[i] instanceof Array) {
				const seriesItemData = data[i].map( (item, index) => { return { value: item, name: fields[index] };});
				seriesItemData.shift();
				seriesData.push(
					{
						name:`人群${i+1}`,
						type:'pie',
						//radius: [`${5 + radiusUnit * i + radiusInterval}%`, `${5 + radiusUnit * (i+1)}%`],
						radius: ['5%','25%'],
						data:seriesItemData,
						label: {
							normal: {
								show: false
							}
						},
						labelLine: {
							normal: {
								show: false
							}
						},
						// center: ['50%', '40%']
						center: [`${33 * (i%3) + 16.5}%`, `${30 * Math.floor(i/3) + 25}%`]
					}
				);
			} else {
				seriesData.push(
					{
						name:legend[i],
						type:'pie',
						radius: [`${35 + radiusUnit * i + radiusInterval}%`, `${35 + radiusUnit * (i+1)}%`],
						data:{ value: data[i], name: fields }
					}
				);
			}
		}

        myChart.setOption({
			toolbox: {
				show: true,
				feature: {
					dataZoom: {
						yAxisIndex: 'none'
					},
					dataView: {readOnly: false},
					restore: {},
					saveAsImage: {}
				}
			},
            tooltip: {
                trigger: 'item',
                formatter: "{a}
{b}: {c} ({d}%)"
            },
            legend: [{
                orient: 'horizontal',
				top:20,
                data:legendData
            },{
				orient:'horizontal',
				bottom: 20,
				data: fields
			}],
			series: seriesData
            // series: [
            //     {
            //         name:'访问来源',
            //         type:'pie',
            //         selectedMode: 'single',
            //         radius: [0, '30%'],
			//
            //         label: {
            //             normal: {
            //                 position: 'inner'
            //             }
            //         },
            //         labelLine: {
            //             normal: {
            //                 show: false
            //             }
            //         },
            //         data:[
            //             {value:335, name:'直达', selected:true},
            //             {value:679, name:'营销广告'},
            //             {value:1548, name:'搜索引擎'}
            //         ]
            //     },
            //     {
            //         name:'访问来源',
            //         type:'pie',
            //         radius: ['40%', '55%'],
			//
            //         data:[
            //             {value:335, name:'直达'},
            //             {value:310, name:'邮件营销'},
            //             {value:234, name:'联盟广告'},
            //             {value:135, name:'视频广告'},
            //             {value:1048, name:'百度'},
            //             {value:251, name:'谷歌'},
            //             {value:147, name:'必应'},
            //             {value:102, name:'其他'}
            //         ]
            //     }
            // ]
        });

    }

    render() {
        const style = {
            width: this.props.width,
            height: this.props.height
        };
        return (

        );
    }
}

export default PieCharts;
<|endoftext|>


<commit_before>#!/usr/bin/env node
// cover zim folder to atom-note
'use strict';
require('shelljs/global');
var path = require("path");
var walk = require("walk");
var fs   = require("fs");

if(process.argv[2] && process.argv[3]){
  var srcDir = path.normalize(process.argv[2]);
  var destDir = path.normalize(process.argv[3]);

  try {
    fs.statSync(destDir);
    console.log('destDir is existed!');
    process.exit();
  } catch (e) {
  }

  process.stdin.resume();
  process.stdout.write('input the note name: ');
  process.stdin.once('data',function(data){
    var noteName = data.toString().trim();
    process.stdout.write('input the author name: ');
    process.stdin.once('data',function (data) {
      process.stdin.pause();
      var author = data.toString().trim();

      cover(srcDir,destDir,noteName,author);
    })
  });
}else{
  console.log("Usage: node main.js srcDir destDir");
}

function cover(srcDir,destDir,noteName,author){
  try {
    fs.statSync(destDir);
    console.log('destDir is existed!');
    process.exit();
  } catch (e) {
    cp('-R',srcDir+'/*',destDir);
  }

  // create a json file in the root of note folder
  createNoteJson(destDir,noteName,author);

  var walker = walk.walk(destDir,{"filters":['.zim','.git','notebook.zim']});
  walker.on('file',function(root,fileStats,next){
    if(path.extname(fileStats.name) == '.txt'){
      var filePath = path.resolve(root,fileStats.name);
      fs.readFile(filePath,'utf-8',function(err,data){
        var mdContent = coverFile(data);
        fs.writeFileSync(filePath,mdContent);

        var newFilePath = path.resolve(root,path.basename(fileStats.name,'.txt')+'.md');
        fs.renameSync(filePath,newFilePath);

        next();
      });
    }
    next();
  });
}

function coverFile(content){
  // cover meta info
  content = content.replace(/^([\s\S]*?)(\r\n\r\n|\r\r|\n\n)/,"---\n$1\n---\n\n");
  content = content.replace(/Content-Type:.*(\r\n|\r|\n)/,'');
  content = content.replace(/Wiki-Format:.*(\r\n|\r|\n)/,'');
  content = content.replace(/Creation-Date:(.*)/,'date:$1');

  // cover heading
  content = content.replace(/^======\s+(.*?)\s*======/mg,"# $1");
  content = content.replace(/^=====\s+(.*?)\s*=====/mg,"## $1");
  content = content.replace(/^====\s+(.*?)\s*====/mg,"### $1");
  content = content.replace(/^===\s+(.*?)\s*===/mg,"#### $1");
  content = content.replace(/^==\s+(.*?)\s*==/mg,"##### $1");
  content = content.replace(/^=\s+(.*?)\s*=/mg,"###### $1");

  //cover link
  content = content.replace(/\[\[(.*)\|(.*)\]\]/gm,'[$1]($2)');
  content = content.replace(/\[\[(.*)\]\]/gm,'[$1]($1)');

  // cover todo
  content = content.replace(/^(\s*)\[[ x]\]/mg,'$1- [ ]');
  content = content.replace(/^(\s*)\[\*\]/mg,'$1- [x]');
  return content;
}

function createNoteJson(folderPath,noteName,author){
  var jsonData = {
    "name"   : noteName,
    "author" : author,
    "format" : "atom-note-v0.01"
  };
  fs.writeFileSync(path.join(folderPath,'note.json'),JSON.stringify(jsonData,null,2));
}
<commit_msg>add feature: del notebook.zim<commit_after>#!/usr/bin/env node
// cover zim folder to atom-note
'use strict';
require('shelljs/global');
var path = require("path");
var walk = require("walk");
var fs   = require("fs");

if(process.argv[2] && process.argv[3]){
  var srcDir = path.normalize(process.argv[2]);
  var destDir = path.normalize(process.argv[3]);

  try {
    fs.statSync(destDir);
    console.log('destDir is existed!');
    process.exit();
  } catch (e) {
  }

  process.stdin.resume();
  process.stdout.write('input the note name: ');
  process.stdin.once('data',function(data){
    var noteName = data.toString().trim();
    process.stdout.write('input the author name: ');
    process.stdin.once('data',function (data) {
      process.stdin.pause();
      var author = data.toString().trim();

      cover(srcDir,destDir,noteName,author);
    })
  });
}else{
  console.log("Usage: node main.js srcDir destDir");
}

function cover(srcDir,destDir,noteName,author){
  try {
    fs.statSync(destDir);
    console.log('destDir is existed!');
    process.exit();
  } catch (e) {
    cp('-R',srcDir+'/*',destDir);

    var zimFilePath = path.join(destDir,'notebook.zim');
    ifExistedThenDo(zimFilePath,function(){
      rm(zimFilePath);
    });
  }

  // create a json file in the root of note folder
  createNoteJson(destDir,noteName,author);

  var walker = walk.walk(destDir,{"filters":['.zim','.git','notebook.zim']});
  walker.on('file',function(root,fileStats,next){
    if(path.extname(fileStats.name) == '.txt'){
      var filePath = path.resolve(root,fileStats.name);
      fs.readFile(filePath,'utf-8',function(err,data){
        var mdContent = coverFile(data);
        fs.writeFileSync(filePath,mdContent);

        var newFilePath = path.resolve(root,path.basename(fileStats.name,'.txt')+'.md');
        fs.renameSync(filePath,newFilePath);

        next();
      });
    }
    next();
  });
}

function coverFile(content){
  // cover meta info
  content = content.replace(/^([\s\S]*?)(\r\n\r\n|\r\r|\n\n)/,"---\n$1\n---\n\n");
  content = content.replace(/Content-Type:.*(\r\n|\r|\n)/,'');
  content = content.replace(/Wiki-Format:.*(\r\n|\r|\n)/,'');
  content = content.replace(/Creation-Date:(.*)/,'date:$1');

  // cover heading
  content = content.replace(/^======\s+(.*?)\s*======/mg,"# $1");
  content = content.replace(/^=====\s+(.*?)\s*=====/mg,"## $1");
  content = content.replace(/^====\s+(.*?)\s*====/mg,"### $1");
  content = content.replace(/^===\s+(.*?)\s*===/mg,"#### $1");
  content = content.replace(/^==\s+(.*?)\s*==/mg,"##### $1");
  content = content.replace(/^=\s+(.*?)\s*=/mg,"###### $1");

  //cover link
  content = content.replace(/\[\[(.*)\|(.*)\]\]/gm,'[$1]($2)');
  content = content.replace(/\[\[(.*)\]\]/gm,'[$1]($1)');

  // cover todo
  content = content.replace(/^(\s*)\[[ x]\]/mg,'$1- [ ]');
  content = content.replace(/^(\s*)\[\*\]/mg,'$1- [x]');
  return content;
}

function createNoteJson(folderPath,noteName,author){
  var jsonData = {
    "name"   : noteName,
    "author" : author,
    "format" : "atom-note-v0.01"
  };
  fs.writeFileSync(path.join(folderPath,'note.json'),JSON.stringify(jsonData,null,2));
}

function ifExistedThenDo(path,callback){
  try {
    var stats = fs.statSync(path);
    callback(stats);
  } catch (e) {
  }
}
<|endoftext|>