<commit_before>EstablishmentShot.Charts = (function () {
    'use strict';

    var count = 0,
        colors = [
            '#26b01f', // green
            '#ffcf28', // yellow
            '#009cff', // blue
            '#ff2600' // red
        ],
        smallColors = [
            [
                '#DDDDDE',
                '#9E6C00',
                '#EBA000',
                '#9E1D00',
                '#EB2B00'
            ],
            [
                '#DDDDDE',
                '#CCE4FF',
                '#80D4FF',
                '#3C9AC9',
                '#B01200',
                '#E6C337',
                '#ffcf28'
            ],
            [
                '#DDDDDE',
                '#38DC2D',
                '#26b01f'
            ],
            [
                '#DDDDDE',
                '#6E3E00',
                '#B05E00',
                '#FCB100',
                '#006FB0',
                '#00A0FC'
            ]
        ],
        smallChartDefaults = function () {
            return {
                type: EstablishmentShot.BarChart,
                width: 150,
                height: 198,
                color_gradient: smallColors[count++],
                showY: true,
                showMaxLabel: false,
                margin: {
                    top: 10,
                    right: 0,
                    bottom: 20,
                    left: 50
                },
                mouseover: function (d) {
                    $(this).find(".legend ul li")
                        .stop().animate({ 'opacity': 0.2 }, 500);

                    $(this).find(".legend ul li." + d.key)
                        .stop().animate({'opacity': 1.0 }, 500);
                },
                mouseout: function (d) {
                    $(this).find(".legend ul li")
                        .stop().animate({'opacity': 1.0 }, 500);
                }
            }
        };

    return {
        charts: {
            bar_chart: {
                width: 250,
                height: 380,
                margin: {
                    top: 20,
                    right: 0,
                    bottom: 25,
                    left: 10
                },
                showY: false,
                showMaxLabel: true,
                color_gradient: colors,
                type: EstablishmentShot.BarChart,
                series: [
                    { key: 'co2_sheet_agriculture_total_co2_emissions',
                      fa_icon: '\uf06c' },
                    { key: 'co2_sheet_industry_energy_total_co2_emissions',
                      fa_icon: '\uf275' },
                    { key: 'co2_sheet_transport_total_co2_emissions',
                      fa_icon: '\uf1b9' },
                    { key: 'co2_sheet_buildings_households_total_co2_emissions',
                      fa_icon: '\uf015' }
                ],
                mouseover: function (d) {
                    $(".column .column-inner .chart")
                        .stop().animate({ 'opacity': 0.2 }, 500);

                    $(".column .column-inner .chart[data-chart='" + d.key + "']")
                        .stop().animate({'opacity': 1.0 }, 500);
                },
                mouseout: function (d) {
                    $(".column .column-inner .chart")
                        .stop().animate({'opacity': 1.0 }, 500);
                }
            },
            co2_sheet_buildings_households_total_co2_emissions: $.extend({
                left: true,
                top: false,
                fa_icon: 'f015',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_built_environment' },
                    { key: 'co2_sheet_buildings_households_space_heating_cooling_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_hot_water_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_cooking_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_appliances_light_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_industry_energy_total_co2_emissions: $.extend({
                left: false,
                top: false,
                fa_icon: 'f275',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_industry_energy' },
                    { key: 'co2_sheet_industry_metal_co2_emissions' },
                    { key: 'co2_sheet_industry_chemical_co2_emissions' },
                    { key: 'co2_sheet_industry_food_co2_emissions' },
                    { key: 'co2_sheet_industry_paper_co2_emissions' },
                    { key: 'co2_sheet_energy_sector_total_co2_emissions' },
                    { key: 'co2_sheet_industry_other_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_agriculture_total_co2_emissions: $.extend({
                left: false,
                top: true,
                fa_icon: 'f06c',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_agriculture' },
                    { key: 'co2_sheet_agriculture_heat_co2_emissions' },
                    { key: 'co2_sheet_agriculture_power_and_light_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_transport_total_co2_emissions: $.extend({
                left: true,
                top: true,
                fa_icon: 'f1b9',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_transport' },
                    { key: 'co2_sheet_transport_total_domestic_aviation_co2_emissions' },
                    { key: 'co2_sheet_transport_total_domestic_freight_co2_emissions' },
                    { key: 'co2_sheet_transport_total_private_transport_co2_emissions' },
                    { key: 'co2_sheet_transport_total_public_transport_co2_emissions' }
                ]
            }, smallChartDefaults())
        },
        getQueries: function () {
            var chart,
                queries = [];

            for (chart in this.charts) {
                this.charts[chart].series.forEach(function (serie) {
                    queries.push(serie.key);
                });
            }

            return queries;
        }
    }
}());
<commit_msg>Increase top margin of establishment shot chart<commit_after>EstablishmentShot.Charts = (function () {
    'use strict';

    var count = 0,
        colors = [
            '#26b01f', // green
            '#ffcf28', // yellow
            '#009cff', // blue
            '#ff2600' // red
        ],
        smallColors = [
            [
                '#DDDDDE',
                '#9E6C00',
                '#EBA000',
                '#9E1D00',
                '#EB2B00'
            ],
            [
                '#DDDDDE',
                '#CCE4FF',
                '#80D4FF',
                '#3C9AC9',
                '#B01200',
                '#E6C337',
                '#ffcf28'
            ],
            [
                '#DDDDDE',
                '#38DC2D',
                '#26b01f'
            ],
            [
                '#DDDDDE',
                '#6E3E00',
                '#B05E00',
                '#FCB100',
                '#006FB0',
                '#00A0FC'
            ]
        ],
        smallChartDefaults = function () {
            return {
                type: EstablishmentShot.BarChart,
                width: 150,
                height: 198,
                color_gradient: smallColors[count++],
                showY: true,
                showMaxLabel: false,
                margin: {
                    top: 10,
                    right: 0,
                    bottom: 20,
                    left: 50
                },
                mouseover: function (d) {
                    $(this).find(".legend ul li")
                        .stop().animate({ 'opacity': 0.2 }, 500);

                    $(this).find(".legend ul li." + d.key)
                        .stop().animate({'opacity': 1.0 }, 500);
                },
                mouseout: function (d) {
                    $(this).find(".legend ul li")
                        .stop().animate({'opacity': 1.0 }, 500);
                }
            }
        };

    return {
        charts: {
            bar_chart: {
                width: 250,
                height: 380,
                margin: {
                    top: 25,
                    right: 0,
                    bottom: 25,
                    left: 10
                },
                showY: false,
                showMaxLabel: true,
                color_gradient: colors,
                type: EstablishmentShot.BarChart,
                series: [
                    { key: 'co2_sheet_agriculture_total_co2_emissions',
                      fa_icon: '\uf06c' },
                    { key: 'co2_sheet_industry_energy_total_co2_emissions',
                      fa_icon: '\uf275' },
                    { key: 'co2_sheet_transport_total_co2_emissions',
                      fa_icon: '\uf1b9' },
                    { key: 'co2_sheet_buildings_households_total_co2_emissions',
                      fa_icon: '\uf015' }
                ],
                mouseover: function (d) {
                    $(".column .column-inner .chart")
                        .stop().animate({ 'opacity': 0.2 }, 500);

                    $(".column .column-inner .chart[data-chart='" + d.key + "']")
                        .stop().animate({'opacity': 1.0 }, 500);
                },
                mouseout: function (d) {
                    $(".column .column-inner .chart")
                        .stop().animate({'opacity': 1.0 }, 500);
                }
            },
            co2_sheet_buildings_households_total_co2_emissions: $.extend({
                left: true,
                top: false,
                fa_icon: 'f015',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_built_environment' },
                    { key: 'co2_sheet_buildings_households_space_heating_cooling_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_hot_water_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_cooking_co2_emissions' },
                    { key: 'co2_sheet_buildings_households_appliances_light_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_industry_energy_total_co2_emissions: $.extend({
                left: false,
                top: false,
                fa_icon: 'f275',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_industry_energy' },
                    { key: 'co2_sheet_industry_metal_co2_emissions' },
                    { key: 'co2_sheet_industry_chemical_co2_emissions' },
                    { key: 'co2_sheet_industry_food_co2_emissions' },
                    { key: 'co2_sheet_industry_paper_co2_emissions' },
                    { key: 'co2_sheet_energy_sector_total_co2_emissions' },
                    { key: 'co2_sheet_industry_other_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_agriculture_total_co2_emissions: $.extend({
                left: false,
                top: true,
                fa_icon: 'f06c',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_agriculture' },
                    { key: 'co2_sheet_agriculture_heat_co2_emissions' },
                    { key: 'co2_sheet_agriculture_power_and_light_co2_emissions' }
                ]
            }, smallChartDefaults()),
            co2_sheet_transport_total_co2_emissions: $.extend({
                left: true,
                top: true,
                fa_icon: 'f1b9',
                series: [
                    { key: 'co2_sheet_non_energy_emissions_transport' },
                    { key: 'co2_sheet_transport_total_domestic_aviation_co2_emissions' },
                    { key: 'co2_sheet_transport_total_domestic_freight_co2_emissions' },
                    { key: 'co2_sheet_transport_total_private_transport_co2_emissions' },
                    { key: 'co2_sheet_transport_total_public_transport_co2_emissions' }
                ]
            }, smallChartDefaults())
        },
        getQueries: function () {
            var chart,
                queries = [];

            for (chart in this.charts) {
                this.charts[chart].series.forEach(function (serie) {
                    queries.push(serie.key);
                });
            }

            return queries;
        }
    }
}());
<|endoftext|>


<commit_before>"use strict";
/* eslint new-cap: 0 */

require('should');
var path = require('path');
var fs = require('fs');

var Gherkin = require('gherkin');
var Parser = new Gherkin.Parser();

function unwrapSingleColumnTable(singleColumnTable) {
  return (singleColumnTable.raw()).map(function (valueWrappedInArray) {return valueWrappedInArray[0]});
}

function firstRowFirstCell(table) {
  return table.raw()[0][0];
}

// Important because need to check that steps
// have been assigned to the correct scenario.
var scenarioNumberToIndex = {
  "default": 0,
  "first": 0,
  "second": 1,
  "third": 2,
  "fourth": 3
};

module.exports = function() {
  // Shared variables
  var featureText;
  var features;

  function compareFeatureValues(key) {
    return function compare(table) {
      var featureValues = features[key].map(function(a) {
        if(key === "comments") {
          return a.text;
        }

        return a.name;
      });
      var expectedValues = unwrapSingleColumnTable(table);
      featureValues.should.containDeepOrdered(expectedValues);
    }
  }

  // TODO: FAR TOO COMPLICATED! Maybe remove the conditionals
  // TODO: by having two different functions. See Example tags scenario for a possible alternative.
  // key1 is a key on the scenario
  // key2 is an optional key on a sub-object.
  function compareScenarioValues(key1, key2) {
    return function compare(scenarioNumber, table) {
      var done = undefined;

      /**
       * Sometimes just a table is passed in the first argument slot,
       * in that case adjust the parameters.
       *
       * CucumberJS determines if the step definition completion
       * should be dependent on a callback by counting the number
       * of arguments, so we have to cope with that.
       **/
      if (typeof scenarioNumber === "object") {
        done = table;
        table = scenarioNumber;
        scenarioNumber = "default";
      }

      var scenarioIndex = scenarioNumberToIndex[scenarioNumber];
      var scenario = features.scenarioDefinitions[scenarioIndex];
      var scenarioValues;

      // If the suboject key is specified dig the values out of the objects.
      // e.g. get the names of steps out of an array of steps.
      // c.f. https://lodash.com/docs#pluck .
      if (key2) {
        scenarioValues = scenario[key1].map(function(subObject) { return subObject[key2]; });
      } else {
        scenarioValues = scenario[key1];
      }

      var expectedValues = unwrapSingleColumnTable(table);

      // Do the test.
      scenarioValues.should.containDeepOrdered(expectedValues);

      if (typeof done === "function") {
        done();
      }
    }
  }

  // Get scenarios etc and properties of such.
  function getScenarios(feature, tokenType) {
    tokenType = tokenType || 'Scenario';
    return feature.scenarioDefinitions
      .filter(function(scenario) {return scenario.type === tokenType;});
  }
  function getScenarioOutlines(feature) {
    return getScenarios(feature, 'ScenarioOutline');
  }
  function getScenarioNames(feature, tokenType) {
      return getScenarios(feature, tokenType)
        .map(function(scenario) {return scenario.name});
  }

  this.Given(/^an example feature file\.?$/, function () {
    var exampleFeatureFilePath = path.join(__dirname, '..', 'test-data', 'example-feature-file.feature');
    featureText = fs.readFileSync(exampleFeatureFilePath, {encoding: 'utf8'});
  });

  this.When(/^I parse this specification\.?$/, function () {
    features = Parser.parse(featureText);
  });

  this.Then(/^I get a feature with title "([^"]*)"\.?$/, function (featureTitle) {
    features.name.should.be.exactly(featureTitle);
  });

  this.Then(/^I get a background with the title "([^"]*)"\.?$/, function (backgroundTitle) {
    var backgroundNames = features.background.name;
    backgroundNames.should.containEql(backgroundTitle);
  });

  this.Then(/^I get scenarios with titles\.?$/, function (table) {
    var expectedScenarioNames = unwrapSingleColumnTable(table);
    var scenarioNames = getScenarioNames(features, 'Scenario');
    scenarioNames.should.containDeep(expectedScenarioNames);
  });

  this.Then(/^I get a scenario outline with the title "([^"]*)"\.?$/, function (scenarioOutlineTitle) {
    var scenarioOutlineNames = getScenarioNames(features, 'ScenarioOutline');
    scenarioOutlineNames.should.containEql(scenarioOutlineTitle);
  });

  this.Then(/^I get a set of examples with the title "([^"]*)"\.?$/, function (expectedExampleTitle) {
    var scenarioOutlines = getScenarioOutlines(features);
    var exampleTitle = scenarioOutlines[0].examples[0].name;
    exampleTitle.should.be.exactly(expectedExampleTitle);
  });

  this.Then(/^feature tags are associated with features\.?$/, compareFeatureValues('tags'));

  this.Then(/^scenario tags are associated with scenarios\.?$/, compareScenarioValues('tags', 'name'));

  this.Then(/^feature comments are associated with features\.?$/, compareFeatureValues('comments'));

  this.Then(/^the "([^"]*)" scenario has steps with the names\.?$/, compareScenarioValues('steps', 'text'));

  this.Then(/^example tags are associated with examples$/, function (table) {
    var expectedTagValues = unwrapSingleColumnTable(table);
    var scenarioOutlines = getScenarioOutlines(features);

    var exampleTagData = scenarioOutlines[0].examples[0].tags.map(function(a) {
      return a.name;
    });

    exampleTagData.should.containDeep(expectedTagValues);
  });

  this.Then(/^scenario outlines have example data\.?$/, function (table) {
    var expectedExampleDataValues = unwrapSingleColumnTable(table);
    var scenarioOutlines = getScenarioOutlines(features);

    var exampleDataValues = scenarioOutlines[0].examples[0].tableBody
      .map(function(row) { return row.cells.map(function(a) {
        return a.value
      }); })
      .reduce(function(a, b) { return a.concat(b); });
    exampleDataValues.should.containDeep(expectedExampleDataValues);
  });

  this.Then(/^steps with tables have that table data\.?$/, function (table) {
      var expectedTableDataValues = unwrapSingleColumnTable(table);
      var scenarios = getScenarios(features);

      // Dig the relevant values out of the data structure.
      // TODO: too complicated, abstract or find another solution.
      var scenarioTableData = scenarios
        .map(function(scenario) {
          return scenario.steps
            .filter(function(step) {
              return step.argument && step.argument.type === 'DataTable';
            })
            .map(function(step) {
              return step.argument.rows.map(function(row) {
                return row.cells.map(function(cell) {
                  return cell.value;
                });
              })
              .reduce(function(a, b) { return a.concat(b) }, []);
            }).reduce(function(a, b) { return a.concat(b) }, []);
        }).reduce(function(a, b) { return a.concat(b) }, []);

      scenarioTableData.should.containDeep(expectedTableDataValues);
  });

  this.Then(/^steps with doc strings have that doc string content\.?$/, function (table) {
    var expectedDocStringValues = firstRowFirstCell(table);
    var scenarios = getScenarios(features);

    // Dig the relevant values out of the data structure.
    // TODO: too complicated, abstract or find another solution.
    var scenarioDocStringData = scenarios
      .map(function(scenario) {
        return scenario.steps
          .filter(function(step) {
            return step.argument && step.argument.type === 'DocString';
          })
          .map(function(step) {
            return step.argument.content;
          })
      }).reduce(function(a, b) {
            return a.concat(b);
      })[0];

    scenarioDocStringData.should.match(expectedDocStringValues);
  });
};
<commit_msg>Missing semicolon.<commit_after>"use strict";
/* eslint new-cap: 0 */

require('should');
var path = require('path');
var fs = require('fs');

var Gherkin = require('gherkin');
var Parser = new Gherkin.Parser();

function unwrapSingleColumnTable(singleColumnTable) {
  return (singleColumnTable.raw()).map(function (valueWrappedInArray) {return valueWrappedInArray[0];});
}

function firstRowFirstCell(table) {
  return table.raw()[0][0];
}

// Important because need to check that steps
// have been assigned to the correct scenario.
var scenarioNumberToIndex = {
  "default": 0,
  "first": 0,
  "second": 1,
  "third": 2,
  "fourth": 3
};

module.exports = function() {
  // Shared variables
  var featureText;
  var features;

  function compareFeatureValues(key) {
    return function compare(table) {
      var featureValues = features[key].map(function(a) {
        if(key === "comments") {
          return a.text;
        }

        return a.name;
      });
      var expectedValues = unwrapSingleColumnTable(table);
      featureValues.should.containDeepOrdered(expectedValues);
    }
  }

  // TODO: FAR TOO COMPLICATED! Maybe remove the conditionals
  // TODO: by having two different functions. See Example tags scenario for a possible alternative.
  // key1 is a key on the scenario
  // key2 is an optional key on a sub-object.
  function compareScenarioValues(key1, key2) {
    return function compare(scenarioNumber, table) {
      var done = undefined;

      /**
       * Sometimes just a table is passed in the first argument slot,
       * in that case adjust the parameters.
       *
       * CucumberJS determines if the step definition completion
       * should be dependent on a callback by counting the number
       * of arguments, so we have to cope with that.
       **/
      if (typeof scenarioNumber === "object") {
        done = table;
        table = scenarioNumber;
        scenarioNumber = "default";
      }

      var scenarioIndex = scenarioNumberToIndex[scenarioNumber];
      var scenario = features.scenarioDefinitions[scenarioIndex];
      var scenarioValues;

      // If the suboject key is specified dig the values out of the objects.
      // e.g. get the names of steps out of an array of steps.
      // c.f. https://lodash.com/docs#pluck .
      if (key2) {
        scenarioValues = scenario[key1].map(function(subObject) { return subObject[key2]; });
      } else {
        scenarioValues = scenario[key1];
      }

      var expectedValues = unwrapSingleColumnTable(table);

      // Do the test.
      scenarioValues.should.containDeepOrdered(expectedValues);

      if (typeof done === "function") {
        done();
      }
    }
  }

  // Get scenarios etc and properties of such.
  function getScenarios(feature, tokenType) {
    tokenType = tokenType || 'Scenario';
    return feature.scenarioDefinitions
      .filter(function(scenario) {return scenario.type === tokenType;});
  }
  function getScenarioOutlines(feature) {
    return getScenarios(feature, 'ScenarioOutline');
  }
  function getScenarioNames(feature, tokenType) {
      return getScenarios(feature, tokenType)
        .map(function(scenario) {return scenario.name});
  }

  this.Given(/^an example feature file\.?$/, function () {
    var exampleFeatureFilePath = path.join(__dirname, '..', 'test-data', 'example-feature-file.feature');
    featureText = fs.readFileSync(exampleFeatureFilePath, {encoding: 'utf8'});
  });

  this.When(/^I parse this specification\.?$/, function () {
    features = Parser.parse(featureText);
  });

  this.Then(/^I get a feature with title "([^"]*)"\.?$/, function (featureTitle) {
    features.name.should.be.exactly(featureTitle);
  });

  this.Then(/^I get a background with the title "([^"]*)"\.?$/, function (backgroundTitle) {
    var backgroundNames = features.background.name;
    backgroundNames.should.containEql(backgroundTitle);
  });

  this.Then(/^I get scenarios with titles\.?$/, function (table) {
    var expectedScenarioNames = unwrapSingleColumnTable(table);
    var scenarioNames = getScenarioNames(features, 'Scenario');
    scenarioNames.should.containDeep(expectedScenarioNames);
  });

  this.Then(/^I get a scenario outline with the title "([^"]*)"\.?$/, function (scenarioOutlineTitle) {
    var scenarioOutlineNames = getScenarioNames(features, 'ScenarioOutline');
    scenarioOutlineNames.should.containEql(scenarioOutlineTitle);
  });

  this.Then(/^I get a set of examples with the title "([^"]*)"\.?$/, function (expectedExampleTitle) {
    var scenarioOutlines = getScenarioOutlines(features);
    var exampleTitle = scenarioOutlines[0].examples[0].name;
    exampleTitle.should.be.exactly(expectedExampleTitle);
  });

  this.Then(/^feature tags are associated with features\.?$/, compareFeatureValues('tags'));

  this.Then(/^scenario tags are associated with scenarios\.?$/, compareScenarioValues('tags', 'name'));

  this.Then(/^feature comments are associated with features\.?$/, compareFeatureValues('comments'));

  this.Then(/^the "([^"]*)" scenario has steps with the names\.?$/, compareScenarioValues('steps', 'text'));

  this.Then(/^example tags are associated with examples$/, function (table) {
    var expectedTagValues = unwrapSingleColumnTable(table);
    var scenarioOutlines = getScenarioOutlines(features);

    var exampleTagData = scenarioOutlines[0].examples[0].tags.map(function(a) {
      return a.name;
    });

    exampleTagData.should.containDeep(expectedTagValues);
  });

  this.Then(/^scenario outlines have example data\.?$/, function (table) {
    var expectedExampleDataValues = unwrapSingleColumnTable(table);
    var scenarioOutlines = getScenarioOutlines(features);

    var exampleDataValues = scenarioOutlines[0].examples[0].tableBody
      .map(function(row) { return row.cells.map(function(a) {
        return a.value
      }); })
      .reduce(function(a, b) { return a.concat(b); });
    exampleDataValues.should.containDeep(expectedExampleDataValues);
  });

  this.Then(/^steps with tables have that table data\.?$/, function (table) {
      var expectedTableDataValues = unwrapSingleColumnTable(table);
      var scenarios = getScenarios(features);

      // Dig the relevant values out of the data structure.
      // TODO: too complicated, abstract or find another solution.
      var scenarioTableData = scenarios
        .map(function(scenario) {
          return scenario.steps
            .filter(function(step) {
              return step.argument && step.argument.type === 'DataTable';
            })
            .map(function(step) {
              return step.argument.rows.map(function(row) {
                return row.cells.map(function(cell) {
                  return cell.value;
                });
              })
              .reduce(function(a, b) { return a.concat(b) }, []);
            }).reduce(function(a, b) { return a.concat(b) }, []);
        }).reduce(function(a, b) { return a.concat(b) }, []);

      scenarioTableData.should.containDeep(expectedTableDataValues);
  });

  this.Then(/^steps with doc strings have that doc string content\.?$/, function (table) {
    var expectedDocStringValues = firstRowFirstCell(table);
    var scenarios = getScenarios(features);

    // Dig the relevant values out of the data structure.
    // TODO: too complicated, abstract or find another solution.
    var scenarioDocStringData = scenarios
      .map(function(scenario) {
        return scenario.steps
          .filter(function(step) {
            return step.argument && step.argument.type === 'DocString';
          })
          .map(function(step) {
            return step.argument.content;
          })
      }).reduce(function(a, b) {
            return a.concat(b);
      })[0];

    scenarioDocStringData.should.match(expectedDocStringValues);
  });
};
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Route, Switch } from 'react-router-dom';

import lazyLoadComponent from 'common/lazyLoadComponent';
import TooltipProvider from 'interface/common/TooltipProvider/index';
import retryingPromise from 'common/retryingPromise';
import { API_DOWN, clearError, INTERNET_EXPLORER, internetExplorerError, REPORT_NOT_FOUND, UNKNOWN_NETWORK_ISSUE } from 'interface/actions/error';
import { fetchUser } from 'interface/actions/user';
import { getError } from 'interface/selectors/error';
import { getOpenModals } from 'interface/selectors/openModals';
import ApiDownBackground from 'interface/common/images/api-down-background.gif';
import FullscreenError from 'interface/common/FullscreenError';
import makeAnalyzerUrl from 'interface/common/makeAnalyzerUrl';
import Footer from 'interface/layout/Footer/index';
import HomePage from 'interface/home/Page';
import ThunderSoundEffect from 'interface/audio/Thunder Sound effect.mp3';
import ReportPage from 'interface/report';
import PortalTarget from 'interface/PortalTarget';

import 'react-toggle/style.css';
import './layout/App.scss';
import Tracker from './Tracker';

const CharacterParsesPage = lazyLoadComponent(() => retryingPromise(() => import(/* webpackChunkName: 'CharacterParsesPage' */ 'interface/character/Page').then(exports => exports.default)));

function isIE() {
  const myNav = navigator.userAgent.toLowerCase();
  return myNav.includes('msie') || myNav.includes('trident');
}

class App extends React.Component {
  static propTypes = {
    push: PropTypes.func.isRequired,

    error: PropTypes.shape({
      error: PropTypes.string.isRequired,
      details: PropTypes.any,
    }),
    clearError: PropTypes.func.isRequired,
    internetExplorerError: PropTypes.func.isRequired,
    fetchUser: PropTypes.func.isRequired,
    openModals: PropTypes.number.isRequired,
  };

  constructor(props) {
    super(props);
    if (isIE()) {
      props.internetExplorerError();
    }

    TooltipProvider.load();
    if (process.env.REACT_APP_FORCE_PREMIUM !== 'true') {
      // If Premium is forced (development environments), fetching the user would probably fail too
      props.fetchUser().then(user => {
        if (user === false || (user && !user.premium)) {
          (window.adsbygoogle = window.adsbygoogle || []).push({
            google_ad_client: "ca-pub-8048055232081854",
            enable_page_level_ads: true,
          });
        }
      });
    }
  }

  renderError(error) {
    if (error.error === API_DOWN) {
      return (
        <FullscreenError
          error="The API is down."
          details="This is usually because we're leveling up with another patch."
          background={ApiDownBackground}
        >

            Aside from the great news that you'll be the first to experience something new that is probably going to pretty amazing, you'll probably also enjoy knowing that our updates usually only take about 10 seconds. So just give it another try.

          {/* I couldn't resist */}
          <audio autoPlay>
            <source src={ThunderSoundEffect} />
          </audio>
        </FullscreenError>
      );
    }
    if (error.error === REPORT_NOT_FOUND) {
      return (
        <FullscreenError
          error="Report not found."
          details="Either you entered a wrong report, or it is private."
          background="https://media.giphy.com/media/DAgxA6qRfa5La/giphy.gif"
        >

            Private logs can not be used, if your guild has private logs you will have to upload your own logs or change the existing logs to the unlisted privacy option instead.

            <button type="button" className="btn btn-primary" onClick={() => {
              this.props.clearError();
              this.props.push(makeAnalyzerUrl());
            }}>
              < Back
            </button>

        </FullscreenError>
      );
    }
    if (error.error === UNKNOWN_NETWORK_ISSUE) {
      return (
        <FullscreenError
          error="An API error occured."
          details="Something went wrong talking to our servers, please try again."
          background="https://media.giphy.com/media/m4TbeLYX5MaZy/giphy.gif"
        >

            {error.details.message}

            Refresh

        </FullscreenError>
      );
    }
    if (error.error === INTERNET_EXPLORER) {
      return (
        <FullscreenError
          error="A wild INTERNET EXPLORER appeared!"
          details="This browser is too unstable for WoWAnalyzer to work properly."
          background="https://media.giphy.com/media/njYrp176NQsHS/giphy.gif"
        >
          {/* Lower case the button so it doesn't seem to aggressive */}
          Download a proper browser
        </FullscreenError>
      );
    }
    return (
      <FullscreenError
        error="An unknown error occured."
        details={error.details.message || error.details}
        background="https://media.giphy.com/media/m4TbeLYX5MaZy/giphy.gif"
      >

          <button type="button" className="btn btn-primary" onClick={() => {
            this.props.clearError();
            this.props.push(makeAnalyzerUrl());
          }}>
            < Back
          </button>

      </FullscreenError>
    );
  }
  renderContent() {
    const { error } = this.props;

    if (error) {
      return this.renderError(error);
    }

    return (
      <Switch>
        <Route
          path="/character/:region/:realm/:name"
          render={({ match }) => (
            <CharacterParsesPage
              region={decodeURI(match.params.region.replace(/\+/g, ' '))}
              realm={decodeURI(match.params.realm.replace(/\+/g, ' '))}
              name={decodeURI(match.params.name.replace(/\+/g, ' '))}
            />
          )}
        />
        <Route
          path="/report/:reportCode?/:fightId?/:player?/:resultTab?"
          component={ReportPage}
        />
        <Route component={HomePage} />
      </Switch>
    );
  }

  render() {
    const { error, openModals } = this.props;

    return (
      <>
        <div className={`app ${openModals > 0 ? 'modal-open' : ''}`}>
          {this.renderContent()}

        {!error && }

        <PortalTarget />
        <Tracker />
      </>
    );
  }
}

const mapStateToProps = state => ({
  error: getError(state),
  openModals: getOpenModals(state),
});

export default connect(
  mapStateToProps,
  {
    push,
    clearError,
    internetExplorerError,
    fetchUser,
  }
)(App);
<commit_msg>Fix issue where routing was inconsistent<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { connect } from 'react-redux';
import { push } from 'react-router-redux';
import { Route, Switch, withRouter } from 'react-router-dom';

import lazyLoadComponent from 'common/lazyLoadComponent';
import TooltipProvider from 'interface/common/TooltipProvider/index';
import retryingPromise from 'common/retryingPromise';
import { API_DOWN, clearError, INTERNET_EXPLORER, internetExplorerError, REPORT_NOT_FOUND, UNKNOWN_NETWORK_ISSUE } from 'interface/actions/error';
import { fetchUser } from 'interface/actions/user';
import { getError } from 'interface/selectors/error';
import { getOpenModals } from 'interface/selectors/openModals';
import ApiDownBackground from 'interface/common/images/api-down-background.gif';
import FullscreenError from 'interface/common/FullscreenError';
import makeAnalyzerUrl from 'interface/common/makeAnalyzerUrl';
import Footer from 'interface/layout/Footer/index';
import HomePage from 'interface/home/Page';
import ThunderSoundEffect from 'interface/audio/Thunder Sound effect.mp3';
import ReportPage from 'interface/report';
import PortalTarget from 'interface/PortalTarget';

import 'react-toggle/style.css';
import './layout/App.scss';
import Tracker from './Tracker';

const CharacterParsesPage = lazyLoadComponent(() => retryingPromise(() => import(/* webpackChunkName: 'CharacterParsesPage' */ 'interface/character/Page').then(exports => exports.default)));

function isIE() {
  const myNav = navigator.userAgent.toLowerCase();
  return myNav.includes('msie') || myNav.includes('trident');
}

class App extends React.Component {
  static propTypes = {
    push: PropTypes.func.isRequired,

    error: PropTypes.shape({
      error: PropTypes.string.isRequired,
      details: PropTypes.any,
    }),
    clearError: PropTypes.func.isRequired,
    internetExplorerError: PropTypes.func.isRequired,
    fetchUser: PropTypes.func.isRequired,
    openModals: PropTypes.number.isRequired,
  };

  constructor(props) {
    super(props);
    if (isIE()) {
      props.internetExplorerError();
    }

    TooltipProvider.load();
    if (process.env.REACT_APP_FORCE_PREMIUM !== 'true') {
      // If Premium is forced (development environments), fetching the user would probably fail too
      props.fetchUser().then(user => {
        if (user === false || (user && !user.premium)) {
          (window.adsbygoogle = window.adsbygoogle || []).push({
            google_ad_client: "ca-pub-8048055232081854",
            enable_page_level_ads: true,
          });
        }
      });
    }
  }

  renderError(error) {
    if (error.error === API_DOWN) {
      return (
        <FullscreenError
          error="The API is down."
          details="This is usually because we're leveling up with another patch."
          background={ApiDownBackground}
        >

            Aside from the great news that you'll be the first to experience something new that is probably going to pretty amazing, you'll probably also enjoy knowing that our updates usually only take about 10 seconds. So just give it another try.

          {/* I couldn't resist */}
          <audio autoPlay>
            <source src={ThunderSoundEffect} />
          </audio>
        </FullscreenError>
      );
    }
    if (error.error === REPORT_NOT_FOUND) {
      return (
        <FullscreenError
          error="Report not found."
          details="Either you entered a wrong report, or it is private."
          background="https://media.giphy.com/media/DAgxA6qRfa5La/giphy.gif"
        >

            Private logs can not be used, if your guild has private logs you will have to upload your own logs or change the existing logs to the unlisted privacy option instead.

            <button type="button" className="btn btn-primary" onClick={() => {
              this.props.clearError();
              this.props.push(makeAnalyzerUrl());
            }}>
              < Back
            </button>

        </FullscreenError>
      );
    }
    if (error.error === UNKNOWN_NETWORK_ISSUE) {
      return (
        <FullscreenError
          error="An API error occured."
          details="Something went wrong talking to our servers, please try again."
          background="https://media.giphy.com/media/m4TbeLYX5MaZy/giphy.gif"
        >

            {error.details.message}

            Refresh

        </FullscreenError>
      );
    }
    if (error.error === INTERNET_EXPLORER) {
      return (
        <FullscreenError
          error="A wild INTERNET EXPLORER appeared!"
          details="This browser is too unstable for WoWAnalyzer to work properly."
          background="https://media.giphy.com/media/njYrp176NQsHS/giphy.gif"
        >
          {/* Lower case the button so it doesn't seem to aggressive */}
          Download a proper browser
        </FullscreenError>
      );
    }
    return (
      <FullscreenError
        error="An unknown error occured."
        details={error.details.message || error.details}
        background="https://media.giphy.com/media/m4TbeLYX5MaZy/giphy.gif"
      >

          <button type="button" className="btn btn-primary" onClick={() => {
            this.props.clearError();
            this.props.push(makeAnalyzerUrl());
          }}>
            < Back
          </button>

      </FullscreenError>
    );
  }
  renderContent() {
    const { error } = this.props;

    if (error) {
      return this.renderError(error);
    }

    return (
      <Switch>
        <Route
          path="/character/:region/:realm/:name"
          render={({ match }) => (
            <CharacterParsesPage
              region={decodeURI(match.params.region.replace(/\+/g, ' '))}
              realm={decodeURI(match.params.realm.replace(/\+/g, ' '))}
              name={decodeURI(match.params.name.replace(/\+/g, ' '))}
            />
          )}
        />
        <Route
          path="/report/:reportCode?/:fightId?/:player?/:resultTab?"
          component={ReportPage}
        />
        <Route component={HomePage} />
      </Switch>
    );
  }

  render() {
    const { error, openModals } = this.props;

    return (
      <>
        <div className={`app ${openModals > 0 ? 'modal-open' : ''}`}>
          {this.renderContent()}

        {!error && }

        <PortalTarget />
        <Tracker />
      </>
    );
  }
}

const mapStateToProps = state => ({
  error: getError(state),
  openModals: getOpenModals(state),
});

const ConnectedComponent = connect(
  mapStateToProps,
  {
    push,
    clearError,
    internetExplorerError,
    fetchUser,
  }
)(App);

// This needs the `withRouter` so its props change (causing a render) when the route changes
export default withRouter(ConnectedComponent);
<|endoftext|>


<commit_before>(function(){

  var stylus  = require( 'stylus' ),
      nib     = require( 'nib'    ),
      cssmin  = require( 'cssmin' ),
      gzip    = require( 'gzip'   ),
      watch   = require( 'watch-tree' ),
      uglify  = require( 'uglify-js'  ),
      coffee  = require( 'coffee-script' ),
      async   = require( 'asyncjs' ),
      fs      = require( 'fs' ),
      util    = require( 'util' ),
      path    = require( 'path' ),
      inspect = util.inspect,
      jshint  = require( 'jshint' ).JSHINT;
      steps   = {};

  module.exports.steps    = steps;
  module.exports.Compiler = Compiler;

  function Compiler( rootDir, outputDir, watchMode ) {
    this.rootDir   = rootDir;
    this.outputDir = outputDir;
    this.watchMode = !!watchMode;
    this.rules     = [];
    return this;
  }

  Compiler.prototype.start = function() {
    var that      = this,
        watchMode = that.watchMode,
        rootDir   = that.rootDir,
        outputDir = that.outputDir;

    var watcher = watch.watchTree(rootDir, {
      'sample-rate' : 5,
      'ignore'      : new RegExp('/[._]')
    });

    var _compile = function(path){ return that._compile(path); }
    var _delete  = function(path){ return that._delete(path);  }

    watcher.on( 'filePreexisted', _compile );
    watcher.on( 'fileCreated',    _compile );
    watcher.on( 'fileModified',   _compile );
    watcher.on( 'fileDeleted',    _delete  );
    watcher.on( 'allPreexistingFilesReported', function(){
      if (watchMode) {
        console.log("-----> Entering watch mode!");
      } else {
        console.log("-----> Done!");
        watcher.end();
      }
    });
  }

  Compiler.prototype.addRule = function( test, outputFilenameFunction, ruleList ) {
    this.rules.push({
      test:test,
      outputFilenameFunction:outputFilenameFunction,
      ruleList:ruleList
    });
  }

  Compiler.prototype._compile = function(path) {
    path = path.replace(this.rootDir + "/", "");
    for (var i = 0, len = this.rules.length; i < len; i++) {
      var rule = this.rules[i];
      if (rule.test instanceof RegExp) {
        if (rule.test.test(path)) {
          this._runChain( path, rule, rule.ruleList );
          break;
        }
      }
      else if (typeof test === 'function') {
        if (test(path)) {
          this._runChain( path, rule, rule.ruleList );
          break;
        }
      } else if (typeof test === 'string') {
        if (path === test) {
          this._runChain( path, rule, rule.ruleList );
          break;
        }
      }
    }
  }

  Compiler.prototype._delete = function(path) {
  }

  Compiler.prototype._runChain = function(file, rule, functions) {
    async.list(functions).call({compiler:this,rule:rule,path:file,save:{}}).end(function(e){
      if (e) {
        console.log("---\n---\n---\n\nERROR IN FILE: "+file+"\n\nError: "+e+"\n\n---\n---\n---\n");
      } else {
        console.log(" COMPILED: " + file);
      }
    });
  }

  steps.minifyJs = function(next) {
    var ast, code;
    try {
      ast = uglify.parser.parse(this.data);
      ast = uglify.uglify.ast_mangle(ast);
      ast = uglify.uglify.ast_squeeze(ast);
      code = uglify.uglify.gen_code(ast);
      this.save.minified = code;
      this.data = code;
      return next();
    } catch (e) {
      return next(e);
    }
  }

  steps.jshint = function(next) {
    var result = jshint(this.data);
    if (result) {
      next();
    } else {
      next( require('sys').inspect(jshint.errors) );
    }
  }

  steps.gzip = function(next) {
    var that = this;
    return gzip(this.data, 9, function(err, cmp) {
      if (err) {
        next(err);
      } else {
        that.data = cmp;
        that.save.compressed = cmp;
        next();
      }
    });
  }

  steps.read = function(next) {
    var that = this;
    return fs.readFile(this.compiler.rootDir + "/" + this.path, function(err, data) {
      if (err) {
        return next(err);
      }
      var d = data.toString();
      that.save.original = d;
      that.data = d;
      next();
    });
  }

  steps.minifyCss = function(next) {
    try {
      var d = cssmin(this.data);
      this.data = d;
      this.save.minified = d;
      next();
    } catch (e) {
      next(e);
    }
  }

  steps.parseStylus = function(next) {
    var that = this;
    stylus.render(this.data, {
      filename: this.path
    },
    function(err, css) {
      if (err) {
        next(err);
      } else {
        that.data = css;
        next();
      }
    });
  }

  /*

  repeater(i) {
  if( i < length ) {
     asyncwork( function(){
       repeater( i + 1 )
     })
  }
}
repeater(0)

  */
  steps.save = function(next) {
    var savedFiles = [],
        that = this;
    for (var i in this.save) {
      savedFiles.push([ i, this.save[i] ]);
    }

    var doSave = function(i){
      if (i < savedFiles.length) {
        var entry = savedFiles[i],
            filename = that.rule.outputFilenameFunction( entry[0], that.path ),
            data     = entry[1],
            fullPath = path.join( that.compiler.outputDir, filename ),
            dirname  = path.dirname( fullPath );

        if (filename) {
          console.log("" + (new Date()) + "> Saving: " + fullPath);
          mkdir_p( dirname, function(e){
            if (e) { return next(e); }

            fs.writeFile( fullPath, data, function(err) {
              if (err) { return next(err);     }
              else     { return doSave(i + 1); }
            });
          });
        } else {
          doSave(i + 1);
        }
      }
    }
    doSave(0);
  }

  steps.debug = function(next) {
    console.log("DEBUG :---------------------------------------------");
    console.log("file  : ", this.path )
    console.log("data  : ", inspect(this.data) );
    for (var i in this.save) {
      console.log("      :---------------------------------------------");
      console.log("save  : " + i);
      console.log("data  : ", inspect(this.save[i]));
    }
    console.log("------:---------------------------------------------");

    next();
  }

function mkdir_p( dir, cb, mode ) {
  mode = mode || 0755;
  path.exists(dir, function(exists){
    if (exists) {
      cb();
    } else {
      var dirs = dir.split("/");
      if ( dir.indexOf('/') === 0) {
        dirs[0] = '/';
      }
      var seed = dirs.shift();
      mkdir_p$( seed, dirs );
    }
  });

  var mkdir_p$ = function( str, segments ) {
    var str = path.join(str, segments[0]);
    segments = segments.slice(1);
    var ret = function(){
      if (segments.length) {
        mkdir_p$( str, segments );
      } else {
        cb();
      }
    }

    path.exists( str, function(exists){
      if (exists) {
        ret();
      } else {

        fs.mkdir( str, mode, function(err) {
          if (err) { return cb(err); }
          ret();
        });
      }
    });

  }
}

})();<commit_msg>copy/ignore rules<commit_after>(function(){

  var stylus  = require( 'stylus' ),
      nib     = require( 'nib'    ),
      cssmin  = require( 'cssmin' ),
      gzip    = require( 'gzip'   ),
      watch   = require( 'watch-tree' ),
      uglify  = require( 'uglify-js'  ),
      coffee  = require( 'coffee-script' ),
      async   = require( 'asyncjs' ),
      fs      = require( 'fs' ),
      util    = require( 'util' ),
      path    = require( 'path' ),
      inspect = util.inspect,
      jshint  = require( 'jshint' ).JSHINT;
      steps   = {};

  module.exports.steps    = steps;
  module.exports.Compiler = Compiler;

  function Compiler( rootDir, outputDir, watchMode ) {
    this.rootDir   = rootDir;
    this.outputDir = outputDir;
    this.watchMode = !!watchMode;
    this.rules     = [];
    this.ignores   = [];
    return this;
  }

  Compiler.prototype.start = function() {
    var that      = this,
        watchMode = that.watchMode,
        rootDir   = that.rootDir,
        outputDir = that.outputDir;

    var watcher = watch.watchTree(rootDir, {
      'sample-rate' : 5,
      'ignore'      : new RegExp('/[._]')
    });

    var _compile = function(path){ return that._compile(path); };
    var _delete  = function(path){ return that._delete(path);  };

    watcher.on( 'filePreexisted', _compile );
    watcher.on( 'fileCreated',    _compile );
    watcher.on( 'fileModified',   _compile );
    watcher.on( 'fileDeleted',    _delete  );
    watcher.on( 'allPreexistingFilesReported', function(){
      if (watchMode) {
        console.log("-----> Entering watch mode!");
      } else {
        console.log("-----> Done!");
        watcher.end();
      }
    });
  }

  Compiler.prototype.addRule = function( test, outputFilenameFunction, ruleList ) {
    this.rules.push({
      test:test,
      outputFilenameFunction:outputFilenameFunction,
      ruleList:ruleList
    });
  }

  Compiler.prototype.copy = function( test ) {
    this.rules.push({
      test: test,
      outputFilenameFunction: function(type, filePath){ return type === 'original' ? filePath : null; },
      ruleList: [steps.read, steps.save]
    });
  }

  Compiler.prototype.ignore = function( test ) {
    this.ignores.push( test );
  }

  function checkTest( test, target ) {
    if (test instanceof RegExp && test.test(target) ) {
      return true;
    }
    else if (typeof test === 'function' && test(target) === true) {
      return true;
    }
    else if (typeof test === 'string' && test === target) {
      return true;
    }
  }

  Compiler.prototype._compile = function(path) {
    path = path.replace(this.rootDir + "/", "");

    for (var i = 0, len = this.ignores.length; i < len; i++) {
      if (checkTest( this.ignores[i], path )) {
        return;
      }
    }

    for (var i = 0, len = this.rules.length; i < len; i++) {
      var rule = this.rules[i];
      if (checkTest( rule.test, path )) {
        this._runChain( path, rule, rule.ruleList );
        return;
      }
    }

    // should probably bark that no rule covered this?
  }

  Compiler.prototype._delete = function(path) {
  }

  Compiler.prototype._runChain = function(file, rule, functions) {
    async.list(functions).call({compiler:this,rule:rule,path:file,save:{}}).end(function(e){
      if (e) {
        console.log("---\n---\n---\n\nERROR IN FILE: "+file+"\n\nError: "+e+"\n\n---\n---\n---\n");
      } else {
//        console.log(" COMPILED: " + file);
      }
    });
  }

  steps.minifyJs = function(next) {
    var ast, code;
    try {
      ast = uglify.parser.parse(this.data);
      ast = uglify.uglify.ast_mangle(ast);
      ast = uglify.uglify.ast_squeeze(ast);
      code = uglify.uglify.gen_code(ast);
      this.save.minified = code;
      this.data = code;
      return next();
    } catch (e) {
      return next(e);
    }
  }

  steps.jshint = function(next) {
    var result = jshint(this.data);
    if (result) {
      next();
    } else {
      next( require('sys').inspect(jshint.errors) );
    }
  }

  steps.gzip = function(next) {
    var that = this;
    return gzip(this.data, 9, function(err, cmp) {
      if (err) {
        next(err);
      } else {
        that.data = cmp;
        that.save.compressed = cmp;
        next();
      }
    });
  }

  steps.read = function(next) {
    var that = this;
    return fs.readFile(this.compiler.rootDir + "/" + this.path, function(err, data) {
      if (err) {
        return next(err);
      }
      var d = data.toString();
      that.save.original = d;
      that.data = d;
      next();
    });
  }

  steps.minifyCss = function(next) {
    try {
      var d = cssmin(this.data);
      this.data = d;
      this.save.minified = d;
      next();
    } catch (e) {
      next(e);
    }
  }

  steps.parseStylus = function(next) {
    var that = this;
    stylus.render(this.data, {
      filename: this.path
    },
    function(err, css) {
      if (err) {
        next(err);
      } else {
        that.data = css;
        next();
      }
    });
  }

  steps.save = function(next) {
    var savedFiles = [],
        that = this;
    for (var i in this.save) {
      savedFiles.push([ i, this.save[i] ]);
    }

    var doSave = function(i){
      if (i < savedFiles.length) {
        var entry = savedFiles[i],
            filename = that.rule.outputFilenameFunction( entry[0], that.path ),
            data     = entry[1],
            fullPath = path.join( that.compiler.outputDir, filename ),
            dirname  = path.dirname( fullPath );

        if (filename) {
          console.log("" + (new Date()) + "> Saving: " + fullPath);
          mkdir_p( dirname, function(e){
            if (e) { return next(e); }

            fs.writeFile( fullPath, data, function(err) {
              if (err) { return next(err);     }
              else     { return doSave(i + 1); }
            });
          });
        } else {
          doSave(i + 1);
        }
      }
    }
    doSave(0);
  }

  steps.debug = function(next) {
    console.log("DEBUG :---------------------------------------------");
    console.log("file  : ", this.path )
    console.log("data  : ", inspect(this.data) );
    for (var i in this.save) {
      console.log("      :---------------------------------------------");
      console.log("save  : " + i);
      console.log("data  : ", inspect(this.save[i]));
    }
    console.log("------:---------------------------------------------");

    next();
  }

function mkdir_p( dir, cb, mode ) {
  mode = mode || 0755;
  path.exists(dir, function(exists){
    if (exists) {
      cb();
    } else {
      var dirs = dir.split("/");
      if ( dir.indexOf('/') === 0) {
        dirs[0] = '/';
      }
      var seed = dirs.shift();
      mkdir_p$( seed, dirs );
    }
  });

  var mkdir_p$ = function( str, segments ) {
    var str = path.join(str, segments[0]);
    segments = segments.slice(1);
    var ret = function(){
      if (segments.length) {
        mkdir_p$( str, segments );
      } else {
        cb();
      }
    }

    path.exists( str, function(exists){
      if (exists) {
        ret();
      } else {

        fs.mkdir( str, mode, function(err) {
          if (err) { return cb(err); }
          ret();
        });
      }
    });

  }
}

})();<|endoftext|>


<commit_before>const facetClass = 'b-facet-box__facet';
const facetTerm = `${facetClass}-term-toggle`;
const facetTermTick = `${facetTerm}-tick`;
const facetTextClass = `${facetClass}-text`;
const facetTermContainerClass = `${facetClass}-term-container`;

const termClass = 'b-facet-box__term';
const termListClass = `${termClass}-list`;
const termList = document.querySelector(`.${termListClass}`);
const termCheckboxClass = `${facetClass}-term-toggle-checkbox`;

const facetCloseClass = 'b-facet-box__close-button';

const facetsWithIndex = {};

const termButtonHTML = (facet, term) => `

        ${facet}: ${term}

`;

const dateFacetHTML = () => `

      Dates

          From year:

        <input class="b-facet-box__facet-date-input" placeholder="Year" type="number" name="after_year">

          To year:

        <input class="b-facet-box__facet-date-input" placeholder="Year" type="number" name="before_year">

        <button class="b-facet-box__facet-date-button">
          <svg class="b-facet-box__facet-date-button-icon" role="img">
            <use xlink:href="/svg/vamicons.svg#search"></use>
          </svg>
        </button>

`;

const termCheckbox = (facet, paramName, term, value, count) => {
  const checkbox = document.createElement('LI');
  checkbox.className = 'b-facet-box__facet-term-toggle';
  checkbox.dataset.id = `${paramName}-${value}`;
  checkbox.dataset.facet = facet;
  checkbox.dataset.paramName = paramName;
  checkbox.dataset.term = term;
  checkbox.dataset.value = value;
  checkbox.dataset.count = count;

  checkbox.innerHTML = `

      <svg class="b-facet-box__facet-term-toggle-tick" role="img">
        <use xlink:href="/svg/vamicons.svg#tick"></use>
      </svg>

      ${term}

      (${count})

  `;

  const hiddenInput = document.createElement('INPUT');
  hiddenInput.type = 'checkbox';
  hiddenInput.className = 'b-facet-box__hidden-input';
  hiddenInput.name = paramName;
  hiddenInput.value = value;
  hiddenInput.id = `${paramName}=${value}`;

  checkbox.addEventListener('termToggle', (e) => {
    const existingHiddenInput = document.querySelector(`input[id="${`${paramName}=${value}`}"]`);

    console.log(existingHiddenInput)

    console.log(!e.detail.refreshing_page)

    console.log(e.detail.refreshing_page && !existingHiddenInput)

    if (!e.detail.refreshing_page || (e.detail.refreshing_page && !existingHiddenInput)) {

      // GOTTA ASSUME THERE'S A FORM ON THE PAGE FOR THIS TO WORK!!!
      // this is because formData has an order which is annoying to change

      if (existingHiddenInput) {

        existingHiddenInput.checked = false;
        existingHiddenInput.remove();
      } else {
        document.querySelector('#vam-etc-search').appendChild(hiddenInput);
        document.querySelector(`input[id="${`${paramName}=${value}`}"]`).checked = true;
      }
    }

    e.target.querySelector(`.${facetTermTick}`).classList.toggle(
      `${facetTermTick}--active`
    );
    document.querySelector('.b-facet-box').dispatchEvent(new Event('boxChecked', { bubbles: true }));
  });

  return checkbox;
};

const facetHTML = (facet, seeMore) => `

    ${facet}

${
  seeMore ? `
    See more
  ` : ''
}
`;

const revealMoreFacets = (e) => {
  e.preventDefault();
  const linkEl = e.target;
  const facetContainer = e.target.parentNode;
  const { terms, index, facet, paramName } = facetsWithIndex[e.target.dataset.facet];
  e.target.remove();
  terms.slice(index, index + 5).forEach(({ term, count, value }) => {
    facetContainer.appendChild(termCheckbox(facet, paramName, term, value, count));
  });
  facetsWithIndex[facet].index += 5;

  if (facetsWithIndex[facet].index !== terms.length) {
    facetContainer.appendChild(linkEl);
  }
};

const createFacets = (activeFacets) => {
  const facetBoxContainer = document.querySelector('.b-facet-box__facet-container');
  const facetToTerm = Array.from(activeFacets).reduce((res, termfacet) => {
    const facet = termfacet.split('-')[0];
    const term = termfacet.split('-')[1];

    if (res[facet]) {
      res[facet].push(term);
    } else {
      res[facet] = [term];
    }

    return res;
  }, {});

  Object.values(facetsWithIndex).forEach(({ facet, terms, paramName, index }) => {
    const newFacet = document.createElement('DIV');
    newFacet.className = 'b-facet-box__facet';
    newFacet.innerHTML = facetHTML(facet, terms.length > 5);

    newFacet.addEventListener('click', (e) => {
      if (e.target.classList.contains(facetTextClass)) {
        e.target.classList.toggle(`${e.target.classList[0]}--active`);
        e.target.parentNode.querySelector(`.${facetTermContainerClass}`).classList.toggle(`${facetTermContainerClass}--active`);
      }
    });

    const termValues = terms.map(t => t.value);

    let newIndex = (facetToTerm[paramName] && facetToTerm[paramName].reduce((current, term) => {
      const test = termValues.indexOf(term);
      return (current > test ? current : test);
    }, 5)) || 0;

    newIndex = ((Math.ceil(newIndex / 5) * 5));

    newIndex = newIndex > terms.length ? terms.length : (newIndex || 5);

    terms.slice(index, newIndex).forEach(({ term, count, value }) => {
      newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(termCheckbox(facet, paramName, term, value, count));
    });

    facetsWithIndex[facet].index += (newIndex);

    if (terms.length > 5) {
      if (facetsWithIndex[facet].index < terms.length) {
        newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(newFacet.querySelector('.b-facet-box__term-more'));
        newFacet.querySelector(`.${facetTermContainerClass} .b-facet-box__term-more`).onclick = e => revealMoreFacets(e);
      } else {
        newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(newFacet.querySelector('.b-facet-box__term-more')).remove();
      }
    }

    facetBoxContainer.appendChild(newFacet);
  });
};

const newTermToggleEvent = (detail, bubbles = true) => new CustomEvent('termToggle', {
  detail,
  bubbles
});

const initialiseFacetOverlay = () => {
  const toggleTerm = ({ id, facet, term, paramName }) => {
    if (id) {
      // if term already exists, get rid of it
      if (document.querySelector(`div[data-id='${id}']`)) {
        Array.from(document.querySelectorAll(`div[data-id='${id}']`)).forEach(el => el.remove());
        if (!document.querySelector('.b-search-form__facets').children.length) {
          document.querySelector('.b-search-form__facet-pane').classList.remove('b-search-form__facet-pane--active');
        }
        window.dispatchEvent(new Event('resize'));
      } else {
        const newTermOnClick = () => {
          Array.from(document.querySelectorAll(`div[data-id='${id}']`)).forEach(el => el.dispatchEvent(newTermToggleEvent({ id, facet, term, paramName })));
          if (document.querySelector(`li[data-id='${id}']`)) {
            document.querySelector(`li[data-id='${id}']`).dispatchEvent(newTermToggleEvent({ id, facet, term, paramName }));
          }
        };

        const newTerm = document.createElement('DIV');
        newTerm.dataset.id = id;
        newTerm.className = 'b-facet-box__term';
        newTerm.innerHTML = termButtonHTML(facet, term);
        newTerm.onclick = e => newTermOnClick(e);
        termList.appendChild(newTerm);

        const newFormTerm = newTerm.cloneNode(true);
        newFormTerm.onclick = e => newTermOnClick(e);
        newFormTerm.classList.add('b-facet-box__term--form');
        if (document.querySelector('.b-search-form__facets')) {
          document.querySelector('.b-search-form__facets').appendChild(newFormTerm);
        }

        if (!document.querySelector('.b-search-form__facet-pane--active')) {
          document.querySelector('.b-search-form__facet-pane').classList.add('b-search-form__facet-pane--active');
        }

        window.dispatchEvent(new Event('resize'));
      }
    }
  };

  termList.addEventListener('termToggle', (e) => {
    e.stopPropagation();
    toggleTerm(e.detail);
  });

  document.querySelector('.b-facet-box').addEventListener('newFacets', (e) => {
    const { facets, activeFacets } = e.detail;
    const currentBeforeDate = document.querySelector('input[name="before_year"]') ? document.querySelector('input[name="before_year"]').value : '';
    const currentAfterDate = document.querySelector('input[name="after_year"]') ? document.querySelector('input[name="after_year"]').value : '';

    facets.forEach((facet) => {
      Object.assign(facetsWithIndex, {
        [facet.facet]: Object.assign(facet, { index: 0 })
      });
    });

    Array.from(document.querySelectorAll('.b-facet-box__hidden-input')).forEach(el => el.remove());

    const facetBoxContainer = document.querySelector('.b-facet-box__facet-container');
    facetBoxContainer.innerHTML = '';
    termList.innerHTML = '';

    createFacets(activeFacets);

    const dateFacet = document.createElement('DIV');
    dateFacet.className = 'b-facet-box__facet b-facet-box__facet-date';
    dateFacet.innerHTML = dateFacetHTML();
    dateFacet.addEventListener('click', (ev) => {
      if (ev.target.classList.contains(facetTextClass)) {
        ev.target.classList.toggle(`${ev.target.classList[0]}--active`);
        ev.target.parentNode.querySelector(`.${facetTermContainerClass}`).classList.toggle(`${facetTermContainerClass}--active`);
      }
    });
    dateFacet.querySelector('input[name="before_year"]').value = currentBeforeDate;
    dateFacet.querySelector('input[name="after_year"]').value = currentAfterDate;

    facetBoxContainer.append(dateFacet);

    if (activeFacets) {
      // is a set...
      Array.from(activeFacets).forEach((facetId) => {
        const target = document.querySelector(`li[data-id='${facetId}'`);
        if (target) {
          target.dispatchEvent(newTermToggleEvent(Object.assign(target.dataset, {refreshing_page: true})));
          document.querySelector(`.${termListClass}`).dispatchEvent(newTermToggleEvent(target.dataset));
        }
      });
    }

    window.dispatchEvent(new Event('resize'));
  }, true);

  document.onclick = (e) => {
    if (e.target.classList.contains(facetCloseClass)) {
      e.target.dispatchEvent(new Event('closeFacetOverlay', {
        bubbles: true
      }));
    }

    if (e.target.parentElement && e.target.parentElement.classList.contains(facetTerm)) {
      const parent = e.target.closest(facetTerm) || e.target.parentElement;
      termList.dispatchEvent(newTermToggleEvent(parent.dataset, false));
      parent.dispatchEvent(newTermToggleEvent(parent.dataset));
    }
  };
};

(() => {
  if (document.querySelector('.b-facet-box')) {
    initialiseFacetOverlay();

    if (document.querySelector('.b-facet-box__modal-button-open')) {
      document.querySelectorAll('.b-facet-box__modal-button-open').forEach(el => el.addEventListener('click', () => document.querySelector('.b-facet-box').classList.add('b-facet-box--active')));
    }
    if (document.querySelector('.b-facet-box__close-button')) {
      document.querySelector('.b-facet-box__close-button').addEventListener('click', () => document.querySelector('.b-facet-box').classList.remove('b-facet-box--active'));
    }

    window.onresize = () => {
      const facetFormTerms = Array.from(document.querySelectorAll('.b-facet-box__term.b-facet-box__term--form'));
      if (document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross')) {
        if (window.innerWidth > 499 && window.innerWidth < 992) {
          const facetContainerWidth = document.querySelector('.b-search-form__facets').offsetWidth;
          let cutOffWidth = 0;
          let currentIndex = 1;
          facetFormTerms.forEach((el) => {
            cutOffWidth += el.offsetWidth + 10;
            if (cutOffWidth < facetContainerWidth) {
              currentIndex += 1;
            }
          });
          if ((facetFormTerms.length - currentIndex) > 0) {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'block';
          } else {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
          }
          document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross').innerHTML = `+${facetFormTerms.length - currentIndex}`;
        } else if (window.innerWidth < 500) {
          if ((facetFormTerms.length) > 0) {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'block';
          } else {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
          }
          document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross').innerHTML = `${facetFormTerms.length - 1} filters applied`;
        } else {
          document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
        }
      }
    };
  }
})();
<commit_msg>fix for facets<commit_after>const facetClass = 'b-facet-box__facet';
const facetTerm = `${facetClass}-term-toggle`;
const facetTermTick = `${facetTerm}-tick`;
const facetTextClass = `${facetClass}-text`;
const facetTermContainerClass = `${facetClass}-term-container`;

const termClass = 'b-facet-box__term';
const termListClass = `${termClass}-list`;
const termList = document.querySelector(`.${termListClass}`);
const termCheckboxClass = `${facetClass}-term-toggle-checkbox`;

const facetCloseClass = 'b-facet-box__close-button';

const facetsWithIndex = {};

const termButtonHTML = (facet, term) => `

        ${facet}: ${term}

`;

const dateFacetHTML = () => `

      Dates

          From year:

        <input class="b-facet-box__facet-date-input" placeholder="Year" type="number" name="after_year">

          To year:

        <input class="b-facet-box__facet-date-input" placeholder="Year" type="number" name="before_year">

        <button class="b-facet-box__facet-date-button">
          <svg class="b-facet-box__facet-date-button-icon" role="img">
            <use xlink:href="/svg/vamicons.svg#search"></use>
          </svg>
        </button>

`;

const termCheckbox = (facet, paramName, term, value, count) => {
  const checkbox = document.createElement('LI');
  checkbox.className = 'b-facet-box__facet-term-toggle';
  checkbox.dataset.id = `${paramName}-${value}`;
  checkbox.dataset.facet = facet;
  checkbox.dataset.paramName = paramName;
  checkbox.dataset.term = term;
  checkbox.dataset.value = value;
  checkbox.dataset.count = count;

  checkbox.innerHTML = `

      <svg class="b-facet-box__facet-term-toggle-tick" role="img">
        <use xlink:href="/svg/vamicons.svg#tick"></use>
      </svg>

      ${term}

      (${count})

  `;

  const hiddenInput = document.createElement('INPUT');
  hiddenInput.type = 'checkbox';
  hiddenInput.className = 'b-facet-box__hidden-input';
  hiddenInput.name = paramName;
  hiddenInput.value = value;
  hiddenInput.id = `${paramName}=${value}`;

  checkbox.addEventListener('termToggle', (e) => {
    const existingHiddenInput = document.querySelector(`input[id="${`${paramName}=${value}`}"]`);
    // GOTTA ASSUME THERE'S A FORM ON THE PAGE FOR THIS TO WORK!!!
    // this is because formData has an order which is annoying to change

    if (existingHiddenInput) {
      existingHiddenInput.checked = false;
      existingHiddenInput.remove();
    } else {
      document.querySelector('#vam-etc-search').appendChild(hiddenInput);
      document.querySelector(`input[id="${`${paramName}=${value}`}"]`).checked = true;
    }

    e.target.querySelector(`.${facetTermTick}`).classList.toggle(
      `${facetTermTick}--active`
    );

    if (!e.detail.refreshing_page) {
      document.querySelector('.b-facet-box').dispatchEvent(new Event('boxChecked', { bubbles: true }));
    }
  });

  return checkbox;
};

const facetHTML = (facet, seeMore) => `

    ${facet}

${
  seeMore ? `
    See more
  ` : ''
}
`;

const revealMoreFacets = (e) => {
  e.preventDefault();
  const linkEl = e.target;
  const facetContainer = e.target.parentNode;
  const { terms, index, facet, paramName } = facetsWithIndex[e.target.dataset.facet];
  e.target.remove();
  terms.slice(index, index + 5).forEach(({ term, count, value }) => {
    facetContainer.appendChild(termCheckbox(facet, paramName, term, value, count));
  });
  facetsWithIndex[facet].index += 5;

  if (facetsWithIndex[facet].index !== terms.length) {
    facetContainer.appendChild(linkEl);
  }
};

const createFacets = (activeFacets) => {
  const facetBoxContainer = document.querySelector('.b-facet-box__facet-container');
  const facetToTerm = Array.from(activeFacets).reduce((res, termfacet) => {
    const facet = termfacet.split('-')[0];
    const term = termfacet.split('-')[1];

    if (res[facet]) {
      res[facet].push(term);
    } else {
      res[facet] = [term];
    }

    return res;
  }, {});

  Object.values(facetsWithIndex).forEach(({ facet, terms, paramName, index }) => {
    const newFacet = document.createElement('DIV');
    newFacet.className = 'b-facet-box__facet';
    newFacet.innerHTML = facetHTML(facet, terms.length > 5);

    newFacet.addEventListener('click', (e) => {
      if (e.target.classList.contains(facetTextClass)) {
        e.target.classList.toggle(`${e.target.classList[0]}--active`);
        e.target.parentNode.querySelector(`.${facetTermContainerClass}`).classList.toggle(`${facetTermContainerClass}--active`);
      }
    });

    const termValues = terms.map(t => t.value);

    let newIndex = (facetToTerm[paramName] && facetToTerm[paramName].reduce((current, term) => {
      const test = termValues.indexOf(term);
      return (current > test ? current : test);
    }, 5)) || 0;

    newIndex = ((Math.ceil(newIndex / 5) * 5));

    newIndex = newIndex > terms.length ? terms.length : (newIndex || 5);

    terms.slice(index, newIndex).forEach(({ term, count, value }) => {
      newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(termCheckbox(facet, paramName, term, value, count));
    });

    facetsWithIndex[facet].index += (newIndex);

    if (terms.length > 5) {
      if (facetsWithIndex[facet].index < terms.length) {
        newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(newFacet.querySelector('.b-facet-box__term-more'));
        newFacet.querySelector(`.${facetTermContainerClass} .b-facet-box__term-more`).onclick = e => revealMoreFacets(e);
      } else {
        newFacet.querySelector(`.${facetTermContainerClass}`).appendChild(newFacet.querySelector('.b-facet-box__term-more')).remove();
      }
    }

    facetBoxContainer.appendChild(newFacet);
  });
};

const newTermToggleEvent = (detail, bubbles = true) => new CustomEvent('termToggle', {
  detail,
  bubbles
});

const initialiseFacetOverlay = () => {
  const toggleTerm = ({ id, facet, term, paramName }) => {
    if (id) {
      // if term already exists, get rid of it
      if (document.querySelector(`div[data-id='${id}']`)) {
        Array.from(document.querySelectorAll(`div[data-id='${id}']`)).forEach(el => el.remove());
        if (!document.querySelector('.b-search-form__facets').children.length) {
          document.querySelector('.b-search-form__facet-pane').classList.remove('b-search-form__facet-pane--active');
        }
        window.dispatchEvent(new Event('resize'));
      } else {
        const newTermOnClick = () => {
          Array.from(document.querySelectorAll(`div[data-id='${id}']`)).forEach(el => el.dispatchEvent(newTermToggleEvent({ id, facet, term, paramName })));
          if (document.querySelector(`li[data-id='${id}']`)) {
            document.querySelector(`li[data-id='${id}']`).dispatchEvent(newTermToggleEvent({ id, facet, term, paramName }));
          }
        };

        const newTerm = document.createElement('DIV');
        newTerm.dataset.id = id;
        newTerm.className = 'b-facet-box__term';
        newTerm.innerHTML = termButtonHTML(facet, term);
        newTerm.onclick = e => newTermOnClick(e);
        termList.appendChild(newTerm);

        const newFormTerm = newTerm.cloneNode(true);
        newFormTerm.onclick = e => newTermOnClick(e);
        newFormTerm.classList.add('b-facet-box__term--form');
        if (document.querySelector('.b-search-form__facets')) {
          document.querySelector('.b-search-form__facets').appendChild(newFormTerm);
        }

        if (!document.querySelector('.b-search-form__facet-pane--active')) {
          document.querySelector('.b-search-form__facet-pane').classList.add('b-search-form__facet-pane--active');
        }

        window.dispatchEvent(new Event('resize'));
      }
    }
  };

  termList.addEventListener('termToggle', (e) => {
    e.stopPropagation();
    toggleTerm(e.detail);
  });

  document.querySelector('.b-facet-box').addEventListener('newFacets', (e) => {
    const { facets, activeFacets } = e.detail;
    const currentBeforeDate = document.querySelector('input[name="before_year"]') ? document.querySelector('input[name="before_year"]').value : '';
    const currentAfterDate = document.querySelector('input[name="after_year"]') ? document.querySelector('input[name="after_year"]').value : '';

    facets.forEach((facet) => {
      Object.assign(facetsWithIndex, {
        [facet.facet]: Object.assign(facet, { index: 0 })
      });
    });

    Array.from(document.querySelectorAll('.b-facet-box__hidden-input')).forEach(el => el.remove());

    const facetBoxContainer = document.querySelector('.b-facet-box__facet-container');
    facetBoxContainer.innerHTML = '';
    termList.innerHTML = '';

    createFacets(activeFacets);

    const dateFacet = document.createElement('DIV');
    dateFacet.className = 'b-facet-box__facet b-facet-box__facet-date';
    dateFacet.innerHTML = dateFacetHTML();
    dateFacet.addEventListener('click', (ev) => {
      if (ev.target.classList.contains(facetTextClass)) {
        ev.target.classList.toggle(`${ev.target.classList[0]}--active`);
        ev.target.parentNode.querySelector(`.${facetTermContainerClass}`).classList.toggle(`${facetTermContainerClass}--active`);
      }
    });
    dateFacet.querySelector('input[name="before_year"]').value = currentBeforeDate;
    dateFacet.querySelector('input[name="after_year"]').value = currentAfterDate;

    facetBoxContainer.append(dateFacet);

    if (activeFacets) {
      // is a set...
      Array.from(activeFacets).forEach((facetId) => {
        const target = document.querySelector(`li[data-id='${facetId}'`);
        if (target) {
          target.dispatchEvent(newTermToggleEvent(Object.assign(target.dataset, {refreshing_page: true})));
          document.querySelector(`.${termListClass}`).dispatchEvent(newTermToggleEvent(target.dataset));
        }
      });
    }

    window.dispatchEvent(new Event('resize'));
  }, true);

  document.onclick = (e) => {
    if (e.target.classList.contains(facetCloseClass)) {
      e.target.dispatchEvent(new Event('closeFacetOverlay', {
        bubbles: true
      }));
    }

    if (e.target.parentElement && e.target.parentElement.classList.contains(facetTerm)) {
      const parent = e.target.closest(facetTerm) || e.target.parentElement;
      termList.dispatchEvent(newTermToggleEvent(parent.dataset, false));
      parent.dispatchEvent(newTermToggleEvent(parent.dataset));
    }
  };
};

(() => {
  if (document.querySelector('.b-facet-box')) {
    initialiseFacetOverlay();

    if (document.querySelector('.b-facet-box__modal-button-open')) {
      document.querySelectorAll('.b-facet-box__modal-button-open').forEach(el => el.addEventListener('click', () => document.querySelector('.b-facet-box').classList.add('b-facet-box--active')));
    }
    if (document.querySelector('.b-facet-box__close-button')) {
      document.querySelector('.b-facet-box__close-button').addEventListener('click', () => document.querySelector('.b-facet-box').classList.remove('b-facet-box--active'));
    }

    window.onresize = () => {
      const facetFormTerms = Array.from(document.querySelectorAll('.b-facet-box__term.b-facet-box__term--form'));
      if (document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross')) {
        if (window.innerWidth > 499 && window.innerWidth < 992) {
          const facetContainerWidth = document.querySelector('.b-search-form__facets').offsetWidth;
          let cutOffWidth = 0;
          let currentIndex = 1;
          facetFormTerms.forEach((el) => {
            cutOffWidth += el.offsetWidth + 10;
            if (cutOffWidth < facetContainerWidth) {
              currentIndex += 1;
            }
          });
          if ((facetFormTerms.length - currentIndex) > 0) {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'block';
          } else {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
          }
          document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross').innerHTML = `+${facetFormTerms.length - currentIndex}`;
        } else if (window.innerWidth < 500) {
          if ((facetFormTerms.length) > 0) {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'block';
          } else {
            document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
          }
          document.querySelector('.b-facet-box__term-text.b-facet-box__term-text--no-cross').innerHTML = `${facetFormTerms.length - 1} filters applied`;
        } else {
          document.querySelector('.b-search-form__facets-mobile').style.display = 'none';
        }
      }
    };
  }
})();
<|endoftext|>


<commit_before>const _ = require('lodash');

const {isNumber} = require('../../lib/utils');
const {CURRENT_SEASON} = require('../../lib/constants');

const RECORD_REGEX = /^\d{1,2}-\d{1,2}$/;
const RECORD_REGEX_WITH_TIES = /^\d{1,2}-\d{1,2}-\d{1,2}$/;

module.exports = (
  {records, season, isHomeGame, weekIndex, completedGameCountForSeason},
  assert,
  ignoredAssert
) => {
  const wrappedAssert = (statement, message) => {
    assert(statement, message, {records, isHomeGame, weekIndex, completedGameCountForSeason});
  };

  const wrappedIgnoredAssert = (statement, message) => {
    ignoredAssert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  if (season <= CURRENT_SEASON) {
    if (season < 2018) {
      // TODO: Fully enable this assert when all completed games have records.
      wrappedIgnoredAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );
    } else {
      wrappedAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );

      if (typeof records !== 'undefined') {
        wrappedAssert(
          _.isEqual(_.keys(records).sort(), ['home', 'away'].sort()),
          'Records object has unexpected keys.'
        );

        ['home', 'away'].forEach((homeOrAway) => {
          const isNdRecord = isHomeGame ? homeOrAway === 'home' : homeOrAway === 'away';
          const homeOrAwayRecords = records[homeOrAway];
          if (typeof homeOrAwayRecords !== 'undefined') {
            wrappedAssert(
              _.isEqual(_.keys(homeOrAwayRecords).sort(), ['overall', 'home', 'away'].sort()),
              `${_.capitalize(homeOrAway)} record has unexpected keys.`
            );

            _.forEach(homeOrAwayRecords, (currentRecord, homeAwayOrOverall) => {
              wrappedAssert(
                currentRecord.match(RECORD_REGEX) || currentRecord.match(RECORD_REGEX_WITH_TIES),
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has invalid format.`
              );

              const currentRecordTokens = currentRecord.split('-');

              const winCount = Number(currentRecordTokens[0]);
              const lossCount = Number(currentRecordTokens[1]);
              const tieCount =
                currentRecordTokens.length === 2 ? 0 : Number(currentRecordTokens[2]);

              wrappedAssert(
                isNumber(winCount) && winCount >= 0,
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has unexpected wins value.`
              );

              wrappedAssert(
                isNumber(lossCount) && lossCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayOrOverall} record has unexpected losses value.`
              );

              wrappedAssert(
                isNumber(tieCount) && tieCount >= 0,
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has unexpected ties value.`
              );

              if (homeAwayOrOverall === 'overall' && isNdRecord) {
                wrappedAssert(
                  winCount + lossCount + tieCount ===
                    Math.min(weekIndex + 1, completedGameCountForSeason),
                  `${_.capitalize(
                    homeOrAway
                  )} ${homeAwayOrOverall} record has unexpected number of games.`
                );
              }
            });
          }
        });
      }
    }
  } else {
    wrappedAssert(
      typeof records === 'undefined',
      'Future season game should not have records object.'
    );
  }
};
<commit_msg>Improved team record validation<commit_after>const _ = require('lodash');

const {isNumber} = require('../../lib/utils');
const {CURRENT_SEASON} = require('../../lib/constants');

const RECORD_REGEX = /^\d{1,2}-\d{1,2}$/;
const RECORD_REGEX_WITH_TIES = /^\d{1,2}-\d{1,2}-\d{1,2}$/;

const _parseRecord = (record) => {
  const recordTokens = record.split('-');

  const winCount = Number(recordTokens[0]);
  const lossCount = Number(recordTokens[1]);
  const tieCount = recordTokens.length === 2 ? 0 : Number(recordTokens[2]);

  return [winCount, lossCount, tieCount];
};

module.exports = (
  {records, season, isHomeGame, weekIndex, opponentId, completedGameCountForSeason},
  assert,
  ignoredAssert
) => {
  const wrappedAssert = (statement, message) => {
    assert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  const wrappedIgnoredAssert = (statement, message) => {
    ignoredAssert(statement, message, {
      records,
      isHomeGame,
      weekIndex,
      completedGameCountForSeason,
    });
  };

  if (season <= CURRENT_SEASON) {
    if (season < 2018) {
      // TODO: Fully enable this assert when all completed games have records.
      wrappedIgnoredAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );
    } else {
      wrappedAssert(
        typeof records !== 'undefined',
        `Current or former season game should have records object.`
      );

      if (typeof records !== 'undefined') {
        wrappedAssert(
          _.isEqual(_.keys(records).sort(), ['home', 'away'].sort()),
          'Records object has unexpected keys.'
        );

        ['home', 'away'].forEach((homeOrAway) => {
          const isNdRecord = isHomeGame ? homeOrAway === 'home' : homeOrAway === 'away';
          const homeOrAwayRecords = records[homeOrAway];
          if (typeof homeOrAwayRecords !== 'undefined') {
            wrappedAssert(
              _.isEqual(_.keys(homeOrAwayRecords).sort(), ['overall', 'home', 'away'].sort()),
              `${_.capitalize(homeOrAway)} record has unexpected keys.`
            );

            // Validate home, away, and overall records.
            _.forEach(homeOrAwayRecords, (currentRecord, homeAwayOrOverall) => {
              wrappedAssert(
                currentRecord.match(RECORD_REGEX) || currentRecord.match(RECORD_REGEX_WITH_TIES),
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has invalid format.`
              );

              const [winCount, lossCount, tieCount] = _parseRecord(currentRecord);

              wrappedAssert(
                isNumber(winCount) && winCount >= 0,
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has unexpected wins value.`
              );

              wrappedAssert(
                isNumber(lossCount) && lossCount >= 0,
                `${_.capitalize(
                  homeOrAway
                )} ${homeAwayOrOverall} record has unexpected losses value.`
              );

              wrappedAssert(
                isNumber(tieCount) && tieCount >= 0,
                `${_.capitalize(homeOrAway)} ${homeAwayOrOverall} record has unexpected ties value.`
              );

              if (homeAwayOrOverall === 'overall') {
                // The number of games Notre Dame has played should be the minimum of the week
                // index (which is 0-indexed; for weeks with completed games) or the completed
                // game count (for upcoming games).
                const ndExpectedGamesPlayed = Math.min(weekIndex + 1, completedGameCountForSeason);

                const gamesPlayedCountFromRecord = winCount + lossCount + tieCount;

                if (isNdRecord) {
                  // ND's actual games played count from their record should equal their expected
                  // games played count.
                  wrappedAssert(
                    gamesPlayedCountFromRecord === ndExpectedGamesPlayed,
                    `${_.capitalize(
                      homeOrAway
                    )} (ND) overall record has unexpected number of games.`
                  );
                } else {
                  // Opponent's actual games played count from their record should be no more than
                  // 1 away from the ND's expected games played count.
                  wrappedAssert(
                    Math.abs(gamesPlayedCountFromRecord - ndExpectedGamesPlayed) <= 1,
                    `${_.capitalize(
                      homeOrAway
                    )} (opponent) overall record has unexpected number of games.`
                  );
                }

                // TODO: Handle neutral site games.
                const [awayWinCount, awayLossCount, awayTieCount] = _parseRecord(
                  records[homeOrAway].away
                );
                const [homeWinCount, homeLossCount, homeTieCount] = _parseRecord(
                  records[homeOrAway].home
                );

                wrappedAssert(
                  gamesPlayedCountFromRecord ===
                    awayWinCount +
                      awayLossCount +
                      awayTieCount +
                      homeWinCount +
                      homeLossCount +
                      homeTieCount,
                  `${_.capitalize(
                    homeOrAway
                  )} overall record has different games played count than their away and home records combined.`
                );
              }
            });
          }
        });
      }
    }
  } else {
    wrappedAssert(
      typeof records === 'undefined',
      'Future season game should not have records object.'
    );
  }
};
<|endoftext|>