<commit_before>// This file expects a number of variables to be defined globally.
// Use only in conjunction with GraphView.getView
document.addEventListener("DOMContentLoaded", function(event) {
    var retryFrequency = 10,
        delay = 0;
    var intervalID = setInterval(function() {
        delay += retryFrequency;
        if (!document.body.offsetWidth || !document.body.offsetHeight) {
            if (delay > 6000) {
                displayError("Could not find document body.");
                clearInterval(intervalID);
            }
            return;
        }
        clearInterval(intervalID);

        try {
            // Match graph size to view size
            var titleHeight = (document.getElementById('chart-title') || { offsetHeight: 0 }).offsetHeight;
            config.size = {
                height: document.documentElement.offsetHeight - titleHeight,
                width: document.documentElement.offsetWidth,
            };

            // Turn off default hover/click behaviors
            config.interaction = { enabled: true };
            var formatXTooltip = function(x) {
                return x;
            }
            if (type === "time") {
                formatXTooltip = d3.time.format(config.axis.x.tick.format);
            }
            config.tooltip = {
                show: true,
                grouped: type === "bar",
                contents: function(yData, defaultTitleFormat, defaultValueFormat, color) {
                    var html = "";

                    // Add rows for y values
                    for (var i = 0; i < yData.length; i++) {
                        if (data.isData[yData[i].id]) {
                            var yName = config.data.names[yData[i].id];
                            html += "
" + yName + "	" + yData[i].value + "
";
                        }
                    }
                    if (!html) {
                        return "";
                    }

                    // Add a top row for x value
                    if (type === "bar") {
                        html = "
" + data.barLabels[yData[0].x] + "
" + html;
                    } else {
                        html = "
" + data.xNames[yData[0].id] + "	"
                                + formatXTooltip(yData[0].x) + "
"
                                + html;
                    }

                    if (type === "bubble") {
                        html += "
Radius	" + data.radii[d.id][d.index] + "
";
                    }

                    html = "
" + html + "
";
                    html = "
" + html + "
";
                    return html;
                },
            };

            // Set point size for bubble charts, and turn points off altogether
            // for other charts (we'll be using custom point shapes)
            config.point = {
                r: function(d) {
                    if (data.radii[d.id]) {
                        // Arbitrary max size of 30
                        return 30 * data.radii[d.id][d.index] / data.maxRadii[d.id];
                    }
                    return 0;
                },
            };

            // Add functions for custom tick label text (where foo-labels was an object).
            // Don't do this if the tick format was already set by Java (which will
            // only happen for time-based graphs that are NOT using custom tick text).
            if (config.axis.x.tick && !config.axis.x.tick.format) {
                config.axis.x.tick.format = function(d) {
                    var key = String(d);
                    if (type === "time") {
                        var time = key.match(/\d+:\d+:\d+/)[0];
                        key = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " " + time;

                    }
                    var label = axis.xLabels[key] || d;
                    return Math.round(label) || label;
                };
            }
            if (config.axis.y.tick) {
                config.axis.y.tick.format = function(d) {
                    return axis.yLabels[String(d)] || Math.round(d);
                };
            }
            if (config.axis.y2.tick) {
                config.axis.y2.tick.format = function(d) {
                    return axis.y2Labels[String(d)] || Math.round(d);
                };
            }

            // Hide any system-generated series from legend
            var hideSeries = [];
            for (var yID in config.data.xs) {
                if (!data.isData[yID]) {
                    hideSeries.push(yID);
                }
            }
            config.legend.hide = hideSeries;

            // Configure data labels, which we use only to display annotations
            config.data.labels = {
                format: function(value, id, index) {
                    return data.annotations[id] || '';
                },
            };

            // Don't use C3's default ordering for stacked series, use the order series are defined
            config.data.order = false;

            // Post-processing
            config.onrendered = function() {
                // For annotations series, nudge text so it appears on top of data point
                d3.selectAll("g.c3-texts text").attr("dy", 10);

                // Support point-style
                for (var yID in data.pointStyles) {
                    var symbol = data.pointStyles[yID];
                    applyPointShape(yID, symbol);
                    applyLegendShape(yID, symbol);
                }

                // Configure colors more specifically than C3 allows
                for (var yID in config.data.colors) {
                    // Data itself
                    if (type === "bar") {
                        var bars = d3.selectAll(".c3-bars-" + yID + " path")[0];
                        for (var i = 0; i < bars.length; i++) {
                            // If there's a bar-specific color, set it
                            if (data.barColors[yID] && data.barColors[yID][i]) {
                                bars[i].style.fill = data.barColors[yID][i];
                            }
                            // Get opacity: bar-specific if it's there, otherwise series-specific
                            var opacity;
                            if (data.barOpacities[yID]) {
                                opacity = data.barOpacities[yID][i];
                            }
                            opacity = opacity || data.lineOpacities[yID];
                            bars[i].style.opacity = opacity;
                        }
                    } else {
                        var line = d3.selectAll(".c3-lines-" + yID + " path")[0][0];
                        if (line) {
                            line.style.opacity = data.lineOpacities[yID];
                        }
                    }

                    // Legend
                    var legend = d3.selectAll(".c3-legend-item-" + yID + " path")[0];
                    if (!legend.length) {
                        legend = d3.selectAll(".c3-legend-item-" + yID + " line")[0];
                    }
                    if (legend.length) {
                        legend = legend[0];
                        legend.style.opacity = data.lineOpacities[yID];
                    }

                    // Point shapes
                    var points = d3.selectAll(".c3-circles-" + yID + " path")[0];
                    if (!points.length) {
                        points = d3.selectAll(".c3-circles-" + yID + " circle")[0];
                    }
                    for (var i = 0; i < points.length; i++) {
                        points[i].style.opacity = data.lineOpacities[yID];
                    }
                }
                for (var yID in data.areaColors) {
                    var area = d3.selectAll(".c3-areas-" + yID + " path")[0][0];
                    if (area) {
                        area.style.fill = data.areaColors[yID];
                        area.style.opacity = data.areaOpacities[yID];
                    }
                }
            };

            // Generate chart
            c3.generate(config);
        } catch(e) {
            displayError(e);
        }
    }, retryFrequency);
});

/**
 * Replace C3's default circle points with user-requested symbols.
 * @param yID String ID of y-values to manipulate
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 */
function applyPointShape(yID, symbol) {
    if (type === 'bar' || type === 'bubble') {
        return;
    }

    var circleSet = d3.selectAll(".c3-circles-" + yID);
    var circles = circleSet.selectAll("circle")[0];
    if (!circles) {
        return;
    }

    for (var j = 0; j < circles.length; j++) {
        circles[j].style.opacity = 0;    // hide default circle
        appendSymbol(
            circleSet,
            circles[j].cx.baseVal.value,
            circles[j].cy.baseVal.value,
            symbol,
            circles[j].style.fill
        );
    }
}

/**
 * Make shape displayed in legend match shape used on line.
 * @param yID String ID of y-values to manipulate
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 */
function applyLegendShape(yID, symbol) {
    if (symbol !== "none") {
        var legendItem = d3.selectAll(".c3-legend-item-" + yID);
        var line = legendItem.selectAll("line");    // there will only be one line
        if (!line || !line.length) {
            return;
        }
        line = line[0][0]
        line.style.opacity = 0;    // hide default square
        appendSymbol(
            legendItem,
            line.x1.baseVal.value + 5,
            line.y1.baseVal.value,
            symbol,
            line.style.stroke
        );
    }
}

/**
 * Add symbol to given element.
 * @param parent Element to attach symbol to
 * @param x x-coordinate to draw at
 * @param y y-coordinate to draw at
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 * @param color Color to draw symbol
 */
function appendSymbol(parent, x, y, symbol, color) {
    if (symbol === 'none') {
        return;
    }

    parent.append("path")
        .attr("transform", function (d) {
        return "translate(" + x + ", " + y + ")";
    })
        .attr("class", "symbol")
        .attr("d", d3.svg.symbol()
              .type(symbol)
              .size(50))
        .style("fill", color)
        .style("stroke", color);
}
<commit_msg>Fix graphs getting cut off<commit_after>// This file expects a number of variables to be defined globally.
// Use only in conjunction with GraphView.getView
document.addEventListener("DOMContentLoaded", function(event) {
    var retryFrequency = 10,
        delay = 0;
    var intervalID = setInterval(function() {
        delay += retryFrequency;
        if (!document.body.offsetWidth || !document.body.offsetHeight) {
            if (delay > 6000) {
                displayError("Could not find document body.");
                clearInterval(intervalID);
            }
            return;
        }
        clearInterval(intervalID);

        try {
            // Match graph size to view size
            var titleHeight = (document.getElementById('chart-title') || { offsetHeight: 0 }).offsetHeight;
            config.size = {
                height: document.body.offsetHeight - titleHeight,
                width: document.body.offsetWidth,
            };

            // Turn off default hover/click behaviors
            config.interaction = { enabled: true };
            var formatXTooltip = function(x) {
                return x;
            }
            if (type === "time") {
                formatXTooltip = d3.time.format(config.axis.x.tick.format);
            }
            config.tooltip = {
                show: true,
                grouped: type === "bar",
                contents: function(yData, defaultTitleFormat, defaultValueFormat, color) {
                    var html = "";

                    // Add rows for y values
                    for (var i = 0; i < yData.length; i++) {
                        if (data.isData[yData[i].id]) {
                            var yName = config.data.names[yData[i].id];
                            html += "
" + yName + "	" + yData[i].value + "
";
                        }
                    }
                    if (!html) {
                        return "";
                    }

                    // Add a top row for x value
                    if (type === "bar") {
                        html = "
" + data.barLabels[yData[0].x] + "
" + html;
                    } else {
                        html = "
" + data.xNames[yData[0].id] + "	"
                                + formatXTooltip(yData[0].x) + "
"
                                + html;
                    }

                    if (type === "bubble") {
                        html += "
Radius	" + data.radii[d.id][d.index] + "
";
                    }

                    html = "
" + html + "
";
                    html = "
" + html + "
";
                    return html;
                },
            };

            // Set point size for bubble charts, and turn points off altogether
            // for other charts (we'll be using custom point shapes)
            config.point = {
                r: function(d) {
                    if (data.radii[d.id]) {
                        // Arbitrary max size of 30
                        return 30 * data.radii[d.id][d.index] / data.maxRadii[d.id];
                    }
                    return 0;
                },
            };

            // Add functions for custom tick label text (where foo-labels was an object).
            // Don't do this if the tick format was already set by Java (which will
            // only happen for time-based graphs that are NOT using custom tick text).
            if (config.axis.x.tick && !config.axis.x.tick.format) {
                config.axis.x.tick.format = function(d) {
                    var key = String(d);
                    if (type === "time") {
                        var time = key.match(/\d+:\d+:\d+/)[0];
                        key = d.getFullYear() + "-" + (d.getMonth() + 1) + "-" + d.getDate() + " " + time;

                    }
                    var label = axis.xLabels[key] || d;
                    return Math.round(label) || label;
                };
            }
            if (config.axis.y.tick) {
                config.axis.y.tick.format = function(d) {
                    return axis.yLabels[String(d)] || Math.round(d);
                };
            }
            if (config.axis.y2.tick) {
                config.axis.y2.tick.format = function(d) {
                    return axis.y2Labels[String(d)] || Math.round(d);
                };
            }

            // Hide any system-generated series from legend
            var hideSeries = [];
            for (var yID in config.data.xs) {
                if (!data.isData[yID]) {
                    hideSeries.push(yID);
                }
            }
            config.legend.hide = hideSeries;

            // Configure data labels, which we use only to display annotations
            config.data.labels = {
                format: function(value, id, index) {
                    return data.annotations[id] || '';
                },
            };

            // Don't use C3's default ordering for stacked series, use the order series are defined
            config.data.order = false;

            // Post-processing
            config.onrendered = function() {
                // For annotations series, nudge text so it appears on top of data point
                d3.selectAll("g.c3-texts text").attr("dy", 10);

                // Support point-style
                for (var yID in data.pointStyles) {
                    var symbol = data.pointStyles[yID];
                    applyPointShape(yID, symbol);
                    applyLegendShape(yID, symbol);
                }

                // Configure colors more specifically than C3 allows
                for (var yID in config.data.colors) {
                    // Data itself
                    if (type === "bar") {
                        var bars = d3.selectAll(".c3-bars-" + yID + " path")[0];
                        for (var i = 0; i < bars.length; i++) {
                            // If there's a bar-specific color, set it
                            if (data.barColors[yID] && data.barColors[yID][i]) {
                                bars[i].style.fill = data.barColors[yID][i];
                            }
                            // Get opacity: bar-specific if it's there, otherwise series-specific
                            var opacity;
                            if (data.barOpacities[yID]) {
                                opacity = data.barOpacities[yID][i];
                            }
                            opacity = opacity || data.lineOpacities[yID];
                            bars[i].style.opacity = opacity;
                        }
                    } else {
                        var line = d3.selectAll(".c3-lines-" + yID + " path")[0][0];
                        if (line) {
                            line.style.opacity = data.lineOpacities[yID];
                        }
                    }

                    // Legend
                    var legend = d3.selectAll(".c3-legend-item-" + yID + " path")[0];
                    if (!legend.length) {
                        legend = d3.selectAll(".c3-legend-item-" + yID + " line")[0];
                    }
                    if (legend.length) {
                        legend = legend[0];
                        legend.style.opacity = data.lineOpacities[yID];
                    }

                    // Point shapes
                    var points = d3.selectAll(".c3-circles-" + yID + " path")[0];
                    if (!points.length) {
                        points = d3.selectAll(".c3-circles-" + yID + " circle")[0];
                    }
                    for (var i = 0; i < points.length; i++) {
                        points[i].style.opacity = data.lineOpacities[yID];
                    }
                }
                for (var yID in data.areaColors) {
                    var area = d3.selectAll(".c3-areas-" + yID + " path")[0][0];
                    if (area) {
                        area.style.fill = data.areaColors[yID];
                        area.style.opacity = data.areaOpacities[yID];
                    }
                }
            };

            // Generate chart
            c3.generate(config);
        } catch(e) {
            displayError(e);
        }
    }, retryFrequency);
});

/**
 * Replace C3's default circle points with user-requested symbols.
 * @param yID String ID of y-values to manipulate
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 */
function applyPointShape(yID, symbol) {
    if (type === 'bar' || type === 'bubble') {
        return;
    }

    var circleSet = d3.selectAll(".c3-circles-" + yID);
    var circles = circleSet.selectAll("circle")[0];
    if (!circles) {
        return;
    }

    for (var j = 0; j < circles.length; j++) {
        circles[j].style.opacity = 0;    // hide default circle
        appendSymbol(
            circleSet,
            circles[j].cx.baseVal.value,
            circles[j].cy.baseVal.value,
            symbol,
            circles[j].style.fill
        );
    }
}

/**
 * Make shape displayed in legend match shape used on line.
 * @param yID String ID of y-values to manipulate
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 */
function applyLegendShape(yID, symbol) {
    if (symbol !== "none") {
        var legendItem = d3.selectAll(".c3-legend-item-" + yID);
        var line = legendItem.selectAll("line");    // there will only be one line
        if (!line || !line.length) {
            return;
        }
        line = line[0][0]
        line.style.opacity = 0;    // hide default square
        appendSymbol(
            legendItem,
            line.x1.baseVal.value + 5,
            line.y1.baseVal.value,
            symbol,
            line.style.stroke
        );
    }
}

/**
 * Add symbol to given element.
 * @param parent Element to attach symbol to
 * @param x x-coordinate to draw at
 * @param y y-coordinate to draw at
 * @param symbol string representing symbol: "none", "circle", "cross", etc.
 *  Unknown symbols will be drawn as circles.
 * @param color Color to draw symbol
 */
function appendSymbol(parent, x, y, symbol, color) {
    if (symbol === 'none') {
        return;
    }

    parent.append("path")
        .attr("transform", function (d) {
        return "translate(" + x + ", " + y + ")";
    })
        .attr("class", "symbol")
        .attr("d", d3.svg.symbol()
              .type(symbol)
              .size(50))
        .style("fill", color)
        .style("stroke", color);
}
<|endoftext|>


<commit_before>'use strict';

var sharp = require('sharp');
var map   = require('map-stream');
var env   = require('../config/environment_vars');
var dims  = require('../lib/dimensions');

module.exports = function () {

  return map( function(image, callback) {

    // do nothing if there is an error on the image object
    if (image.isError()){
      return callback(null, image);
    }

    // let this pass through if we are requesting the metadata as JSON
    if (image.modifiers.action === 'json'){
      image.log.log('resize: json metadata call');
      return callback(null, image);
    }

    if (image.modifiers.action === 'original' && env.RESIZE_PROCESS_ORIGINAL === false){
      image.log.log('resize: original no resize');
      return callback(null, image);
    }

    image.log.time('resize');

    var resizeResponse = function (err, buffer) {
      if (err) {
        image.log.error('resize error', err);
        image.error = new Error(err);
      }
      else {
        image.contents = buffer;
      }

      image.log.timeEnd('resize');
      callback(null, image);
    };

    var r = sharp(image.contents);

    // never enlarge an image beyond its original size, unless we're padding
    // the image, as even though this can count as an "enlargement" the padded
    // result can be reasonably generated in most cases.
    if (image.modifiers.action !== 'crop' && image.modifiers.crop !== 'pad') {
      r.withoutEnlargement();
    }

    // if allowed auto rotate images, very helpful for photos off of an iphone
    // which are landscape by default and the metadata tells them what to show.
    if (env.AUTO_ORIENT) {
      r.rotate();
    }

    // by default we remove the metadata from resized images, setting the env
    // var to false can retain it.
    if (!env.REMOVE_METADATA) {
      r.withMetadata();
    }

    var d, wd, ht;

    switch(image.modifiers.action){
    case 'original' :
      r.toBuffer(resizeResponse);
      break;

    case 'resize':
      r.resize(image.modifiers.width, image.modifiers.height);
      r.max();
      r.toBuffer(resizeResponse);
      break;

    case 'square':
      r.metadata(function(err, metadata){
        if (err){
          image.error = new Error(err);
          callback(null, image);
          return;
        }

        d = dims.cropFill(image.modifiers, metadata);

        // resize then crop the image
        r.resize(
            d.resize.width,
            d.resize.height
          ).extract(
            d.crop.y,
            d.crop.x,
            d.crop.width,
            d.crop.height
          );

        r.toBuffer(resizeResponse);
      });

      break;

    case 'crop':
      r.metadata(function(err, size){
        if (err){
          image.error = new Error(err);
          callback(null, image);
          return;
        }

        switch(image.modifiers.crop){
        case 'fit':
          r.resize(image.modifiers.width, image.modifiers.height);
          r.max();
          break;
        case 'fill':
          d = dims.cropFill(image.modifiers, size);

          r.resize(
              d.resize.width,
              d.resize.height
            ).extract(
              d.crop.y,
              d.crop.x,
              d.crop.width,
              d.crop.height
            );
          break;
        case 'cut':
          wd = image.modifiers.width || image.modifiers.height;
          ht = image.modifiers.height || image.modifiers.width;

          d = dims.gravity(
            image.modifiers.gravity,
            size.width,
            size.height,
            wd,
            ht
          );
          r.extract(d.y, d.x, wd, ht);
          break;
        case 'scale':
          // TODO: deal with scale
          r.resize(image.modifiers.width, image.modifiers.height);
          break;
        case 'pad':
          r.resize(
            image.modifiers.width,
            image.modifiers.height
          ).background(env.IMAGE_PADDING_COLOR || 'white').embed();
        }

        r.toBuffer(resizeResponse);
      });

      break;
    }
  });

};
<commit_msg>fix extract calls<commit_after>'use strict';

var sharp = require('sharp');
var map   = require('map-stream');
var env   = require('../config/environment_vars');
var dims  = require('../lib/dimensions');

module.exports = function () {

  return map( function(image, callback) {

    // do nothing if there is an error on the image object
    if (image.isError()){
      return callback(null, image);
    }

    // let this pass through if we are requesting the metadata as JSON
    if (image.modifiers.action === 'json'){
      image.log.log('resize: json metadata call');
      return callback(null, image);
    }

    if (image.modifiers.action === 'original' && env.RESIZE_PROCESS_ORIGINAL === false){
      image.log.log('resize: original no resize');
      return callback(null, image);
    }

    image.log.time('resize');

    var resizeResponse = function (err, buffer) {
      if (err) {
        image.log.error('resize error', err);
        image.error = new Error(err);
      }
      else {
        image.contents = buffer;
      }

      image.log.timeEnd('resize');
      callback(null, image);
    };

    var r = sharp(image.contents);

    // never enlarge an image beyond its original size, unless we're padding
    // the image, as even though this can count as an "enlargement" the padded
    // result can be reasonably generated in most cases.
    if (image.modifiers.action !== 'crop' && image.modifiers.crop !== 'pad') {
      r.withoutEnlargement();
    }

    // if allowed auto rotate images, very helpful for photos off of an iphone
    // which are landscape by default and the metadata tells them what to show.
    if (env.AUTO_ORIENT) {
      r.rotate();
    }

    // by default we remove the metadata from resized images, setting the env
    // var to false can retain it.
    if (!env.REMOVE_METADATA) {
      r.withMetadata();
    }

    var d, wd, ht;

    switch(image.modifiers.action){
    case 'original' :
      r.toBuffer(resizeResponse);
      break;

    case 'resize':
      r.resize(image.modifiers.width, image.modifiers.height);
      r.max();
      r.toBuffer(resizeResponse);
      break;

    case 'square':
      r.metadata(function(err, metadata){
        if (err){
          image.error = new Error(err);
          callback(null, image);
          return;
        }

        d = dims.cropFill(image.modifiers, metadata);

        // resize then crop the image
        r.resize(
            d.resize.width,
            d.resize.height
          ).extract({
            left: d.crop.x,
            top: d.crop.y,
            width: d.crop.width,
            height: d.crop.height
          });

        r.toBuffer(resizeResponse);
      });

      break;

    case 'crop':
      r.metadata(function(err, size){
        if (err){
          image.error = new Error(err);
          callback(null, image);
          return;
        }

        switch(image.modifiers.crop){
        case 'fit':
          r.resize(image.modifiers.width, image.modifiers.height);
          r.max();
          break;
        case 'fill':
          d = dims.cropFill(image.modifiers, size);

          r.resize(
              d.resize.width,
              d.resize.height
            ).extract({
              left: d.crop.x,
              top: d.crop.y,
              width: d.crop.width,
              height: d.crop.height
            });
          break;
        case 'cut':
          wd = image.modifiers.width || image.modifiers.height;
          ht = image.modifiers.height || image.modifiers.width;

          d = dims.gravity(
            image.modifiers.gravity,
            size.width,
            size.height,
            wd,
            ht
          );
          r.extract({
            left: d.x,
            top: d.y,
            width: wd,
            height: ht
          });
          break;
        case 'scale':
          // TODO: deal with scale
          r.resize(image.modifiers.width, image.modifiers.height);
          break;
        case 'pad':
          r.resize(
            image.modifiers.width,
            image.modifiers.height
          ).background(env.IMAGE_PADDING_COLOR || 'white').embed();
        }

        r.toBuffer(resizeResponse);
      });

      break;
    }
  });

};
<|endoftext|>


<commit_before>import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { persistState } from 'redux-devtools';
const socket = require('socket.io-client')('http://localhost:3000');

import rootReducer from 'redux/modules/rootReducer';
import { CardModel } from 'redux/modules/card';
import { DevTools } from 'containers';

function logSomething(name) {
  return (data) => {
    console.log(`yay, we got the event: ${name} ${data ? 'with data:' : ''}`, data);
  };
}

socket.on('connect', logSomething('connect'));
socket.on('disconnect', logSomething('disconnect'));

const ioMiddleWare = () => next => action => {
  if (!action.fromOpponent && action.type !== 'NEW_GAME') {
    console.log(action);
    if (action.card) {
      console.log('typeof action.card', typeof action.card);
    }
    socket.emit('action', { action });
  }
  next(action);
};

const enhancer = compose(
  applyMiddleware(thunk, ioMiddleWare),
  DevTools.instrument(),
  persistState(
    window.location.href.match(
      /[?&]debug_session=([^&#]+)\b/
    )
  )
);

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState, enhancer);

  socket.on('action', (payload) => {
    console.log('action came in through socket!!!', payload);
    const { action } = payload;

    if (action.card) {
      action.card = new CardModel(action.card);
    }

    store.dispatch({ fromOpponent: true, ...action });
  });

  if (module.hot) {
    module.hot.accept('./modules/rootReducer', () => (
      store.replaceReducer(require('./modules/rootReducer').default)
    ));
  }

  return store;
}
<commit_msg>Rename fromOpponent to fromServer<commit_after>import { createStore, compose, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import { persistState } from 'redux-devtools';
const socket = require('socket.io-client')('http://localhost:3000');

import rootReducer from 'redux/modules/rootReducer';
import { CardModel } from 'redux/modules/card';
import { DevTools } from 'containers';

function logSomething(name) {
  return (data) => {
    console.log(`yay, we got the event: ${name} ${data ? 'with data:' : ''}`, data);
  };
}

socket.on('connect', logSomething('connect'));
socket.on('disconnect', logSomething('disconnect'));

const ioMiddleWare = () => next => action => {
  if (!action.fromServer && action.type !== 'NEW_GAME') {
    console.log(action);
    if (action.card) {
      console.log('typeof action.card', typeof action.card);
    }
    socket.emit('action', { action });
  }
  next(action);
};

const enhancer = compose(
  applyMiddleware(thunk, ioMiddleWare),
  DevTools.instrument(),
  persistState(
    window.location.href.match(
      /[?&]debug_session=([^&#]+)\b/
    )
  )
);

export default function configureStore(initialState) {
  const store = createStore(rootReducer, initialState, enhancer);

  socket.on('action', (payload) => {
    console.log('action came in through socket!!!', payload);
    const { action } = payload;

    if (action.card) {
      action.card = new CardModel(action.card);
    }

    store.dispatch({ fromServer: true, ...action });
  });

  if (module.hot) {
    module.hot.accept('./modules/rootReducer', () => (
      store.replaceReducer(require('./modules/rootReducer').default)
    ));
  }

  return store;
}
<|endoftext|>


<commit_before>const {app, BrowserWindow, ipcMain} = require('electron');
const url = require('url');
const path = require('path');
const jayson = require('jayson');
const semver = require('semver');
const https = require('https');
// tree-kill has better cross-platform handling of
// killing a process.  child-process.kill was unreliable
const kill = require('tree-kill');
const child_process = require('child_process');
const assert = require('assert');
const {version: localVersion} = require(app.getAppPath() + '/package.json');

const VERSION_CHECK_INTERVAL = 30 * 60 * 1000;
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';

let client = jayson.client.http('http://localhost:5279/lbryapi');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
// Also keep the daemon subprocess alive
let daemonSubprocess;

// This is set to true right before we try to shut the daemon subprocess --
// if it dies when we didn't ask it to shut down, we want to alert the user.
let daemonStopRequested = false;

// When a quit is attempted, we cancel the quit, do some preparations, then
// this is set to true and app.quit() is called again to quit for real.
let readyToQuit = false;

// If we receive a URI to open from an external app but there's no window to
// send it to, it's cached in this variable.
let openUri = null;

function denormalizeUri(uri) {
  // Windows normalizes URIs when they're passed in from other apps. This tries
  // to restore the original URI that was typed.
  //   - If the URI has no path, Windows adds a trailing slash. LBRY URIs
  //     can't have a slash with no path, so we just strip it off.
  //   - In a URI with a claim ID, like lbry://channel#claimid, Windows
  //     interprets the hash mark as an anchor and converts it to
  //     lbry://channel/#claimid. We remove the slash here as well.

  if (process.platform == 'win32') {
    return uri.replace(/\/$/, '').replace('/#', '#');
  } else {
    return uri;
  }
}

function checkForNewVersion(callback) {
  function formatRc(ver) {
    // Adds dash if needed to make RC suffix semver friendly
    return ver.replace(/([^-])rc/, '$1-rc');
  }

  let result = '';
  const opts = {
    headers: {
      'User-Agent': `LBRY/${localVersion}`,
    }
  };
  const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => {
    res.on('data', (data) => {
      result += data;
    });
    res.on('end', () => {
      console.log('Local version:', localVersion);
      const tagName = JSON.parse(result).tag_name;
      const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
      if (!remoteVersion) {
        console.log('Malformed remote version string:', tagName);
        win.webContents.send('version-info-received', null);
      } else {
        console.log('Remote version:', remoteVersion);
        const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion));
        console.log(upgradeAvailable ? 'Upgrade available' : 'No upgrade available');
        win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable});
      }
    })
  });

  req.on('error', (err) => {
    console.log('Failed to get current version from GitHub. Error:', err);
    win.webContents.send('version-info-received', null);
  });
}

ipcMain.on('version-info-requested', checkForNewVersion);

/*
 * Replacement for Electron's shell.openItem. The Electron version doesn't
 * reliably work from the main process, and we need to be able to run it
 * when no windows are open.
 */
function openItem(fullPath) {
    const subprocOptions = {
      detached: true,
      stdio: 'ignore',
    };

    let child;
    if (process.platform == 'darwin') {
      child = child_process.spawn('open', [fullPath], subprocOptions);
    } else if (process.platform == 'linux') {
      child = child_process.spawn('xdg-open', [fullPath], subprocOptions);
    } else if (process.platform == 'win32') {
      child = child_process.spawn(fullPath, [], subprocOptions);
    }

    // Causes child process reference to be garbage collected, allowing main process to exit
    child.unref();
}

function getPidsForProcessName(name) {
  if (process.platform == 'win32') {
    const tasklistOut = child_process.execSync(`tasklist /fi "Imagename eq ${name}.exe" /nh`, {encoding: 'utf8'});
    if (tasklistOut.startsWith('INFO')) {
      return [];
    } else {
      return tasklistOut.match(/[^\r\n]+/g).map((line) => line.split(/\s+/)[1]); // Second column of every non-empty line
    }
  } else {
    const pgrepOut = child_process.spawnSync('pgrep', ['-x', name], {encoding: 'utf8'}).stdout;
    return pgrepOut.match(/\d+/g);
  }
}

function createWindow () {
  win = new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600 }) //$color-primary

  win.maximize()
  // win.webContents.openDevTools();
  win.loadURL(`file://${__dirname}/dist/index.html`)
  if (openUri) { // We stored and received a URI that an external app requested before we had a window object
    win.webContents.on('did-finish-load', () => {
      win.webContents.send('open-uri-requested', openUri);
    });
  }

  win.on('closed', () => {
    win = null
  })
};

function handleDaemonSubprocessExited() {
  console.log('The daemon has exited.');
  daemonSubprocess = null;
  if (!daemonStopRequested) {
    // We didn't request to stop the daemon, so display a
    // warning and schedule a quit.
    //
    // TODO: maybe it would be better to restart the daemon?
    if (win) {
      console.log('Did not request daemon stop, so quitting in 5 seconds.');
      win.loadURL(`file://${__dirname}/dist/warning.html`);
      setTimeout(quitNow, 5000);
    } else {
      console.log('Did not request daemon stop, so quitting.');
      quitNow();
    }
  }
}

function launchDaemon() {
  assert(!daemonSubprocess, 'Tried to launch daemon twice');

  if (process.env.LBRY_DAEMON) {
    executable = process.env.LBRY_DAEMON;
  } else {
    executable = path.join(__dirname, 'dist', 'lbrynet-daemon');
  }
  console.log('Launching daemon:', executable)
  daemonSubprocess = child_process.spawn(executable)
  // Need to handle the data event instead of attaching to
  // process.stdout because the latter doesn't work. I believe on
  // windows it buffers stdout and we don't get any meaningful output
  daemonSubprocess.stdout.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.stderr.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.on('exit', handleDaemonSubprocessExited);
}

/*
 * Quits without any preparation. When a quit is requested (either through the
 * interface or through app.quit()), we abort the quit, try to shut down the daemon,
 * and then call this to quit for real.
 */
function quitNow() {
  readyToQuit = true;
  app.quit();
}

const isSecondaryInstance = app.makeSingleInstance((argv) => {
  if (win) {
    if (win.isMinimized()) {
      win.restore();
    }
    win.focus();

    if (argv.length >= 2) {
      win.webContents.send('open-uri-requested', denormalizeUri(argv[1]));
    }
  } else if (argv.length >= 2) {
    openUri = denormalizeUri(argv[1]);
  }
});

if (isSecondaryInstance) { // We're not in the original process, so quit
  quitNow();
  return;
}

app.on('ready', function(){
  launchDaemonIfNotRunning();
  createWindow();
});

function launchDaemonIfNotRunning() {
  // Check if the daemon is already running. If we get
  // an error its because its not running
  console.log('Checking for lbrynet daemon');
  client.request(
    'status', [],
    function (err, res) {
      if (err) {
        console.log('lbrynet daemon needs to be launched')
        launchDaemon();
      } else {
        console.log('lbrynet daemon is already running')
      }
    }
  );
}

/*
 * Last resort for killing unresponsive daemon instances.
 * Looks for any processes called "lbrynet-daemon" and
 * tries to force kill them.
 */
function forceKillAllDaemonsAndQuit() {
  console.log('Attempting to force kill any running lbrynet-daemon instances...');

  const daemonPids = getPidsForProcessName('lbrynet-daemon');
  if (!daemonPids) {
    console.log('No lbrynet-daemon found running.');
    quitNow();
  } else {
    console.log(`Found ${daemonPids.length} running daemon instances. Attempting to force kill...`);

    for (const pid of daemonPids) {
      let daemonKillAttemptsComplete = 0;
      kill(pid, 'SIGKILL', (err) => {
        daemonKillAttemptsComplete++;
        if (err) {
          console.log(`Failed to force kill daemon task with pid ${pid}. Error message: ${err.message}`);
        } else {
          console.log(`Force killed daemon task with pid ${pid}.`);
        }
        if (daemonKillAttemptsComplete >= daemonPids.length - 1) {
          quitNow();
        }
      });
    }
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('before-quit', (event) => {
  if (!readyToQuit) {
    // We need to shutdown the daemon before we're ready to actually quit. This
    // event will be triggered re-entrantly once preparation is done.
    event.preventDefault();
    shutdownDaemonAndQuit();
  } else {
    console.log('Quitting.')
  }
});

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
});

// When a quit is attempted, this is called. It attempts to shutdown the daemon,
// then calls quitNow() to quit for real.
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
  function doShutdown() {
    console.log('Asking daemon to shut down down');
    daemonStopRequested = true;
    client.request('daemon_stop', [], (err, res) => {
      if (err) {
        console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
        console.log('You will need to manually kill the daemon.');
      } else {
        console.log('Successfully stopped daemon via RPC call.')
        quitNow();
      }
    });
  }

  if (daemonSubprocess) {
    doShutdown();
  } else if (!evenIfNotStartedByApp) {
    console.log('Not killing lbrynet-daemon because app did not start it');
    quitNow();
  } else {
    doShutdown();
  }

  // Is it safe to start the installer before the daemon finishes running?
  // If not, we should wait until the daemon is closed before we start the install.
}

function upgrade(event, installerPath) {
  app.on('quit', () => {
    console.log('Launching upgrade installer at', installerPath);
    // This gets triggered called after *all* other quit-related events, so
    // we'll only get here if we're fully prepared and quitting for real.
    openItem(installerPath);
  });

  if (win) {
    win.loadURL(`file://${__dirname}/dist/upgrade.html`);
  }

  shutdownDaemonAndQuit(true);
  // wait for daemon to shut down before upgrading
  // what to do if no shutdown in a long time?
  console.log('Update downloaded to', installerPath);
  console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
  console.log('After the install is complete, please reopen the app.');
}

ipcMain.on('upgrade', upgrade);

app.setAsDefaultProtocolClient('lbry');

if (process.platform == 'darwin') {
  app.on('open-url', (event, uri) => {
    if (!win) {
      // Window not created yet, so store up requested URI for when it is
      openUri = uri;
    } else {
      win.webContents.send('open-uri-requested', uri);
    }
  });
} else if (process.argv.length >= 2) {
  if (!win) {
    openUri = denormalizeUri(process.argv[1]);
  } else {
    win.webContents.send('open-uri-requested', denormalizeUri(process.argv[1]));
  }
}
<commit_msg>Disable single instance app on Linux for now (Electron bug)<commit_after>const {app, BrowserWindow, ipcMain} = require('electron');
const url = require('url');
const path = require('path');
const jayson = require('jayson');
const semver = require('semver');
const https = require('https');
// tree-kill has better cross-platform handling of
// killing a process.  child-process.kill was unreliable
const kill = require('tree-kill');
const child_process = require('child_process');
const assert = require('assert');
const {version: localVersion} = require(app.getAppPath() + '/package.json');

const VERSION_CHECK_INTERVAL = 30 * 60 * 1000;
const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/lbryio/lbry-app/releases/latest';

let client = jayson.client.http('http://localhost:5279/lbryapi');
// Keep a global reference of the window object, if you don't, the window will
// be closed automatically when the JavaScript object is garbage collected.
let win;
// Also keep the daemon subprocess alive
let daemonSubprocess;

// This is set to true right before we try to shut the daemon subprocess --
// if it dies when we didn't ask it to shut down, we want to alert the user.
let daemonStopRequested = false;

// When a quit is attempted, we cancel the quit, do some preparations, then
// this is set to true and app.quit() is called again to quit for real.
let readyToQuit = false;

// If we receive a URI to open from an external app but there's no window to
// send it to, it's cached in this variable.
let openUri = null;

function denormalizeUri(uri) {
  // Windows normalizes URIs when they're passed in from other apps. This tries
  // to restore the original URI that was typed.
  //   - If the URI has no path, Windows adds a trailing slash. LBRY URIs
  //     can't have a slash with no path, so we just strip it off.
  //   - In a URI with a claim ID, like lbry://channel#claimid, Windows
  //     interprets the hash mark as an anchor and converts it to
  //     lbry://channel/#claimid. We remove the slash here as well.

  if (process.platform == 'win32') {
    return uri.replace(/\/$/, '').replace('/#', '#');
  } else {
    return uri;
  }
}

function checkForNewVersion(callback) {
  function formatRc(ver) {
    // Adds dash if needed to make RC suffix semver friendly
    return ver.replace(/([^-])rc/, '$1-rc');
  }

  let result = '';
  const opts = {
    headers: {
      'User-Agent': `LBRY/${localVersion}`,
    }
  };
  const req = https.get(Object.assign(opts, url.parse(LATEST_RELEASE_API_URL)), (res) => {
    res.on('data', (data) => {
      result += data;
    });
    res.on('end', () => {
      console.log('Local version:', localVersion);
      const tagName = JSON.parse(result).tag_name;
      const [_, remoteVersion] = tagName.match(/^v([\d.]+(?:-?rc\d+)?)$/);
      if (!remoteVersion) {
        console.log('Malformed remote version string:', tagName);
        win.webContents.send('version-info-received', null);
      } else {
        console.log('Remote version:', remoteVersion);
        const upgradeAvailable = semver.gt(formatRc(remoteVersion), formatRc(localVersion));
        console.log(upgradeAvailable ? 'Upgrade available' : 'No upgrade available');
        win.webContents.send('version-info-received', {remoteVersion, localVersion, upgradeAvailable});
      }
    })
  });

  req.on('error', (err) => {
    console.log('Failed to get current version from GitHub. Error:', err);
    win.webContents.send('version-info-received', null);
  });
}

ipcMain.on('version-info-requested', checkForNewVersion);

/*
 * Replacement for Electron's shell.openItem. The Electron version doesn't
 * reliably work from the main process, and we need to be able to run it
 * when no windows are open.
 */
function openItem(fullPath) {
    const subprocOptions = {
      detached: true,
      stdio: 'ignore',
    };

    let child;
    if (process.platform == 'darwin') {
      child = child_process.spawn('open', [fullPath], subprocOptions);
    } else if (process.platform == 'linux') {
      child = child_process.spawn('xdg-open', [fullPath], subprocOptions);
    } else if (process.platform == 'win32') {
      child = child_process.spawn(fullPath, [], subprocOptions);
    }

    // Causes child process reference to be garbage collected, allowing main process to exit
    child.unref();
}

function getPidsForProcessName(name) {
  if (process.platform == 'win32') {
    const tasklistOut = child_process.execSync(`tasklist /fi "Imagename eq ${name}.exe" /nh`, {encoding: 'utf8'});
    if (tasklistOut.startsWith('INFO')) {
      return [];
    } else {
      return tasklistOut.match(/[^\r\n]+/g).map((line) => line.split(/\s+/)[1]); // Second column of every non-empty line
    }
  } else {
    const pgrepOut = child_process.spawnSync('pgrep', ['-x', name], {encoding: 'utf8'}).stdout;
    return pgrepOut.match(/\d+/g);
  }
}

function createWindow () {
  win = new BrowserWindow({backgroundColor: '#155B4A', minWidth: 800, minHeight: 600 }) //$color-primary

  win.maximize()
  // win.webContents.openDevTools();
  win.loadURL(`file://${__dirname}/dist/index.html`)
  if (openUri) { // We stored and received a URI that an external app requested before we had a window object
    win.webContents.on('did-finish-load', () => {
      win.webContents.send('open-uri-requested', openUri);
    });
  }

  win.on('closed', () => {
    win = null
  })
};

function handleDaemonSubprocessExited() {
  console.log('The daemon has exited.');
  daemonSubprocess = null;
  if (!daemonStopRequested) {
    // We didn't request to stop the daemon, so display a
    // warning and schedule a quit.
    //
    // TODO: maybe it would be better to restart the daemon?
    if (win) {
      console.log('Did not request daemon stop, so quitting in 5 seconds.');
      win.loadURL(`file://${__dirname}/dist/warning.html`);
      setTimeout(quitNow, 5000);
    } else {
      console.log('Did not request daemon stop, so quitting.');
      quitNow();
    }
  }
}

function launchDaemon() {
  assert(!daemonSubprocess, 'Tried to launch daemon twice');

  if (process.env.LBRY_DAEMON) {
    executable = process.env.LBRY_DAEMON;
  } else {
    executable = path.join(__dirname, 'dist', 'lbrynet-daemon');
  }
  console.log('Launching daemon:', executable)
  daemonSubprocess = child_process.spawn(executable)
  // Need to handle the data event instead of attaching to
  // process.stdout because the latter doesn't work. I believe on
  // windows it buffers stdout and we don't get any meaningful output
  daemonSubprocess.stdout.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.stderr.on('data', (buf) => {console.log(String(buf).trim());});
  daemonSubprocess.on('exit', handleDaemonSubprocessExited);
}

/*
 * Quits without any preparation. When a quit is requested (either through the
 * interface or through app.quit()), we abort the quit, try to shut down the daemon,
 * and then call this to quit for real.
 */
function quitNow() {
  readyToQuit = true;
  app.quit();
}

if (process.platform != 'linux') {
  // On Linux, this is always returning true due to an Electron bug,
  // so for now we just don't support single-instance apps on Linux.
  const isSecondaryInstance = app.makeSingleInstance((argv) => {
    if (win) {
      if (win.isMinimized()) {
        win.restore();
      }
      win.focus();

      if (argv.length >= 2) {
        win.webContents.send('open-uri-requested', denormalizeUri(argv[1]));
      }
    } else if (argv.length >= 2) {
      openUri = denormalizeUri(argv[1]);
    }
  });

  if (isSecondaryInstance) { // We're not in the original process, so quit
    quitNow();
    return;
  }
}

app.on('ready', function(){
  launchDaemonIfNotRunning();
  createWindow();
});

function launchDaemonIfNotRunning() {
  // Check if the daemon is already running. If we get
  // an error its because its not running
  console.log('Checking for lbrynet daemon');
  client.request(
    'status', [],
    function (err, res) {
      if (err) {
        console.log('lbrynet daemon needs to be launched')
        launchDaemon();
      } else {
        console.log('lbrynet daemon is already running')
      }
    }
  );
}

/*
 * Last resort for killing unresponsive daemon instances.
 * Looks for any processes called "lbrynet-daemon" and
 * tries to force kill them.
 */
function forceKillAllDaemonsAndQuit() {
  console.log('Attempting to force kill any running lbrynet-daemon instances...');

  const daemonPids = getPidsForProcessName('lbrynet-daemon');
  if (!daemonPids) {
    console.log('No lbrynet-daemon found running.');
    quitNow();
  } else {
    console.log(`Found ${daemonPids.length} running daemon instances. Attempting to force kill...`);

    for (const pid of daemonPids) {
      let daemonKillAttemptsComplete = 0;
      kill(pid, 'SIGKILL', (err) => {
        daemonKillAttemptsComplete++;
        if (err) {
          console.log(`Failed to force kill daemon task with pid ${pid}. Error message: ${err.message}`);
        } else {
          console.log(`Force killed daemon task with pid ${pid}.`);
        }
        if (daemonKillAttemptsComplete >= daemonPids.length - 1) {
          quitNow();
        }
      });
    }
  }
}

// Quit when all windows are closed.
app.on('window-all-closed', () => {
  // On macOS it is common for applications and their menu bar
  // to stay active until the user quits explicitly with Cmd + Q
  if (process.platform !== 'darwin') {
    app.quit()
  }
})

app.on('before-quit', (event) => {
  if (!readyToQuit) {
    // We need to shutdown the daemon before we're ready to actually quit. This
    // event will be triggered re-entrantly once preparation is done.
    event.preventDefault();
    shutdownDaemonAndQuit();
  } else {
    console.log('Quitting.')
  }
});

app.on('activate', () => {
  // On macOS it's common to re-create a window in the app when the
  // dock icon is clicked and there are no other windows open.
  if (win === null) {
    createWindow()
  }
});

// When a quit is attempted, this is called. It attempts to shutdown the daemon,
// then calls quitNow() to quit for real.
function shutdownDaemonAndQuit(evenIfNotStartedByApp = false) {
  function doShutdown() {
    console.log('Asking daemon to shut down down');
    daemonStopRequested = true;
    client.request('daemon_stop', [], (err, res) => {
      if (err) {
        console.log(`received error when stopping lbrynet-daemon. Error message: ${err.message}\n`);
        console.log('You will need to manually kill the daemon.');
      } else {
        console.log('Successfully stopped daemon via RPC call.')
        quitNow();
      }
    });
  }

  if (daemonSubprocess) {
    doShutdown();
  } else if (!evenIfNotStartedByApp) {
    console.log('Not killing lbrynet-daemon because app did not start it');
    quitNow();
  } else {
    doShutdown();
  }

  // Is it safe to start the installer before the daemon finishes running?
  // If not, we should wait until the daemon is closed before we start the install.
}

function upgrade(event, installerPath) {
  app.on('quit', () => {
    console.log('Launching upgrade installer at', installerPath);
    // This gets triggered called after *all* other quit-related events, so
    // we'll only get here if we're fully prepared and quitting for real.
    openItem(installerPath);
  });

  if (win) {
    win.loadURL(`file://${__dirname}/dist/upgrade.html`);
  }

  shutdownDaemonAndQuit(true);
  // wait for daemon to shut down before upgrading
  // what to do if no shutdown in a long time?
  console.log('Update downloaded to', installerPath);
  console.log('The app will close, and you will be prompted to install the latest version of LBRY.');
  console.log('After the install is complete, please reopen the app.');
}

ipcMain.on('upgrade', upgrade);

app.setAsDefaultProtocolClient('lbry');

if (process.platform == 'darwin') {
  app.on('open-url', (event, uri) => {
    if (!win) {
      // Window not created yet, so store up requested URI for when it is
      openUri = uri;
    } else {
      win.webContents.send('open-uri-requested', uri);
    }
  });
} else if (process.argv.length >= 2) {
  if (!win) {
    openUri = denormalizeUri(process.argv[1]);
  } else {
    win.webContents.send('open-uri-requested', denormalizeUri(process.argv[1]));
  }
}
<|endoftext|>


<commit_before>define(["../core/Tone", "../core/Transport", "../core/Buffer", "../core/OfflineContext", "../core/Master"], function(Tone){

	/**
	 * Because of a bug in iOS causing the currentTime to increment
	 * before the rendering is started, sometimes it takes multiple
	 * attempts to render the audio correctly.
	 * @private
	 */
	function attemptRender(callback, duration, sampleRate, tries){
		tries = Tone.defaultArg(tries, 0);
		var context = new Tone.OfflineContext(2, duration, sampleRate);
		Tone.context = context;

		//invoke the callback/scheduling
		var response = callback(Tone.Transport);

		if (context.currentTime > 0 && tries < 1000){
			return attemptRender(callback, duration, sampleRate, ++tries);
		} else {
			return {
				"response" : response,
				"context" : context
			};
		}
	}

	/**
	 *  Generate a buffer by rendering all of the Tone.js code within the callback using the OfflineAudioContext.
	 *  The OfflineAudioContext is capable of rendering much faster than real time in many cases.
	 *  The callback function also passes in an offline instance of Tone.Transport which can be used
	 *  to schedule events along the Transport. **NOTE** OfflineAudioContext has the same restrictions
	 *  as the AudioContext in that on certain platforms (like iOS) it must be invoked by an explicit
	 *  user action like a click or tap.
	 *  @param  {Function}  callback  All Tone.js nodes which are created and scheduled within this callback are recorded into the output Buffer.
	 *  @param  {Time}  duration     the amount of time to record for.
	 *  @return  {Promise}  The promise which is invoked with the Tone.Buffer of the recorded output.
	 *  @example
	 * //render 2 seconds of the oscillator
	 * Tone.Offline(function(){
	 * 	//only nodes created in this callback will be recorded
	 * 	var oscillator = new Tone.Oscillator().toMaster().start(0)
	 * 	//schedule their events
	 * }, 2).then(function(buffer){
	 * 	//do something with the output buffer
	 * })
	 * @example
	 * //can also schedule events along the Transport
	 * //using the passed in Offline Transport
	 * Tone.Offline(function(Transport){
	 * 	var osc = new Tone.Oscillator().toMaster()
	 * 	Transport.schedule(function(time){
	 * 		osc.start(time).stop(time + 0.1)
	 * 	}, 1)
	 * 	Transport.start(0.2)
	 * }, 4).then(function(buffer){
	 * 	//do something with the output buffer
	 * })
	 */
	Tone.Offline = function(callback, duration){
		//set the OfflineAudioContext
		var sampleRate = Tone.context.sampleRate;
		var originalContext = Tone.context;

		var renderRet = attemptRender(callback, duration, sampleRate);
		var response = renderRet.response;
		var context = renderRet.context;

		var ret;
		if (response && Tone.isFunction(response.then)){
			//wait for the promise to resolve
			ret = response.then(function(){
				//then render the audio
				return context.render();
			});
		} else {
			//process the audio
			ret = context.render();
		}

		//return the original AudioContext
		Tone.context = originalContext;

		//return the audio
		return ret.then(function(buffer){
			//wrap it in a Tone.Buffer
			return new Tone.Buffer(buffer);
		});
	};

	return Tone.Offline;
});
<commit_msg>removing unnecessary function<commit_after>define(["../core/Tone", "../core/Transport", "../core/Buffer", "../core/OfflineContext", "../core/Master"], function(Tone){

	/**
	 *  Generate a buffer by rendering all of the Tone.js code within the callback using the OfflineAudioContext.
	 *  The OfflineAudioContext is capable of rendering much faster than real time in many cases.
	 *  The callback function also passes in an offline instance of Tone.Transport which can be used
	 *  to schedule events along the Transport. **NOTE** OfflineAudioContext has the same restrictions
	 *  as the AudioContext in that on certain platforms (like iOS) it must be invoked by an explicit
	 *  user action like a click or tap.
	 *  @param  {Function}  callback  All Tone.js nodes which are created and scheduled within this callback are recorded into the output Buffer.
	 *  @param  {Time}  duration     the amount of time to record for.
	 *  @return  {Promise}  The promise which is invoked with the Tone.Buffer of the recorded output.
	 *  @example
	 * //render 2 seconds of the oscillator
	 * Tone.Offline(function(){
	 * 	//only nodes created in this callback will be recorded
	 * 	var oscillator = new Tone.Oscillator().toMaster().start(0)
	 * 	//schedule their events
	 * }, 2).then(function(buffer){
	 * 	//do something with the output buffer
	 * })
	 * @example
	 * //can also schedule events along the Transport
	 * //using the passed in Offline Transport
	 * Tone.Offline(function(Transport){
	 * 	var osc = new Tone.Oscillator().toMaster()
	 * 	Transport.schedule(function(time){
	 * 		osc.start(time).stop(time + 0.1)
	 * 	}, 1)
	 * 	Transport.start(0.2)
	 * }, 4).then(function(buffer){
	 * 	//do something with the output buffer
	 * })
	 */
	Tone.Offline = function(callback, duration){
		//set the OfflineAudioContext
		var sampleRate = Tone.context.sampleRate;
		var originalContext = Tone.context;

		var context = new Tone.OfflineContext(2, duration, sampleRate);
		Tone.context = context;

		//invoke the callback/scheduling
		var response = callback(Tone.Transport);

		if (response && Tone.isFunction(response.then)){
			//wait for the promise to resolve
			ret = response.then(function(){
				//then render the audio
				return context.render();
			});
		} else {
			//process the audio
			ret = context.render();
		}

		//return the original AudioContext
		Tone.context = originalContext;

		//return the audio
		return ret.then(function(buffer){
			//wrap it in a Tone.Buffer
			return new Tone.Buffer(buffer);
		});
	};

	return Tone.Offline;
});
<|endoftext|>


<commit_before>var ngWebAudio = angular.module('ngWebAudio', [])

.factory('deferredApply', ['$timeout', function($timeout) {
  'use strict';
  return function(f, delay) {
    $timeout(f, delay || 0);
    if ($timeout.flush) $timeout.flush();
  };
}])

.factory('WebAudio', ['deferredApply', function(deferredApply) {
  'use strict';
  var LOADING = 1;

  var AudioContext = window.AudioContext || window.webkitAudioContext;
  if (AudioContext) {
    if (!ngWebAudio.audioContext) ngWebAudio.audioContext = new AudioContext();
    var audioCtx = ngWebAudio.audioContext;
  }
  var audioBuffers = {}, eventHandlers = {};

  // Buffer audio via XHR
  function bufferAudio(src, retryInterval) {
    if (audioBuffers[src]) return;
    retryInterval = retryInterval || 1000;
    audioBuffers[src] = LOADING;

    var req = new XMLHttpRequest();
    req.open('GET', src, true);
    req.responseType = 'arraybuffer';

    req.onload = function() {
      if (req.status !== 200 && audioBuffers[src]) return req.onerror();

      audioCtx.decodeAudioData(req.response, function(buffer) {
        audioBuffers[src] = buffer;

        // Fire onBuffered event
        var handlers = eventHandlers[src].buffered;
        if (handlers) {
          // We can safely clean up all onBuffered event handlers, as once the
          // src media is cached, the onBuffered event can be fired immediately
          // for any new audio objects that are created henceforth
          eventHandlers[src].buffered = null;

          for (var i = 0; i < handlers.length; i++) {
            deferredApply(handlers[i]);
          }
        }
      });
    };

    // Keep retrying until XHR succeeds
    req.onerror = function() {
      console.error('Retrying ', src);
      audioBuffers[src] = null;
      setTimeout(function() { bufferAudio(src, retryInterval); }, retryInterval);
    };

    req.send();
  }

  // Create WebAudio source
  function createWebAudio(src, options) {
    var playStartTime = 0;  // Used to keep track how long clip is played for
    var playOffset = 0;  // Used to keep track of how far into clip we are

    var self = {
      stopped: true,
      src: src,
      options: options,
      isWebAudio: true,

      play: function play() {
        if (!self.stopped) return;
        self.stopped = false;

        // Buffer audio if not buffered, and schedule play() for later
        if (!self.isCached()) {
          self.buffer();
          (function retry() {
            if (self.isCached() && !self.stopped) {
              self.stopped = true;
              play(src);
            }
            else setTimeout(retry, 200);
          })();
          return;
        }

        var audioSrc = self.audioSrc = audioCtx.createBufferSource();
        var gainNode = audioCtx.createGain();
        gainNode.gain.value = options.gain;

        audioSrc.buffer = audioBuffers[src];
        audioSrc.connect(audioCtx.destination);
        audioSrc.loop = !!options.loop;
        audioSrc.onended = function() {
          self.stopped = true;
          if (self.onEnd) deferredApply(self.onEnd);
        };

        if (audioSrc.start) audioSrc.start(0, playOffset);
        else if(audioSrc.noteOn) audioSrc.noteOn(0, playOffset);
        else console.error('AudioContextBuffer.start() not available');

        if (self.onPlay) deferredApply(self.onPlay);
        playStartTime = audioCtx.currentTime;
      },

      stop: function(pause) {
        if (self.stopped) return;
        self.stopped = true;

        if (!pause) playOffset = 0;
        else playOffset += audioCtx.currentTime - playStartTime;

        if (!pause && self.audioSrc.onended) self.audioSrc.onended();
        self.audioSrc.onended = null;

        if (self.audioSrc.stop) self.audioSrc.stop(0);
        else if(self.audioSrc.noteOff) self.audioSrc.noteOff(0);
        else console.error('AudioContextBuffer.stop() not available');
      },

      pause: function() {
        self.stop(true);
      },

      buffer: function() {
        bufferAudio(src, options.retryInterval);

        // onBuffered event
        // We need to wrap this in setTimeout() because buffer() can be
        // automatically called on creation so the user does not have an
        // opportunity to set an onBuffered event handler
        setTimeout(function() {
          if (self.isCached()) {
            if (self.onBuffered) deferredApply(self.onBuffered);
          }
          else {
            if (!eventHandlers[src].buffered) eventHandlers[src].buffered = [];
            eventHandlers[src].buffered.push(function() {
              if (self.onBuffered) deferredApply(self.onBuffered);
            });
          }
        }, 0);
      },

      offset: function() {
        return self.stopped || !self.isCached() ?
          playOffset :
          playOffset + audioCtx.currentTime - playStartTime;
      },

      isCached: function() {
        return audioBuffers[src] && audioBuffers[src] !== LOADING;
      }
    };

    return self;
  }

  // Create HTML Audio source (fallback)
  function createHTMLAudio(src, options) {
    var audioSrc = new Audio(src);

    var self = {
      audioSrc: audioSrc,
      stopped: true,
      src: src,
      options: options,
      loaded: false,
      isWebAudio: false,

      play: function play() {
        if (!self.stopped) return;
        self.stopped = false;

        // Wait for audio to be buffered
        if (!self.loaded) {
          (function retry() {
            if (self.loaded && !self.stopped) {
              self.stopped = true;
              play(src);
            }
            else setTimeout(retry, 200);
          })();
          return;
        }

        audioSrc.volume = options.gain;
        audioSrc.loop = !!options.loop;
        audioSrc.play();
      },

      stop: function(pause) {
        if (self.stopped) return;
        self.stopped = true;

        audioSrc.pause();
        if (!pause) {
          audioSrc.currentTime = 0;
          if (self.onEnd) deferredApply(self.onEnd);
        }
      },

      pause: function() {
        self.stop(true);
      },

      buffer: function() {
        audioSrc.load();
      },

      offset: function() {
        return audioSrc.duration && audioSrc.currentTime <= audioSrc.duration ?
          audioSrc.currentTime : 0;
      }
    };

    audioSrc.addEventListener('ended', function() {
      self.stopped = true;
      self.audioSrc.currentTime = 0;
      if (!options.loop) {
        audioSrc.pause();
        if (self.onEnd) deferredApply(self.onEnd);
      }
    });
    audioSrc.addEventListener('play', function() {
      if (self.onPlay) deferredApply(self.onPlay);
    });
    audioSrc.addEventListener('canplaythrough', function handler() {
      audioSrc.removeEventListener('canplaythrough', handler);
      self.loaded = true;
      if (self.onBuffered) deferredApply(self.onBuffered);
    });

    return self;
  }

  return function(src, options) {
    if (!eventHandlers[src]) eventHandlers[src] = {};

    options = options || {};
    if (options.buffer === undefined) options.buffer = true;
    if (options.loop === undefined) options.loop = false;
    if (options.gain === undefined) options.gain = 1;
    if (options.retryInterval === undefined) options.retryInterval = 1000;

    var audio = (audioCtx ? createWebAudio : createHTMLAudio)(src, options);
    if (options.buffer) audio.buffer();
    return audio;
  };
}]);
<commit_msg>Clean up. deferredApply() accepts undefined.<commit_after>var ngWebAudio = angular.module('ngWebAudio', [])

.factory('deferredApply', ['$timeout', function($timeout) {
  'use strict';
  return function(f, delay) {
    if (!f) return;
    $timeout(f, delay || 0);
    if ($timeout.flush) $timeout.flush();
  };
}])

.factory('WebAudio', ['deferredApply', function(deferredApply) {
  'use strict';
  var LOADING = 1;

  var AudioContext = window.AudioContext || window.webkitAudioContext;
  if (AudioContext) {
    if (!ngWebAudio.audioContext) ngWebAudio.audioContext = new AudioContext();
    var audioCtx = ngWebAudio.audioContext;
  }
  var audioBuffers = {}, eventHandlers = {};

  // Buffer audio via XHR
  function bufferAudio(src, retryInterval) {
    if (audioBuffers[src]) return;
    retryInterval = retryInterval || 1000;
    audioBuffers[src] = LOADING;

    var req = new XMLHttpRequest();
    req.open('GET', src, true);
    req.responseType = 'arraybuffer';

    req.onload = function() {
      if (req.status !== 200 && audioBuffers[src]) return req.onerror();

      audioCtx.decodeAudioData(req.response, function(buffer) {
        audioBuffers[src] = buffer;

        // Fire onBuffered event
        var handlers = eventHandlers[src].buffered;
        if (handlers) {
          // We can safely clean up all onBuffered event handlers, as once the
          // src media is cached, the onBuffered event can be fired immediately
          // for any new audio objects that are created henceforth
          eventHandlers[src].buffered = null;

          for (var i = 0; i < handlers.length; i++) {
            deferredApply(handlers[i]);
          }
        }
      });
    };

    // Keep retrying until XHR succeeds
    req.onerror = function() {
      console.error('Retrying ', src);
      audioBuffers[src] = null;
      setTimeout(function() { bufferAudio(src, retryInterval); }, retryInterval);
    };

    req.send();
  }

  // Create WebAudio source
  function createWebAudio(src, options) {
    var playStartTime = 0;  // Used to keep track how long clip is played for
    var playOffset = 0;  // Used to keep track of how far into clip we are

    var self = {
      stopped: true,
      src: src,
      options: options,
      isWebAudio: true,

      play: function play() {
        if (!self.stopped) return;
        self.stopped = false;

        // Buffer audio if not buffered, and schedule play() for later
        if (!self.isCached()) {
          self.buffer();
          (function retry() {
            if (self.isCached() && !self.stopped) {
              self.stopped = true;
              play(src);
            }
            else setTimeout(retry, 200);
          })();
          return;
        }

        var audioSrc = self.audioSrc = audioCtx.createBufferSource();
        var gainNode = audioCtx.createGain();
        gainNode.gain.value = options.gain;

        audioSrc.buffer = audioBuffers[src];
        audioSrc.connect(audioCtx.destination);
        audioSrc.loop = !!options.loop;
        audioSrc.onended = function() {
          self.stopped = true;
          deferredApply(self.onEnd);
        };

        if (audioSrc.start) audioSrc.start(0, playOffset);
        else if(audioSrc.noteOn) audioSrc.noteOn(0, playOffset);
        else console.error('AudioContextBuffer.start() not available');

        deferredApply(self.onPlay);
        playStartTime = audioCtx.currentTime;
      },

      stop: function(pause) {
        if (self.stopped) return;
        self.stopped = true;

        if (!pause) playOffset = 0;
        else playOffset += audioCtx.currentTime - playStartTime;

        if (!pause && self.audioSrc.onended) self.audioSrc.onended();
        self.audioSrc.onended = null;

        if (self.audioSrc.stop) self.audioSrc.stop(0);
        else if(self.audioSrc.noteOff) self.audioSrc.noteOff(0);
        else console.error('AudioContextBuffer.stop() not available');
      },

      pause: function() {
        self.stop(true);
      },

      buffer: function() {
        bufferAudio(src, options.retryInterval);

        // onBuffered event
        // We need to wrap this in setTimeout() because buffer() can be
        // automatically called on creation so the user does not have an
        // opportunity to set an onBuffered event handler
        setTimeout(function() {
          if (self.isCached()) deferredApply(self.onBuffered);
          else {
            if (!eventHandlers[src].buffered) eventHandlers[src].buffered = [];
            eventHandlers[src].buffered.push(function() {
              deferredApply(self.onBuffered);
            });
          }
        }, 0);
      },

      offset: function() {
        return self.stopped || !self.isCached() ?
          playOffset :
          playOffset + audioCtx.currentTime - playStartTime;
      },

      isCached: function() {
        return audioBuffers[src] && audioBuffers[src] !== LOADING;
      }
    };

    return self;
  }

  // Create HTML Audio source (fallback)
  function createHTMLAudio(src, options) {
    var audioSrc = new Audio(src);

    var self = {
      audioSrc: audioSrc,
      stopped: true,
      src: src,
      options: options,
      loaded: false,
      isWebAudio: false,

      play: function play() {
        if (!self.stopped) return;
        self.stopped = false;

        // Wait for audio to be buffered
        if (!self.loaded) {
          (function retry() {
            if (self.loaded && !self.stopped) {
              self.stopped = true;
              play(src);
            }
            else setTimeout(retry, 200);
          })();
          return;
        }

        audioSrc.volume = options.gain;
        audioSrc.loop = !!options.loop;
        audioSrc.play();
      },

      stop: function(pause) {
        if (self.stopped) return;
        self.stopped = true;

        audioSrc.pause();
        if (!pause) {
          audioSrc.currentTime = 0;
          deferredApply(self.onEnd);
        }
      },

      pause: function() {
        self.stop(true);
      },

      buffer: function() {
        audioSrc.load();
      },

      offset: function() {
        return audioSrc.duration && audioSrc.currentTime <= audioSrc.duration ?
          audioSrc.currentTime : 0;
      }
    };

    audioSrc.addEventListener('ended', function() {
      self.stopped = true;
      self.audioSrc.currentTime = 0;
      if (!options.loop) {
        audioSrc.pause();
        deferredApply(self.onEnd);
      }
    });
    audioSrc.addEventListener('play', function() {
      deferredApply(self.onPlay);
    });
    audioSrc.addEventListener('canplaythrough', function handler() {
      audioSrc.removeEventListener('canplaythrough', handler);
      self.loaded = true;
      deferredApply(self.onBuffered);
    });

    return self;
  }

  return function(src, options) {
    if (!eventHandlers[src]) eventHandlers[src] = {};

    options = options || {};
    if (options.buffer === undefined) options.buffer = true;
    if (options.loop === undefined) options.loop = false;
    if (options.gain === undefined) options.gain = 1;
    if (options.retryInterval === undefined) options.retryInterval = 1000;

    var audio = (audioCtx ? createWebAudio : createHTMLAudio)(src, options);
    if (options.buffer) audio.buffer();
    return audio;
  };
}]);
<|endoftext|>


<commit_before>
function RestRoutingViewModel() {
    var self = this;

    self.available_method    = ko.observableArray(['GET',
                                                   'POST',
                                                   'PUT',
                                                   'DELETE',
                                                   'OPTIONS',
                                                   'HEAD',
                                                   'TRACE'
                                                  ]);
    self.method              = ko.observable();
    self.address             = ko.observable();
    self.format              = ko.observable();
    self.field_list          = ko.observableArray();
    self.field_edit          = ko.observable();
    self.field_selected      = ko.observable();
    self.content             = ko.observable();
    self.storedItems         = ko.observableArray();

    self.answer              = ko.observableArray();

    self.can_send = function() {
        if (self.address() === undefined) {
            return false;
        }
        return _.isEmpty(self.address().trim()) === false;
    };

    self.is_add_available = function() {
        var field = self.field_edit();
        return field !== undefined && _.indexOf(self.field_list(), field) === -1;
    };

    self.is_remove_available = function() {
        var selected = self.field_selected();
        return selected !== undefined && _.indexOf(self.field_list(), selected) > -1;
    };

    self.have_storage = function() {
        return typeof(Storage) !== 'undefined';
    };

    self.list_requests = function() {
        if (! self.have_storage()) {
            return ;
        }

        self.storedItems(localStorage.stored_requests || []);
    };

    self.save_request = function() {
        if (! self.have_storage()) {
            report_error('Your browser does not support local storage');
            return;
        }
    };

    self.remove_field = function() {
        var selected = self.field_selected();
        if (selected === undefined) {
            return report_error('No field was selected to be removed');
        }

        if (! _.isEmpty(selected.trim())) {
            if (_.indexOf(self.field_list(), selected) > -1) {
              self.field_list.remove(selected);
            } else {
                report_error('Unable to find selected field to remove');
            }
        } else {
            report_error('The selected field to be removed is empty');
        }

    };

    self.add_field = function() {
        var field = self.field_edit();
        if (field === undefined) {
            return report_error('Field Edit is empty');
        }
        if (! _.isEmpty(field.trim())) {
            if (_.indexOf(self.field_list(), field) === -1) {
                self.field_list.push(field);
            } else {
                report_error('Field alreay exists in the list');
            }
        } else {
            report_error('The field to be added is empty');
        }
    };

    self.execRest = function() {
        var params = {method: self.method(),
                      address: self.address(),
                      field_list: self.field_list(),
                      format: self.format() || '',
                      content: self.content() || ''};
        $.post('/request', params).
            done(function(data, req_status, req_obj) {
                self.answer(data);

            }).
        error(function(){
            report_error('Unable to communicate with the server');
        });

    };
}

var rest_client;
$(function(){
    rest_client = new RestRoutingViewModel();
    ko.applyBindings(rest_client);
});
<commit_msg>now hiding the messages on a new request, and placing headers on error<commit_after>
function RestRoutingViewModel() {
    var self = this;

    self.available_method    = ko.observableArray(['GET',
                                                   'POST',
                                                   'PUT',
                                                   'DELETE',
                                                   'OPTIONS',
                                                   'HEAD',
                                                   'TRACE'
                                                  ]);
    self.method              = ko.observable();
    self.address             = ko.observable();
    self.format              = ko.observable();
    self.field_list          = ko.observableArray();
    self.field_edit          = ko.observable();
    self.field_selected      = ko.observable();
    self.content             = ko.observable();
    self.storedItems         = ko.observableArray();

    self.answer              = ko.observableArray();

    self.can_send = function() {
        if (self.address() === undefined) {
            return false;
        }
        return _.isEmpty(self.address().trim()) === false;
    };

    self.is_add_available = function() {
        var field = self.field_edit();
        return field !== undefined && _.indexOf(self.field_list(), field) === -1;
    };

    self.is_remove_available = function() {
        var selected = self.field_selected();
        return selected !== undefined && _.indexOf(self.field_list(), selected) > -1;
    };

    self.have_storage = function() {
        return typeof(Storage) !== 'undefined';
    };

    self.list_requests = function() {
        if (! self.have_storage()) {
            return ;
        }

        self.storedItems(localStorage.stored_requests || []);
    };

    self.save_request = function() {
        if (! self.have_storage()) {
            report_error('Your browser does not support local storage');
            return;
        }
    };

    self.remove_field = function() {
        var selected = self.field_selected();
        if (selected === undefined) {
            return report_error('No field was selected to be removed');
        }

        if (! _.isEmpty(selected.trim())) {
            if (_.indexOf(self.field_list(), selected) > -1) {
              self.field_list.remove(selected);
            } else {
                report_error('Unable to find selected field to remove');
            }
        } else {
            report_error('The selected field to be removed is empty');
        }

    };

    self.add_field = function() {
        var field = self.field_edit();
        if (field === undefined) {
            return report_error('Field Edit is empty');
        }
        if (! _.isEmpty(field.trim())) {
            if (_.indexOf(self.field_list(), field) === -1) {
                self.field_list.push(field);
            } else {
                report_error('Field alreay exists in the list');
            }
        } else {
            report_error('The field to be added is empty');
        }
    };

    self.execRest = function() {
        var params = {method: self.method(),
                      address: self.address(),
                      field_list: self.field_list(),
                      format: self.format() || '',
                      content: self.content() || ''};
        $.post('/request', params).
            done(function(data, req_status, req_obj) {
                self.answer(data);
                $('#messages').addClass('hide');

            }).
        error(function(data){
            self.answer([{key: 'Error', value: 'There was an error with the request'},
                         {key: 'code', value: data.status},
                         {key: 'statusText', value: data.statusTest},
                         {key: 'responseText', value: data.responseText},
                         {key: 'readyState', value: data.readyState},
            ]);
            report_error('Unable to communicate with the server, or bad error code');
        });

    };
}

var rest_client;
$(function(){
    rest_client = new RestRoutingViewModel();
    ko.applyBindings(rest_client);
});
<|endoftext|>


<commit_before>var concat = require('concat-stream')
var through = require('through2')
var Selector = require('digger-selector')
var streamworks = require('streamworks')
var duplexer = require('reduplexer')
var cascade = require('group-cascade-stream')

// the front-end ship handler
// the contract is the body
module.exports = function(api){

	// create a stream for a single selector step - multiple node ids will be piped in
	function queryFactory(selector, laststep){
		var headers = {
			'x-digger-selector':selector
		}
		if(laststep){
			headers['x-digger-laststep'] = true
		}
		return api({
			method:'get',
			url:'/warehouse',
			headers:headers
		})
	}

	function selectorMultiStream(selector, laststep){
		var factory = queryFactory(selector, laststep)

		var output = through.obj()

		var input = through.obj(function(chunk, enc, nextinput){
			var self = this;
			console.log('run query');
			console.dir(chunk);
			console.dir(selector);

			factory(chunk)
				//.pipe(filter)
				.pipe(through.obj(function(chunk, enc, cb){
					console.log('result: ' + selector.tag);
					console.dir(chunk);
					output.push(chunk)
					cb()
				}, function(){
					console.log('-------------------------------------------');
					console.log('-------------------------------------------');
					console.log(chunk);
					console.dir(selector.tag);
					console.log('search finished');
					nextinput()
				}))
		}, function(){
			console.log('-------------------------------------------');
			console.log('-------------------------------------------');
			console.log('pipeline finished');
			output.push(null)
		})

		return duplexer(input, output, {
			objectMode:true
		})
	}

	// create a stream for a selector phase of steps
	// multiple steps are piped through each other
	// the input is the starting contexts
	function selectorPhaseStream(phase){
		if(phase.length>1){
			var selectorStreams = phase.map(function(step, index){
				return selectorMultiStream(step, index==phase.length-1)
			})

			var query = streamworks.pipeObjects(selectorStreams)

			return query/*
			var r = []

			var filter = through.obj(function(chunk, enc, cb){
				r.push(chunk)
				console.log('After Qiuer PIPE');
				console.dir(chunk);
				this.push(chunk)
				cb()
			}, function(){
				console.log('-------------------------------------------');
				console.log('-------------------------------------------');
				console.log('query pupe ended');
				console.dir(r);
			})

			query.pipe(filter)

			return duplexer(query, filter, {
				objectMode:true
			})*/
		}
		else{
			return selectorStepStream(phase[0], true)
		}
	}

	// create a stream for multiple phases (selectors split by ',')
	// multiple phases are merged
	function selectorStringStream(selector){
		if(selector.phases.length>1){
			return streamworks.mergeObjects(selector.phases.map(selectorPhaseStream))
		}
		else{
			return selectorPhaseStream(selector.phases[0])
		}
	}

	// the master stream for the selector
	return function(req){

		var selector = null
		var context = null

		if(req.headers['x-digger-selector']){
			selector = selectorStringStream(Selector(req.headers['x-digger-selector']))
		}
		if(req.headers['x-digger-context']){
			context = selectorStringStream(Selector(req.headers['x-digger-context']))
		}

		if(!selector && !contract){
			throw new Error('no selector or context given')
		}
		else if(selector && context){
			return streamworks.pipeObjects([
				context,
				selector
			])
		}
		else{
			return selector || context
		}
	}
}<commit_msg>simple streaming<commit_after>var concat = require('concat-stream')
var through = require('through2')
var Selector = require('digger-selector')
var streamworks = require('streamworks')
var duplexer = require('reduplexer')
var cascade = require('group-cascade-stream')

// the front-end ship handler
// the contract is the body
module.exports = function(api){

	// create a stream for a single selector step - multiple node ids will be piped in
	function queryFactory(selector, laststep){
		var headers = {
			'x-digger-selector':selector
		}
		if(laststep){
			headers['x-digger-laststep'] = true
		}
		return api({
			method:'get',
			url:'/warehouse',
			headers:headers
		})
	}

	function selectorMultiStream(selector, laststep){
		var query = queryFactory(selector, laststep)
		var output = query.filter || through.obj()
		var open = 0
		var input = through.obj(function(chunk, enc, nextinput){
			var self = this;
			open++
			var results = query.select(chunk)
			results.on('end', function(){
				open--
				if(open<=0){
					output.end()
				}
			})
			results.pipe(output, {end:false})
			nextinput()
		})

		return duplexer(input, output, {
			objectMode:true
		})
	}

	// create a stream for a selector phase of steps
	// multiple steps are piped through each other
	// the input is the starting contexts
	function selectorPhaseStream(phase){
		if(phase.length>1){
			var selectorStreams = phase.map(function(step, index){
				return selectorMultiStream(step, index==phase.length-1)
			})
			var query = streamworks.pipeObjects(selectorStreams)
			return query
		}
		else{
			return selectorStepStream(phase[0], true)
		}
	}

	// create a stream for multiple phases (selectors split by ',')
	// multiple phases are merged
	function selectorStringStream(selector){
		if(selector.phases.length>1){
			return streamworks.mergeObjects(selector.phases.map(selectorPhaseStream))
		}
		else{
			return selectorPhaseStream(selector.phases[0])
		}
	}

	// the master stream for the selector
	return function(req){

		var selector = null
		var context = null

		if(req.headers['x-digger-selector']){
			selector = selectorStringStream(Selector(req.headers['x-digger-selector']))
		}
		if(req.headers['x-digger-context']){
			context = selectorStringStream(Selector(req.headers['x-digger-context']))
		}

		if(!selector && !contract){
			throw new Error('no selector or context given')
		}
		else if(selector && context){
			return streamworks.pipeObjects([
				context,
				selector
			])
		}
		else{
			return selector || context
		}
	}
}<|endoftext|>