<commit_before>module.exports = function (gulp, options) {

    var jshint = require('gulp-jshint'),
        rimraf = require('gulp-rimraf'),
        fs = require('fs'),
        _ = require('lodash'),
        browserify = require('browserify'),
        source = require('vinyl-source-stream'),
        streamify = require('gulp-streamify'),
        watchify = require('watchify'),
        gulpif = require('gulp-if'),
        autoprefixer = require('gulp-autoprefixer'),
        minify = require('gulp-minify-css'),
        concat = require('gulp-concat'),
        embedlr = require('gulp-embedlr'),
        minimist = require('minimist'),
        watch = require('gulp-watch'),
        sass = require('gulp-sass'),
        plumber = require('gulp-plumber'),
        karma = require('karma').server,
        uglify = require('gulp-uglify'),
        express = require('express'),
        refresh = require('gulp-livereload'),
        livereload = require('connect-livereload'),
        lrserver = require('tiny-lr')(),
        gutil = require('gulp-util'),
        livereloadport = 35729,
        serverport = options.serverPort,
        server = express();

    var DIST_FOLDER = options.distribution,
        KARMA_CONFIG = '/karma.conf.js',
        BUNDLE_FILENAME = options.bundleFilename,
        watching = options.module,
        currentVariant = getVariantOption("debug-main");

    if (!options.module) {
        server.use(express.static(getDistDirectory()));
        server.use(livereload({port: livereloadport}));

        server.all('/*', function (req, res) {
            res.sendfile('index.html', { root: getDistDirectory() });
        });
    }

    !options.module && gulp.task('build', ['clean'], function () {
        var variant = getVariantOption(),
            variants = [];
        if (watching) {
            variants = [currentVariant];
        } else if (variant !== 'all') {
            variants = [variant];
        } else {
            variants = getDirectories(__dirname + "/boot");
            variants = _.flatten(_.map(variants, function (variant) {
                return ['release-' + variant, 'debug-' + variant];
            }));
        }
        _.forEach(variants, function (variant) {
            currentVariant = variant;
            gulp.start('views', 'styles', 'images', 'browserify');
        });
    });

    gulp.task('clean', function () {
        return gulp.src([DIST_FOLDER, 'coverage/'], { read: false })
            .pipe(plumber())
            .pipe(rimraf({force: true}));
    });

    gulp.task('lint', function () {
        gulp.src('scripts/*.js')
            .pipe(jshint())
            .pipe(jshint.reporter('default'));
    });

    !options.module && gulp.task('styles', function () {
        gulp.src('./boot/' + getVariantPart() + '/bootstrapper.scss')
            .pipe(concat(BUNDLE_FILENAME + '.css'))
            .pipe(plumber())
            .pipe(sass({ includePaths: ['./'] }))
            .pipe(autoprefixer('last 2 versions', '> 1%', 'ie 8'))
            .pipe(gulpif(isRelease(), minify()))
            .pipe(gulp.dest(getDistDirectory() + 'css/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('browserify', function () {
        process.env.DEBUG = currentVariant.indexOf('debug') > -1;

        var browserifyOptions = {
            entries: ['./boot/' + getVariantPart() + '/bootstrapper.js'],
            basedir: process.cwd(),
            debug: !isRelease(),
            cache: {},
            packageCache: {},
            fullPaths: true
        };

        var bundleStream = watching ? watchify(browserify(browserifyOptions)) :
            browserify(browserifyOptions);
        if (watching)
            bundleStream.on('update', rebundle);

        function rebundle() {
            bundleStream.bundle()
                .on('error', gutil.log)
                .pipe(source(BUNDLE_FILENAME + '.js'))
                .pipe(gulpif(isRelease(), streamify(uglify())))
                .pipe(gulp.dest(getDistDirectory() + 'js'))
                .pipe(gulpif(watching, refresh(lrserver)));
        }

        return rebundle();
    });

    gulp.task('test', function (done) {
        karma.start({
            configFile: __dirname + KARMA_CONFIG,
            singleRun: !watching
        }, function () {
            if (watching)
                gulp.start('test');
            else
                done();
        });
    });

    !options.module && gulp.task('views', function () {
        gulp.src('index.html')
            .pipe(gulpif(watching, embedlr()))
            .pipe(gulp.dest(getDistDirectory()));
        gulp.src('views/**/*')
            .pipe(gulp.dest(getDistDirectory() + 'views/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('images', function () {
        gulp.src('images/**/*')
            .pipe(gulp.dest(getDistDirectory() + 'images/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('watch', function () {
        watching = true;
        currentVariant = getVariantOption("debug-main");

        gulp.start('build', 'serve', function () {
            gulp.watch(['./boot/' + getVariantPart() + '/bootstrapper.scss',
                    './boot/base.scss',
                    './styles/**/*.scss'],
                ['styles']);

            gulp.watch(['views/**/*.html'], ['views']);

            watch(['images/*'], function () {
                gulp.start('images');
            });
        });
    });

    !options.module && gulp.task('watch-test', ['watch', 'test']);

    !options.module && gulp.task('serve', function () {
        if (!currentVariant)
            currentVariant = getVariantOption("debug-main");

        server.listen(serverport);
        refresh.listen(livereloadport);
        console.log('Variant ' + currentVariant + ' listening on http://localhost:' + serverport);
    });

    gulp.task('default', [!options.module ? 'build' : 'test']);

    function getDirectories(rootDir) {
        var files = fs.readdirSync(rootDir),
            directories = [];
        _.forEach(files, function (file) {
            if (file[0] != '.') {
                var filePath = rootDir + '/' + file,
                    stat = fs.statSync(filePath);
                if (stat.isDirectory())
                    directories.push(file);
            }
        });
        return directories;
    }

    function isRelease() {
        return currentVariant.indexOf("release") > -1;
    }

    function getDistDirectory() {
        return DIST_FOLDER + '/' + currentVariant + '/';
    }

    function getVariantPart() {
        return currentVariant.split('-')[1];
    }

    function getVariantOption(defaultOption) {
        return minimist(process.argv.slice(2), {
            string: 'variant',
            default: { variant: defaultOption || 'release-main' }
        }).variant;
    }
};<commit_msg>Remove gulp-util<commit_after>module.exports = function (gulp, options) {

    var jshint = require('gulp-jshint'),
        rimraf = require('gulp-rimraf'),
        fs = require('fs'),
        _ = require('lodash'),
        browserify = require('browserify'),
        source = require('vinyl-source-stream'),
        streamify = require('gulp-streamify'),
        watchify = require('watchify'),
        gulpif = require('gulp-if'),
        autoprefixer = require('gulp-autoprefixer'),
        minify = require('gulp-minify-css'),
        concat = require('gulp-concat'),
        embedlr = require('gulp-embedlr'),
        minimist = require('minimist'),
        watch = require('gulp-watch'),
        sass = require('gulp-sass'),
        plumber = require('gulp-plumber'),
        karma = require('karma').server,
        uglify = require('gulp-uglify'),
        express = require('express'),
        refresh = require('gulp-livereload'),
        livereload = require('connect-livereload'),
        lrserver = require('tiny-lr')(),
        livereloadport = 35729,
        serverport = options.serverPort,
        server = express();

    var DIST_FOLDER = options.distribution,
        KARMA_CONFIG = '/karma.conf.js',
        BUNDLE_FILENAME = options.bundleFilename,
        COVERAGE = options.coverageOutput,
        watching = options.module,
        currentVariant = getVariantOption("debug-main");

    if (!options.module) {
        server.use(express.static(getDistDirectory()));
        server.use(livereload({port: livereloadport}));

        server.all('/*', function (req, res) {
            res.sendfile('index.html', { root: getDistDirectory() });
        });
    }

    !options.module && gulp.task('build', ['clean'], function () {
        var variant = getVariantOption(),
            variants = [];
        if (watching) {
            variants = [currentVariant];
        } else if (variant !== 'all') {
            variants = [variant];
        } else {
            variants = getDirectories(__dirname + "/boot");
            variants = _.flatten(_.map(variants, function (variant) {
                return ['release-' + variant, 'debug-' + variant];
            }));
        }
        _.forEach(variants, function (variant) {
            currentVariant = variant;
            gulp.start('views', 'styles', 'images', 'browserify');
        });
    });

    gulp.task('clean', function () {
        return gulp.src([DIST_FOLDER, COVERAGE], { read: false })
            .pipe(plumber())
            .pipe(rimraf({force: true}));
    });

    gulp.task('lint', function () {
        gulp.src('scripts/*.js')
            .pipe(jshint())
            .pipe(jshint.reporter('default'));
    });

    !options.module && gulp.task('styles', function () {
        gulp.src('./boot/' + getVariantPart() + '/bootstrapper.scss')
            .pipe(concat(BUNDLE_FILENAME + '.css'))
            .pipe(plumber())
            .pipe(sass({ includePaths: ['./'] }))
            .pipe(autoprefixer('last 2 versions', '> 1%', 'ie 8'))
            .pipe(gulpif(isRelease(), minify()))
            .pipe(gulp.dest(getDistDirectory() + 'css/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('browserify', function () {
        process.env.DEBUG = currentVariant.indexOf('debug') > -1;

        var browserifyOptions = {
            entries: ['./boot/' + getVariantPart() + '/bootstrapper.js'],
            basedir: process.cwd(),
            debug: !isRelease(),
            cache: {},
            packageCache: {},
            fullPaths: true
        };

        var bundleStream = watching ? watchify(browserify(browserifyOptions)) :
            browserify(browserifyOptions);
        if (watching)
            bundleStream.on('update', rebundle);

        function rebundle() {
            bundleStream.bundle()
                .pipe(plumber())
                .pipe(source(BUNDLE_FILENAME + '.js'))
                .pipe(gulpif(isRelease(), streamify(uglify())))
                .pipe(gulp.dest(getDistDirectory() + 'js'))
                .pipe(gulpif(watching, refresh(lrserver)));
        }

        return rebundle();
    });

    gulp.task('test', function (done) {
        karma.start({
            configFile: __dirname + KARMA_CONFIG,
            singleRun: !watching
        }, function () {
            if (watching)
                gulp.start('test');
            else
                done();
        });
    });

    !options.module && gulp.task('views', function () {
        gulp.src('index.html')
            .pipe(gulpif(watching, embedlr()))
            .pipe(gulp.dest(getDistDirectory()));
        gulp.src('views/**/*')
            .pipe(gulp.dest(getDistDirectory() + 'views/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('images', function () {
        gulp.src('images/**/*')
            .pipe(gulp.dest(getDistDirectory() + 'images/'))
            .pipe(gulpif(watching, refresh(lrserver)));
    });

    !options.module && gulp.task('watch', function () {
        watching = true;
        currentVariant = getVariantOption("debug-main");

        gulp.start('build', 'serve', function () {
            gulp.watch(['./boot/' + getVariantPart() + '/bootstrapper.scss',
                    './boot/base.scss',
                    './styles/**/*.scss'],
                ['styles']);

            gulp.watch(['views/**/*.html'], ['views']);

            watch(['images/*'], function () {
                gulp.start('images');
            });
        });
    });

    !options.module && gulp.task('watch-test', ['watch', 'test']);

    !options.module && gulp.task('serve', function () {
        if (!currentVariant)
            currentVariant = getVariantOption("debug-main");

        server.listen(serverport);
        refresh.listen(livereloadport);
        console.log('Variant ' + currentVariant + ' listening on http://localhost:' + serverport);
    });

    gulp.task('default', [!options.module ? 'build' : 'test']);

    function getDirectories(rootDir) {
        var files = fs.readdirSync(rootDir),
            directories = [];
        _.forEach(files, function (file) {
            if (file[0] != '.') {
                var filePath = rootDir + '/' + file,
                    stat = fs.statSync(filePath);
                if (stat.isDirectory())
                    directories.push(file);
            }
        });
        return directories;
    }

    function isRelease() {
        return currentVariant.indexOf("release") > -1;
    }

    function getDistDirectory() {
        return DIST_FOLDER + '/' + currentVariant + '/';
    }

    function getVariantPart() {
        return currentVariant.split('-')[1];
    }

    function getVariantOption(defaultOption) {
        return minimist(process.argv.slice(2), {
            string: 'variant',
            default: { variant: defaultOption || 'release-main' }
        }).variant;
    }
};<|endoftext|>


<commit_before>// Global vars
var pymChild = null;
var isMobile = false;

/* Initialize the graphic.
----------------------------------------------------*/
var onWindowLoaded = function () {
    if (Modernizr.svg) {
        formatData();

        pymChild = new pym.Child({
            renderCallback: render,
        });
    } else {
        pymChild = new pym.Child({});
    }
};

/*
 * Format graphic data for processing by D3.
 */
var formatData = function () {
    DATA.forEach(function (d) {
        d.amt = +d.amt;
    });
};

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function (containerWidth) {
    containerWidth = containerWidth || DEFAULT_WIDTH;
    isMobile = (containerWidth <= MOBILE_THRESHOLD);

    // Render the chart
    renderWaffleChart();

    // Update iframe
    if (pymChild) {
        pymChild.sendHeight();
    }
};

/*
 * Render a waffle chart.
 */
var renderWaffleChart = function () {
    /*
     * Setup
     */
    var labelWidth = parseInt(LABELS.labelWidth || 85);
    var labelMargin = parseInt(LABELS.labelMargin || 6);

    var margins = {
        top: parseInt(LABELS.marginTop || 0),
        right: parseInt(LABELS.marginRight || (labelWidth + labelMargin)),
        bottom: parseInt(LABELS.marginBottom || 0),
        left: parseInt(LABELS.marginLeft || 0),
    };

    // Clear existing graphic (for redraw)
    var containerElement = d3.select('#waffle-chart')
        .style('max-width', (parseInt(LABELS.maxWidth) || 420) + 'px' )

    containerElement.html('');

    // Center align if alignCenter is set
    if (LABELS.alignCenter === 'on') containerElement.classed('align-center', true);

    /*
     * Create the root SVG element.
     */
    var chartWrapper = containerElement.append('div')
        .attr('class', 'graphics-wrapper');

    // Calculate actual chart dimensions
    var innerWidth = chartWrapper.node().getBoundingClientRect().width;
    var chartWidth = (innerWidth - margins.left - margins.right >= parseInt(LABELS.maxWidth))
        ? parseInt(LABELS.maxWidth) : innerWidth - margins.left - margins.right;
    var chartHeight = chartWidth;

    var chartSvg = chartWrapper.append('svg')
        .attr({
            width: chartWidth + margins.left + margins.right,
            height: chartHeight + margins.top + margins.bottom,
        });

    var chartElement = chartSvg.append('g')
            .attr('transform', makeTranslate(margins.left, margins.top));

    var totalAmount = 0; // Init total number of squares

    var widthSquares = 10,
        heightSquares = 10,
        squareSize = Math.round(chartHeight / heightSquares),
        squareValue = 0, // Set later
        gap = 1,
        squareData = []; // Data for individual squares

    var colorList = colorArray(LABELS, MULTICOLORS);
    var colorScale = d3.scale.ordinal()
        .range(colorList);

    // Total of all data
    totalAmount = d3.sum(DATA, function(d) { return d.amt; });

    // Value of a square
    squareValue = totalAmount / (heightSquares * widthSquares);

    // Remap data for individual squares
    DATA.forEach(function(d, i) {
        d.amt = +d.amt;

        d.units = Math.floor(d.amt/squareValue);

        squareData = squareData.concat(
            Array(d.units+1).join(1).split('').map(function()
            {
                return {
                    squareValue:squareValue,
                    units: d.units,
                    amt: d.amt,
                    groupIndex: i
                };
            })
        );
    });

    // Create a transparent SVG to use as for patterns
    var svgPatterns = d3.select("#waffle-chart").append("svg")
        .attr('width', 0)
        .attr('height', 0)

        svgDefs = svgPatterns.append('defs');

        svgDefs.append('pattern')
            .attr('id', 'diagonalHatchRight') // ID of pattern
            .attr('patternUnits', 'userSpaceOnUse')
            .attr('width', 4)
            .attr('height', 4)
        .append('path')
            .attr('d', 'M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2') // Draw // pattern
            .attr('stroke', 'white')
            .attr('stroke-width', 1)

        svgDefs.append('pattern')
            .attr('id', 'diagonalHatchLeft') // ID of pattern
            .attr('patternUnits', 'userSpaceOnUse')
            .attr('width', 4)
            .attr('height', 4)
        .append('path')
            .attr('d', 'M5,1 l-2,-2 M4,4 l-4,-4 M1,5 l-2,-2') // Draw \\ pattern
            .attr('stroke', 'white')
            .attr('stroke-width', 1);

    // Define the tooltip for squares
    var tooltip = d3.select("body")
        .append("div")
        .classed('tooltip', true);

    /*
     * Render the squares
     */
    var squares = chartElement.selectAll('rect')
        .data(squareData)
        .enter()
        .call( function(selection) {
            // Render bottom layer of squares
            selection.append('rect')
                .attr("width", squareSize - gap)
                .attr("height", squareSize - gap)
                .attr("fill", function(d) {
                    return colorScale(d.groupIndex);
                })
                .attr("x", function(d, i)
                {
                    col = i%widthSquares;
                    var x = (col * (squareSize - gap)) + (col * gap);
                    return x;
                })
                .attr("y", function(d, i) {
                    //group n squares for column
                    row = Math.floor(i/widthSquares);
                    return (row * (squareSize - gap)) + (row * gap);
                });

            /* Render top layer of squares
            ----------------------------------------------------*/
            selection.append('rect')
                .attr("width", squareSize - gap)
                .attr("height", squareSize - gap)
                .attr("fill", function (d,i) {
                     switch (d.groupIndex % 4) {
                        case 0: return "rgba(255,255,255,0.0)"; // fully transparent
                        case 1: return "url(#diagonalHatchLeft)";
                        case 2: return "rgba(255,255,255,0.0)"; // fully transparent
                        case 3: return "url(#diagonalHatchRight)";
                    }
                })
                .attr("x", function(d, i) {
                    col = i%widthSquares;
                    var x = (col * (squareSize - gap)) + (col * gap);
                    return x;
                })
                .attr("y", function(d, i) {
                    //group n squares for column
                    row = Math.floor(i/widthSquares);
                    return (row * (squareSize - gap)) + (row * gap);
                })
                .on("mouseover", function(d, i) {
                    return tooltip.style("visibility", "visible");
                })
                .on("click", function(d, i) { // for mobile
                    return tooltip.style("visibility", "visible");
                })
                .on("mousemove", function(d, i) {
                    tooltip.html('
' + DATA[d.groupIndex].label + "

"
                    +  d.amt + ", " + d.units + "%
");
                    return tooltip.style("top", (d3.event.pageY - 10)+"px").style("left",(d3.event.pageX + 14)+"px");
                })
                .on("mouseout", function(d, i) {
                    return tooltip.style("visibility", "hidden");
                });
        });

    /*
     * Output the legend
     */

    // Create a legend div wrapper
    var chartLegend = chartWrapper.append("ul")
        .attr('class', 'labels')
        .style({
            width: labelWidth + 'px',
            top: '0px',
            left: chartWidth + labelMargin + 'px',
            height: chartHeight + 'px',
            padding: (squareSize / 2) - 7 + 'px 0', // half square - half lineHeight
        });

    // Append a li per data
    chartLegend.selectAll("li")
    .data(DATA)
    .enter()
    .append("li")
        .style('flex-grow', function (d) {
            return Math.floor((d.units - 1) / widthSquares);
        })
        .style("color", function(d, i) {
            return colorScale(i);
        })
        .append("span")
            .html(function(d, i) {
                return d.label + " " + "" + d.units + "%";
            })
            .attr("title", function (d, i) {
                            return d.label + " " + d.amt + ", " + d.units + "%"
                        });

        // Output the total stats
        var chartTotal = chartWrapper.append("div")
            .classed('labels', true)
            .text('Total data: ' + totalAmount);
};

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;<commit_msg>Add option to hide totals<commit_after>// Global vars
var pymChild = null;
var isMobile = false;

/* Initialize the graphic.
----------------------------------------------------*/
var onWindowLoaded = function() {
  if (Modernizr.svg) {
    formatData();

    pymChild = new pym.Child({
      renderCallback: render
    });
  } else {
    pymChild = new pym.Child({});
  }
};

/*
 * Format graphic data for processing by D3.
 */
var formatData = function() {
  DATA.forEach(function(d) {
    d.amt = +d.amt;
  });
};

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function(containerWidth) {
  containerWidth = containerWidth || DEFAULT_WIDTH;
  isMobile = containerWidth <= MOBILE_THRESHOLD;

  // Render the chart
  renderWaffleChart();

  // Update iframe
  if (pymChild) {
    pymChild.sendHeight();
  }
};

/*
 * Render a waffle chart.
 */
var renderWaffleChart = function() {
  /*
     * Setup
     */
  var labelWidth = parseInt(LABELS.labelWidth || 85);
  var labelMargin = parseInt(LABELS.labelMargin || 6);

  // Show or hide total amounts
  var showTotals = true;
  if (LABELS.showTotals !== "on") showTotals = false;

  var margins = {
    top: parseInt(LABELS.marginTop || 0),
    right: parseInt(LABELS.marginRight || labelWidth + labelMargin),
    bottom: parseInt(LABELS.marginBottom || 0),
    left: parseInt(LABELS.marginLeft || 0)
  };

  // Clear existing graphic (for redraw)
  var containerElement = d3
    .select("#waffle-chart")
    .style("max-width", (parseInt(LABELS.maxWidth) || 420) + "px");

  containerElement.html("");

  // Center align if alignCenter is set
  if (LABELS.alignCenter === "on")
    containerElement.classed("align-center", true);

  /*
     * Create the root SVG element.
     */
  var chartWrapper = containerElement
    .append("div")
    .attr("class", "graphics-wrapper");

  // Calculate actual chart dimensions
  var innerWidth = chartWrapper.node().getBoundingClientRect().width;
  var chartWidth =
    innerWidth - margins.left - margins.right >= parseInt(LABELS.maxWidth)
      ? parseInt(LABELS.maxWidth)
      : innerWidth - margins.left - margins.right;
  var chartHeight = chartWidth;

  var chartSvg = chartWrapper.append("svg").attr({
    width: chartWidth + margins.left + margins.right,
    height: chartHeight + margins.top + margins.bottom
  });

  var chartElement = chartSvg
    .append("g")
    .attr("transform", makeTranslate(margins.left, margins.top));

  var totalAmount = 0; // Init total number of squares

  var widthSquares = 10,
    heightSquares = 10,
    squareSize = Math.round(chartHeight / heightSquares),
    squareValue = 0, // Set later
    gap = 1,
    squareData = []; // Data for individual squares

  var colorList = colorArray(LABELS, MULTICOLORS);
  var colorScale = d3.scale.ordinal().range(colorList);

  // Total of all data
  totalAmount = d3.sum(DATA, function(d) {
    return d.amt;
  });

  // Value of a square
  squareValue = totalAmount / (heightSquares * widthSquares);

  // Remap data for individual squares
  DATA.forEach(function(d, i) {
    d.amt = +d.amt;

    d.units = Math.floor(d.amt / squareValue);

    squareData = squareData.concat(
      Array(d.units + 1)
        .join(1)
        .split("")
        .map(function() {
          return {
            squareValue: squareValue,
            units: d.units,
            amt: d.amt,
            groupIndex: i
          };
        })
    );
  });

  // Create a transparent SVG to use as for patterns
  var svgPatterns = d3
    .select("#waffle-chart")
    .append("svg")
    .attr("width", 0)
    .attr("height", 0);

  svgDefs = svgPatterns.append("defs");

  svgDefs
    .append("pattern")
    .attr("id", "diagonalHatchRight") // ID of pattern
    .attr("patternUnits", "userSpaceOnUse")
    .attr("width", 4)
    .attr("height", 4)
    .append("path")
    .attr("d", "M-1,1 l2,-2 M0,4 l4,-4 M3,5 l2,-2") // Draw // pattern
    .attr("stroke", "white")
    .attr("stroke-width", 1);

  svgDefs
    .append("pattern")
    .attr("id", "diagonalHatchLeft") // ID of pattern
    .attr("patternUnits", "userSpaceOnUse")
    .attr("width", 4)
    .attr("height", 4)
    .append("path")
    .attr("d", "M5,1 l-2,-2 M4,4 l-4,-4 M1,5 l-2,-2") // Draw \\ pattern
    .attr("stroke", "white")
    .attr("stroke-width", 1);

  // Define the tooltip for squares
  var tooltip = d3
    .select("body")
    .append("div")
    .classed("tooltip", true);

  /*
     * Render the squares
     */
  var squares = chartElement
    .selectAll("rect")
    .data(squareData)
    .enter()
    .call(function(selection) {
      // Render bottom layer of squares
      selection
        .append("rect")
        .attr("width", squareSize - gap)
        .attr("height", squareSize - gap)
        .attr("fill", function(d) {
          return colorScale(d.groupIndex);
        })
        .attr("x", function(d, i) {
          col = i % widthSquares;
          var x = col * (squareSize - gap) + col * gap;
          return x;
        })
        .attr("y", function(d, i) {
          //group n squares for column
          row = Math.floor(i / widthSquares);
          return row * (squareSize - gap) + row * gap;
        });

      /* Render top layer of squares
            ----------------------------------------------------*/
      selection
        .append("rect")
        .attr("width", squareSize - gap)
        .attr("height", squareSize - gap)
        .attr("fill", function(d, i) {
          switch (d.groupIndex % 4) {
            case 0:
              return "rgba(255,255,255,0.0)"; // fully transparent
            case 1:
              return "url(#diagonalHatchLeft)";
            case 2:
              return "rgba(255,255,255,0.0)"; // fully transparent
            case 3:
              return "url(#diagonalHatchRight)";
          }
        })
        .attr("x", function(d, i) {
          col = i % widthSquares;
          var x = col * (squareSize - gap) + col * gap;
          return x;
        })
        .attr("y", function(d, i) {
          //group n squares for column
          row = Math.floor(i / widthSquares);
          return row * (squareSize - gap) + row * gap;
        })
        .on("mouseover", function(d, i) {
          return tooltip.style("visibility", "visible");
        })
        .on("click", function(d, i) {
          // for mobile
          return tooltip.style("visibility", "visible");
        })
        .on("mousemove", function(d, i) {
          if (showTotals) {
            tooltip.html(
              "
" +
                DATA[d.groupIndex].label +
                "

" +
                d.amt +
                ", " +
                d.units +
                "%
"
            );
          } else {
            tooltip.html(
              "
" +
                DATA[d.groupIndex].label +
                "

" +
                d.units +
                "%
"
            );
          }
          return tooltip
            .style("top", d3.event.pageY - 10 + "px")
            .style("left", d3.event.pageX + 14 + "px");
        })
        .on("mouseout", function(d, i) {
          return tooltip.style("visibility", "hidden");
        });
    });

  /*
     * Output the legend
     */

  // Create a legend div wrapper
  var chartLegend = chartWrapper
    .append("ul")
    .attr("class", "labels")
    .style({
      width: labelWidth + "px",
      top: "0px",
      left: chartWidth + labelMargin + "px",
      height: chartHeight + "px",
      padding: squareSize / 2 - 7 + "px 0" // half square - half lineHeight
    });

  // Append a li per data
  chartLegend
    .selectAll("li")
    .data(DATA)
    .enter()
    .append("li")
    .style("flex-grow", function(d) {
      return Math.floor((d.units - 1) / widthSquares);
    })
    .style("color", function(d, i) {
      return colorScale(i);
    })
    .append("span")
    .html(function(d, i) {
      return d.label + " " + "" + d.units + "%";
    })
    .attr("title", function(d, i) {
      return d.label + " " + d.amt + ", " + d.units + "%";
    });

  // Output the total stats
  if (showTotals) {
    var chartTotal = chartWrapper
      .append("div")
      .classed("labels", true)
      .text("Total data: " + totalAmount);
  }
};

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<|endoftext|>


<commit_before>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.4
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        http://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @connect      jimboy3100.github.io
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License

Copyright (c) [The Legend Mod]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// Start of script
GM_registerMenuCommand('Legend Mod Website', function() {
    window.open("http://legendmod.ml");
}, 'r');
GM_registerMenuCommand('LM Library', function() {
    window.open("https://github.com/jimboy3100/jimboy3100.github.io/");
}, 'r');
GM_registerMenuCommand('Donate for Legend Mod', function() {
    window.open("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CM3GDVCW6PBF6");
}, 'r');

if (location.protocol != 'http:')
{
 location.href = 'http:' + window.location.href.substring(window.location.protocol.length);
}

var url = window.location.href;
if (location.pathname == "/LMoldskins"){
eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('"u v";k(2(){2 e(){g e=p.x("F"),a=b;G(e){H{a=I.z(e)}A(e){6.J(!1,e)}a&&a.5&&(C.B(a.5),6.D("%c[9] d E y...","n: m"))}}g a,t,o;a="//l.q/r.w/f/j.h.f",t=2(){6.s("[9] O 11...")},(o=3.10("Z")).K="X/Y",o.12="13-8",o.4?o.i=2(){"d"!=o.4&&"14"!=o.4||(o.i=b,t&&t())}:(3.7&&3.7.15("V-j-h",a),t&&(o.W=t,o.N=e)),o.5=a+"?M="+~~(L.P()/Q/U),3.T("S")[0].R(o)},0);',62,68,'||function|document|readyState|src|console|body||VANILLA||null||loaded||js|var|core|onreadystatechange|vanilla|setTimeout|imaster|darkorange|color||localStorage|space|agar|info||use|strict|io|getItem|cache|parse|catch|eval|window|log|from|cachedVanilla|if|try|JSON|assert|type|Date|_|onerror|inject|now|1e3|appendChild|head|getElementsByTagName|60|data|onload|text|javascript|script|createElement|success|charset|utf|complete|setAttribute'.split('|'),0,{}))

setTimeout(function() {

document.body.style.background = "#f3f3f3 url('https://jimboy3100.github.io/banners/iconmod3.png') no-repeat center fixed";
$( "body" ).append('

');
}, 4000);
setTimeout(function() {
$("#canvas").remove();$("#adsBottom").remove();$("#rightPanel").remove();$(".agario-panel.agario-side-panel.agario-profile-panel").remove();$("#dailyquests-panel").remove();$("#v-ex-menu").remove();$("#service-message-area").remove();$(".radio-module").remove();$(".tosBox.right").remove();$(".tosBox.left").remove();$(".form-group.clearfix").remove();$("#skinCustomButton").remove();$("#settings").remove();$("#vanilla-home-link").remove();$("#settingsButton").remove();$("#instructions").remove();$(".btn.btn-play.btn-primary").remove();$(".btn.btn-play-guest.btn-success").remove();$(".btn.btn-warning.btn-login-play").text("Login");$(".btn.btn-warning.btn-login-play").css("margin-left", "80px");$("#helloContainer").css("margin-left", "-150px");$('.agario-panel.agario-side-panel.agario-shop-panel').append('<button id="logoutbtn" onclick="logout(); return false;" class="btn btn-danger btn-logout" data-itr="page_logout">Logout</button>');$("#imagebig").remove();
}, 10000);
}
else if(getParameterByName("mod", url)=="tiny"){
var tinyJS = '';
	    function inject(page) {
        page = page.replace("", tinyJS + "");
        return page;
    }
    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "http://agar.io/",
        onload: function(e) {
            var doc = inject(e.responseText);
            document.open();
            document.write(doc);
			document.close();
        }
    });

}

else if (location.host === "agar.io" && location.pathname === "/") {
	window.stop();
	location.href = "about:blank" + window.location.search + location.hash;
// Dependencies

	var modVersion = GM_info.script.version;

    // Inject Legend
    function inject(page) {
        var page = page.replace("", "" + "");
        return page;
    }

    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "https://jimboy3100.github.io/LMexpress/LMexpress.html",
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            document.close();
        }
    });

    // Inject Chat to text userscript
    (function() {
        'use strict';

        function pre_loop() {
            if (!document.getElementById("message-box")) {
                setTimeout(pre_loop, 4000);
                console.log("VoiceDeOChat:wait for Legend load");
                return;
            }
            return initialize();
        }
        return pre_loop();

        function initialize() {
            var lang_hash = {
                "default": "default",
                "ja": "日本語",
                "en-US": "English",
                "el-GR": "Ελληνικά",
                "zh-CN": "简体中文",
                "zh-TW": "繁體中文",
                "ko": "한국어"
            };
            var cfg = {};
            cfg.prefix = GM_getValue("prefix", "🎤");
            cfg.lang = GM_getValue("lang", "default");
            cfg.unpause = GM_getValue("unpause", false);
            console.log("load prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            $("#message-box").mousedown(function() {
                return false;
            });
            $(".team-top-menu").mousedown(function() {
                return false;
            });
            $("#message-menu").append('X');
            $(".chatbox-hide").click(function() {
                $("#message-box").css("display", "none");
                if (cfg.unpause && $("#pause-hud").css("display") == "block") {
                    var code = 82; // 'R'
                    $(document).trigger(jQuery.Event('keydown', {
                        keyCode: code,
                        which: code
                    }));
                }
            });
            $("#message-menu").append('C');
            $(".chatbox-clear").click(function() {
                $("#message").val("");
            });
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new window.SpeechRecognition();
            if (cfg.lang !== "default") {
                recognition.lang = cfg.lang;
            }
            console.log("cfg.lang/recognition.lang=" + cfg.lang + "/" + recognition.lang);
            recognition.addEventListener('result', function(event) {
                var text_to = event.results.item(0).item(0).transcript;
                var text_pre = $("#message").val();
                if (text_pre === "") {
                    text_to = cfg.prefix + text_to;
                } else {
                    text_to = text_pre + " " + text_to;
                }
                $("#message").val(text_to);
            }, false);
            recognition.addEventListener('end', function(event) {
                fn_recognition_end();
            }, false);
            $("#message-menu").append('🎤');
            $(".voice-start").click(function() {
                fn_recognition_start();
            });

            function fn_recognition_start() {
                $("#voice-config").css("display", "none");
                $(".voice-start").css("background-color", "green");
                recognition.start();
            }

            function fn_recognition_end() {
                $(".voice-start").css("background-color", "");
            }
            $("#og-options").append('

');
            $("#voice-config").append('
Voice
');
            $("#voice-config").append('Voice-Prefix:<input type="text" id="voice-prefix" style="width:4em; float:none;" value="' + cfg.prefix + '"/>');

            function fn_lang_make() {
                $("#voice-config").append('Voice-lang:<select id="voice-lang"/></select>');
                for (var code in lang_hash) {
                    var desc = lang_hash[code];
                    var selected = (code === cfg.lang) ? ' selected' : '';
                    $("#voice-lang").append('<option value="' + code + '"' + selected + '>' + desc + '</option>');
                }
            }
            fn_lang_make();
            $("#voice-config").append('<input type="checkbox" id="voice-unpause"' + (cfg.unpause ? ' checked' : '') + '/>UnPause');

            var observ_obj = $("#og-settings");
            var observ_cur = observ_obj.css("display");
            var observer = new MutationObserver(function(mutations) {
                var observ_pre = observ_cur;
                var observ_new = observ_obj.css("display");
                observ_cur = observ_new;
                if (observ_new == "none" && observ_pre == "block") {
                    fn_config_save();
                }
            });
            observer.observe(observ_obj[0], {
                attributes: true,
                attributeFilter: ['style']
            });

            function fn_config_save() {
                cfg.prefix = $("#voice-prefix").val();
                GM_setValue("prefix", cfg.prefix);
                cfg.lang = $("#voice-lang").val();
                GM_setValue("lang", cfg.lang);
                if (cfg.lang !== "default") {
                    recognition.lang = cfg.lang;
                }
                cfg.unpause = $("#voice-unpause").prop('checked');
                GM_setValue("unpause", cfg.unpause);
                console.log("saved prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            }
        }
    })();
}

//runs only if play.google.com is a popup, doesnt if directly joined
if (location.host == "play.google.com") {
	window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
//End of Legend Mod
<commit_msg>Update LMexpress.user.js<commit_after>// ==UserScript==
// @name         Legend Express Agar.io Extension
// @namespace    Legend Express Agario Mod
// @version      1.5
// @description  Agario Mod - Legend,Ogario,Kitty,Old Skins,Animated Skins,Language Packs,Manual User Scripts,Chat,60++ Macros/Hotkeys(Tricksplit,Doublesplit,Quick Feeding,Popsplit,Auto Coins,Freeze Cell Macro,Auto respawn)
// @homepage     http://www.legendmod.ml
// @author       Jimboy3100
// @license      MIT
// @icon         https://jimboy3100.github.io/banners/CropedImage128.gif
// @match        *://agar.io/*
// @match        https://play.google.com/*
// @downloadURL  jimboy3100.github.io/legendmod.user.js
// @updateURL    jimboy3100.github.io/legendmod.user.js
// @run-at       document-start
// @grant        GM_xmlhttpRequest
// @grant        GM_setValue
// @grant        GM_getValue
// @grant        GM_registerMenuCommand
// @grant        GM_deleteValue
// @connect      jimboy3100.github.io
// ==/UserScript==

// Legend Mod by Jimboy3100
/*MIT License

Copyright (c) [The Legend Mod]

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*/

// Start of script
GM_registerMenuCommand('Legend Mod Website', function() {
    window.open("http://legendmod.ml");
}, 'r');
GM_registerMenuCommand('LM Library', function() {
    window.open("https://github.com/jimboy3100/jimboy3100.github.io/");
}, 'r');
GM_registerMenuCommand('Donate for Legend Mod', function() {
    window.open("https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=CM3GDVCW6PBF6");
}, 'r');

if (location.protocol != 'http:')
{
 location.href = 'http:' + window.location.href.substring(window.location.protocol.length);
}

var url = window.location.href;
if (location.pathname == "/LMoldskins"){
eval(function(p,a,c,k,e,d){e=function(c){return(c35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--){d[e(c)]=k[c]||e(c)}k=[function(e){return d[e]}];e=function(){return'\\w+'};c=1};while(c--){if(k[c]){p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c])}}return p}('"u v";k(2(){2 e(){g e=p.x("F"),a=b;G(e){H{a=I.z(e)}A(e){6.J(!1,e)}a&&a.5&&(C.B(a.5),6.D("%c[9] d E y...","n: m"))}}g a,t,o;a="//l.q/r.w/f/j.h.f",t=2(){6.s("[9] O 11...")},(o=3.10("Z")).K="X/Y",o.12="13-8",o.4?o.i=2(){"d"!=o.4&&"14"!=o.4||(o.i=b,t&&t())}:(3.7&&3.7.15("V-j-h",a),t&&(o.W=t,o.N=e)),o.5=a+"?M="+~~(L.P()/Q/U),3.T("S")[0].R(o)},0);',62,68,'||function|document|readyState|src|console|body||VANILLA||null||loaded||js|var|core|onreadystatechange|vanilla|setTimeout|imaster|darkorange|color||localStorage|space|agar|info||use|strict|io|getItem|cache|parse|catch|eval|window|log|from|cachedVanilla|if|try|JSON|assert|type|Date|_|onerror|inject|now|1e3|appendChild|head|getElementsByTagName|60|data|onload|text|javascript|script|createElement|success|charset|utf|complete|setAttribute'.split('|'),0,{}))

setTimeout(function() {

document.body.style.background = "#f3f3f3 url('https://jimboy3100.github.io/banners/iconmod3.png') no-repeat center fixed";
$( "body" ).append('

');
}, 4000);
setTimeout(function() {
$("#canvas").remove();$("#adsBottom").remove();$("#rightPanel").remove();$(".agario-panel.agario-side-panel.agario-profile-panel").remove();$("#dailyquests-panel").remove();$("#v-ex-menu").remove();$("#service-message-area").remove();$(".radio-module").remove();$(".tosBox.right").remove();$(".tosBox.left").remove();$(".form-group.clearfix").remove();$("#skinCustomButton").remove();$("#settings").remove();$("#vanilla-home-link").remove();$("#settingsButton").remove();$("#instructions").remove();$(".btn.btn-play.btn-primary").remove();$(".btn.btn-play-guest.btn-success").remove();$(".btn.btn-warning.btn-login-play").text("Login");$(".btn.btn-warning.btn-login-play").css("margin-left", "80px");$("#helloContainer").css("margin-left", "-150px");$('.agario-panel.agario-side-panel.agario-shop-panel').append('<button id="logoutbtn" onclick="logout(); return false;" class="btn btn-danger btn-logout" data-itr="page_logout">Logout</button>');$("#imagebig").remove();
}, 10000);
}
else if(getParameterByName("mod", url)=="tiny"){
var tinyJS = '';
	    function inject(page) {
        page = page.replace("", tinyJS + "");
        return page;
    }
    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "http://agar.io/",
        onload: function(e) {
            var doc = inject(e.responseText);
            document.open();
            document.write(doc);
			document.close();
        }
    });

}

else if (location.host === "agar.io" && location.pathname === "/") {
	window.stop();
	location.href = "about:blank" + window.location.search + location.hash;
// Dependencies

	var modVersion = GM_info.script.version;

    // Inject Legend
    function inject(page) {
        var page = page.replace("", "" + "");
        return page;
    }

    window.stop();
    document.documentElement.innerHTML = "";
    GM_xmlhttpRequest({
        method: "GET",
        url: "https://jimboy3100.github.io/LMexpress/LMexpress.html",
        onload: function(legend) {
            var doc = inject(legend.responseText);
            document.open();
            document.write(doc);
            document.close();
        }
    });

    // Inject Chat to text userscript
    (function() {
        'use strict';

        function pre_loop() {
            if (!document.getElementById("message-box")) {
                setTimeout(pre_loop, 4000);
                console.log("VoiceDeOChat:wait for Legend load");
                return;
            }
            return initialize();
        }
        return pre_loop();

        function initialize() {
            var lang_hash = {
                "default": "default",
                "ja": "日本語",
                "en-US": "English",
                "el-GR": "Ελληνικά",
                "zh-CN": "简体中文",
                "zh-TW": "繁體中文",
                "ko": "한국어"
            };
            var cfg = {};
            cfg.prefix = GM_getValue("prefix", "🎤");
            cfg.lang = GM_getValue("lang", "default");
            cfg.unpause = GM_getValue("unpause", false);
            console.log("load prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            $("#message-box").mousedown(function() {
                return false;
            });
            $(".team-top-menu").mousedown(function() {
                return false;
            });
            $("#message-menu").append('X');
            $(".chatbox-hide").click(function() {
                $("#message-box").css("display", "none");
                if (cfg.unpause && $("#pause-hud").css("display") == "block") {
                    var code = 82; // 'R'
                    $(document).trigger(jQuery.Event('keydown', {
                        keyCode: code,
                        which: code
                    }));
                }
            });
            $("#message-menu").append('C');
            $(".chatbox-clear").click(function() {
                $("#message").val("");
            });
            window.SpeechRecognition = window.SpeechRecognition || webkitSpeechRecognition;
            var recognition = new window.SpeechRecognition();
            if (cfg.lang !== "default") {
                recognition.lang = cfg.lang;
            }
            console.log("cfg.lang/recognition.lang=" + cfg.lang + "/" + recognition.lang);
            recognition.addEventListener('result', function(event) {
                var text_to = event.results.item(0).item(0).transcript;
                var text_pre = $("#message").val();
                if (text_pre === "") {
                    text_to = cfg.prefix + text_to;
                } else {
                    text_to = text_pre + " " + text_to;
                }
                $("#message").val(text_to);
            }, false);
            recognition.addEventListener('end', function(event) {
                fn_recognition_end();
            }, false);
            $("#message-menu").append('🎤');
            $(".voice-start").click(function() {
                fn_recognition_start();
            });

            function fn_recognition_start() {
                $("#voice-config").css("display", "none");
                $(".voice-start").css("background-color", "green");
                recognition.start();
            }

            function fn_recognition_end() {
                $(".voice-start").css("background-color", "");
            }
            $("#og-options").append('

');
            $("#voice-config").append('
Voice
');
            $("#voice-config").append('Voice-Prefix:<input type="text" id="voice-prefix" style="width:4em; float:none;" value="' + cfg.prefix + '"/>');

            function fn_lang_make() {
                $("#voice-config").append('Voice-lang:<select id="voice-lang"/></select>');
                for (var code in lang_hash) {
                    var desc = lang_hash[code];
                    var selected = (code === cfg.lang) ? ' selected' : '';
                    $("#voice-lang").append('<option value="' + code + '"' + selected + '>' + desc + '</option>');
                }
            }
            fn_lang_make();
            $("#voice-config").append('<input type="checkbox" id="voice-unpause"' + (cfg.unpause ? ' checked' : '') + '/>UnPause');

            var observ_obj = $("#og-settings");
            var observ_cur = observ_obj.css("display");
            var observer = new MutationObserver(function(mutations) {
                var observ_pre = observ_cur;
                var observ_new = observ_obj.css("display");
                observ_cur = observ_new;
                if (observ_new == "none" && observ_pre == "block") {
                    fn_config_save();
                }
            });
            observer.observe(observ_obj[0], {
                attributes: true,
                attributeFilter: ['style']
            });

            function fn_config_save() {
                cfg.prefix = $("#voice-prefix").val();
                GM_setValue("prefix", cfg.prefix);
                cfg.lang = $("#voice-lang").val();
                GM_setValue("lang", cfg.lang);
                if (cfg.lang !== "default") {
                    recognition.lang = cfg.lang;
                }
                cfg.unpause = $("#voice-unpause").prop('checked');
                GM_setValue("unpause", cfg.unpause);
                console.log("saved prefix=" + cfg.prefix + " lang=" + cfg.lang + " unpause=" + cfg.unpause);
            }
        }
    })();
}

//runs only if play.google.com is a popup, doesnt if directly joined
if (location.host == "play.google.com") {
	window.close();
}

function getParameterByName(name, url) {
    if (!url) url = window.location.href;
    name = name.replace(/[\[\]]/g, "\\$&");
    var regex = new RegExp("[?&]" + name + "(=([^&#]*)|&|#|$)"),
        results = regex.exec(url);
    if (!results) return null;
    if (!results[2]) return '';
    return decodeURIComponent(results[2].replace(/\+/g, " "));
}
//End of Legend Mod
<|endoftext|>


<commit_before>var theta;

function setup() {
 createCanvas(640, 420);
 background(0,130,200);
}

function draw(30) {
	frameRate(); // Numero di frame
	 strokeWeight(1); // Spessore delle linee
	 var a = (mouseX / (var) width) * 360f; // Generazione di un angolo da 0 a 360 gradi in base alla posizione del mouse
	 theta = radians(a); // Conversione in radianti
	 translate(width/2, height); // Posizione delle linee sull'asse x
	  translate(0, -170); // Posizione delle linee sull'asse y
	  //slash(120); // Numero di ramificazioni
}
function slash(var h) {
h *= 0.66; // Ogni linea è lunga 2/3 rispetto alle dimensioni di quella precedente
		if (mouseIsPressed) {
    background(0,130,200); // Cliccando con il mouse si resetta la schermata
  } else {
		if (h > 20) {
			push();    // Salvataggio dello stato attuale della trasformazione (cioè il sistema di coordinate corrente)
			rotate(theta);   // Rotazione delle linee
			var c = map(mouseX, 0, width, 255, 0); // Controllo del movimento del primo gruppo attraverso il mouse
			stroke(255, c, 0); // Colorazione della linea
			line(-10, 0, 0, -h);  // Creazione della prima linea
            translate(0, -h); // Posizionamento sugli assi x e y della prima linea
            line(-10, 0, 0, h);
            translate(h, 0);
            slash(h); // Creazione di sottogruppi di linee
            pop(); // Ripristino dello stato precedente della matrice
// Ripetizione delle operazione per il secondo gruppo di linee
            push();    // Salvataggio dello stato attuale della trasformazione (cioè il sistema di coordinate corrente)
			rotate(-theta);   // Rotazione delle linee
			var c = map(mouseX, 0, width, 0, 255); // Controllo del movimento del primo gruppo attraverso il mouse
			stroke(255); // Colorazione della linea
			line(10, 0, 0, -h);  // Creazione della prima linea
            translate(0, -h); // Posizionamento sugli assi x e y della prima linea
            line(10, 0, 0, h);
            translate(-h, 0);
            slash(h);       // Creazione di sottogruppi di linee
            pop();
        }
    }
    if (keyIsPressed) { // premendo il tasto "s", l'immagine "frame.jpg" viene salvata nello Sketch folder
    	if (key == 's') {
    		save("frame.jpg");
    	}
    }
}

<commit_msg>Update sketch.js<commit_after>var cells; // griglia delle celle
var stack; // stack viene usato per salvare le celle visitate
var current;  // cella corrente
var maze; // variabile per disegnare il labirinto

function setup() {
  createCanvas(windowWidth, windowHeight);
  background(0, 130, 200);

  initializeVariables();
  createGrid();
}

function draw() {
  updateMaze();
  displayMaze();
}

function mousePressed() {
  createGrid();
}

function initializeVariables() {
  maze = createGraphics(600, 300);
  Cell.l = 22;

  Cell.h = Cell.l*sqrt(3)/2;
  Cell.r = Cell.h*2/3;
  Cell.theta = TWO_PI/3;

  Cell.cols = floor(1.8*maze.width/Cell.l)-3;
  Cell.rows = floor(maze.height/Cell.h);
}

function createGrid() {
  cells = [];
  stack = [];

  var x = 0, y = 0, up = false;

  for (var j = 0; j < Cell.rows; j += 1) {
    for (var i = j; i <= Cell.cols-j; i += 1) {

      if (i%2 === 0) {
        up = j%2  === 0 ? false : true;
      } else {
        up = j%2  === 1 ? false : true;
      }

      x = Cell.l + i*Cell.l/2;
      y = up ? Cell.r : Cell.h - Cell.r;
      y += j*Cell.h;

      cells.push(new Cell(x, y, up));
    }
  }

  current = cells[0];
}

function updateMaze() {
  maze.background(0, 130, 200);

  current.visited = true;

  // codice per passare al neighbor
  var next = current.chooseNeighbor();
  if (next) {
    stack.push(current);
    Cell.removeWalls(current, next);
    current = next;
  } else if (stack.length > 0) {
    current = stack.pop();
  }

  // codice per visualizzare le celle
  for (var i = 0, l = cells.length; i < l; i += 1) {
    cells[i].display(maze);
  }

  // codice per evidenziare la cella corrente
  if (stack.length > 0) {
    current.highlight(maze);
  }
}

// posizione e dimensione di tutto il disegno
function displayMaze() {
  translate(width/2, (height - maze.width)/2);
  rotate(HALF_PI);

  image(maze, -40, 0);

  scale(1, -1);
  image(maze, 90, 0);
}
<|endoftext|>


<commit_before>import layout from '../layout';
import i18n from '../../i18n';
import { header } from '../shared/common';
import { view as renderPromotion } from '../shared/offlineRound/promotion';
import helper from '../helper';
import { renderBoard } from '../round/view/roundView';
import m from 'mithril';

export default function view(ctrl) {
  return layout.board(
    header.bind(undefined, i18n('training')),
    renderContent.bind(undefined, ctrl),
    () => [renderPromotion(ctrl)]
  );

}

function renderContent(ctrl) {
  if (!ctrl.data) return;

  if (helper.isPortrait())
    return [
      renderExplanation(ctrl),
      renderBoard(ctrl),
      ctrl.data.mode === 'view' ? renderViewTable(ctrl) : renderPlayerTable(ctrl),
      renderActionsBar(ctrl)
    ];
  else
    return [
      renderBoard(ctrl)
    ];
}

function renderExplanation(ctrl) {
  return (

        {i18n(ctrl.data.puzzle.color === 'white' ? 'findTheBestMoveForWhite' : 'findTheBestMoveForBlack')}

  );
}

function renderPlayerTable(ctrl) {
  return (

        {i18n(ctrl.chessground.data.turnColor === ctrl.data.puzzle.color ? 'yourTurn' : 'waiting')}

      {renderCommentary(ctrl)}
      {renderResult(ctrl)}

  );
}

function renderViewTable(ctrl) {
  return (

      {renderResult(ctrl)}

  );
}

function renderActionsBar(ctrl) {
  var vdom = [
    m('button.training_action.fa.fa-ellipsis-h', {
      key: 'puzzleMenu'
    })
  ];
  if (ctrl.data.mode === 'view') {
    Array.prototype.push.apply(vdom, renderViewControls(ctrl));
  } else {
    vdom.push(
      m('button.training_action[data-icon=b]', {
        key: 'giveUpPuzzle',
        config: helper.ontouch(ctrl.giveUp, () => window.plugins.toast.show(i18n('giveUp'), 'short', 'bottom'))
      })
    );
  }
  return m('section#training_actions', vdom);
}

function renderViewControls(ctrl) {
  var history = ctrl.data.replay.history;
  var step = ctrl.data.replay.step;
  return [
    m('button.training_action[data-icon=G]', {
      key: 'continueTraining',
      config: helper.ontouch(ctrl.newPuzzle, () => window.plugins.toast.show(i18n('continueTraining'), 'short', 'bottom'))
    }),
    !(ctrl.data.attempt && ctrl.data.attempt.win || ctrl.data.win) ? m('button.training_action[data-icon=P]', {
      key: 'retryPuzzle',
      config: helper.ontouch(ctrl.retry, () => window.plugins.toast.show(i18n('retryThisPuzzle'), 'short', 'bottom'))
    }) : null,
    ctrl.data.puzzle.gameId ? m('button.training_action[data-icon=v]', {
      config: helper.ontouch(
        () => m.route(`/game/${ctrl.data.puzzle.gameId}/${ctrl.data.puzzle.color}`),
        () => window.plugins.toast.show(i18n('fromGameLink', ctrl.data.puzzle.gameId), 'short', 'bottom')
      )
    }) : null,
    m('button.training_action[data-icon=I]', {
      config: helper.ontouch(ctrl.jumpPrev),
      className: helper.classSet({
        disabled: !(step !== step - 1 && step - 1 >= 0 && step - 1 < history.length)
      })
    }),
    m('button.training_action[data-icon=H]', {
      config: helper.ontouch(ctrl.jumpNext),
      className: helper.classSet({
        disabled: !(step !== step + 1 && step + 1 >= 0 && step + 1 < history.length)
      })
    })
  ];
}

function renderCommentary(ctrl) {
  switch (ctrl.data.comment) {
    case 'retry':
      return m('div.puzzleComment.retry', [
        m('h3.puzzleState', m('strong', i18n('goodMove'))),
        m('span', i18n('butYouCanDoBetter'))
      ]);
    case 'great':
      return m('div.puzzleComment.great', [
        m('h3.puzzleState.withIcon[data-icon=E]', m('strong', i18n('bestMove'))),
        m('span', i18n('keepGoing'))
      ]);
    case 'fail':
      return m('div.puzzleComment.fail', [
        m('h3.puzzleState.withIcon[data-icon=k]', m('strong', i18n('puzzleFailed'))),
        ctrl.data.mode === 'try' ? m('span', i18n('butYouCanKeepTrying')) : null
      ]);
    default:
      return ctrl.data.comment;
  }
}

function renderRatingDiff(diff) {
  return m('strong.rating', diff > 0 ? '+' + diff : diff);
}

function renderWin(ctrl, attempt) {
  return m('div.puzzleComment.win', [
    m('h3.puzzleState.withIcon[data-icon=E]', [
      m('strong', i18n('victory')),
      attempt ? renderRatingDiff(attempt.userRatingDiff) : null
    ]),
    attempt ? m('span', i18n('puzzleSolvedInXSeconds', attempt.seconds)) : null
  ]);
}

function renderLoss(ctrl, attempt) {
  return m('div.puzzleComment.loss',
    m('h3.puzzleState.withIcon[data-icon=k]', [
      m('strong', i18n('puzzleFailed')),
      attempt ? renderRatingDiff(attempt.userRatingDiff) : null
    ])
  );
}

function renderResult(ctrl) {
  switch (ctrl.data.win) {
    case true:
      return renderWin(ctrl, null);
    case false:
      return renderLoss(ctrl, null);
    default:
      switch (ctrl.data.attempt && ctrl.data.attempt.win) {
        case true:
          return renderWin(ctrl, ctrl.data.attempt);
        case false:
          return renderLoss(ctrl, ctrl.data.attempt);
      }
  }
}

function renderFooter(ctrl) {
  if (ctrl.data.mode !== 'view') return null;
  var fen = ctrl.data.replay.history[ctrl.data.replay.step].fen;
  return m('div', [
    renderViewControls(ctrl, fen)
  ]);
}

function renderHistory(ctrl) {
  return m('div.history', {
    // config: function(el, isUpdate, context) {
    //   var hash = ctrl.data.user.history.join('');
    //   if (hash == context.hash) return;
    //   context.hash = hash;
    //   $.ajax({
    //     url: '/training/history',
    //     cache: false,
    //     success: function(html) {
    //       el.innerHTML = html;
    //     }
    //   });
    // }
  });
}
<commit_msg>Render problem details<commit_after>import layout from '../layout';
import i18n from '../../i18n';
import { header } from '../shared/common';
import { view as renderPromotion } from '../shared/offlineRound/promotion';
import helper from '../helper';
import { renderBoard } from '../round/view/roundView';
import m from 'mithril';

export default function view(ctrl) {
  return layout.board(
    header.bind(undefined, i18n('training')),
    renderContent.bind(undefined, ctrl),
    () => [renderPromotion(ctrl)]
  );

}

function renderContent(ctrl) {
  if (!ctrl.data) return;

  if (helper.isPortrait())
    return [
      ctrl.data.mode === 'view' ? renderProblemDetails(ctrl) : renderExplanation(ctrl),
      renderBoard(ctrl),
      ctrl.data.mode === 'view' ? renderViewTable(ctrl) : renderPlayerTable(ctrl),
      renderActionsBar(ctrl)
    ];
  else
    return [
      renderBoard(ctrl)
    ];
}

function renderExplanation(ctrl) {
  return (

        {i18n(ctrl.data.puzzle.color === 'white' ? 'findTheBestMoveForWhite' : 'findTheBestMoveForBlack')}

  );
}

function renderProblemDetails(ctrl) {
  return (

{i18n('puzzleId', ctrl.data.puzzle.id)}

{i18n('ratingX', ctrl.data.puzzle.rating)}

{i18n('playedXTimes', ctrl.data.puzzle.attempts)}

  );
}

function renderPlayerTable(ctrl) {
  return (

        {i18n(ctrl.chessground.data.turnColor === ctrl.data.puzzle.color ? 'yourTurn' : 'waiting')}

      {renderCommentary(ctrl)}
      {renderResult(ctrl)}

  );
}

function renderViewTable(ctrl) {
  return (

      {renderResult(ctrl)}

  );
}

function renderActionsBar(ctrl) {
  var vdom = [
    m('button.training_action.fa.fa-ellipsis-h', {
      key: 'puzzleMenu'
    })
  ];
  if (ctrl.data.mode === 'view') {
    Array.prototype.push.apply(vdom, renderViewControls(ctrl));
  } else {
    vdom.push(
      m('button.training_action[data-icon=b]', {
        key: 'giveUpPuzzle',
        config: helper.ontouch(ctrl.giveUp, () => window.plugins.toast.show(i18n('giveUp'), 'short', 'bottom'))
      })
    );
  }
  return m('section#training_actions', vdom);
}

function renderViewControls(ctrl) {
  var history = ctrl.data.replay.history;
  var step = ctrl.data.replay.step;
  return [
    m('button.training_action[data-icon=G]', {
      key: 'continueTraining',
      config: helper.ontouch(ctrl.newPuzzle, () => window.plugins.toast.show(i18n('continueTraining'), 'short', 'bottom'))
    }),
    !(ctrl.data.attempt && ctrl.data.attempt.win || ctrl.data.win) ? m('button.training_action[data-icon=P]', {
      key: 'retryPuzzle',
      config: helper.ontouch(ctrl.retry, () => window.plugins.toast.show(i18n('retryThisPuzzle'), 'short', 'bottom'))
    }) : null,
    ctrl.data.puzzle.gameId ? m('button.training_action[data-icon=v]', {
      config: helper.ontouch(
        () => m.route(`/game/${ctrl.data.puzzle.gameId}/${ctrl.data.puzzle.color}`),
        () => window.plugins.toast.show(i18n('fromGameLink', ctrl.data.puzzle.gameId), 'short', 'bottom')
      )
    }) : null,
    m('button.training_action[data-icon=I]', {
      config: helper.ontouch(ctrl.jumpPrev),
      className: helper.classSet({
        disabled: !(step !== step - 1 && step - 1 >= 0 && step - 1 < history.length)
      })
    }),
    m('button.training_action[data-icon=H]', {
      config: helper.ontouch(ctrl.jumpNext),
      className: helper.classSet({
        disabled: !(step !== step + 1 && step + 1 >= 0 && step + 1 < history.length)
      })
    })
  ];
}

function renderCommentary(ctrl) {
  switch (ctrl.data.comment) {
    case 'retry':
      return m('div.puzzleComment.retry', [
        m('h3.puzzleState', m('strong', i18n('goodMove'))),
        m('span', i18n('butYouCanDoBetter'))
      ]);
    case 'great':
      return m('div.puzzleComment.great', [
        m('h3.puzzleState.withIcon[data-icon=E]', m('strong', i18n('bestMove'))),
        m('span', i18n('keepGoing'))
      ]);
    case 'fail':
      return m('div.puzzleComment.fail', [
        m('h3.puzzleState.withIcon[data-icon=k]', m('strong', i18n('puzzleFailed'))),
        ctrl.data.mode === 'try' ? m('span', i18n('butYouCanKeepTrying')) : null
      ]);
    default:
      return ctrl.data.comment;
  }
}

function renderRatingDiff(diff) {
  return m('strong.rating', diff > 0 ? '+' + diff : diff);
}

function renderWin(ctrl, attempt) {
  return m('div.puzzleComment.win', [
    m('h3.puzzleState.withIcon[data-icon=E]', [
      m('strong', i18n('victory')),
      attempt ? renderRatingDiff(attempt.userRatingDiff) : null
    ]),
    attempt ? m('span', i18n('puzzleSolvedInXSeconds', attempt.seconds)) : null
  ]);
}

function renderLoss(ctrl, attempt) {
  return m('div.puzzleComment.loss',
    m('h3.puzzleState.withIcon[data-icon=k]', [
      m('strong', i18n('puzzleFailed')),
      attempt ? renderRatingDiff(attempt.userRatingDiff) : null
    ])
  );
}

function renderResult(ctrl) {
  switch (ctrl.data.win) {
    case true:
      return renderWin(ctrl, null);
    case false:
      return renderLoss(ctrl, null);
    default:
      switch (ctrl.data.attempt && ctrl.data.attempt.win) {
        case true:
          return renderWin(ctrl, ctrl.data.attempt);
        case false:
          return renderLoss(ctrl, ctrl.data.attempt);
      }
  }
}

<|endoftext|>


<commit_before>'use strict';

var svgicons2svgfont = require('svgicons2svgfont'),
    fs = require('fs'),
    svg2ttf = require('svg2ttf'),
    ttf2eot = require('ttf2eot'),
    ttf2woff = require('ttf2woff'),
    ttf2woff2 = require('ttf2woff2') ;

var config = {
  fontName: 'KephaFont',
  author: 'Grégoire Oliveira Silva',
  license: 'Licensed under the Creative Common By 4.0',
  pathSvg: 'src/svg',
  pathFont: 'dist/font',
  pathLessSrc: 'src/icons.less',
  pathLess: 'dist/KephaFont.less',
  firstGlyph: 0xE001
} ;

/**
 * On initialise la police
 */

var fontStream = svgicons2svgfont({
  fontName: config.fontName,
  normalize: true,
  metadata: config.author + '. ' + config.license
}) ;
fontStream.pipe(
    fs.createWriteStream(config.pathFont + '/' + config.fontName + '.svg'))
  .on('finish', function () {
    console.log('SVG font successfully created!') ;
    createLess(glyphs) ;
    convertFont() ;
    console.log('Font ' + config.fontName + ' successfully created!') ;
  })
  .on('error', function (err) {
    console.log(err) ;
  }) ;

var unicode = config.firstGlyph ;
var glyphs = Array() ;

/**
 * Créé le fichier Less
 */

var createLess = function (glyphs) {

  fs.readFile(config.pathLessSrc, function (err, data) {

    if (err) throw err ;

    data = data.toString().replace(/{{fontName}}/g, config.fontName) ;

    // liste des caractères
    var listChar = '' ;
    // les classes
    var classes = '' ;

    glyphs.forEach(function (glyph) {

      listChar += '  ' + glyph.name + ': "'
               + glyph.string + '" ; \n' ;
      classes  += '.icon-' + glyph.name + ' { \n'
               +  '  .icon(' + glyph.name + ') ; \n'
               +  '} \n' ;
    }) ;

    data = data.toString().replace(/{{listChar}}/, listChar) ;
    data = data.toString().replace(/{{classes}}/, classes) ;

    fs.writeFile(config.pathLess, data, function (err) {

      if (err) throw err ;
      console.log('Fichier LESS créé') ;
    }) ;
  }) ;
}

/**
 * Créé les différents formats de polices
 */

var convertFont = function () {

  // TTF
  var ttf = svg2ttf(fs.readFileSync(
                config.pathFont + '/' + config.fontName + '.svg')
              .toString(), {}) ;
  fs.writeFileSync(
      config.pathFont + '/' + config.fontName + '.ttf',
      new Buffer(ttf.buffer)
  ) ;
  console.log('TTF font created!') ;

  // EOT
  var eot = new Buffer(ttf2eot(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.eot',
      eot, function (err) {
        if (err) throw err ;
        console.log('EOT font created')
      }) ;

  // WOFF
  var woff = new Buffer(ttf2woff(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.woff',
      woff, function (err) {
        if (err) throw err ;
        console.log('WOFF font created')
      }) ;

  // WOFF2
  var woff2 = new Buffer(ttf2woff2(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.woff2',
      woff2, function (err) {
        if (err) throw err ;
        console.log('WOFF2 font created')
      }) ;
}

/**
 * On charge la liste des icônes
 */

fs.readdir(config.pathSvg, function (err, files) {

  if (err) throw err ;

  files.forEach(function (file) {

    if (file.search(/\.svg$/) > -1) {

      var glyphName = file.match(/^(.+)\.svg$/)[1] ;
      var glyph = fs.createReadStream(config.pathSvg + '/' + file) ;
      glyph.metadata = {
        unicode: [String.fromCharCode(unicode)],
        name: glyphName
      } ;
      fontStream.write(glyph) ;
      glyph.metadata.string = '\\' + unicode.toString(16).toUpperCase() ;
      glyphs.push(glyph.metadata) ;
      unicode++ ;
    }
  }) ;

  fontStream.end() ;
}) ;

<commit_msg>Cosmétique<commit_after>'use strict';

var svgicons2svgfont = require('svgicons2svgfont'),
    fs = require('fs'),
    svg2ttf = require('svg2ttf'),
    ttf2eot = require('ttf2eot'),
    ttf2woff = require('ttf2woff'),
    ttf2woff2 = require('ttf2woff2') ;

/**
 * Configuration de la police
 */
var config = {
  fontName: 'KephaFont',
  author:   'Grégoire Oliveira Silva',
  license:  'Licensed under the Creative Common By 4.0',
  pathSvg:  'src/svg',
  pathFont: 'dist/font',
  pathLessSrc: 'src/icons.less',
  pathLess: 'dist/KephaFont.less',
  firstGlyph: 0xE001
} ;

/**
 * On initialise la police
 */

var fontStream = svgicons2svgfont({
  fontName: config.fontName,
  normalize: true,
  metadata: config.author + '. ' + config.license
}) ;
fontStream.pipe(
    fs.createWriteStream(config.pathFont + '/' + config.fontName + '.svg'))
  .on('finish', function () {
    console.log('SVG font successfully created!') ;
    createLess(glyphs) ;
    convertFont() ;
    console.log('Font ' + config.fontName + ' successfully created!') ;
  })
  .on('error', function (err) {
    console.log(err) ;
  }) ;

var unicode = config.firstGlyph ;
var glyphs = Array() ;

/**
 * Créé le fichier Less
 */

var createLess = function (glyphs) {

  // Charge le template
  fs.readFile(config.pathLessSrc, function (err, data) {

    if (err) throw err ;

    data = data.toString().replace(/{{fontName}}/g, config.fontName) ;

    // liste des caractères
    var listChar = '' ;
    // les classes
    var classes = '' ;

    // On prépare le contenu du Less
    glyphs.forEach(function (glyph) {

      listChar += '  ' + glyph.name + ': "'
               + glyph.string + '" ; \n' ;
      classes  += '.icon-' + glyph.name + ' { \n'
               +  '  .icon(' + glyph.name + ') ; \n'
               +  '} \n' ;
    }) ;

    // On insert la liste des caractères et des classes
    data = data.toString().replace(/{{listChar}}/, listChar) ;
    data = data.toString().replace(/{{classes}}/, classes) ;

    // On sauve le fichier
    fs.writeFile(config.pathLess, data, function (err) {
      if (err) throw err ;
      console.log('Fichier LESS créé') ;
    }) ;
  }) ;
}

/**
 * Créé les différents formats de polices
 */

var convertFont = function () {

  // TTF
  var ttf = svg2ttf(fs.readFileSync(
                config.pathFont + '/' + config.fontName + '.svg')
              .toString(), {}) ;
  fs.writeFileSync(
      config.pathFont + '/' + config.fontName + '.ttf',
      new Buffer(ttf.buffer)
  ) ;
  console.log('TTF font created!') ;

  // EOT
  var eot = new Buffer(ttf2eot(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.eot',
      eot, function (err) {
        if (err) throw err ;
        console.log('EOT font created')
      }) ;

  // WOFF
  var woff = new Buffer(ttf2woff(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.woff',
      woff, function (err) {
        if (err) throw err ;
        console.log('WOFF font created')
      }) ;

  // WOFF2
  var woff2 = new Buffer(ttf2woff2(ttf.buffer).buffer) ;
  fs.writeFile(
      config.pathFont + '/' + config.fontName + '.woff2',
      woff2, function (err) {
        if (err) throw err ;
        console.log('WOFF2 font created')
      }) ;
}

/**
 * On charge la liste des icônes
 */

fs.readdir(config.pathSvg, function (err, files) {

  if (err) throw err ;

  files.forEach(function (file) {

    if (file.search(/\.svg$/) > -1) {

      var glyphName = file.match(/^(.+)\.svg$/)[1] ;
      var glyph = fs.createReadStream(config.pathSvg + '/' + file) ;
      glyph.metadata = {
        unicode: [String.fromCharCode(unicode)],
        name: glyphName
      } ;
      fontStream.write(glyph) ;
      glyph.metadata.string = '\\' + unicode.toString(16).toUpperCase() ;
      glyphs.push(glyph.metadata) ;
      unicode++ ;
    }
  }) ;

  fontStream.end() ;
}) ;

<|endoftext|>


<commit_before>/*---------------------------------------------------------------------------*\
 |  Player.js                                                                |
 |                                                                           |
 |  Copyright © 2017-2020, Rajiv Bakulesh Shah, original author.             |
 |                                                                           |
 |      This program is free software: you can redistribute it and/or modify |
 |      it under the terms of the GNU General Public License as published by |
 |      the Free Software Foundation, either version 3 of the License, or    |
 |      (at your option) any later version.                                  |
 |                                                                           |
 |      This program is distributed in the hope that it will be useful, but  |
 |      WITHOUT ANY WARRANTY; without even the implied warranty of           |
 |      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
 |      General Public License for more details.                             |
 |                                                                           |
 |      You should have received a copy of the GNU General Public License    |
 |      along with this program.  If not, see:                               |
 |          <http://www.gnu.org/licenses/>                                   |
\*---------------------------------------------------------------------------*/

import React from 'react';
import { connect } from 'react-redux';
import '../monkey';
import { previousVideo, nextVideo, fetchQueue } from '../actions/player';
import { clearSearch } from '../actions/search';
import './Player.css';

class Player extends React.PureComponent {
  constructor(props) {
    super(props);
    this.NEXT_KEYS = [39];
    this.PREV_KEYS = [37];
  }

  componentDidMount() {
    document.addEventListener('keyup', this.onKeyUp);
    document.addEventListener('visibilitychange', this.onVisibilityChange);
  }

  componentWillUnmount() {
    document.removeEventListener('keyup', this.onKeyUp);
    document.removeEventListener('visibilitychange', this.onVisibilityChange);
  }

  onKeyUp = (eventObject) => {
    if (document.activeElement === document.body) {
      if (this.NEXT_KEYS.includes(eventObject.which)) {
        this.props.nextVideo();
      } else if (this.PREV_KEYS.includes(eventObject.which)) {
        this.props.previousVideo();
      }
    }
  }

  onVisibilityChange = () => {
    const video = document.getElementsByTagName('video')[0];
    if (video) {
      video[document.hidden ? 'pause' : 'play']();
    }
  }

  render() {
    return <ConnectedBuffer {...this.props} />;
  }
}

let mapStateToProps = (state) => ({});

let mapDispatchToProps = (dispatch) => ({
  previousVideo: () => dispatch(previousVideo()),
  nextVideo: () => dispatch(nextVideo()),
});

const ConnectedPlayer = connect(mapStateToProps, mapDispatchToProps)(Player);

class Buffer extends React.Component {
  componentDidMount() {
    this.props.fetchQueue(this.props.artistId, this.props.songId);
  }

  componentDidUpdate(prevProps) {
    if (
      this.props.artistId !== prevProps.artistId
      || this.props.songId !== prevProps.songId
    ) {
      if (this.props.history.action !== 'REPLACE') {
        this.props.fetchQueue(this.props.artistId, this.props.songId);
      }
    }
  }

  render() {
    const videos = [];
    let states;

    if (
      this.props.player.index === null
      || this.props.player.index > this.props.player.queue.length - 1
    ) {
      states = [];
    } else if (
      this.props.player.index === this.props.player.queue.length - 1
      || this.props.state === 'background'
    ) {
      states = [this.props.state];
    } else {
      states = ['playing', 'buffering'];
    }

    states.forEach((state, index) => {
      const video = this.props.player.queue[this.props.player.index + index];
      videos.push(
        <ConnectedVideo
          key={state}
          video={video}
          state={state}
          history={this.props.history}
        />
      );
    });

    return
{videos}
;
  }
}

mapStateToProps = (state) => ({
  player: state.player,
});

mapDispatchToProps = (dispatch) => ({
  fetchQueue: (artistId, songId) => dispatch(fetchQueue(artistId, songId)),
});

const ConnectedBuffer = connect(mapStateToProps, mapDispatchToProps)(Buffer);

class Video extends React.PureComponent {
  componentDidMount() {
    this.updateUrlAndTitle();
  }

  componentDidUpdate() {
    this.updateUrlAndTitle();
  }

  onMouseDown = (eventObject) => {
    if (this.props.state === 'playing') {
      if (eventObject.target.paused) {
        eventObject.target.play().catch(() => this.props.nextVideo());
      } else if (document.activeElement === document.body) {
        this.props.nextVideo();
      } else {
        this.props.clearSearch();
      }
    }
  }

  updateUrlAndTitle() {
    if (this.props.state === 'playing') {
      const { artist__id, song__id, artist, song } = this.props.video;
      this.props.history.replace(`/${artist__id}/${song__id}`);
      document.title = `Spool - ${artist} - ${song}`;
    }
  }

  render() {
    const className = this.props.state.capitalize();
    return (
      <>
        <video
          className={className}
          src={this.props.video.mp4_url}
          preload="auto"
          loop
          autoPlay={this.props.state === 'buffering' ? null : 'autoplay'}
          muted={this.props.state !== 'playing'}
          playsInline
          onMouseDown={this.onMouseDown}
        />
        <Credits video={this.props.video} state={this.props.state} />
      </>
    );
  }
}

mapStateToProps = (state) => ({});

mapDispatchToProps = (dispatch) => ({
  nextVideo: () => dispatch(nextVideo()),
  clearSearch: () => dispatch(clearSearch()),
});

const ConnectedVideo = connect(mapStateToProps, mapDispatchToProps)(Video);

function Credits(props) {
  if (props.state !== 'playing') {
    return null;
  }

  const cleanArtist = props.video.artist.cleanName();
  const cleanSong = props.video.song.cleanName();
  const cleanAlbum = 'album' in props.video ? props.video.album.cleanName() : null;

  if (cleanAlbum) {
    return (

    );
  } else {
    return (

    );
  }
}

export default ConnectedPlayer;
<commit_msg>Use inline conditional in JSX<commit_after>/*---------------------------------------------------------------------------*\
 |  Player.js                                                                |
 |                                                                           |
 |  Copyright © 2017-2020, Rajiv Bakulesh Shah, original author.             |
 |                                                                           |
 |      This program is free software: you can redistribute it and/or modify |
 |      it under the terms of the GNU General Public License as published by |
 |      the Free Software Foundation, either version 3 of the License, or    |
 |      (at your option) any later version.                                  |
 |                                                                           |
 |      This program is distributed in the hope that it will be useful, but  |
 |      WITHOUT ANY WARRANTY; without even the implied warranty of           |
 |      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU    |
 |      General Public License for more details.                             |
 |                                                                           |
 |      You should have received a copy of the GNU General Public License    |
 |      along with this program.  If not, see:                               |
 |          <http://www.gnu.org/licenses/>                                   |
\*---------------------------------------------------------------------------*/

import React from 'react';
import { connect } from 'react-redux';
import '../monkey';
import { previousVideo, nextVideo, fetchQueue } from '../actions/player';
import { clearSearch } from '../actions/search';
import './Player.css';

class Player extends React.PureComponent {
  constructor(props) {
    super(props);
    this.NEXT_KEYS = [39];
    this.PREV_KEYS = [37];
  }

  componentDidMount() {
    document.addEventListener('keyup', this.onKeyUp);
    document.addEventListener('visibilitychange', this.onVisibilityChange);
  }

  componentWillUnmount() {
    document.removeEventListener('keyup', this.onKeyUp);
    document.removeEventListener('visibilitychange', this.onVisibilityChange);
  }

  onKeyUp = (eventObject) => {
    if (document.activeElement === document.body) {
      if (this.NEXT_KEYS.includes(eventObject.which)) {
        this.props.nextVideo();
      } else if (this.PREV_KEYS.includes(eventObject.which)) {
        this.props.previousVideo();
      }
    }
  }

  onVisibilityChange = () => {
    const video = document.getElementsByTagName('video')[0];
    if (video) {
      video[document.hidden ? 'pause' : 'play']();
    }
  }

  render() {
    return <ConnectedBuffer {...this.props} />;
  }
}

let mapStateToProps = (state) => ({});

let mapDispatchToProps = (dispatch) => ({
  previousVideo: () => dispatch(previousVideo()),
  nextVideo: () => dispatch(nextVideo()),
});

const ConnectedPlayer = connect(mapStateToProps, mapDispatchToProps)(Player);

class Buffer extends React.Component {
  componentDidMount() {
    this.props.fetchQueue(this.props.artistId, this.props.songId);
  }

  componentDidUpdate(prevProps) {
    if (
      this.props.artistId !== prevProps.artistId
      || this.props.songId !== prevProps.songId
    ) {
      if (this.props.history.action !== 'REPLACE') {
        this.props.fetchQueue(this.props.artistId, this.props.songId);
      }
    }
  }

  render() {
    const videos = [];
    let states;

    if (
      this.props.player.index === null
      || this.props.player.index > this.props.player.queue.length - 1
    ) {
      states = [];
    } else if (
      this.props.player.index === this.props.player.queue.length - 1
      || this.props.state === 'background'
    ) {
      states = [this.props.state];
    } else {
      states = ['playing', 'buffering'];
    }

    states.forEach((state, index) => {
      const video = this.props.player.queue[this.props.player.index + index];
      videos.push(
        <ConnectedVideo
          key={state}
          video={video}
          state={state}
          history={this.props.history}
        />
      );
    });

    return
{videos}
;
  }
}

mapStateToProps = (state) => ({
  player: state.player,
});

mapDispatchToProps = (dispatch) => ({
  fetchQueue: (artistId, songId) => dispatch(fetchQueue(artistId, songId)),
});

const ConnectedBuffer = connect(mapStateToProps, mapDispatchToProps)(Buffer);

class Video extends React.PureComponent {
  componentDidMount() {
    this.updateUrlAndTitle();
  }

  componentDidUpdate() {
    this.updateUrlAndTitle();
  }

  onMouseDown = (eventObject) => {
    if (this.props.state === 'playing') {
      if (eventObject.target.paused) {
        eventObject.target.play().catch(() => this.props.nextVideo());
      } else if (document.activeElement === document.body) {
        this.props.nextVideo();
      } else {
        this.props.clearSearch();
      }
    }
  }

  updateUrlAndTitle() {
    if (this.props.state === 'playing') {
      const { artist__id, song__id, artist, song } = this.props.video;
      this.props.history.replace(`/${artist__id}/${song__id}`);
      document.title = `Spool - ${artist} - ${song}`;
    }
  }

  render() {
    const className = this.props.state.capitalize();
    return (
      <>
        <video
          className={className}
          src={this.props.video.mp4_url}
          preload="auto"
          loop
          autoPlay={this.props.state === 'buffering' ? null : 'autoplay'}
          muted={this.props.state !== 'playing'}
          playsInline
          onMouseDown={this.onMouseDown}
        />
        <Credits video={this.props.video} state={this.props.state} />
      </>
    );
  }
}

mapStateToProps = (state) => ({});

mapDispatchToProps = (dispatch) => ({
  nextVideo: () => dispatch(nextVideo()),
  clearSearch: () => dispatch(clearSearch()),
});

const ConnectedVideo = connect(mapStateToProps, mapDispatchToProps)(Video);

function Credits(props) {
  if (props.state !== 'playing') {
    return null;
  }

  const cleanArtist = props.video.artist.cleanName();
  const cleanSong = props.video.song.cleanName();
  const cleanAlbum = 'album' in props.video ? props.video.album.cleanName() : null;

  return (

      {cleanAlbum &&
        <>

        </>
      }

  );
}

export default ConnectedPlayer;
<|endoftext|>


<commit_before>jQuery(document).ready(function() {

$.getScript("https://openaccessbutton.org/static/oabutton.js", function() {

    var guid = (function() {
      function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
                   .toString(16)
                   .substring(1);
      }
      return function() {
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
               s4() + '-' + s4() + s4() + s4();
      };
    })();

    // TODO: this bookmarklet should be updated with the code from the old project that
    // pulls title author etc from the page the bookmarklet is opened on
    // then those useful bits of info should be shown in text input fields
    // in a hidden panel of the bookmarklet panel below
    // if no info can be scraped, some may be returned from the oab.status call
    // but if none at all can be found, the hidden panel should open and the user
    // should be asked to fill in the fields

    $('body').append('
' +
        '
Open Access Button
' +
        '
' +
        '<textarea class="form-control" id="oabookmarkletstory" placeholder="' +
        'Tell your story - why were you blocked? What were you trying to do at the time?" style="height:200px;width:265px;"></textarea>' +
        '<input type="checkbox" id="oabookmarkletwishlist"> add this to your wishlist' +
        'share your open access story' +
        '
' +
        '

' +
        '

close
' +
    '

');

    // TODO: the bookmarklet needs to know which user API KEY should actually be used
    // the last bookmarklet appeared to write this directly into the code of the bookmarklet
    // code that the user downloaded, so perhaps we just do the same too, so when the user
    // saves the bookmarklet from the site their API KEY is written into a var that gets passed in here
    // I (MM) will look into this further
    oab = new oabutton({
        api: 'https://openaccessbutton.org/api',
        api_key: oabuid
    });

    /*oab.status({
        data: {url: window.location.href},
        success: function(data) {
            // TODO: if the status query returns useful info this should be displayed
            // neatly on the oabutton bookmarklet panel
            $('#oabookmarkletstatus').html('

' + JSON.stringify(data,"","    ") + '

');
        }
    });*/

    var oabookmarkletblock = function(event) {
        event.preventDefault();
        // TODO: if the tp type is blocked rather than wishlist the data object
        // below that is posted to the backend should be populated with extra data
        // so where the process above that builds the bookmarklet panel scrapes author
        // title etc from the page, or asks the user to provide it, the values in those
        // fields at the time the block button is pressed triggering this call
        var rid = guid();
        oab['blocked']({
            data: {
                url: window.location.href,
                story: $('#oabookmarkletstory').val(),
                id: rid
            }
        });
        $('#oabookmarkletlinks').remove();
        $('#oabookmarklet').append('

Your story has been registered. View it to find more useful information.
 \
        View your story

');
        if ( $('#oabookmarkletwishlist').is(':checked') ) {
            oab['wishlist']({
                data: {
                    url: window.location.href
                }
            });
            $('#oabookmarkletlinks').append("
This item has been added to your wishlist. We'll let you know as soon as a copy is available
" +
            'View your wishlist");
        }
    }
    $('#oabookmarkletblock').bind('click',oabookmarkletblock);

});

});<commit_msg>bookmarklet<commit_after>jQuery(document).ready(function() {

$.getScript("https://openaccessbutton.org/static/oabutton.js", function() {

    var guid = (function() {
      function s4() {
        return Math.floor((1 + Math.random()) * 0x10000)
                   .toString(16)
                   .substring(1);
      }
      return function() {
        return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
               s4() + '-' + s4() + s4() + s4();
      };
    })();

    // TODO: this bookmarklet should be updated with the code from the old project that
    // pulls title author etc from the page the bookmarklet is opened on
    // then those useful bits of info should be shown in text input fields
    // in a hidden panel of the bookmarklet panel below
    // if no info can be scraped, some may be returned from the oab.status call
    // but if none at all can be found, the hidden panel should open and the user
    // should be asked to fill in the fields

    $('body').append('
' +
        '
Open Access Button
' +
        '
' +
        '<textarea class="form-control" id="oabookmarkletstory" placeholder="' +
        'Tell your story - why were you blocked? What were you trying to do at the time?" style="height:200px;width:265px;"></textarea>' +
        '<input type="checkbox" id="oabookmarkletwishlist"> add this to your wishlist' +
        'share your open access story' +
        '
' +
        '

' +
        '

close
' +
    '

');

    // TODO: the bookmarklet needs to know which user API KEY should actually be used
    // the last bookmarklet appeared to write this directly into the code of the bookmarklet
    // code that the user downloaded, so perhaps we just do the same too, so when the user
    // saves the bookmarklet from the site their API KEY is written into a var that gets passed in here
    // I (MM) will look into this further
    oab = new oabutton({
        api: 'https://openaccessbutton.org/api',
        api_key: oabuid
    });

    /*oab.status({
        data: {url: window.location.href},
        success: function(data) {
            // TODO: if the status query returns useful info this should be displayed
            // neatly on the oabutton bookmarklet panel
            $('#oabookmarkletstatus').html('

' + JSON.stringify(data,"","    ") + '

');
        }
    });*/

    var oabookmarkletblock = function(event) {
        event.preventDefault();
        // TODO: if the tp type is blocked rather than wishlist the data object
        // below that is posted to the backend should be populated with extra data
        // so where the process above that builds the bookmarklet panel scrapes author
        // title etc from the page, or asks the user to provide it, the values in those
        // fields at the time the block button is pressed triggering this call
        var rid = guid();
        oab['blocked']({
            data: {
                url: window.location.href,
                story: $('#oabookmarkletstory').val(),
                id: rid
            }
        });
        $('#oabookmarkletlinks').remove();
        $('#oabookmarklet').append('

Your story has been registered. View it to find more useful information.
 \
        View your story

');
        if ( $('#oabookmarkletwishlist').is(':checked') ) {
            oab['wishlist']({
                data: {
                    url: window.location.href
                }
            });
            $('#oabookmarkletlinks').append("
This item has been added to your wishlist. We'll let you know as soon as a copy is available.");
            $('#oabookmarkletlinks').append('View your wishlist
');
        }
    }
    $('#oabookmarkletblock').bind('click',oabookmarkletblock);

});

});<|endoftext|>