<commit_before>function renderHistogram(data, hash, theForm) {
  var margin = {top: 5, right: 25, bottom: 35, left: 55};
  var svgWidth = 830;
  var svgHeight = 380;
  var chartWidth = svgWidth - margin.left - margin.right;
  var chartHeight = svgHeight - margin.top - margin.bottom;
  var barPadding = 2;

  var dataset = [];
  $.each(data.hist, function(index, item) {dataset.push([parseInt(index), item])});
  var mean = data.meanSuc;
  var stdDev = data.stdDevSuc;
  var xMin = d3.min(dataset, function(d) {return d[0];});
  var xMax = d3.max(dataset, function(d) {return d[0];});
  var yMin = d3.min(dataset, function(d) {return d[1];});
  var yMax = d3.max(dataset, function(d) {return d[1];});

  d3.selectAll("svg > *").remove();

  var svg = d3.select("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight);

  var numBars = xMax - xMin;
  var barWidth = chartWidth / numBars - barPadding;
  if(barWidth < 1) {barWidth = 1}

  var xScale = d3.scale.linear()
    .domain([xMin-1, xMax+1])
    .range([margin.left + barWidth/2, chartWidth - barWidth/2]);

  var yScale = d3.scale.linear()
    .domain([0, yMax])
    .range([chartHeight, margin.top]);

  var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom");

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

  var stdDevBoxes = [[xScale(xMin) - barWidth, xScale(mean - stdDev) -xScale(xMin) + barWidth, "dimgrey"],
                    [xScale(mean - stdDev), xScale(mean) - xScale(mean - stdDev), "darkgrey"],
                    [xScale(mean), xScale(mean + stdDev) - xScale(mean), "lightgrey"],
                    [xScale(mean + stdDev), xScale(xMax) - xScale(mean + stdDev) + barWidth, "gainsboro"]];

  var stdDevLine = [xScale(mean - stdDev), xScale(mean), xScale(mean + stdDev)];

  var stdDevText = [[xScale(mean - stdDev), "-\u03C3"], [xScale(mean), "\u03BC"], [xScale(mean + stdDev),"+\u03C3"]];

  // Render Background standard deviation shading
  svg.selectAll("noHighlight")
    .data(stdDevBoxes)
    .enter()
    .append("rect")
    .attr("id", "stdDevShading")
    .attr("class", "noHighlight")
    .attr("x", function(d) {return d[0]})
    .attr("y", yScale(yMax))
    .attr("width", function(d) {return d[1]})
    .attr("height", chartHeight - yScale(yMax))
    .attr("fill", function(d) {return d[2]});

  // Render mean, +/- stdDev lines
  svg.selectAll("line")
    .data(stdDevLine)
    .enter()
    .append("line")
    .attr("id", "stdDevLines")
    .attr("x1", function(d) {return d})
    .attr("x2", function(d) {return d})
    .attr("y1", yScale(yMax))
    .attr("y2", chartHeight)
    .attr("stroke-width", 2)
    .attr("stroke", "black");

  // Render Histogram
  svg.selectAll("histogramBars")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("class", "histogramBars")
    .attr("x", function(d) {return xScale(d[0]) - barWidth/2;})
    .attr("y", function(d) {return  yScale(d[1]);})
    .attr("width", barWidth)
    .attr("height", function(d) {return chartHeight - yScale(d[1]);})
    .attr("fill", function(d) {return (d[0] < hash["targetThreshold"]) ? "crimson" : "gold";})
    .on("mouseover", function(d) {
      var tooltipText = [d[1] + " trials with " + d[0] + " successes",
                        (100*d[1]/theForm.elements.namedItem("numAttempts").value).toFixed(1) + "% of all trials"];
      var xPosition = xScale(d[0]);
      var yPosition = 3*(chartHeight - yScale(yMax))/4;
      var tooltipWidth = 2+5*Math.max(tooltipText[0].length,tooltipText[1].length);
      var tooltipHeight = 26;
      svg.append("rect")
        .attr("id", "tooltipRect")
        .attr("class", "noHighlight")
        .attr("x", xPosition - tooltipWidth/2)
        .attr("y", yPosition - 11)
        .attr("width", tooltipWidth)
        .attr("height", tooltipHeight)
        .attr("fill", "white");
      //render tooltip text
      var tblock = svg.append("text")
        .attr("id", "tooltipText")
        .attr("text-anchor", "middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "11px");
      tblock.append("tspan")
        .attr("x", (xPosition))
        .attr("y", yPosition)
        .text(tooltipText[0]);
      tblock.append("tspan")
        .attr("x", (xPosition))
        .attr("y", yPosition + 11)
        .text(tooltipText[1]);
     })
     .on("mouseout", function() {
      //Hide the tooltip
      d3.select("#tooltipText").remove();
      d3.select("#tooltipRect").remove();
     });

  // Render line annotations
  svg.selectAll("text")
    .data(stdDevText)
    .enter()
    .append("text")
    .text(function(d) {return d[1]})
    .attr("x", function(d) {return d[0] + 3})
    .attr("y", yScale(7*yMax/8))
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black");

  // Render X Axis
  svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0," + (chartHeight) + ")")
    .call(xAxis);

  // Render X Axis Label
  svg.append("text")
    .attr("transform", "translate(" + (chartWidth / 2) + " ," + (chartHeight + margin.bottom) + ")")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black");
    .style("text-anchor", "middle")
    .text("Total Threshold Successes per Crafting Attempt");

  // Render Y Axis
  svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(" + (margin.left + barWidth/2) + ", 0)")
    .call(yAxis);

  svg.append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 0 )
    .attr("x", 0-chartHeight/2 )
    .attr("dy", "1em")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black");
    .style("text-anchor", "middle")
    .text("Number of Crafting Attempts");
}
<commit_msg>Added bar color annotations, made all svg text writing commands consistent in order of operations<commit_after>function renderHistogram(data, hash, theForm) {
  var margin = {top: 5, right: 25, bottom: 35, left: 55};
  var svgWidth = 830;
  var svgHeight = 380;
  var chartWidth = svgWidth - margin.left - margin.right;
  var chartHeight = svgHeight - margin.top - margin.bottom;
  var barPadding = 2;

  var dataset = [];
  $.each(data.hist, function(index, item) {dataset.push([parseInt(index), item])});
  var mean = data.meanSuc;
  var stdDev = data.stdDevSuc;
  var xMin = d3.min(dataset, function(d) {return d[0];});
  var xMax = d3.max(dataset, function(d) {return d[0];});
  var yMin = d3.min(dataset, function(d) {return d[1];});
  var yMax = d3.max(dataset, function(d) {return d[1];});

  d3.selectAll("svg > *").remove();

  var svg = d3.select("svg")
    .attr("width", svgWidth)
    .attr("height", svgHeight);

  var numBars = xMax - xMin;
  var barWidth = chartWidth / numBars - barPadding;
  if(barWidth < 1) {barWidth = 1}

  var xScale = d3.scale.linear()
    .domain([xMin-1, xMax+1])
    .range([margin.left + barWidth/2, chartWidth - barWidth/2]);

  var yScale = d3.scale.linear()
    .domain([0, yMax])
    .range([chartHeight, margin.top]);

  var xAxis = d3.svg.axis()
    .scale(xScale)
    .orient("bottom");

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

  var stdDevBoxes = [[xScale(xMin) - barWidth, xScale(mean - stdDev) -xScale(xMin) + barWidth, "dimgrey"],
                    [xScale(mean - stdDev), xScale(mean) - xScale(mean - stdDev), "darkgrey"],
                    [xScale(mean), xScale(mean + stdDev) - xScale(mean), "lightgrey"],
                    [xScale(mean + stdDev), xScale(xMax) - xScale(mean + stdDev) + barWidth, "gainsboro"]];

  var stdDevLine = [xScale(mean - stdDev), xScale(mean), xScale(mean + stdDev)];

  var stdDevText = [[xScale(mean - stdDev), "-\u03C3"], [xScale(mean), "\u03BC"], [xScale(mean + stdDev),"+\u03C3"]];

  // Render Background standard deviation shading
  svg.selectAll("noHighlight")
    .data(stdDevBoxes)
    .enter()
    .append("rect")
    .attr("id", "stdDevShading")
    .attr("class", "noHighlight")
    .attr("x", function(d) {return d[0]})
    .attr("y", yScale(yMax))
    .attr("width", function(d) {return d[1]})
    .attr("height", chartHeight - yScale(yMax))
    .attr("fill", function(d) {return d[2]});

  // Render mean, +/- stdDev lines
  svg.selectAll("line")
    .data(stdDevLine)
    .enter()
    .append("line")
    .attr("id", "stdDevLines")
    .attr("x1", function(d) {return d})
    .attr("x2", function(d) {return d})
    .attr("y1", yScale(yMax))
    .attr("y2", chartHeight)
    .attr("stroke-width", 2)
    .attr("stroke", "black");

  // Render Histogram
  svg.selectAll("histogramBars")
    .data(dataset)
    .enter()
    .append("rect")
    .attr("class", "histogramBars")
    .attr("x", function(d) {return xScale(d[0]) - barWidth/2;})
    .attr("y", function(d) {return  yScale(d[1]);})
    .attr("width", barWidth)
    .attr("height", function(d) {return chartHeight - yScale(d[1]);})
    .attr("fill", function(d) {return (d[0] < hash["targetThreshold"]) ? "crimson" : "gold";})
    .on("mouseover", function(d) {
      var tooltipText = [d[1] + " trials with " + d[0] + " successes",
                        (100*d[1]/theForm.elements.namedItem("numAttempts").value).toFixed(1) + "% of all trials"];
      var xPosition = xScale(d[0]);
      var yPosition = 3*(chartHeight - yScale(yMax))/4;
      var tooltipWidth = 2+5*Math.max(tooltipText[0].length,tooltipText[1].length);
      var tooltipHeight = 26;
      svg.append("rect")
        .attr("id", "tooltipRect")
        .attr("class", "noHighlight")
        .attr("x", xPosition - tooltipWidth/2)
        .attr("y", yPosition - 11)
        .attr("width", tooltipWidth)
        .attr("height", tooltipHeight)
        .attr("fill", "white");
      //render tooltip text
      var tblock = svg.append("text")
        .attr("id", "tooltipText")
        .attr("text-anchor", "middle")
        .attr("font-family", "sans-serif")
        .attr("font-size", "11px");
      tblock.append("tspan")
        .attr("x", (xPosition))
        .attr("y", yPosition)
        .text(tooltipText[0]);
      tblock.append("tspan")
        .attr("x", (xPosition))
        .attr("y", yPosition + 11)
        .text(tooltipText[1]);
     })
     .on("mouseout", function() {
      //Hide the tooltip
      d3.select("#tooltipText").remove();
      d3.select("#tooltipRect").remove();
     });

  // Render line annotations
  svg.selectAll("text")
    .data(stdDevText)
    .enter()
    .append("text")
    .attr("x", function(d) {return d[0] + 3})
    .attr("y", yScale(7*yMax/8))
    .attr("dy", "1em")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black")
    .text(function(d) {return d[1]});

  // Render bar color annotations
  svg.append("text")
    .attr("x", xScale(xMin))
    .attr("y", yScale(7*yMax/8))
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("font-weight", "bold")
    .attr("fill", "red")
    .style("text-anchor", "start")
    .text("Red Bars: Failed Attempts");
  svg.append("text")
    .attr("x", xScale(xMin))
    .attr("y", yScale(7*yMax/8))
    .attr("dy", "-1em")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("font-weight", "bold")
    .attr("fill", "Gold")
    .style("text-anchor", "start")
    .text("Gold Bars: Successful Attempts");

  // Render X Axis
  svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(0," + (chartHeight) + ")")
    .call(xAxis);

  // Render X Axis Label
  svg.append("text")
    .attr("transform", "translate(" + (chartWidth / 2) + " ," + (chartHeight + margin.bottom) + ")")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black")
    .style("text-anchor", "middle")
    .text("Total Threshold Successes per Crafting Attempt");

  // Render Y Axis
  svg.append("g")
    .attr("class", "axis")
    .attr("transform", "translate(" + (margin.left + barWidth/2) + ", 0)")
    .call(yAxis);

  // Render Y Axis Label
  svg.append("text")
    .attr("transform", "rotate(-90)")
    .attr("y", 0 )
    .attr("x", 0-chartHeight/2 )
    .attr("dy", "1em")
    .attr("font-family", "sans-serif")
    .attr("font-size", "14px")
    .attr("fill", "black")
    .style("text-anchor", "middle")
    .text("Number of Crafting Attempts");
}
<|endoftext|>


<commit_before>// requestAnimationFrame polyfil
(function() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame =
      window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function() { callback(currTime + timeToCall); },
        timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };

  if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}());

(function() {
  function el(id) { return document.getElementById(id); }
  function remove(id) { if (el(id)) el(id).parentElement.removeChild(el(id)); }

  function callChain(a,cb) {
    var args = Array.prototype.slice.call(arguments,2), i=0;
    function next() {
      if ( ! a[i] ) return cb ? cb.apply(this,args) : null;
      a[i++].apply(this,args);
    }
    args.push(next);
    next();
  }

  var ws;
  var inputHandlers = [];
  var outputHandlers = [];
  chat.os.upgrades = {};
  var replaceables = {};
  var intervals = {};
  var timeouts = {};
  var animationFrames = {};

  window.onload = function() {
    el('message').onkeydown = function(e) {
      e=e||window.event; var code=e.keyCode||e.which;
      if ( code == 13 ) {
        chat.os.send( el('message').value );
        el('message').value = '';
        return false;
      }
      return true;
    }
    startSocket();
    el('message').focus();
  }

  function startSocket( reconnecting ) {
    var started = new Date().getTime();
    ws = io.connect();
    ws.on('connect', function() {
      ws.send(JSON.stringify({type:reconnecting?'reconnect':'identify', identity:chat.os.identity, room:chat.os.room}) );
    });
    ws.on('data', function(m) {
      callChain( inputHandlers, null, m );
    });
  }

  function upgrade( message, next ) {
    if ( message.type != 'upgrade' ) return next();

    if ( intervals[message.name] ) {
      for (var i in intervals[message.name]) clearInterval( intervals[message.name][i] );
      delete intervals[message.name];
    }

    if ( timeouts[message.name] ) {
      for (var i in timeouts[message.name]) clearTimeout( timeouts[message.name][i] );
      delete timeouts[message.name];
    }

    if ( animationFrames[message.name] ) {
      for (var i in animationFrames[message.name]) cancelAnimationFrame( animationFrames[message.name][i] );
      delete animationFrames[message.name];
    }

    if ( message.style ) {
      var style = document.createElement('STYLE');
      style.id = 'upgrade-style-' + message.name;
      style.setAttribute('type','text/css')
      style.appendChild( document.createTextNode(message.style) );
      remove(style.id);
      el('head').appendChild(style);
    }

    if ( message.markup ) {
      var markup = document.createElement('DIV');
      markup.innerHTML = message.markup;
      while ( markup.childNodes[0] ) {
        if ( markup.childNodes[0].id ) remove( markup.childNodes[0].id );
        document.body.appendChild( markup.childNodes[0] );
      }
    }

    if ( message.script ) {
      var script = document.createElement('SCRIPT');
      script.id = 'upgrade-script-' + message.name;
      script.setAttribute('language','javascript')
      script.appendChild( document.createTextNode(message.script) );
      remove( script.id );
      el('head').appendChild(script);
    }

    chat.os.upgrades[ message.name ] = message;
  }

  function reset( message, next ) {
    if ( message.type != 'reset' ) return next();
    return document.location.href = document.location.href;
  }

  function onaction( context, next ) {
    if ( ! context.text ) return next();
    var match = context.text.match(/^:(\S+)($|\s(.*)$)/);
    if ( ! match ) return next();
    if ( match[3] && match[3].match(/^[{\['"]/) )
      context.message = JSON.parse( match[3] );
    else
      context.message = {text:match[3]};
    context.message.type = match[1];
    next();
  }

  function display(message) {
    var text;
    if (message.type == 'comment')
      text = message.body;
    else if (message.type in {joined:1,disconnected:1})
      text = message.from.email + ' ' + message.type;
    else
      text = JSON.stringify(message);
    var response = document.createElement('P');
    response.appendChild( document.createTextNode(text) );
    el('responses').appendChild(response);
  }

  chat.os.send = function send( text, message ) {
    var context = { text:text||'', message: message || {type:'comment', body:text} };
    callChain( outputHandlers, sendMessage, context );
    function sendMessage(context) { ws.emit( 'message', JSON.stringify(context.message) ); }
  }

  chat.os.addInputHandler = function addInputHandler(handler, priority) {
    handler.priority = priority == null ? 5 : priority;
    inputHandlers = inputHandlers.filter(function(ih) { return !ih.name || ih.name != handler.name; }).concat([handler]);
    inputHandlers.sort(function(a,b) { return a.priority - b.priority;});
  }

  chat.os.addOutputHandler = function addOutputHandler(handler, priority) {
    handler.priority = priority == null ? 5 : priority;
    outputHandlers = outputHandlers.filter(function(oh) { return !oh.name || oh.name != handler.name; }).concat([handler]);
    outputHandlers.sort(function(a,b) { return a.priority - b.priority;});
  }

  chat.os.replaceSafe = function replaceSafe( name, f ) {
    if ( replaceables[name] ) return replaceables[name].replace(f);
    return (replaceables[name] = Replaceable(name,f));

    function Replaceable(name, f) {
      function wrapper() { return f.apply(this,arguments); }
      wrapper.replace = function replace(newF) { return f = newF, null; };
      return wrapper;
    }
  }

  chat.os.setInterval = function( upgrade, name, f, interval ) {
    intervals[upgrade] = intervals[upgrade] || {};
    if ( intervals[upgrade][name] ) clearInterval( intervals[upgrade][name] );
    return intervals[upgrade][name] = setInterval( f, interval );
  }

  chat.os.setTimeout = function( upgrade, name, f, interval ) {
    timeouts[upgrade] = timeouts[upgrade] || {};
    if ( timeouts[upgrade][name] ) clearInterval( timeouts[upgrade][name] );
    return timeouts[upgrade][name] = setInterval( f, interval );
  }

  chat.os.requestAnimationFrame = function( upgrade, name, f ) {
    animationFrames[upgrade] = animationFrames[upgrade] || {};
    if ( animationFrames[upgrade][name] ) cancelAnimationFrame( animationFrames[upgrade][name] );
    return animationFrames[upgrade][name] = requestAnimationFrame( f );
  }

  chat.os.addInputHandler(reset,1);
  chat.os.addInputHandler(upgrade);
  chat.os.addInputHandler(display,10);

  chat.os.addOutputHandler(onaction,1);
})();
<commit_msg>sanity testing input and output handlers to prevent simple mistakes from crashing rooms<commit_after>// requestAnimationFrame polyfil
(function() {
  var lastTime = 0;
  var vendors = ['ms', 'moz', 'webkit', 'o'];
  for(var x = 0; x < vendors.length && !window.requestAnimationFrame; ++x) {
    window.requestAnimationFrame = window[vendors[x]+'RequestAnimationFrame'];
    window.cancelAnimationFrame =
      window[vendors[x]+'CancelAnimationFrame'] || window[vendors[x]+'CancelRequestAnimationFrame'];
  }

  if (!window.requestAnimationFrame)
    window.requestAnimationFrame = function(callback, element) {
      var currTime = new Date().getTime();
      var timeToCall = Math.max(0, 16 - (currTime - lastTime));
      var id = window.setTimeout(function() { callback(currTime + timeToCall); },
        timeToCall);
      lastTime = currTime + timeToCall;
      return id;
    };

  if (!window.cancelAnimationFrame)
    window.cancelAnimationFrame = function(id) {
        clearTimeout(id);
    };
}());

(function() {
  function el(id) { return document.getElementById(id); }
  function remove(id) { if (el(id)) el(id).parentElement.removeChild(el(id)); }

  function callChain(a,cb) {
    var args = Array.prototype.slice.call(arguments,2), i=0;
    function next() {
      if ( ! a[i] ) return cb ? cb.apply(this,args) : null;
      a[i++].apply(this,args);
    }
    args.push(next);
    next();
  }

  var ws;
  var inputHandlers = [];
  var outputHandlers = [];
  chat.os.upgrades = {};
  var replaceables = {};
  var intervals = {};
  var timeouts = {};
  var animationFrames = {};

  window.onload = function() {
    el('message').onkeydown = function(e) {
      e=e||window.event; var code=e.keyCode||e.which;
      if ( code == 13 ) {
        chat.os.send( el('message').value );
        el('message').value = '';
        return false;
      }
      return true;
    }
    startSocket();
    el('message').focus();
  }

  function startSocket( reconnecting ) {
    var started = new Date().getTime();
    ws = io.connect();
    ws.on('connect', function() {
      ws.send(JSON.stringify({type:reconnecting?'reconnect':'identify', identity:chat.os.identity, room:chat.os.room}) );
    });
    ws.on('data', function(m) {
      callChain( inputHandlers, display, m );
    });
  }

  function upgrade( message, next ) {
    if ( message.type != 'upgrade' ) return next();

    if ( intervals[message.name] ) {
      for (var i in intervals[message.name]) clearInterval( intervals[message.name][i] );
      delete intervals[message.name];
    }

    if ( timeouts[message.name] ) {
      for (var i in timeouts[message.name]) clearTimeout( timeouts[message.name][i] );
      delete timeouts[message.name];
    }

    if ( animationFrames[message.name] ) {
      for (var i in animationFrames[message.name]) cancelAnimationFrame( animationFrames[message.name][i] );
      delete animationFrames[message.name];
    }

    if ( message.style ) {
      var style = document.createElement('STYLE');
      style.id = 'upgrade-style-' + message.name;
      style.setAttribute('type','text/css')
      style.appendChild( document.createTextNode(message.style) );
      remove(style.id);
      el('head').appendChild(style);
    }

    if ( message.markup ) {
      var markup = document.createElement('DIV');
      markup.innerHTML = message.markup;
      while ( markup.childNodes[0] ) {
        if ( markup.childNodes[0].id ) remove( markup.childNodes[0].id );
        document.body.appendChild( markup.childNodes[0] );
      }
    }

    if ( message.script ) {
      var script = document.createElement('SCRIPT');
      script.id = 'upgrade-script-' + message.name;
      script.setAttribute('language','javascript')
      script.appendChild( document.createTextNode(message.script) );
      remove( script.id );
      el('head').appendChild(script);
    }

    chat.os.upgrades[ message.name ] = message;
  }

  function reset( message, next ) {
    if ( message.type != 'reset' ) return next();
    return document.location.href = document.location.href;
  }

  function onaction( context, next ) {
    if ( ! context.text ) return next();
    var match = context.text.match(/^:(\S+)($|\s(.*)$)/);
    if ( ! match ) return next();
    if ( match[3] && match[3].match(/^[{\['"]/) )
      context.message = JSON.parse( match[3] );
    else
      context.message = {text:match[3]};
    context.message.type = match[1];
    next();
  }

  function display(message) {
    var text;
    if (message.type == 'comment')
      text = message.body;
    else if (message.type in {joined:1,disconnected:1})
      text = message.from.email + ' ' + message.type;
    else
      text = JSON.stringify(message);
    var response = document.createElement('P');
    response.appendChild( document.createTextNode(text) );
    el('responses').appendChild(response);
  }

  function sanityTestInputHandler( handler, success ) {
    var timeout = setTimeout( timeoutError, 500 );
    return handler( {type:'sanity-test'}, next );

    function next() { clearTimeout(timeout); success(); }
    function timeoutError() {
      console.error( handler.toString() );
      throw new Error("TIMEOUT sanity checking input handler: " + handler.name);
    }
  }

  function sanityTestOutputHandler( handler, success ) {
    var timeout = setTimeout( timeoutError, 500 );
    return handler( { text:'sanity', message:{type:'sanity-test'} }, next );

    function next() { clearTimeout(timeout); success(); }
    function timeoutError() {
      console.error( handler.toString() );
      throw new Error("TIMEOUT sanity checking output handler: " + handler.name);
    }
  }

  chat.os.send = function send( text, message ) {
    if ( typeof text == 'object' ) message = text, text = '';
    var context = { text:text||'', message: message || {type:'comment', body:text} };
    callChain( outputHandlers, sendMessage, context );
    function sendMessage(context) { ws.emit( 'message', JSON.stringify(context.message) ); }
  }

  chat.os.addInputHandler = function addInputHandler(handler, priority) {
    handler.priority = priority == null ? 5 : priority;
    return sanityTestInputHandler( handler, addHandler );

    function addHandler() {
      inputHandlers = inputHandlers.filter(function(ih) { return !ih.name || ih.name != handler.name; }).concat([handler]);
      inputHandlers.sort(function(a,b) { return a.priority - b.priority; });
    }
  }

  chat.os.addOutputHandler = function addOutputHandler(handler, priority) {
    handler.priority = priority == null ? 5 : priority;
    return sanityTestOutputHandler( handler, addHandler );

    function addHandler() {
      outputHandlers = outputHandlers.filter(function(oh) { return !oh.name || oh.name != handler.name; }).concat([handler]);
      outputHandlers.sort(function(a,b) { return a.priority - b.priority;});
    }
  }

  chat.os.replaceSafe = function replaceSafe( name, f ) {
    if ( replaceables[name] ) return replaceables[name].replace(f);
    return (replaceables[name] = Replaceable(name,f));

    function Replaceable(name, f) {
      function wrapper() { return f.apply(this,arguments); }
      wrapper.replace = function replace(newF) { return f = newF, null; };
      return wrapper;
    }
  }

  chat.os.setInterval = function( upgrade, name, f, interval ) {
    intervals[upgrade] = intervals[upgrade] || {};
    if ( intervals[upgrade][name] ) clearInterval( intervals[upgrade][name] );
    return intervals[upgrade][name] = setInterval( f, interval );
  }

  chat.os.setTimeout = function( upgrade, name, f, interval ) {
    timeouts[upgrade] = timeouts[upgrade] || {};
    if ( timeouts[upgrade][name] ) clearInterval( timeouts[upgrade][name] );
    return timeouts[upgrade][name] = setInterval( f, interval );
  }

  chat.os.requestAnimationFrame = function( upgrade, name, f ) {
    animationFrames[upgrade] = animationFrames[upgrade] || {};
    if ( animationFrames[upgrade][name] ) cancelAnimationFrame( animationFrames[upgrade][name] );
    return animationFrames[upgrade][name] = requestAnimationFrame( f );
  }

  chat.os.addInputHandler(reset,1);
  chat.os.addInputHandler(upgrade);

  chat.os.addOutputHandler(onaction,1);
})();
<|endoftext|>


<commit_before>import Cartesian2 from "../Core/Cartesian2.js";
import Cartesian3 from "../Core/Cartesian3.js";
import Cartesian4 from "../Core/Cartesian4.js";
import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import Matrix2 from "../Core/Matrix2.js";
import Matrix3 from "../Core/Matrix3.js";
import Matrix4 from "../Core/Matrix4.js";
import MetadataType from "./MetadataType.js";
import MetadataComponentType from "./MetadataComponentType.js";

/**
 * A metadata property, as part of a {@link MetadataClass}
 *
 * @param {Object} options Object with the following properties:
 * @param {String} options.id The ID of the property.
 * @param {Object} options.property The property JSON object.
 * @param {Object.<String, MetadataEnum>} [options.enums] A dictionary of enums.
 *
 * @alias MetadataClassProperty
 * @constructor
 * @private
 * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
 */
function MetadataClassProperty(options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  var id = options.id;
  var property = options.property;

  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.string("options.id", id);
  Check.typeOf.object("options.property", property);
  //>>includeEnd('debug');

  var enumType;
  if (defined(property.enumType)) {
    enumType = options.enums[property.enumType];
  }

  var type = defaultValue(MetadataType[property.type], MetadataType.SINGLE);
  var componentType = MetadataComponentType[property.componentType];
  if (MetadataComponentType.hasOwnProperty(type)) {
    // in EXT_feature_metadata, single values were part of type, not
    // componentType. Transcode to the newer format.
    type = MetadataType.SINGLE;
    componentType = MetadataComponentType[property.type];
  }
  var valueType = getValueType(componentType, enumType);

  var normalized =
    MetadataComponentType.isIntegerType(componentType) &&
    defaultValue(property.normalized, false);

  this._id = id;
  this._name = property.name;
  this._description = property.description;
  this._type = type;
  this._enumType = enumType;
  this._valueType = valueType;
  this._componentType = componentType;
  this._componentCount = property.componentCount;
  this._normalized = normalized;
  this._min = property.min;
  this._max = property.max;
  this._default = property.default;
  this._optional = defaultValue(property.optional, false);
  this._semantic = property.semantic;
  this._extras = property.extras;
  this._extensions = property.extensions;
}

Object.defineProperties(MetadataClassProperty.prototype, {
  /**
   * The ID of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  id: {
    get: function () {
      return this._id;
    },
  },

  /**
   * The name of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  name: {
    get: function () {
      return this._name;
    },
  },

  /**
   * The description of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  description: {
    get: function () {
      return this._description;
    },
  },

  /**
   * The type of the property. Each type holds one (SINGLE) or more components
   * (ARRAY, VECN, MATN).
   *
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataType}
   * @readonly
   * @private
   */
  type: {
    get: function () {
      return this._type;
    },
  },

  /**
   * The enum type of the property. Only defined when type or componentType is ENUM.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataEnum}
   * @readonly
   * @private
   */
  enumType: {
    get: function () {
      return this._enumType;
    },
  },

  /**
   * The component type of the property. These are
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataComponentType}
   * @readonly
   * @private
   */
  componentType: {
    get: function () {
      return this._componentType;
    },
  },

  /**
   * The datatype used for storing each component of the property. This
   * is usually the same as componentType except for ENUM, where this
   * returns an integer type
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataComponentType}
   * @readonly
   * @private
   */
  valueType: {
    get: function () {
      return this._valueType;
    },
  },

  /**
   * The number of components per element. Only defined when type is a fixed size ARRAY.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number}
   * @readonly
   * @private
   */
  componentCount: {
    get: function () {
      return this._componentCount;
    },
  },

  /**
   * Whether the property is normalized.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean}
   * @readonly
   * @private
   */
  normalized: {
    get: function () {
      return this._normalized;
    },
  },

  /**
   * A number or an array of numbers storing the maximum allowable value of this property. Only defined when type or componentType is a numeric type.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number|Number[]}
   * @readonly
   * @private
   */
  max: {
    get: function () {
      return this._max;
    },
  },

  /**
   * A number or an array of numbers storing the minimum allowable value of this property. Only defined when type or componentType is a numeric type.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number|Number[]}
   * @readonly
   * @private
   */
  min: {
    get: function () {
      return this._min;
    },
  },

  /**
   * A default value to use when an entity's property value is not defined.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean|Number|String|Array}
   * @readonly
   * @private
   */
  default: {
    get: function () {
      return this._default;
    },
  },

  /**
   * Whether the property is optional.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean}
   * @readonly
   * @private
   */
  optional: {
    get: function () {
      return this._optional;
    },
  },

  /**
   * An identifier that describes how this property should be interpreted.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  semantic: {
    get: function () {
      return this._semantic;
    },
  },

  /**
   * Extras in the JSON object.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {*}
   * @readonly
   * @private
   */
  extras: {
    get: function () {
      return this._extras;
    },
  },

  /**
   * Extensions in the JSON object.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Object}
   * @readonly
   * @private
   */
  extensions: {
    get: function () {
      return this._extensions;
    },
  },
});

/**
 * Normalizes integer property values. If the property is not normalized
 * the value is returned unmodified.
 *
 * @param {*} value The integer value or array of integer values.
 * @returns {*} The normalized value or array of normalized values.
 *
 * @private
 */
MetadataClassProperty.prototype.normalize = function (value) {
  return normalize(this, value, MetadataComponentType.normalize);
};

/**
 * Unnormalizes integer property values. If the property is not normalized
 * the value is returned unmodified.
 *
 * @param {*} value The normalized value or array of normalized values.
 * @returns {*} The integer value or array of integer values.
 *
 * @private
 */
MetadataClassProperty.prototype.unnormalize = function (value) {
  return normalize(this, value, MetadataComponentType.unnormalize);
};

/**
 * Unpack VECN values into {@link Cartesian2}, {@link Cartesian3}, or
 * {@link Cartesian4} depending on N. All other values (including arrays of
 * other sizes) are passed through unaltered.
 *
 * @param {*} value the original, normalized values.
 * @returns {*} The appropriate vector type if the value is a vector type. Otherwise, the value is returned unaltered.
 * @private
 */
MetadataClassProperty.prototype.unpackVectorAndMatrixTypes = function (value) {
  switch (this._type) {
    case MetadataType.VEC2:
      return Cartesian2.unpack(value);
    case MetadataType.VEC3:
      return Cartesian3.unpack(value);
    case MetadataType.VEC4:
      return Cartesian4.unpack(value);
    case MetadataType.MAT2:
      return Matrix2.unpack(value);
    case MetadataType.MAT3:
      return Matrix3.unpack(value);
    case MetadataType.MAT4:
      return Matrix4.unpack(value);
    default:
      return value;
  }
};

/**
 * Pack a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} into an
 * array if this property is an VECN
 * All other values (including arrays of other sizes) are passed through unaltered.
 *
 * @param {*} value The value of this property
 * @returns {*} An array of the appropriate length if the property is a vector type. Otherwise, the value is returned unaltered.
 * @private
 */
MetadataClassProperty.prototype.packVectorAndMatrixTypes = function (value) {
  switch (this._type) {
    case MetadataType.VEC2:
      return Cartesian2.pack(value, []);
    case MetadataType.VEC3:
      return Cartesian3.pack(value, []);
    case MetadataType.VEC4:
      return Cartesian4.pack(value, []);
    case MetadataType.MAT2:
      return Matrix2.pack(value, []);
    case MetadataType.MAT3:
      return Matrix3.pack(value, []);
    case MetadataType.MAT4:
      return Matrix4.pack(value, []);
    default:
      return value;
  }
};

/**
 * Validates whether the given value conforms to the property.
 *
 * @param {*} value The value.
 * @returns {String|undefined} An error message if the value does not conform to the property, otherwise undefined.
 * @private
 */
MetadataClassProperty.prototype.validate = function (value) {
  var type = this._type;
  var componentType = this._componentType;

  if (MetadataType.isVectorType(type) || MetadataType.isMatrixType(type)) {
    return validateVectorOrMatrix(value, type, componentType);
  } else if (type === MetadataType.ARRAY) {
    return validateArray(this, value, this._componentCount);
  }

  return checkValue(this, value);
};

function validateArray(classProperty, value, componentCount) {
  if (!Array.isArray(value)) {
    return getTypeErrorMessage(value, MetadataType.ARRAY);
  }
  var length = value.length;
  if (defined(componentCount) && componentCount !== length) {
    return "Array length does not match componentCount";
  }
  for (var i = 0; i < length; ++i) {
    var message = checkValue(classProperty, value[i]);
    if (defined(message)) {
      return message;
    }
  }
}

function validateVectorOrMatrix(value, type, componentType) {
  if (!MetadataComponentType.isVectorCompatible(componentType)) {
    var message = type + " has an incompatible componentType " + componentType;
    if (MetadataType.isVectorType(type)) {
      return "vector value " + message;
    }

    return "matrix value " + message;
  }

  if (type === MetadataType.VEC2 && !(value instanceof Cartesian2)) {
    return "vector value " + value + " must be a Cartesian2";
  }

  if (type === MetadataType.VEC3 && !(value instanceof Cartesian3)) {
    return "vector value " + value + " must be a Cartesian3";
  }

  if (type === MetadataType.VEC4 && !(value instanceof Cartesian4)) {
    return "vector value " + value + " must be a Cartesian4";
  }

  if (type === MetadataType.MAT2 && !(value instanceof Matrix2)) {
    return "matrix value " + value + " must be a Matrix2";
  }

  if (type === MetadataType.MAT3 && !(value instanceof Matrix3)) {
    return "matrix value " + value + " must be a Matrix3";
  }

  if (type === MetadataType.MAT4 && !(value instanceof Matrix4)) {
    return "matrix value " + value + " must be a Matrix4";
  }
}

function getTypeErrorMessage(value, type) {
  return "value " + value + " does not match type " + type;
}

function getOutOfRangeErrorMessage(value, type, normalized) {
  var errorMessage = "value " + value + " is out of range for type " + type;
  if (normalized) {
    errorMessage += " (normalized)";
  }
  return errorMessage;
}

function checkInRange(value, componentType, normalized) {
  if (normalized) {
    var min = MetadataComponentType.isUnsignedIntegerType(componentType)
      ? 0.0
      : -1.0;
    var max = 1.0;
    if (value < min || value > max) {
      return getOutOfRangeErrorMessage(value, componentType, normalized);
    }
    return;
  }

  if (
    value < MetadataComponentType.getMinimum(componentType) ||
    value > MetadataComponentType.getMaximum(componentType)
  ) {
    return getOutOfRangeErrorMessage(value, componentType, normalized);
  }
}

function checkValue(classProperty, value) {
  var javascriptType = typeof value;

  var enumType = classProperty._enumType;
  if (defined(enumType)) {
    if (javascriptType !== "string" || !defined(enumType.valuesByName[value])) {
      return "value " + value + " is not a valid enum name for " + enumType.id;
    }
    return;
  }

  var valueType = classProperty._valueType;
  var normalized = classProperty._normalized;

  switch (valueType) {
    case MetadataComponentType.INT8:
    case MetadataComponentType.UINT8:
    case MetadataComponentType.INT16:
    case MetadataComponentType.UINT16:
    case MetadataComponentType.INT32:
    case MetadataComponentType.UINT32:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      return checkInRange(value, valueType, normalized);
    case MetadataComponentType.INT64:
    case MetadataComponentType.UINT64:
      if (javascriptType !== "number" && javascriptType !== "bigint") {
        return getTypeErrorMessage(value, valueType);
      }
      return checkInRange(value, valueType, normalized);
    case MetadataComponentType.FLOAT32:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      if (isFinite(value)) {
        return checkInRange(value, valueType, normalized);
      }
      break;
    case MetadataComponentType.FLOAT64:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
    case MetadataComponentType.BOOLEAN:
      if (javascriptType !== "boolean") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
    case MetadataComponentType.STRING:
      if (javascriptType !== "string") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
  }
}

function normalize(classProperty, value, normalizeFunction) {
  var normalized = classProperty._normalized;
  if (!normalized) {
    return value;
  }

  var type = classProperty._type;
  var valueType = classProperty._valueType;

  if (type === MetadataType.ARRAY) {
    var length = value.length;
    for (var i = 0; i < length; ++i) {
      value[i] = normalizeFunction(value[i], valueType);
    }
  } else if (MetadataType.isVectorType(type)) {
    throw "TODO: Normalize vector types";
  } else if (MetadataType.isMatrixType(type)) {
    throw "TODO: Normalize matrix types";
  } else {
    value = normalizeFunction(value, valueType);
  }

  return value;
}

function getValueType(componentType, enumType) {
  if (componentType === MetadataComponentType.ENUM) {
    return enumType.valueType;
  }

  return componentType;
}

export default MetadataClassProperty;
<commit_msg>Fix type parsing logic<commit_after>import Cartesian2 from "../Core/Cartesian2.js";
import Cartesian3 from "../Core/Cartesian3.js";
import Cartesian4 from "../Core/Cartesian4.js";
import Check from "../Core/Check.js";
import defaultValue from "../Core/defaultValue.js";
import defined from "../Core/defined.js";
import Matrix2 from "../Core/Matrix2.js";
import Matrix3 from "../Core/Matrix3.js";
import Matrix4 from "../Core/Matrix4.js";
import MetadataType from "./MetadataType.js";
import MetadataComponentType from "./MetadataComponentType.js";

/**
 * A metadata property, as part of a {@link MetadataClass}
 *
 * @param {Object} options Object with the following properties:
 * @param {String} options.id The ID of the property.
 * @param {Object} options.property The property JSON object.
 * @param {Object.<String, MetadataEnum>} [options.enums] A dictionary of enums.
 *
 * @alias MetadataClassProperty
 * @constructor
 * @private
 * @experimental This feature is using part of the 3D Tiles spec that is not final and is subject to change without Cesium's standard deprecation policy.
 */
function MetadataClassProperty(options) {
  options = defaultValue(options, defaultValue.EMPTY_OBJECT);
  var id = options.id;
  var property = options.property;

  //>>includeStart('debug', pragmas.debug);
  Check.typeOf.string("options.id", id);
  Check.typeOf.object("options.property", property);
  //>>includeEnd('debug');

  var enumType;
  if (defined(property.enumType)) {
    enumType = options.enums[property.enumType];
  }

  var type = property.type;
  var componentType;
  if (MetadataComponentType.hasOwnProperty(type)) {
    // For EXT_feature_metadata, single values were part of type, not
    // componentType. Transcode to the newer format.
    componentType = MetadataComponentType[type];
    type = MetadataType.SINGLE;
  } else {
    type = defaultValue(MetadataType[type], MetadataType.SINGLE);
    componentType = MetadataComponentType[property.componentType];
  }
  var valueType = getValueType(componentType, enumType);

  var normalized =
    MetadataComponentType.isIntegerType(componentType) &&
    defaultValue(property.normalized, false);

  this._id = id;
  this._name = property.name;
  this._description = property.description;
  this._type = type;
  this._enumType = enumType;
  this._valueType = valueType;
  this._componentType = componentType;
  this._componentCount = property.componentCount;
  this._normalized = normalized;
  this._min = property.min;
  this._max = property.max;
  this._default = property.default;
  this._optional = defaultValue(property.optional, false);
  this._semantic = property.semantic;
  this._extras = property.extras;
  this._extensions = property.extensions;
}

Object.defineProperties(MetadataClassProperty.prototype, {
  /**
   * The ID of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  id: {
    get: function () {
      return this._id;
    },
  },

  /**
   * The name of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  name: {
    get: function () {
      return this._name;
    },
  },

  /**
   * The description of the property.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  description: {
    get: function () {
      return this._description;
    },
  },

  /**
   * The type of the property. Each type holds one (SINGLE) or more components
   * (ARRAY, VECN, MATN).
   *
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataType}
   * @readonly
   * @private
   */
  type: {
    get: function () {
      return this._type;
    },
  },

  /**
   * The enum type of the property. Only defined when type or componentType is ENUM.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataEnum}
   * @readonly
   * @private
   */
  enumType: {
    get: function () {
      return this._enumType;
    },
  },

  /**
   * The component type of the property. These are
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataComponentType}
   * @readonly
   * @private
   */
  componentType: {
    get: function () {
      return this._componentType;
    },
  },

  /**
   * The datatype used for storing each component of the property. This
   * is usually the same as componentType except for ENUM, where this
   * returns an integer type
   *
   * @memberof MetadataClassProperty.prototype
   * @type {MetadataComponentType}
   * @readonly
   * @private
   */
  valueType: {
    get: function () {
      return this._valueType;
    },
  },

  /**
   * The number of components per element. Only defined when type is a fixed size ARRAY.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number}
   * @readonly
   * @private
   */
  componentCount: {
    get: function () {
      return this._componentCount;
    },
  },

  /**
   * Whether the property is normalized.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean}
   * @readonly
   * @private
   */
  normalized: {
    get: function () {
      return this._normalized;
    },
  },

  /**
   * A number or an array of numbers storing the maximum allowable value of this property. Only defined when type or componentType is a numeric type.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number|Number[]}
   * @readonly
   * @private
   */
  max: {
    get: function () {
      return this._max;
    },
  },

  /**
   * A number or an array of numbers storing the minimum allowable value of this property. Only defined when type or componentType is a numeric type.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Number|Number[]}
   * @readonly
   * @private
   */
  min: {
    get: function () {
      return this._min;
    },
  },

  /**
   * A default value to use when an entity's property value is not defined.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean|Number|String|Array}
   * @readonly
   * @private
   */
  default: {
    get: function () {
      return this._default;
    },
  },

  /**
   * Whether the property is optional.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Boolean}
   * @readonly
   * @private
   */
  optional: {
    get: function () {
      return this._optional;
    },
  },

  /**
   * An identifier that describes how this property should be interpreted.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {String}
   * @readonly
   * @private
   */
  semantic: {
    get: function () {
      return this._semantic;
    },
  },

  /**
   * Extras in the JSON object.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {*}
   * @readonly
   * @private
   */
  extras: {
    get: function () {
      return this._extras;
    },
  },

  /**
   * Extensions in the JSON object.
   *
   * @memberof MetadataClassProperty.prototype
   * @type {Object}
   * @readonly
   * @private
   */
  extensions: {
    get: function () {
      return this._extensions;
    },
  },
});

/**
 * Normalizes integer property values. If the property is not normalized
 * the value is returned unmodified.
 *
 * @param {*} value The integer value or array of integer values.
 * @returns {*} The normalized value or array of normalized values.
 *
 * @private
 */
MetadataClassProperty.prototype.normalize = function (value) {
  return normalize(this, value, MetadataComponentType.normalize);
};

/**
 * Unnormalizes integer property values. If the property is not normalized
 * the value is returned unmodified.
 *
 * @param {*} value The normalized value or array of normalized values.
 * @returns {*} The integer value or array of integer values.
 *
 * @private
 */
MetadataClassProperty.prototype.unnormalize = function (value) {
  return normalize(this, value, MetadataComponentType.unnormalize);
};

/**
 * Unpack VECN values into {@link Cartesian2}, {@link Cartesian3}, or
 * {@link Cartesian4} depending on N. All other values (including arrays of
 * other sizes) are passed through unaltered.
 *
 * @param {*} value the original, normalized values.
 * @returns {*} The appropriate vector type if the value is a vector type. Otherwise, the value is returned unaltered.
 * @private
 */
MetadataClassProperty.prototype.unpackVectorAndMatrixTypes = function (value) {
  switch (this._type) {
    case MetadataType.VEC2:
      return Cartesian2.unpack(value);
    case MetadataType.VEC3:
      return Cartesian3.unpack(value);
    case MetadataType.VEC4:
      return Cartesian4.unpack(value);
    case MetadataType.MAT2:
      return Matrix2.unpack(value);
    case MetadataType.MAT3:
      return Matrix3.unpack(value);
    case MetadataType.MAT4:
      return Matrix4.unpack(value);
    default:
      return value;
  }
};

/**
 * Pack a {@link Cartesian2}, {@link Cartesian3}, or {@link Cartesian4} into an
 * array if this property is an VECN
 * All other values (including arrays of other sizes) are passed through unaltered.
 *
 * @param {*} value The value of this property
 * @returns {*} An array of the appropriate length if the property is a vector type. Otherwise, the value is returned unaltered.
 * @private
 */
MetadataClassProperty.prototype.packVectorAndMatrixTypes = function (value) {
  switch (this._type) {
    case MetadataType.VEC2:
      return Cartesian2.pack(value, []);
    case MetadataType.VEC3:
      return Cartesian3.pack(value, []);
    case MetadataType.VEC4:
      return Cartesian4.pack(value, []);
    case MetadataType.MAT2:
      return Matrix2.pack(value, []);
    case MetadataType.MAT3:
      return Matrix3.pack(value, []);
    case MetadataType.MAT4:
      return Matrix4.pack(value, []);
    default:
      return value;
  }
};

/**
 * Validates whether the given value conforms to the property.
 *
 * @param {*} value The value.
 * @returns {String|undefined} An error message if the value does not conform to the property, otherwise undefined.
 * @private
 */
MetadataClassProperty.prototype.validate = function (value) {
  var type = this._type;
  var componentType = this._componentType;

  if (MetadataType.isVectorType(type) || MetadataType.isMatrixType(type)) {
    return validateVectorOrMatrix(value, type, componentType);
  } else if (type === MetadataType.ARRAY) {
    return validateArray(this, value, this._componentCount);
  }

  return checkValue(this, value);
};

function validateArray(classProperty, value, componentCount) {
  if (!Array.isArray(value)) {
    return getTypeErrorMessage(value, MetadataType.ARRAY);
  }
  var length = value.length;
  if (defined(componentCount) && componentCount !== length) {
    return "Array length does not match componentCount";
  }
  for (var i = 0; i < length; ++i) {
    var message = checkValue(classProperty, value[i]);
    if (defined(message)) {
      return message;
    }
  }
}

function validateVectorOrMatrix(value, type, componentType) {
  if (!MetadataComponentType.isVectorCompatible(componentType)) {
    var message = type + " has an incompatible componentType " + componentType;
    if (MetadataType.isVectorType(type)) {
      return "vector value " + message;
    }

    return "matrix value " + message;
  }

  if (type === MetadataType.VEC2 && !(value instanceof Cartesian2)) {
    return "vector value " + value + " must be a Cartesian2";
  }

  if (type === MetadataType.VEC3 && !(value instanceof Cartesian3)) {
    return "vector value " + value + " must be a Cartesian3";
  }

  if (type === MetadataType.VEC4 && !(value instanceof Cartesian4)) {
    return "vector value " + value + " must be a Cartesian4";
  }

  if (type === MetadataType.MAT2 && !(value instanceof Matrix2)) {
    return "matrix value " + value + " must be a Matrix2";
  }

  if (type === MetadataType.MAT3 && !(value instanceof Matrix3)) {
    return "matrix value " + value + " must be a Matrix3";
  }

  if (type === MetadataType.MAT4 && !(value instanceof Matrix4)) {
    return "matrix value " + value + " must be a Matrix4";
  }
}

function getTypeErrorMessage(value, type) {
  return "value " + value + " does not match type " + type;
}

function getOutOfRangeErrorMessage(value, type, normalized) {
  var errorMessage = "value " + value + " is out of range for type " + type;
  if (normalized) {
    errorMessage += " (normalized)";
  }
  return errorMessage;
}

function checkInRange(value, componentType, normalized) {
  if (normalized) {
    var min = MetadataComponentType.isUnsignedIntegerType(componentType)
      ? 0.0
      : -1.0;
    var max = 1.0;
    if (value < min || value > max) {
      return getOutOfRangeErrorMessage(value, componentType, normalized);
    }
    return;
  }

  if (
    value < MetadataComponentType.getMinimum(componentType) ||
    value > MetadataComponentType.getMaximum(componentType)
  ) {
    return getOutOfRangeErrorMessage(value, componentType, normalized);
  }
}

function checkValue(classProperty, value) {
  var javascriptType = typeof value;

  var enumType = classProperty._enumType;
  if (defined(enumType)) {
    if (javascriptType !== "string" || !defined(enumType.valuesByName[value])) {
      return "value " + value + " is not a valid enum name for " + enumType.id;
    }
    return;
  }

  var valueType = classProperty._valueType;
  var normalized = classProperty._normalized;

  switch (valueType) {
    case MetadataComponentType.INT8:
    case MetadataComponentType.UINT8:
    case MetadataComponentType.INT16:
    case MetadataComponentType.UINT16:
    case MetadataComponentType.INT32:
    case MetadataComponentType.UINT32:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      return checkInRange(value, valueType, normalized);
    case MetadataComponentType.INT64:
    case MetadataComponentType.UINT64:
      if (javascriptType !== "number" && javascriptType !== "bigint") {
        return getTypeErrorMessage(value, valueType);
      }
      return checkInRange(value, valueType, normalized);
    case MetadataComponentType.FLOAT32:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      if (isFinite(value)) {
        return checkInRange(value, valueType, normalized);
      }
      break;
    case MetadataComponentType.FLOAT64:
      if (javascriptType !== "number") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
    case MetadataComponentType.BOOLEAN:
      if (javascriptType !== "boolean") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
    case MetadataComponentType.STRING:
      if (javascriptType !== "string") {
        return getTypeErrorMessage(value, valueType);
      }
      break;
  }
}

function normalize(classProperty, value, normalizeFunction) {
  var normalized = classProperty._normalized;
  if (!normalized) {
    return value;
  }

  var type = classProperty._type;
  var valueType = classProperty._valueType;

  if (type === MetadataType.ARRAY) {
    var length = value.length;
    for (var i = 0; i < length; ++i) {
      value[i] = normalizeFunction(value[i], valueType);
    }
  } else if (MetadataType.isVectorType(type)) {
    throw "TODO: Normalize vector types";
  } else if (MetadataType.isMatrixType(type)) {
    throw "TODO: Normalize matrix types";
  } else {
    value = normalizeFunction(value, valueType);
  }

  return value;
}

function getValueType(componentType, enumType) {
  if (componentType === MetadataComponentType.ENUM) {
    return enumType.valueType;
  }

  return componentType;
}

export default MetadataClassProperty;
<|endoftext|>


<commit_before>app.controller('SearchFormController', ['$scope','Search','User',
    function($scope,Search,User) {
     if (annyang) {

        // Let's define our first command. First the text we expect, and then the function it should call
        var commands = {
          'go to contacts': function(account) {
            window.location.replace('/#/contacts');
          },
          'go to accounts': function(account) {
            window.location.replace('/#/accounts');
          },
          'go to leads': function(account) {
            window.location.replace('/#/leads');
          },
          'go to opportunities': function(account) {
            window.location.replace('/#/opportunities');
          },
          'go to cases': function(account) {
            window.location.replace('/#/cases');
          },
          'go to tasks': function(account) {
            window.location.replace('/#/tasks');
          },
          'search :account contacts': function(account) {
            $scope.searchQuery = account + ' and type:Contact';

            $scope.$apply();
            $scope.executeSearch($scope.searchQuery);
          },
          'search *term': function(term) {
            $scope.searchQuery = term;

            $scope.$apply();
            $scope.executeSearch($scope.searchQuery);
          }

        };

        // Add our commands to annyang
        annyang.addCommands(commands);

        // Start listening. You can call this here, or attach this call to an event, button, etc.
        annyang.start();
      }
     var params ={};
     $scope.results =[];
     $scope.result = undefined;
     $scope.q = undefined;
     $scope.searchQuery = undefined;
     $scope.$watch('searchQuery', function() {

         if($scope.searchQuery!=undefined){
           params['q'] = $scope.searchQuery;
           gapi.client.crmengine.search(params).execute(function(resp) {
              if (resp.items){
                $scope.results = resp.items;
                $scope.$apply();
              };

            });
        }
     });
     $scope.selectResult = function(){
      console.log('You are welcome On the morning day');
        var url = Search.getUrl($scope.searchQuery.type,$scope.searchQuery.id);
        $scope.searchQuery=' ';
        window.location.replace(url);
     };
     $scope.executeSearch = function(searchQuery){
      if (typeof(searchQuery)=='string'){
         window.location.replace('#/search/'+searchQuery);
      }else{
        var url = Search.getUrl($scope.searchQuery.type,$scope.searchQuery.id);
        $scope.searchQuery=' ';
        window.location.replace(url);
      }

     };
//HKA 25.03.2014 update user language
$scope.updatelanguage = function(user){
   //var params = {'id':$scope.user.id,
   // 'language':user.language};
    console.log('-----------hello user language--------');
   //User.patch($scope,params);
   $('#EditSetting').modal('hide');
}

}]);

app.controller('SearchShowController', ['$scope','$route', 'Auth','Search','User',
    function($scope,$route,Auth,Search,User) {
     $scope.isSignedIn = false;
     $scope.immediateFailed = false;
     $scope.nextPageToken = undefined;
     $scope.prevPageToken = undefined;
     $scope.isLoading = false;
     $scope.pagination = {};
     $scope.currentPage = 01;
     $scope.pages = [];

     // What to do after authentication
     $scope.runTheProcess = function(){
          var params = {'limit':7,'q':$route.current.params.q};
          Search.list($scope,params);
     };
     // We need to call this to refresh token when user credentials are invalid
     $scope.refreshToken = function() {
          Auth.refreshToken();
     };

     $scope.listNextPageItems = function(){
        var nextPage = $scope.currentPage + 1;
        var params = {};
          if ($scope.pages[nextPage]){
            params = {'q':$route.current.params.q,
                      'limit':7,

                      'pageToken':$scope.pages[nextPage]
                     }
          }else{
            params = {'q':$route.current.params.q,
                      'limit':7}
          }

          $scope.currentPage = $scope.currentPage + 1 ;
          Search.list($scope,params);
     };
     $scope.listPrevPageItems = function(){
       var prevPage = $scope.currentPage - 1;
       var params = {};
          if ($scope.pages[prevPage]){
            params = { 'q':$route.current.params.q,
                      'limit':7,

                      'pageToken':$scope.pages[prevPage]
                     }
        }else{
            params = {'q':$route.current.params.q,
                      'limit':7}
          }
          $scope.currentPage = $scope.currentPage - 1 ;
          Search.list($scope,params);
     };

//HKA 25.03.2014 update user language
$scope.updatelanguage = function(user,idUser){
  console.log(user.language);
  console.log('i am here');

  var params = {'id':idUser,
     'language':user.language};
   console.log('-----------hello user language--------');
   console.log(params);
   User.patch($scope,params);
   $('#EditSetting').modal('hide');
}
     // Google+ Authentication
     Auth.init($scope);

}]);
<commit_msg>disable voice search for now<commit_after>app.controller('SearchFormController', ['$scope','Search','User',
    function($scope,Search,User) {
     if (annyang) {

        // Let's define our first command. First the text we expect, and then the function it should call
        var commands = {
          'go to contacts': function(account) {
            window.location.replace('/#/contacts');
          },
          'go to accounts': function(account) {
            window.location.replace('/#/accounts');
          },
          'go to leads': function(account) {
            window.location.replace('/#/leads');
          },
          'go to opportunities': function(account) {
            window.location.replace('/#/opportunities');
          },
          'go to cases': function(account) {
            window.location.replace('/#/cases');
          },
          'go to tasks': function(account) {
            window.location.replace('/#/tasks');
          },
          'search :account contacts': function(account) {
            $scope.searchQuery = account + ' and type:Contact';

            $scope.$apply();
            $scope.executeSearch($scope.searchQuery);
          },
          'search *term': function(term) {
            $scope.searchQuery = term;

            $scope.$apply();
            $scope.executeSearch($scope.searchQuery);
          }

        };

        // Add our commands to annyang
        annyang.addCommands(commands);

        // Start listening. You can call this here, or attach this call to an event, button, etc.
        // annyang.start();
      }
     var params ={};
     $scope.results =[];
     $scope.result = undefined;
     $scope.q = undefined;
     $scope.searchQuery = undefined;
     $scope.$watch('searchQuery', function() {

         if($scope.searchQuery!=undefined){
           params['q'] = $scope.searchQuery;
           gapi.client.crmengine.search(params).execute(function(resp) {
              if (resp.items){
                $scope.results = resp.items;
                $scope.$apply();
              };

            });
        }
     });
     $scope.selectResult = function(){
      console.log('You are welcome On the morning day');
        var url = Search.getUrl($scope.searchQuery.type,$scope.searchQuery.id);
        $scope.searchQuery=' ';
        window.location.replace(url);
     };
     $scope.executeSearch = function(searchQuery){
      if (typeof(searchQuery)=='string'){
         window.location.replace('#/search/'+searchQuery);
      }else{
        var url = Search.getUrl($scope.searchQuery.type,$scope.searchQuery.id);
        $scope.searchQuery=' ';
        window.location.replace(url);
      }

     };
//HKA 25.03.2014 update user language
$scope.updatelanguage = function(user){
   //var params = {'id':$scope.user.id,
   // 'language':user.language};
    console.log('-----------hello user language--------');
   //User.patch($scope,params);
   $('#EditSetting').modal('hide');
}

}]);

app.controller('SearchShowController', ['$scope','$route', 'Auth','Search','User',
    function($scope,$route,Auth,Search,User) {
     $scope.isSignedIn = false;
     $scope.immediateFailed = false;
     $scope.nextPageToken = undefined;
     $scope.prevPageToken = undefined;
     $scope.isLoading = false;
     $scope.pagination = {};
     $scope.currentPage = 01;
     $scope.pages = [];

     // What to do after authentication
     $scope.runTheProcess = function(){
          var params = {'limit':7,'q':$route.current.params.q};
          Search.list($scope,params);
     };
     // We need to call this to refresh token when user credentials are invalid
     $scope.refreshToken = function() {
          Auth.refreshToken();
     };

     $scope.listNextPageItems = function(){
        var nextPage = $scope.currentPage + 1;
        var params = {};
          if ($scope.pages[nextPage]){
            params = {'q':$route.current.params.q,
                      'limit':7,

                      'pageToken':$scope.pages[nextPage]
                     }
          }else{
            params = {'q':$route.current.params.q,
                      'limit':7}
          }

          $scope.currentPage = $scope.currentPage + 1 ;
          Search.list($scope,params);
     };
     $scope.listPrevPageItems = function(){
       var prevPage = $scope.currentPage - 1;
       var params = {};
          if ($scope.pages[prevPage]){
            params = { 'q':$route.current.params.q,
                      'limit':7,

                      'pageToken':$scope.pages[prevPage]
                     }
        }else{
            params = {'q':$route.current.params.q,
                      'limit':7}
          }
          $scope.currentPage = $scope.currentPage - 1 ;
          Search.list($scope,params);
     };

//HKA 25.03.2014 update user language
$scope.updatelanguage = function(user,idUser){
  console.log(user.language);
  console.log('i am here');

  var params = {'id':idUser,
     'language':user.language};
   console.log('-----------hello user language--------');
   console.log(params);
   User.patch($scope,params);
   $('#EditSetting').modal('hide');
}
     // Google+ Authentication
     Auth.init($scope);

}]);
<|endoftext|>


<commit_before>(function (flow, $, d3, Backbone) {
    'use strict';

    flow.WorkflowView = Backbone.View.extend({

        initialize: function (settings) {
            this.steps = new Backbone.Collection();
            this.connections = new Backbone.Collection();
            this.edit = settings.edit || false;
        },

        render: function () {
            var newSteps = [], newConnections = [];
            this.model.get('steps').forEach(function (d) {
                d.id = d.id || d.name;
                d.task.outputScale = d3.scale.linear().domain([0, d.task.outputs.length - 1]).range([10, 90]);
                d.task.inputScale = d3.scale.linear().domain([0, d.task.inputs.length - 1]).range([10, 90]);
                newSteps.push(d);
            });
            this.model.get('inputs').forEach(function (d) {
                var input = $.extend(true, {}, d);
                input.isInput = true;
                input.id = d.id || d.name;
                input.task = {
                    inputs: [],
                    outputs: [d],
                    outputScale: function (d) { return 50; }
                }
                newSteps.push(input);
            });
            this.model.get('outputs').forEach(function (d) {
                var output = $.extend(true, {}, d);
                output.isOutput = true;
                output.id = d.id || d.name;
                output.task = {
                    inputs: [d],
                    outputs: [],
                    inputScale: function (d) { return 50; }
                }
                newSteps.push(output);
            });
            this.steps.set(newSteps);

            this.model.get('connections').forEach(_.bind(function (d) {
                var inName = d.input_step || d.name,
                    outName = d.output_step || d.name;
                d.inputStep = this.steps.get(inName);
                d.outputStep = this.steps.get(outName);
                d.inputStep.get('task').inputs.forEach(function (input, index) {
                    if ((input.id || input.name) === (d.input || d.name)) {
                        d.inputIndex = index;
                        d.inputPos = d.inputStep.get('task').inputScale(index);
                    }
                });
                d.outputStep.get('task').outputs.forEach(function (output, index) {
                    if ((output.id || output.name) === (d.output || d.name)) {
                        d.outputIndex = index;
                        d.outputPos = d.outputStep.get('task').outputScale(index);
                    }
                });
                newConnections.push(d);
            }, this));
            this.connections.set(newConnections);

            this.$el.html(jade.templates.workflow(this.model.toJSON()));

            this.stepsView = new flow.ItemsView({
                el: this.$('.steps'),
                collection: this.steps,
                itemView: flow.WorkflowStepView,
                itemOptions: {workflowView: this}
            });
            this.stepsView.render();
            this.connectionsView = new flow.ItemsView({
                el: this.$('.connections'),
                collection: this.connections,
                itemView: flow.WorkflowConnectionView,
                itemOptions: {workflowView: this}
            });
            this.connectionsView.render();
            return this;
        },

        addStep: function(task, girderId, modified) {
            var step = {}, index = 1, model;
            step.id = task.id || task.name;
            step.name = step.id;
            step.isOutput = task.isOutput;
            step.isInput = task.isInput;
            step.visualization = task.visualization || false;
            step.task = task;
            step.task.outputScale = d3.scale.linear().domain([0, step.task.outputs.length - 1]).range([10, 90]);
            step.task.inputScale = d3.scale.linear().domain([0, step.task.inputs.length - 1]).range([10, 90]);
            step.girderId = girderId;
            step.modified = modified;
            step.x = task.x || 200;
            step.y = task.y || 200;
            while (this.steps.get(step.id)) {
                step.id = (task.id || task.name) + ' ' + index;
                step.name = step.id;
                index += 1;
            }
            model = new Backbone.Model(step);
            this.steps.add(model);
            return model;
        },

        editable: function (edit) {
            this.edit = edit;
            this.render();
        },

        serialize: function () {
            var task = {
                inputs: [],
                outputs: [],
                steps: [],
                connections: []
            };

            this.steps.forEach(function (step) {
                if (step.get('isInput')) {
                    task.inputs.push({
                        id: step.id,
                        name: step.get('name'),
                        type: step.get('task').outputs[0].type,
                        format: step.get('task').outputs[0].format,
                        x: step.get('x'),
                        y: step.get('y')
                    });
                } else if (step.get('isOutput')) {
                    task.outputs.push({
                        id: step.id,
                        name: step.get('name'),
                        type: step.get('task').inputs[0].type,
                        format: step.get('task').inputs[0].format,
                        x: step.get('x'),
                        y: step.get('y')
                    });
                } else {
                    task.steps.push({
                        x: step.get('x'),
                        y: step.get('y'),
                        id: step.id,
                        name: step.get('name'),
                        visualization: step.get('visualization'),
                        girderId: step.get('girderId'),
                        modified: step.get('modified'),
                        task: step.get('task')
                    });
                }
            });

            this.connections.forEach(function (c) {
                if (c.get('outputStep').get('isInput')) {
                    task.connections.push({
                        name: c.get('outputStep').id,
                        input_step: c.get('inputStep').id,
                        input: c.get('inputStep').get('task').inputs[c.get('inputIndex')].name
                    });
                } else if (c.get('inputStep').get('isOutput')) {
                    task.connections.push({
                        name: c.get('inputStep').id,
                        output_step: c.get('outputStep').id,
                        output: c.get('outputStep').get('task').outputs[c.get('outputIndex')].name
                    });
                } else {
                    task.connections.push({
                        output_step: c.get('outputStep').id,
                        output: c.get('outputStep').get('task').outputs[c.get('outputIndex')].name,
                        input_step: c.get('inputStep').id,
                        input: c.get('inputStep').get('task').inputs[c.get('inputIndex')].name
                    });
                }
            });

            return task;
        },

        removeTooltips: function () {
            this.$('.tooltip').remove();
        },

        connectionPath: function (d) {
            var dist,
                delta,
                offset,
                portOffset = 20,
                inPos = {x: d.get('inputStep').get('x'), y: d.get('inputStep').get('y')},
                outPos = {x: d.get('outputStep').get('x'), y: d.get('outputStep').get('y')},
                inputPos = d.get('inputPos'),
                outputPos = d.get('outputPos');
            delta = [outPos.x- inPos.x, outPos.y - inPos.y];
            dist = Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
            offset = 0.4 * dist - 50;
            offset = offset < 0 ? 0 : offset;
            return 'M ' + (outPos.x + 150 + portOffset) + ' ' + (outPos.y + outputPos) +
                ' C ' + (outPos.x + 150 + portOffset + offset) + ' ' + (outPos.y + outputPos) +
                ' ' + (inPos.x  - portOffset - offset) + ' ' + (inPos.y + inputPos) +
                ' ' + (inPos.x - portOffset) + ' ' + (inPos.y + inputPos);
        },

        startConnectionDrag: function (step, index) {
            var portOffset = 20;
            this.dragOutput = step;
            this.dragOutputIndex = index;
            this.dragConnection = new Backbone.Model({
                outputStep: step,
                outputPos: step.get('task').outputScale(index),
                inputStep: new Backbone.Model({x: step.get('x') + 150 + portOffset + 20, y: step.get('y') + step.get('task').outputScale(index)}),
                inputPos: 0
            });
            this.$('.drag-connection').attr('visibility', 'visible');
            this.$('.drag-connection').attr('d', this.connectionPath(this.dragConnection));
        },

        updateConnectionDrag: function (dx, dy) {
            this.dragConnection.get('inputStep').set('x', this.dragConnection.get('inputStep').get('x') + dx);
            this.dragConnection.get('inputStep').set('y', this.dragConnection.get('inputStep').get('y') + dy);
            this.$('.drag-connection').attr('d', this.connectionPath(this.dragConnection));
        },

        endConnectionDrag: function () {
            this.$('.drag-connection').attr('visibility', 'hidden');
            this.dragOutput = undefined;
            this.dragOutputIndex = undefined;
        },

        checkConnectionComplete: function (step, index) {
            var existing;
            if (this.dragOutput !== undefined &&
                this.dragOutput.get('task').outputs[this.dragOutputIndex].type === step.get('task').inputs[index].type) {

                // Remove any existing connection to this input
                this.connections.remove(this.connections.filter(function (conn) {
                    return conn.get('inputStep') === step && conn.get('inputIndex') === index;
                }));

                // Add the new connection
                this.connections.add({
                    outputStep: this.dragOutput,
                    outputIndex: this.dragOutputIndex,
                    outputPos: this.dragOutput.get('task').outputScale(this.dragOutputIndex),
                    inputStep: step,
                    inputIndex: index,
                    inputPos: step.get('task').inputScale(index)
                });

                this.dragOutput = undefined;
                this.dragOutputIndex = undefined;
            }
        }
    });

}(window.flow, window.$, window.d3, window.Backbone));
<commit_msg>Fixing serialization<commit_after>(function (flow, $, d3, Backbone) {
    'use strict';

    flow.WorkflowView = Backbone.View.extend({

        initialize: function (settings) {
            this.steps = new Backbone.Collection();
            this.connections = new Backbone.Collection();
            this.edit = settings.edit || false;
        },

        render: function () {
            var newSteps = [], newConnections = [];
            this.model.get('steps').forEach(function (d) {
                d.id = d.id || d.name;
                d.task.outputScale = d3.scale.linear().domain([0, d.task.outputs.length - 1]).range([10, 90]);
                d.task.inputScale = d3.scale.linear().domain([0, d.task.inputs.length - 1]).range([10, 90]);
                newSteps.push(d);
            });
            this.model.get('inputs').forEach(function (d) {
                var input = $.extend(true, {}, d);
                input.isInput = true;
                input.id = d.id || d.name;
                input.task = {
                    inputs: [],
                    outputs: [d],
                    outputScale: function (d) { return 50; }
                }
                newSteps.push(input);
            });
            this.model.get('outputs').forEach(function (d) {
                var output = $.extend(true, {}, d);
                output.isOutput = true;
                output.id = d.id || d.name;
                output.task = {
                    inputs: [d],
                    outputs: [],
                    inputScale: function (d) { return 50; }
                }
                newSteps.push(output);
            });
            this.steps.set(newSteps);

            this.model.get('connections').forEach(_.bind(function (d) {
                var inName = d.input_step || d.name,
                    outName = d.output_step || d.name;
                d.inputStep = this.steps.get(inName);
                d.outputStep = this.steps.get(outName);
                d.inputStep.get('task').inputs.forEach(function (input, index) {
                    if ((input.id || input.name) === (d.input || d.name)) {
                        d.inputIndex = index;
                        d.inputPos = d.inputStep.get('task').inputScale(index);
                    }
                });
                d.outputStep.get('task').outputs.forEach(function (output, index) {
                    if ((output.id || output.name) === (d.output || d.name)) {
                        d.outputIndex = index;
                        d.outputPos = d.outputStep.get('task').outputScale(index);
                    }
                });
                newConnections.push(d);
            }, this));
            this.connections.set(newConnections);

            this.$el.html(jade.templates.workflow(this.model.toJSON()));

            this.stepsView = new flow.ItemsView({
                el: this.$('.steps'),
                collection: this.steps,
                itemView: flow.WorkflowStepView,
                itemOptions: {workflowView: this}
            });
            this.stepsView.render();
            this.connectionsView = new flow.ItemsView({
                el: this.$('.connections'),
                collection: this.connections,
                itemView: flow.WorkflowConnectionView,
                itemOptions: {workflowView: this}
            });
            this.connectionsView.render();
            return this;
        },

        addStep: function(task, girderId, modified) {
            var step = {}, index = 1, model;
            step.id = task.id || task.name;
            step.name = step.id;
            step.isOutput = task.isOutput;
            step.isInput = task.isInput;
            step.visualization = task.visualization || false;
            step.task = task;
            step.task.outputScale = d3.scale.linear().domain([0, step.task.outputs.length - 1]).range([10, 90]);
            step.task.inputScale = d3.scale.linear().domain([0, step.task.inputs.length - 1]).range([10, 90]);
            step.girderId = girderId;
            step.modified = modified;
            step.x = task.x || 200;
            step.y = task.y || 200;
            while (this.steps.get(step.id)) {
                step.id = (task.id || task.name) + ' ' + index;
                step.name = step.id;
                index += 1;
            }
            model = new Backbone.Model(step);
            this.steps.add(model);
            return model;
        },

        editable: function (edit) {
            this.edit = edit;
            this.render();
        },

        serialize: function () {
            var task = {
                inputs: [],
                outputs: [],
                steps: [],
                connections: []
            };

            this.steps.forEach(function (step) {
                var input, output;
                if (step.get('isInput')) {
                    input = {
                        id: step.id,
                        name: step.get('name'),
                        type: step.get('task').outputs[0].type,
                        format: step.get('task').outputs[0].format,
                        x: step.get('x'),
                        y: step.get('y')
                    };
                    ['mode', 'domain', 'default', 'constant', 'description'].forEach(function (key) {
                        if (step.get(key)) {
                            input[key] = step.get(key);
                        }
                    });
                    task.inputs.push(input);
                } else if (step.get('isOutput')) {
                    output ={
                        id: step.id,
                        name: step.get('name'),
                        type: step.get('task').inputs[0].type,
                        format: step.get('task').inputs[0].format,
                        x: step.get('x'),
                        y: step.get('y')
                    };
                    ['description'].forEach(function (key) {
                        if (step.get(key)) {
                            output[key] = step.get(key);
                        }
                    });
                    task.outputs.push(output);
                } else {
                    task.steps.push({
                        x: step.get('x'),
                        y: step.get('y'),
                        id: step.id,
                        name: step.get('name'),
                        visualization: step.get('visualization'),
                        girderId: step.get('girderId'),
                        modified: step.get('modified'),
                        task: step.get('task')
                    });
                }
            });

            this.connections.forEach(function (c) {
                if (c.get('outputStep').get('isInput')) {
                    task.connections.push({
                        name: c.get('outputStep').id,
                        input_step: c.get('inputStep').id,
                        input: c.get('inputStep').get('task').inputs[c.get('inputIndex')].name
                    });
                } else if (c.get('inputStep').get('isOutput')) {
                    task.connections.push({
                        name: c.get('inputStep').id,
                        output_step: c.get('outputStep').id,
                        output: c.get('outputStep').get('task').outputs[c.get('outputIndex')].name
                    });
                } else {
                    task.connections.push({
                        output_step: c.get('outputStep').id,
                        output: c.get('outputStep').get('task').outputs[c.get('outputIndex')].name,
                        input_step: c.get('inputStep').id,
                        input: c.get('inputStep').get('task').inputs[c.get('inputIndex')].name
                    });
                }
            });

            return task;
        },

        removeTooltips: function () {
            this.$('.tooltip').remove();
        },

        connectionPath: function (d) {
            var dist,
                delta,
                offset,
                portOffset = 20,
                inPos = {x: d.get('inputStep').get('x'), y: d.get('inputStep').get('y')},
                outPos = {x: d.get('outputStep').get('x'), y: d.get('outputStep').get('y')},
                inputPos = d.get('inputPos'),
                outputPos = d.get('outputPos');
            delta = [outPos.x- inPos.x, outPos.y - inPos.y];
            dist = Math.sqrt(delta[0] * delta[0] + delta[1] * delta[1]);
            offset = 0.4 * dist - 50;
            offset = offset < 0 ? 0 : offset;
            return 'M ' + (outPos.x + 150 + portOffset) + ' ' + (outPos.y + outputPos) +
                ' C ' + (outPos.x + 150 + portOffset + offset) + ' ' + (outPos.y + outputPos) +
                ' ' + (inPos.x  - portOffset - offset) + ' ' + (inPos.y + inputPos) +
                ' ' + (inPos.x - portOffset) + ' ' + (inPos.y + inputPos);
        },

        startConnectionDrag: function (step, index) {
            var portOffset = 20;
            this.dragOutput = step;
            this.dragOutputIndex = index;
            this.dragConnection = new Backbone.Model({
                outputStep: step,
                outputPos: step.get('task').outputScale(index),
                inputStep: new Backbone.Model({x: step.get('x') + 150 + portOffset + 20, y: step.get('y') + step.get('task').outputScale(index)}),
                inputPos: 0
            });
            this.$('.drag-connection').attr('visibility', 'visible');
            this.$('.drag-connection').attr('d', this.connectionPath(this.dragConnection));
        },

        updateConnectionDrag: function (dx, dy) {
            this.dragConnection.get('inputStep').set('x', this.dragConnection.get('inputStep').get('x') + dx);
            this.dragConnection.get('inputStep').set('y', this.dragConnection.get('inputStep').get('y') + dy);
            this.$('.drag-connection').attr('d', this.connectionPath(this.dragConnection));
        },

        endConnectionDrag: function () {
            this.$('.drag-connection').attr('visibility', 'hidden');
            this.dragOutput = undefined;
            this.dragOutputIndex = undefined;
        },

        checkConnectionComplete: function (step, index) {
            var existing;
            if (this.dragOutput !== undefined &&
                this.dragOutput.get('task').outputs[this.dragOutputIndex].type === step.get('task').inputs[index].type) {

                // Remove any existing connection to this input
                this.connections.remove(this.connections.filter(function (conn) {
                    return conn.get('inputStep') === step && conn.get('inputIndex') === index;
                }));

                // Add the new connection
                this.connections.add({
                    outputStep: this.dragOutput,
                    outputIndex: this.dragOutputIndex,
                    outputPos: this.dragOutput.get('task').outputScale(this.dragOutputIndex),
                    inputStep: step,
                    inputIndex: index,
                    inputPos: step.get('task').inputScale(index)
                });

                this.dragOutput = undefined;
                this.dragOutputIndex = undefined;
            }
        }
    });

}(window.flow, window.$, window.d3, window.Backbone));
<|endoftext|>