<commit_before>// Global config
var GRAPHIC_DEFAULT_WIDTH = 600;
var MOBILE_THRESHOLD = 500;

// Global vars
var pymChild = null;
var isMobile = false;
var graphicData = null;
var graphicConfig = null;

// D3 formatters
var fmtYearAbbrev = d3.time.format('%y');
var fmtYearFull = d3.time.format('%b %Y');

var defaultColors = [ COLORS['blue3'], COLORS['red3'], COLORS['yellow3'], COLORS['orange3'], COLORS['teal3'] ];

/*
 * Initialize graphic
 */
var onWindowLoaded = function() {
    if (Modernizr.svg) {
        graphicConfig = GRAPHIC_CONFIG;
        loadLocalData(GRAPHIC_DATA);

        if (graphicConfig.timeFormatLarge) {
            fmtYearFull = d3.time.format(graphicConfig.timeFormatLarge);
        }

        if (graphicConfig.timeFormatSmall) {
            fmtYearAbbrev = d3.time.format(graphicConfig.timeFormatSmall);
        }
    } else {
        pymChild = new pym.Child({});
    }
}

/*
 * Load graphic data from a local source.
 */
var loadLocalData = function(data) {
    graphicData = data;

    if (graphicData[0].date) {
        formatData();
    }

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

/*
 * Load graphic data from a CSV.
 */
var loadCSV = function(url) {
    d3.csv(GRAPHIC_DATA_URL, function(error, data) {
        graphicData = data;

        if (graphicData[0].date) {
            formatData();
        }

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

/*
 * Format graphic data for processing by D3.
 */
var formatData = function() {
    graphicData.forEach(function(d) {
        var date = d3.time.format('%d/%m/%y').parse(d['date']);
        if (!date) {
            date = d3.time.format('%d/%m/%Y').parse(d['date']);
        }

        d['date'] = date;

        for (var key in d) {
            if (key != 'date') {
                d[key] = +d[key];
            }
        }
    });
}

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function(containerWidth) {
    if (!containerWidth) {
        containerWidth = GRAPHIC_DEFAULT_WIDTH;
    }

    if (containerWidth <= MOBILE_THRESHOLD) {
        isMobile = true;
    } else {
        isMobile = false;
    }

    // Render the chart!
    renderLineChart({
        container: '#graphic',
        width: containerWidth,
        data: graphicData
    });

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

/*
 * Render a line chart.
 */
var renderLineChart = function(config) {
    /*
     * Setup
     */
    var dateColumn = 'date';
    var valueColumn = 'amt';

    var aspectWidth = isMobile ? 4 : 16;
    var aspectHeight = isMobile ? 3 : 9;
    if ('ratio' in graphicConfig) {
        var parts = graphicConfig.ratio.split("x");
        aspectWidth = parseInt(parts[0], 10);
        aspectHeight = parseInt(parts[1], 10);
    }

    var margins = {
        top: 5,
        right: 80,
        bottom: 20,
        left: 30
    };

    if (graphicConfig.marginTop) {
        margins.top = parseInt(graphicConfig.marginTop, 10);
    }

    if (graphicConfig.marginRight) {
        margins.right = parseInt(graphicConfig.marginRight, 10);
    }

    if (graphicConfig.marginBottom) {
        margins.bottom = parseInt(graphicConfig.marginBottom, 10);
    }

    if (graphicConfig.marginLeft) {
        margins.left = parseInt(graphicConfig.marginLeft, 10);
    }

    var ticksX = parseInt(graphicConfig.ticksX || 10, 10);
    var ticksY = parseInt(graphicConfig.ticksY || 10, 10);
    var roundTicksFactor = parseInt(graphicConfig.roundTicksFactor || 5, 10);

    // Mobile
    if (isMobile) {
        ticksX = 5;
        ticksY = 5;
        margins['right'] = 25;
    }

    // Calculate actual chart dimensions
    var chartWidth = config['width'] - margins['left'] - margins['right'];
    var chartHeight = Math.ceil((config['width'] * aspectHeight) / aspectWidth) - margins['top'] - margins['bottom'];

    // Clear existing graphic (for redraw)
    var containerElement = d3.select(config['container']);
    containerElement.html('');

    var formattedData = {};

    /*
     * Restructure tabular data for easier charting.
     */
    for (var column in graphicData[0]) {
        if (column == dateColumn) {
            continue;
        }

        formattedData[column] = graphicData.map(function(d) {
            return {
                'x': d[dateColumn] || d['x'],
                'amt': d[column]
            };
        });
    }

    /*
     * Create D3 scale objects.
     */

    var minY = 'minValue' in graphicConfig ? parseFloat(graphicConfig.minValue, 10) : d3.min(d3.entries(formattedData), function(c) {
        return d3.min(c['value'], function(v) {
            var n = v[valueColumn];
            return Math.floor(n / roundTicksFactor) * roundTicksFactor;
        });
    });

    var maxY = 'maxValue' in graphicConfig ? parseFloat(graphicConfig.maxValue, 10) : d3.max(d3.entries(formattedData), function(c) {
        return d3.max(c['value'], function(v) {
            var n = v[valueColumn];
            return Math.ceil(n / roundTicksFactor) * roundTicksFactor;
        });
    });

    var xFormat;
    var xScale;

    if (formattedData['date']) {
        xFormat = function(d, i) {
            if (isMobile) {
                return '\u2019' + fmtYearAbbrev(d);
            } else {
                return fmtYearFull(d);
            }
        };

        xScale = d3.time.scale()
        .domain(d3.extent(config['data'], function(d) {
            return d[dateColumn];
        }))
        .range([ 0, chartWidth ])
    } else {
        xFormat = function (d, i) {
            return d;
        };

        xScale = d3.scale.ordinal()
        .rangeRoundBands([0, chartWidth], .1)
        .domain(graphicData.map(function (d) {
            return d['x'];
        }));
    }

    var yScale = d3.scale.linear()
        .domain([ minY, maxY ])
        .range([ chartHeight, 0 ]);

    var colorList = defaultColors;
    if ('colors' in graphicConfig) {
        colorList = graphicConfig.colors.split(/\s*,\s*/);
    }

    var colorScale = d3.scale.ordinal()
        .domain([0, colorList.length])
        .range(colorList);

    /*
     * Render the HTML legend.
     */
    var legend = containerElement.append('ul')
        .attr('class', 'key')
        .selectAll('g')
            .data(d3.entries(formattedData))
        .enter().append('li')
            .attr('class', function(d, i) {
                return 'key-item key-' + i + ' ' + classify(d['key']);
            });

    legend.append('b')
        .style('background-color', function(d) {
            return colorScale(d['key']);
        });

    legend.append('label')
        .text(function(d) {
            return d['key'];
        });

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

    var chartElement = chartWrapper.append('svg')
        .attr('width', chartWidth + margins['left'] + margins['right'])
        .attr('height', chartHeight + margins['top'] + margins['bottom'])
        .append('g')
        .attr('transform', 'translate(' + margins['left'] + ',' + margins['top'] + ')');

    /*
     * Create D3 axes.
     */
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(ticksX)
        .tickFormat(xFormat);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(ticksY)
        .tickFormat(function (d) {
            return (graphicConfig.prefixY || '') + d + (graphicConfig.suffixY || '');
        });

    /*
     * Render axes to chart.
     */
    chartElement.append('g')
        .attr('class', 'x axis')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxis);

    chartElement.append('g')
        .attr('class', 'y axis')
        .call(yAxis);

    /*
     * Render grid to chart.
     */
    var xAxisGrid = function() {
        return xAxis;
    }

    var yAxisGrid = function() {
        return yAxis;
    }

    chartElement.append('g')
        .attr('class', 'x grid')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxisGrid()
            .tickSize(-chartHeight, 0, 0)
            .tickFormat('')
        );

    chartElement.append('g')
        .attr('class', 'y grid')
        .call(yAxisGrid()
            .tickSize(-chartWidth, 0, 0)
            .tickFormat('')
        );

    /*
     * Render lines to chart.
     */
    var line = d3.svg.line()
        .interpolate(graphicConfig.interpolate || 'monotone')
        .x(function(d) {
            return xScale(d[dateColumn] || d['x']);
        })
        .y(function(d) {
            return yScale(d[valueColumn]);
        });

    chartElement.append('g')
        .attr('class', 'lines')
        .selectAll('path')
        .data(d3.entries(formattedData))
        .enter()
        .append('path')
            .attr('class', function(d, i) {
                return 'line line-' + i + ' ' + classify(d['key']);
            })
            .attr('stroke', function(d) {
                return colorScale(d['key']);
            })
            .attr('d', function(d) {
                return line(d['value']);
            });

    chartElement.append('g')
        .attr('class', 'value')
        .selectAll('text')
        .data(d3.entries(formattedData))
        .enter().append('text')
            .attr('x', function(d, i) {
                var last = d['value'][d['value'].length - 1];

                return xScale(last[dateColumn]) + 5;
            })
            .attr('y', function(d) {
                var last = d['value'][d['value'].length - 1];

                return yScale(last[valueColumn]) + 3;
            })
            .text(function(d) {
                var last = d['value'][d['value'].length - 1];
                var value = last[valueColumn];

                var label = last[valueColumn].toFixed(1);

                if (!isMobile) {
                    label = d['key'] + ': ' + label;
                }

                return label;
            });
}

/*
 * Initially load the graphic
 * (NB: Use window.load to ensure all images have loaded)
 */
window.onload = onWindowLoaded;
<commit_msg>* Skip x<commit_after>// Global config
var GRAPHIC_DEFAULT_WIDTH = 600;
var MOBILE_THRESHOLD = 500;

// Global vars
var pymChild = null;
var isMobile = false;
var graphicData = null;
var graphicConfig = null;

// D3 formatters
var fmtYearAbbrev = d3.time.format('%y');
var fmtYearFull = d3.time.format('%b %Y');

var defaultColors = [ COLORS['blue3'], COLORS['red3'], COLORS['yellow3'], COLORS['orange3'], COLORS['teal3'] ];

/*
 * Initialize graphic
 */
var onWindowLoaded = function() {
    if (Modernizr.svg) {
        graphicConfig = GRAPHIC_CONFIG;
        loadLocalData(GRAPHIC_DATA);

        if (graphicConfig.timeFormatLarge) {
            fmtYearFull = d3.time.format(graphicConfig.timeFormatLarge);
        }

        if (graphicConfig.timeFormatSmall) {
            fmtYearAbbrev = d3.time.format(graphicConfig.timeFormatSmall);
        }
    } else {
        pymChild = new pym.Child({});
    }
}

/*
 * Load graphic data from a local source.
 */
var loadLocalData = function(data) {
    graphicData = data;

    if (graphicData[0].date) {
        formatData();
    }

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

/*
 * Load graphic data from a CSV.
 */
var loadCSV = function(url) {
    d3.csv(GRAPHIC_DATA_URL, function(error, data) {
        graphicData = data;

        if (graphicData[0].date) {
            formatData();
        }

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

/*
 * Format graphic data for processing by D3.
 */
var formatData = function() {
    graphicData.forEach(function(d) {
        var date = d3.time.format('%d/%m/%y').parse(d['date']);
        if (!date) {
            date = d3.time.format('%d/%m/%Y').parse(d['date']);
        }

        d['date'] = date;

        for (var key in d) {
            if (key != 'date') {
                d[key] = +d[key];
            }
        }
    });
}

/*
 * Render the graphic(s). Called by pym with the container width.
 */
var render = function(containerWidth) {
    if (!containerWidth) {
        containerWidth = GRAPHIC_DEFAULT_WIDTH;
    }

    if (containerWidth <= MOBILE_THRESHOLD) {
        isMobile = true;
    } else {
        isMobile = false;
    }

    // Render the chart!
    renderLineChart({
        container: '#graphic',
        width: containerWidth,
        data: graphicData
    });

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

/*
 * Render a line chart.
 */
var renderLineChart = function(config) {
    /*
     * Setup
     */
    var dateColumn = 'date';
    var valueColumn = 'amt';

    var aspectWidth = isMobile ? 4 : 16;
    var aspectHeight = isMobile ? 3 : 9;
    if ('ratio' in graphicConfig) {
        var parts = graphicConfig.ratio.split("x");
        aspectWidth = parseInt(parts[0], 10);
        aspectHeight = parseInt(parts[1], 10);
    }

    var margins = {
        top: 5,
        right: 80,
        bottom: 20,
        left: 30
    };

    if (graphicConfig.marginTop) {
        margins.top = parseInt(graphicConfig.marginTop, 10);
    }

    if (graphicConfig.marginRight) {
        margins.right = parseInt(graphicConfig.marginRight, 10);
    }

    if (graphicConfig.marginBottom) {
        margins.bottom = parseInt(graphicConfig.marginBottom, 10);
    }

    if (graphicConfig.marginLeft) {
        margins.left = parseInt(graphicConfig.marginLeft, 10);
    }

    var ticksX = parseInt(graphicConfig.ticksX || 10, 10);
    var ticksY = parseInt(graphicConfig.ticksY || 10, 10);
    var roundTicksFactor = parseInt(graphicConfig.roundTicksFactor || 5, 10);

    // Mobile
    if (isMobile) {
        ticksX = 5;
        ticksY = 5;
        margins['right'] = 25;
    }

    // Calculate actual chart dimensions
    var chartWidth = config['width'] - margins['left'] - margins['right'];
    var chartHeight = Math.ceil((config['width'] * aspectHeight) / aspectWidth) - margins['top'] - margins['bottom'];

    // Clear existing graphic (for redraw)
    var containerElement = d3.select(config['container']);
    containerElement.html('');

    var formattedData = {};

    /*
     * Restructure tabular data for easier charting.
     */
    for (var column in graphicData[0]) {
        if (column == dateColumn || column == 'x') {
            continue;
        }

        formattedData[column] = graphicData.map(function(d) {
            return {
                'x': d[dateColumn] || d['x'],
                'amt': d[column]
            };
        });
    }

    /*
     * Create D3 scale objects.
     */

    var minY = 'minValue' in graphicConfig ? parseFloat(graphicConfig.minValue, 10) : d3.min(d3.entries(formattedData), function(c) {
        return d3.min(c['value'], function(v) {
            var n = v[valueColumn];
            return Math.floor(n / roundTicksFactor) * roundTicksFactor;
        });
    });

    var maxY = 'maxValue' in graphicConfig ? parseFloat(graphicConfig.maxValue, 10) : d3.max(d3.entries(formattedData), function(c) {
        return d3.max(c['value'], function(v) {
            var n = v[valueColumn];
            return Math.ceil(n / roundTicksFactor) * roundTicksFactor;
        });
    });

    var xFormat;
    var xScale;

    if (formattedData['date']) {
        xFormat = function(d, i) {
            if (isMobile) {
                return '\u2019' + fmtYearAbbrev(d);
            } else {
                return fmtYearFull(d);
            }
        };

        xScale = d3.time.scale()
        .domain(d3.extent(config['data'], function(d) {
            return d[dateColumn];
        }))
        .range([ 0, chartWidth ])
    } else {
        xFormat = function (d, i) {
            return d;
        };

        xScale = d3.scale.ordinal()
        .rangeRoundBands([0, chartWidth], .1)
        .domain(graphicData.map(function (d) {
            return d['x'];
        }));
    }

    var yScale = d3.scale.linear()
        .domain([ minY, maxY ])
        .range([ chartHeight, 0 ]);

    var colorList = defaultColors;
    if ('colors' in graphicConfig) {
        colorList = graphicConfig.colors.split(/\s*,\s*/);
    }

    var colorScale = d3.scale.ordinal()
        .domain([0, colorList.length])
        .range(colorList);

    /*
     * Render the HTML legend.
     */
    var legend = containerElement.append('ul')
        .attr('class', 'key')
        .selectAll('g')
            .data(d3.entries(formattedData))
        .enter().append('li')
            .attr('class', function(d, i) {
                return 'key-item key-' + i + ' ' + classify(d['key']);
            });

    legend.append('b')
        .style('background-color', function(d) {
            return colorScale(d['key']);
        });

    legend.append('label')
        .text(function(d) {
            return d['key'];
        });

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

    var chartElement = chartWrapper.append('svg')
        .attr('width', chartWidth + margins['left'] + margins['right'])
        .attr('height', chartHeight + margins['top'] + margins['bottom'])
        .append('g')
        .attr('transform', 'translate(' + margins['left'] + ',' + margins['top'] + ')');

    /*
     * Create D3 axes.
     */
    var xAxis = d3.svg.axis()
        .scale(xScale)
        .orient('bottom')
        .ticks(ticksX)
        .tickFormat(xFormat);

    var yAxis = d3.svg.axis()
        .scale(yScale)
        .orient('left')
        .ticks(ticksY)
        .tickFormat(function (d) {
            return (graphicConfig.prefixY || '') + d + (graphicConfig.suffixY || '');
        });

    /*
     * Render axes to chart.
     */
    chartElement.append('g')
        .attr('class', 'x axis')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxis);

    chartElement.append('g')
        .attr('class', 'y axis')
        .call(yAxis);

    /*
     * Render grid to chart.
     */
    var xAxisGrid = function() {
        return xAxis;
    }

    var yAxisGrid = function() {
        return yAxis;
    }

    chartElement.append('g')
        .attr('class', 'x grid')
        .attr('transform', makeTranslate(0, chartHeight))
        .call(xAxisGrid()
            .tickSize(-chartHeight, 0, 0)
            .tickFormat('')
        );

    chartElement.append('g')
        .attr('class', 'y grid')
        .call(yAxisGrid()
            .tickSize(-chartWidth, 0, 0)
            .tickFormat('')
        );

    /*
     * Render lines to chart.
     */
    var line = d3.svg.line()
        .interpolate(graphicConfig.interpolate || 'monotone')
        .x(function(d) {
            return xScale(d[dateColumn] || d['x']);
        })
        .y(function(d) {
            return yScale(d[valueColumn]);
        });

    chartElement.append('g')
        .attr('class', 'lines')
        .selectAll('path')
        .data(d3.entries(formattedData))
        .enter()
        .append('path')
            .attr('class', function(d, i) {
                return 'line line-' + i + ' ' + classify(d['key']);
            })
            .attr('stroke', function(d) {
                return colorScale(d['key']);
            })
            .attr('d', function(d) {
                return line(d['value']);
            });

    chartElement.append('g')
        .attr('class', 'value')
        .selectAll('text')
        .data(d3.entries(formattedData))
        .enter().append('text')
            .attr('x', function(d, i) {
                var last = d['value'][d['value'].length - 1];

                return xScale(last[dateColumn]) + 5;
            })
            .attr('y', function(d) {
                var last = d['value'][d['value'].length - 1];

                return yScale(last[valueColumn]) + 3;
            })
            .text(function(d) {
                var last = d['value'][d['value'].length - 1];
                var value = last[valueColumn];

                var label = last[valueColumn].toFixed(1);

                if (!isMobile) {
                    label = d['key'] + ': ' + label;
                }

                return label;
            });
}

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


<commit_before>/**
 * Copyright (c) 2017 Ali Lokhandwala <ali@huestones.co.uk>. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const _ = require('lodash');
const moment = require('moment');
const shared = require('../lib/shared');

exports.load = load;
exports.search = search;

//--

function load(program) {
  program.command('search <file> [string]')
    .description('search for matching intents and entities within the conversation file')
    .option('-b, --before [date]', 'limit search to items modified (or created) before selected date', moment)
    .option('-a, --after [date]', 'limit search to items modified (or created) after selected date', moment)
    .option('-c, --created', 'use creation date instead of modification date for all date filters', moment)
    .option('-i, --ignorecase', 'perform case insensitive search with string')
    .option('-n, --intents', 'limit search to intents')
    .option('-e, --entities', 'limit search to entities')
    .option('-m, --node <node>', 'specify the node ID to be searched', null)
    .option('-o, --only', 'use in conjunction with -n or -e to output only intents or entities')
    .option('-p, --pretty', 'make the output look pretty')
    .action(program.play(search));
}

function search(program, file, string, options) {
  var workspace = shared.loadWorkspace(file);
  let re = string ? new RegExp(string, options.ignorecase ? 'gi' : 'g') : null;

  if (options.intents && options.entities) {
    options.intents = options.entities = false;
  }

  if (!options.entities) {
    if (options.before && options.before.isValid()) {
      workspace.intents.forEach(intent =>
        _.remove(intent.examples, ex =>
          options.before.isBefore(options.created ? ex.created : ex.updated)));

      _.remove(workspace.intents, i =>
        !i.examples.length && options.before.isBefore(options.created ? i.created : i.updated));
    }

    if (options.after && options.after.isValid()) {
      workspace.intents.forEach(intent =>
        _.remove(intent.examples, ex =>
          options.after.isAfter(options.created ? ex.created : ex.updated)));

      _.remove(workspace.intents, i =>
        !i.examples.length && options.after.isAfter(options.created ? i.created : i.updated));
    }

    if (string) {
      workspace.intents.forEach(i =>
        _.remove(i.examples, e => !re.test(i.intent) && !re.test(e.text))
      );

      _.remove(workspace.intents, i => !i.examples.length && !re.test(i.intent));
    }
  }

  if (!options.intents) {
    if (options.before && options.before.isValid()) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          options.before.isBefore(options.created ? v.created : v.updated)));

      _.remove(workspace.entities, e =>
        !e.values.length && options.before.isBefore(options.created ? e.created : e.updated));
    }

    if (options.after && options.after.isValid()) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          options.after.isAfter(options.created ? v.created : v.updated)));

      _.remove(workspace.entities, e =>
        !e.values.length && options.after.isAfter(options.created ? e.created : e.updated));
    }

    if (string) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          !re.test(entity.entity) && !re.test(v.value) && !_.filter(v.synonyms, s => re.test(s)).length));

      _.remove(workspace.entities, e => !re.test(e.entity) && !e.values.length);
    }
  }

  if (options.only) {
    workspace.dialog_nodes = [];

    if (options.intents) {
      workspace.entities = [];
    }
    if (options.entities) {
      workspace.intents = [];
    }
  }

  if (options.node) {
    var nodeID = program.args[2].node;
    var allNodes = workspace.dialog_nodes;
    workspace = {};

    var yourNode = (_.find(allNodes, {'dialog_node': nodeID})) || {};
    var parentNode = (_.find(allNodes, {'dialog_node': yourNode.parent})) || {};
    var nextStep = {};
    if (yourNode.next_step) {
      nextStep = (_.find(allNodes, {'dialog_node': yourNode.next_step.dialog_node})) || {};
    }

    workspace.PARENT_NODE = parentNode;
    workspace.sep1 = '============================';
    workspace.YOUR_NODE = yourNode;
    workspace.sep2 = '============================';
    workspace.NEXT_STEP = nextStep;
  }

  program.out(JSON.stringify(workspace, null, options.pretty ? 2 : null));
}
<commit_msg>Variable name refactoring<commit_after>/**
 * Copyright (c) 2017 Ali Lokhandwala <ali@huestones.co.uk>. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

'use strict';

const _ = require('lodash');
const moment = require('moment');
const shared = require('../lib/shared');

exports.load = load;
exports.search = search;

//--

function load(program) {
  program.command('search <file> [string]')
    .description('search for matching intents and entities within the conversation file')
    .option('-b, --before [date]', 'limit search to items modified (or created) before selected date', moment)
    .option('-a, --after [date]', 'limit search to items modified (or created) after selected date', moment)
    .option('-c, --created', 'use creation date instead of modification date for all date filters', moment)
    .option('-i, --ignorecase', 'perform case insensitive search with string')
    .option('-n, --intents', 'limit search to intents')
    .option('-e, --entities', 'limit search to entities')
    .option('-m, --node <node>', 'specify the node ID to be searched', null)
    .option('-o, --only', 'use in conjunction with -n or -e to output only intents or entities')
    .option('-p, --pretty', 'make the output look pretty')
    .action(program.play(search));
}

function search(program, file, string, options) {
  var workspace = shared.loadWorkspace(file);
  let re = string ? new RegExp(string, options.ignorecase ? 'gi' : 'g') : null;

  if (options.intents && options.entities) {
    options.intents = options.entities = false;
  }

  if (!options.entities) {
    if (options.before && options.before.isValid()) {
      workspace.intents.forEach(intent =>
        _.remove(intent.examples, ex =>
          options.before.isBefore(options.created ? ex.created : ex.updated)));

      _.remove(workspace.intents, i =>
        !i.examples.length && options.before.isBefore(options.created ? i.created : i.updated));
    }

    if (options.after && options.after.isValid()) {
      workspace.intents.forEach(intent =>
        _.remove(intent.examples, ex =>
          options.after.isAfter(options.created ? ex.created : ex.updated)));

      _.remove(workspace.intents, i =>
        !i.examples.length && options.after.isAfter(options.created ? i.created : i.updated));
    }

    if (string) {
      workspace.intents.forEach(i =>
        _.remove(i.examples, e => !re.test(i.intent) && !re.test(e.text))
      );

      _.remove(workspace.intents, i => !i.examples.length && !re.test(i.intent));
    }
  }

  if (!options.intents) {
    if (options.before && options.before.isValid()) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          options.before.isBefore(options.created ? v.created : v.updated)));

      _.remove(workspace.entities, e =>
        !e.values.length && options.before.isBefore(options.created ? e.created : e.updated));
    }

    if (options.after && options.after.isValid()) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          options.after.isAfter(options.created ? v.created : v.updated)));

      _.remove(workspace.entities, e =>
        !e.values.length && options.after.isAfter(options.created ? e.created : e.updated));
    }

    if (string) {
      workspace.entities.forEach(entity =>
        _.remove(entity.values, v =>
          !re.test(entity.entity) && !re.test(v.value) && !_.filter(v.synonyms, s => re.test(s)).length));

      _.remove(workspace.entities, e => !re.test(e.entity) && !e.values.length);
    }
  }

  if (options.only) {
    workspace.dialog_nodes = [];

    if (options.intents) {
      workspace.entities = [];
    }
    if (options.entities) {
      workspace.intents = [];
    }
  }

  if (options.node) {
    var nodeId = options.node;
    var allNodes = workspace.dialog_nodes;
    workspace = {};

    var yourNode = (_.find(allNodes, {'dialog_node': nodeId})) || {};
    var parentNode = (_.find(allNodes, {'dialog_node': yourNode.parent})) || {};
    var nextStep = {};
    if (yourNode.next_step) {
      nextStep = (_.find(allNodes, {'dialog_node': yourNode.next_step.dialog_node})) || {};
    }

    workspace.PARENT_NODE = parentNode;
    workspace.sep1 = '============================';
    workspace.YOUR_NODE = yourNode;
    workspace.sep2 = '============================';
    workspace.NEXT_STEP = nextStep;
  }

  program.out(JSON.stringify(workspace, null, options.pretty ? 2 : null));
}
<|endoftext|>


<commit_before>define(['sprd/view/svg/ConfigurationRenderer', "sprd/data/ImageService"], function (Renderer, ImageService) {

    return Renderer.inherit("sprd.view.svg.DesignConfigurationRenderer", {

        defaults: {
            tagName: "image",
            href: "{url()}"
        },

        ctor: function() {
            this.callBase();

            this.bind("configuration.printColors", "reset", function() {
                this.trigger("designColorsChanged");
            }, this);
        },

        inject: {
            imageService: ImageService
        },

        url: function () {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design && this.$.configuration.$.printColors) {
                var options = {
                    width: this.$._width,
                    height: this.$._height
                };

                if (!this.$.configuration.hasDefaultColors()) {
                    options.printColors =  this.$.configuration.getPrintColorsAsRGB();
                }

                return this.$.imageService.designImage(this.$.configuration.$.design.$.id, options);
            }

            return null;
        }.onChange("design").on("designColorsChanged")

    })
});<commit_msg>simplified on<commit_after>define(['sprd/view/svg/ConfigurationRenderer', "sprd/data/ImageService"], function (Renderer, ImageService) {

    return Renderer.inherit("sprd.view.svg.DesignConfigurationRenderer", {

        defaults: {
            tagName: "image",
            href: "{url()}"
        },

        inject: {
            imageService: ImageService
        },

        url: function () {

            if (this.$.imageService && this.$.configuration && this.$.configuration.$.design && this.$.configuration.$.printColors) {
                var options = {
                    width: this.$._width,
                    height: this.$._height
                };

                if (!this.$.configuration.hasDefaultColors()) {
                    options.printColors =  this.$.configuration.getPrintColorsAsRGB();
                }

                return this.$.imageService.designImage(this.$.configuration.$.design.$.id, options);
            }

            return null;
        }.onChange("design").on(["configuration.printColors", "reset"])

    })
});<|endoftext|>


<commit_before>import {
  getScrollingElement,
  getTargetScrollOffset,
  getElementsInContainerViewport,
  elementFillsContainer,
  passiveIsSupported,
} from './utilities';

const SCREEN_WIDTH = 800;
const SCREEN_HEIGHT = 600;

Object.defineProperty(document.documentElement, 'clientWidth', { value: SCREEN_WIDTH });
Object.defineProperty(document.documentElement, 'clientHeight', { value: SCREEN_HEIGHT });

describe('getScrolllingElement', () => {
  test('returns same element when container is not body', () => {
    const container = document.createElement('div');
    expect(getScrollingElement(container)).toBe(container);
  });

  test('returns scrollingElement when container is body on modern browser', () => {
    const container = document.body;
    const scrollContainer = document.createElement('div');
    document.scrollingElement = scrollContainer;
    expect(getScrollingElement(container)).toBe(scrollContainer);

    // TODO: Jest should clean this up...
    delete document.scrollingElement;
  });

  test('returns same element when container is body on WebKit browser', () => {
    Object.defineProperty(window.navigator, 'userAgent', { value: 'WebKit', configurable: true });
    const container = document.body;
    expect(getScrollingElement(container)).toBe(container);
  });

  test('returns document element when container is body on legacy browser', () => {
    Object.defineProperty(window.navigator, 'userAgent', { value: 'legacy browser', configurable: true });
    const container = document.body;
    const scrollContainer = document.documentElement;
    expect(getScrollingElement(container)).toBe(scrollContainer);
  });
});

describe('getTargetScrollOffset', () => {
  function testElements(options) {
    const {
      scrollOffset,
      containerDimensions,
      targetDimensions,
      expectedResult,
      toBottom,
      toRight,
    } = options;

    const container = document.createElement('div');
    container.scrollTop = scrollOffset.top;
    container.scrollLeft = scrollOffset.left;
    container.getBoundingClientRect = () => ({
      ...containerDimensions,
      height: containerDimensions.bottom - containerDimensions.top,
      width: containerDimensions.right - containerDimensions.left,
    });

    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      ...targetDimensions,
      height: targetDimensions.bottom - targetDimensions.top,
      width: targetDimensions.right - targetDimensions.left,
    });

    expect(getTargetScrollOffset(container, target, !!toBottom, !!toRight)).toEqual(expectedResult);
  }

  test('calculates scrollOffset for target element', () => {
    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 0, left: 0 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: -100, left: -100 },
      expectedResult: { top: 0, left: 0 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 100, left: 100 },
    });

    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 200, left: 200 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 100, left: 100 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });
  });

  test('calculates scrollOffset for target element bottom', () => {
    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: -100, bottom: 200, left: -100, right: 200,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 200, left: 200 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });
  });

  function testBodyElements(options) {
    const {
      scrollOffset,
      targetDimensions,
      expectedResult,
      toBottom,
      toRight,
    } = options;

    const container = document.body;
    getScrollingElement(document.body).scrollTop = scrollOffset.top;
    getScrollingElement(document.body).scrollLeft = scrollOffset.left;

    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      ...targetDimensions,
      height: targetDimensions.bottom - targetDimensions.top,
      width: targetDimensions.right - targetDimensions.left,
    });

    expect(getTargetScrollOffset(container, target, !!toBottom, !!toRight)).toEqual(expectedResult);
  }

  test('calculates scrollOffset for target element in body', () => {
    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 0, left: 0 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: -100, left: -100 },
      expectedResult: { top: 0, left: 0 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 100, left: 100 },
    });

    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 200, left: 200 },
    });
  });

  test('calculates scrollOffset for target element bottom in body', () => {
    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: {
        top: 0,
        left: 0,
        bottom: SCREEN_HEIGHT,
        right: SCREEN_WIDTH,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: -100,
        left: -100,
        bottom: SCREEN_HEIGHT - 100,
        right: SCREEN_WIDTH - 100,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: 0,
        left: 0,
        bottom: SCREEN_HEIGHT,
        right: SCREEN_WIDTH,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: {
        top: 100,
        left: 100,
        bottom: SCREEN_HEIGHT + 100,
        right: SCREEN_WIDTH + 100,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: 100,
        left: 100,
        bottom: SCREEN_HEIGHT + 100,
        right: SCREEN_WIDTH + 100,
      },
      expectedResult: { top: 200, left: 200 },
      toBottom: true,
      toRight: true,
    });
  });
});

describe('getElementsInContainerViewport', () => {
  function getElements(scrollOffset, amountOfElements, elementSize, horizontal = false) {
    return Array.from(Array(amountOfElements), (_, i) => {
      const target = document.createElement('div');
      const elementOffset = (i * elementSize) - scrollOffset;
      target.getBoundingClientRect = () => ({
        top: horizontal ? 0 : elementOffset,
        bottom: horizontal ? SCREEN_HEIGHT : elementOffset + elementSize,
        left: horizontal ? elementOffset : 0,
        right: horizontal ? elementOffset + elementSize : SCREEN_WIDTH,
      });

      return target;
    });
  }

  test('finds vertical elements in body viewport', () => {
    const test1 = getElementsInContainerViewport(document.body, getElements(0, 5, 300));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(document.body, getElements(200, 5, 300));
    expect(test2).toHaveLength(3);

    const test3 = getElementsInContainerViewport(document.body, getElements(600, 3, 300));
    expect(test3).toHaveLength(1);
  });

  test('finds horizontal elements in body viewport', () => {
    const test1 = getElementsInContainerViewport(document.body, getElements(0, 5, 400, true));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(document.body, getElements(200, 5, 400, true));
    expect(test2).toHaveLength(3);

    const test3 = getElementsInContainerViewport(document.body, getElements(800, 3, 400, true));
    expect(test3).toHaveLength(1);
  });

  test('finds vertical elements in non-body viewport', () => {
    const container = getElements(0, 1, 400)[0];

    const test1 = getElementsInContainerViewport(container, getElements(0, 5, 300));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(container, getElements(0, 5, 400));
    expect(test2).toHaveLength(1);
  });

  test('finds horizontal elements in non-body viewport', () => {
    const container = getElements(0, 1, 400, true)[0];

    const test1 = getElementsInContainerViewport(container, getElements(0, 5, 300, true));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(container, getElements(0, 5, 400, true));
    expect(test2).toHaveLength(1);
  });
});

describe('elementFillsContainer', () => {
  function getElement(top, bottom, left = 0, right = SCREEN_WIDTH) {
    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      top, bottom, left, right,
    });

    return target;
  }

  test('checks element in body viewport', () => {
    expect(elementFillsContainer(document.body, getElement(-100, SCREEN_HEIGHT + 100))).toBe(true);
    expect(elementFillsContainer(document.body, getElement(0, SCREEN_HEIGHT))).toBe(true);
    expect(elementFillsContainer(document.body, getElement(1, SCREEN_HEIGHT + 1))).toBe(false);
    expect(elementFillsContainer(document.body, getElement(-1, SCREEN_HEIGHT - 1))).toBe(false);
  });

  test('checks element in non-body viewport', () => {
    const container = getElement(200, 500);
    expect(elementFillsContainer(container, getElement(100, 600))).toBe(true);
    expect(elementFillsContainer(container, getElement(200, 500))).toBe(true);
    expect(elementFillsContainer(container, getElement(201, 501))).toBe(false);
    expect(elementFillsContainer(container, getElement(99, 499))).toBe(false);
  });
});

describe('isPassiveSupported', () => {
  test('returns false in JSDOM', () => {
    expect(passiveIsSupported).toBe(false);
  });
});
<commit_msg>test: account for new jsdom version now suppporting passive events<commit_after>import {
  getScrollingElement,
  getTargetScrollOffset,
  getElementsInContainerViewport,
  elementFillsContainer,
  passiveIsSupported,
} from './utilities';

const SCREEN_WIDTH = 800;
const SCREEN_HEIGHT = 600;

Object.defineProperty(document.documentElement, 'clientWidth', { value: SCREEN_WIDTH });
Object.defineProperty(document.documentElement, 'clientHeight', { value: SCREEN_HEIGHT });

describe('getScrolllingElement', () => {
  test('returns same element when container is not body', () => {
    const container = document.createElement('div');
    expect(getScrollingElement(container)).toBe(container);
  });

  test('returns scrollingElement when container is body on modern browser', () => {
    const container = document.body;
    const scrollContainer = document.createElement('div');
    document.scrollingElement = scrollContainer;
    expect(getScrollingElement(container)).toBe(scrollContainer);

    // TODO: Jest should clean this up...
    delete document.scrollingElement;
  });

  test('returns same element when container is body on WebKit browser', () => {
    Object.defineProperty(window.navigator, 'userAgent', { value: 'WebKit', configurable: true });
    const container = document.body;
    expect(getScrollingElement(container)).toBe(container);
  });

  test('returns document element when container is body on legacy browser', () => {
    Object.defineProperty(window.navigator, 'userAgent', { value: 'legacy browser', configurable: true });
    const container = document.body;
    const scrollContainer = document.documentElement;
    expect(getScrollingElement(container)).toBe(scrollContainer);
  });
});

describe('getTargetScrollOffset', () => {
  function testElements(options) {
    const {
      scrollOffset,
      containerDimensions,
      targetDimensions,
      expectedResult,
      toBottom,
      toRight,
    } = options;

    const container = document.createElement('div');
    container.scrollTop = scrollOffset.top;
    container.scrollLeft = scrollOffset.left;
    container.getBoundingClientRect = () => ({
      ...containerDimensions,
      height: containerDimensions.bottom - containerDimensions.top,
      width: containerDimensions.right - containerDimensions.left,
    });

    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      ...targetDimensions,
      height: targetDimensions.bottom - targetDimensions.top,
      width: targetDimensions.right - targetDimensions.left,
    });

    expect(getTargetScrollOffset(container, target, !!toBottom, !!toRight)).toEqual(expectedResult);
  }

  test('calculates scrollOffset for target element', () => {
    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 0, left: 0 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: -100, left: -100 },
      expectedResult: { top: 0, left: 0 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 100, left: 100 },
    });

    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 200, left: 200 },
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: { top: 100, left: 100 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });
  });

  test('calculates scrollOffset for target element bottom', () => {
    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: -100, bottom: 200, left: -100, right: 200,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 0, left: 0 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 0, bottom: 300, left: 0, right: 300,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 200, left: 200 },
      toBottom: true,
      toRight: true,
    });

    testElements({
      scrollOffset: { top: 100, left: 100 },
      containerDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      targetDimensions: {
        top: 100, bottom: 400, left: 100, right: 400,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });
  });

  function testBodyElements(options) {
    const {
      scrollOffset,
      targetDimensions,
      expectedResult,
      toBottom,
      toRight,
    } = options;

    const container = document.body;
    getScrollingElement(document.body).scrollTop = scrollOffset.top;
    getScrollingElement(document.body).scrollLeft = scrollOffset.left;

    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      ...targetDimensions,
      height: targetDimensions.bottom - targetDimensions.top,
      width: targetDimensions.right - targetDimensions.left,
    });

    expect(getTargetScrollOffset(container, target, !!toBottom, !!toRight)).toEqual(expectedResult);
  }

  test('calculates scrollOffset for target element in body', () => {
    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 0, left: 0 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: -100, left: -100 },
      expectedResult: { top: 0, left: 0 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: 0, left: 0 },
      expectedResult: { top: 100, left: 100 },
    });

    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 100, left: 100 },
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: { top: 100, left: 100 },
      expectedResult: { top: 200, left: 200 },
    });
  });

  test('calculates scrollOffset for target element bottom in body', () => {
    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: {
        top: 0,
        left: 0,
        bottom: SCREEN_HEIGHT,
        right: SCREEN_WIDTH,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: -100,
        left: -100,
        bottom: SCREEN_HEIGHT - 100,
        right: SCREEN_WIDTH - 100,
      },
      expectedResult: { top: 0, left: 0 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: 0,
        left: 0,
        bottom: SCREEN_HEIGHT,
        right: SCREEN_WIDTH,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 0, left: 0 },
      targetDimensions: {
        top: 100,
        left: 100,
        bottom: SCREEN_HEIGHT + 100,
        right: SCREEN_WIDTH + 100,
      },
      expectedResult: { top: 100, left: 100 },
      toBottom: true,
      toRight: true,
    });

    testBodyElements({
      scrollOffset: { top: 100, left: 100 },
      targetDimensions: {
        top: 100,
        left: 100,
        bottom: SCREEN_HEIGHT + 100,
        right: SCREEN_WIDTH + 100,
      },
      expectedResult: { top: 200, left: 200 },
      toBottom: true,
      toRight: true,
    });
  });
});

describe('getElementsInContainerViewport', () => {
  function getElements(scrollOffset, amountOfElements, elementSize, horizontal = false) {
    return Array.from(Array(amountOfElements), (_, i) => {
      const target = document.createElement('div');
      const elementOffset = (i * elementSize) - scrollOffset;
      target.getBoundingClientRect = () => ({
        top: horizontal ? 0 : elementOffset,
        bottom: horizontal ? SCREEN_HEIGHT : elementOffset + elementSize,
        left: horizontal ? elementOffset : 0,
        right: horizontal ? elementOffset + elementSize : SCREEN_WIDTH,
      });

      return target;
    });
  }

  test('finds vertical elements in body viewport', () => {
    const test1 = getElementsInContainerViewport(document.body, getElements(0, 5, 300));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(document.body, getElements(200, 5, 300));
    expect(test2).toHaveLength(3);

    const test3 = getElementsInContainerViewport(document.body, getElements(600, 3, 300));
    expect(test3).toHaveLength(1);
  });

  test('finds horizontal elements in body viewport', () => {
    const test1 = getElementsInContainerViewport(document.body, getElements(0, 5, 400, true));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(document.body, getElements(200, 5, 400, true));
    expect(test2).toHaveLength(3);

    const test3 = getElementsInContainerViewport(document.body, getElements(800, 3, 400, true));
    expect(test3).toHaveLength(1);
  });

  test('finds vertical elements in non-body viewport', () => {
    const container = getElements(0, 1, 400)[0];

    const test1 = getElementsInContainerViewport(container, getElements(0, 5, 300));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(container, getElements(0, 5, 400));
    expect(test2).toHaveLength(1);
  });

  test('finds horizontal elements in non-body viewport', () => {
    const container = getElements(0, 1, 400, true)[0];

    const test1 = getElementsInContainerViewport(container, getElements(0, 5, 300, true));
    expect(test1).toHaveLength(2);

    const test2 = getElementsInContainerViewport(container, getElements(0, 5, 400, true));
    expect(test2).toHaveLength(1);
  });
});

describe('elementFillsContainer', () => {
  function getElement(top, bottom, left = 0, right = SCREEN_WIDTH) {
    const target = document.createElement('div');
    target.getBoundingClientRect = () => ({
      top, bottom, left, right,
    });

    return target;
  }

  test('checks element in body viewport', () => {
    expect(elementFillsContainer(document.body, getElement(-100, SCREEN_HEIGHT + 100))).toBe(true);
    expect(elementFillsContainer(document.body, getElement(0, SCREEN_HEIGHT))).toBe(true);
    expect(elementFillsContainer(document.body, getElement(1, SCREEN_HEIGHT + 1))).toBe(false);
    expect(elementFillsContainer(document.body, getElement(-1, SCREEN_HEIGHT - 1))).toBe(false);
  });

  test('checks element in non-body viewport', () => {
    const container = getElement(200, 500);
    expect(elementFillsContainer(container, getElement(100, 600))).toBe(true);
    expect(elementFillsContainer(container, getElement(200, 500))).toBe(true);
    expect(elementFillsContainer(container, getElement(201, 501))).toBe(false);
    expect(elementFillsContainer(container, getElement(99, 499))).toBe(false);
  });
});

describe('isPassiveSupported', () => {
  test('returns true in JSDOM', () => {
    expect(passiveIsSupported).toBe(true);
  });
});
<|endoftext|>


<commit_before>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/krkavecVelky/01.jpg'),
//  require('../../images/animals/krkavecVelky/02.jpg'),
//  require('../../images/animals/krkavecVelky/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/krkavecVelky/01-thumb.jpg'),
//  require('../../images/animals/krkavecVelky/02-thumb.jpg'),
//  require('../../images/animals/krkavecVelky/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          <Text style={styles.italic}>Byla jednou půlnoc tmavá, muž za oknem poklimbával,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>nad knihou či pergamenem v křesle znaven víc a víc.</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>Bílá můra zaleskla se ve žlutém svitu bílých svic,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>zobáku už nevyhla se, on smutkem zkřivil svoji líc.</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>Skrz sklo na mě divně zíral, mou návštěvu nepřivítal,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>já zakrákal „nikdy víc“.</Text>
        </AnimalText>
        <AnimalText>
        (Variace na Krkavce Edgara Alana Poea, z překladu Tomáše Jacka)
        </AnimalText>
        <AnimalText>

        </AnimalText>
        <AnimalText>
          Dámy a pánové,
        </AnimalText>
        <AnimalText>
          promiňte za uvítání ponurými verši v metru Poeova Krkavce, kterého většina z vás zná spíše pod Nezvalovým nepřesným překladem Havran.
        </AnimalText>
        <AnimalText>
          Krkavec je v naší kultuře často spojován s temnými silami či smrtí, proto ne náhodou hlavní hrdina básně propadal úzkosti z přítomnosti tak velkého černého ptáka, kterého někdo naučil mluvit. Ano, čtete správně. Krkavec je totiž největším ptákem, kterého řadíme mezi pěvce, takže dokáže bez problému a k nerozeznání napodobit lidský hlas a naučit se mnoho slov. Jako ostatní krkavcovití se vyznačuje vysokou inteligencí.
        </AnimalText>
        <AnimalText>
          Expozice krkavců velkých, latinsky nazývaných <Text style={styles.italic}>Corvus corax</Text>, je v brněnské zoo umístěna nad správní budovou. Pro zajímavost, pokud vám něco říká saltarello či si někdy poslechnete středověkou hudbu, pak je vám latinský název povědomý díky stejnojmenné hudební skupině.
        </AnimalText>
        <AnimalText>
          Krkavci se vyskytují v Asii, Evropě a Severní Americe. V polovině 19. století z české přírody téměř vymizeli. O století později se sice začali vracet, dodnes však patří mezi ohrožené a zvláště chráněné druhy.
        </AnimalText>
        <AnimalText>
          Krkavci žijí v párech. Náš samec se narodil v roce 2004 a do brněnské zoo byl přivezen 14. 12. 2012. Samička se narodila v dubnu roku 2012 a ještě v červenci téhož roku k nám přijela z Košic. Krkavčí pár uvidíte na horních větvích voliéry, kde na sebe často krákají či jinak komunikují. Mladé zatím neměli, ačkoliv jsou krkavci obecně velmi starostliví rodiče, a to jak samec, tak samička. Proto rozhodně nevěřte zažitým pomluvám o krkavčích matkách.
        </AnimalText>
        <AnimalText>
          Krkavci jsou velcí na délku 54–67 cm, přičemž rozpětí křídel mají asi 115–130 cm. Průměrně váží 700–1600 g. Na zobáku mají charakteristické opeření. Živí se bezobratlými živočichy, plazy, ptáky, drobnými obojživelníky, mršinami, případně semeny. Ve volné přírodě se dožívají 10–15 let, ovšem v péči člověka se mohou dožít téměř dvojnásobného věku.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<commit_msg>Update krkavecVelky.adult.js<commit_after>import React, { Component } from 'react';
import { Text } from 'react-native';

import styles from '../../styles/styles';
import InPageImage from '../inPageImage';
import AnimalText from '../animalText';
import AnimalTemplate from '../animalTemplate';

const IMAGES = [
  require('../../images/animals/krkavecVelky/01.jpg'),
//  require('../../images/animals/krkavecVelky/02.jpg'),
//  require('../../images/animals/krkavecVelky/03.jpg'),
];

const THUMBNAILS = [
  require('../../images/animals/krkavecVelky/01-thumb.jpg'),
//  require('../../images/animals/krkavecVelky/02-thumb.jpg'),
//  require('../../images/animals/krkavecVelky/03-thumb.jpg'),
];

var AnimalDetail = React.createClass({
  render() {
    return (
      <AnimalTemplate firstIndex={[0]} thumbnails={THUMBNAILS} images={IMAGES} navigator={this.props.navigator}>
        <AnimalText>
          <Text style={styles.italic}>Byla jednou půlnoc tmavá, muž za oknem poklimbával,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>nad knihou či pergamenem v křesle znaven víc a víc.</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>Bílá můra zaleskla se v žlutém svitu bílých svic,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>zobáku už nevyhla se, on smutkem zkřivil svoji líc.</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>Skrz sklo na mě divně zíral, mou návštěvu nepřivítal,</Text>
        </AnimalText>
        <AnimalText>
          <Text style={styles.italic}>já zakrákal „nikdy víc“.</Text>
        </AnimalText>
        <AnimalText>
        (Variace na Krkavce Edgara Alana Poea, z překladu Tomáše Jacka)
        </AnimalText>
        <AnimalText>

        </AnimalText>
        <AnimalText>
          Dámy a pánové,
        </AnimalText>
        <AnimalText>
          promiňte za uvítání ponurými verši v metru Poeova Krkavce, kterého většina z vás zná spíše pod Nezvalovým nepřesným překladem Havran.
        </AnimalText>
        <AnimalText>
          Krkavec je v naší kultuře často spojován s temnými silami či smrtí, proto ne náhodou hlavní hrdina básně propadal úzkosti z přítomnosti tak velkého černého ptáka, kterého někdo naučil mluvit. Ano, čtete správně. Krkavec je totiž největším ptákem, kterého řadíme mezi pěvce, jelikož dokáže bez problému a k nerozeznání napodobit lidský hlas a naučit se mnoho slov. Jako ostatní krkavcovití se vyznačuje vysokou inteligencí.
        </AnimalText>
        <AnimalText>
          Expozice krkavců velkých, latinsky nazývaných <Text style={styles.italic}>Corvus corax</Text>, je v brněnské zoo umístěna nad správní budovou. Pro zajímavost, pokud vám něco říká saltarello či si někdy poslechnete středověkou hudbu, pak je vám latinský název povědomý díky stejnojmenné hudební skupině.
        </AnimalText>
        <AnimalText>
          Krkavci se vyskytují v Asii, Evropě a Severní Americe. V polovině 19. století z české přírody téměř vymizeli. O století později se sice začali vracet, dodnes však patří mezi ohrožené a zvláště chráněné druhy.
        </AnimalText>
        <AnimalText>
          Krkavci žijí v párech. Náš samec se narodil v roce 2004 a do brněnské zoo byl přivezen 14. 12. 2012. Samička se narodila v dubnu roku 2012 a ještě v červenci téhož roku k nám přijela z Košic. Krkavčí pár uvidíte na horních větvích voliéry, kde na sebe často krákají či jinak komunikují. Mladé zatím neměli, ačkoliv jsou krkavci obecně velmi starostliví rodiče, a to jak samec, tak samička. Proto rozhodně nevěřte zažitým pomluvám o krkavčích matkách.
        </AnimalText>
        <AnimalText>
          Krkavci jsou velcí na délku 54–67 cm, přičemž rozpětí křídel mají asi 115–130 cm. Průměrně váží 700–1600 g. Na zobáku mají charakteristické opeření. Živí se bezobratlými živočichy, plazy, ptáky, drobnými obojživelníky, mršinami, případně semeny. Ve volné přírodě se dožívají 10–15 let, ovšem v péči člověka se mohou dožít téměř dvojnásobného věku.
        </AnimalText>
      </AnimalTemplate>
    );
  }
});

module.exports = AnimalDetail;
<|endoftext|>


<commit_before>/**
 * Author: Jeff Whelpley
 * Date: 5/1/15
 *
 * Livereload for website
 */
var _           = require('lodash');
var nodemon     = require('nodemon');
var livereload  = require('gulp-livereload');

module.exports = function (gulp, opts) {
    var startScript = opts.targetDir + '/start.js';
    var shouldLiveReload = opts.livereload && opts.livereload === 'true';
    var clientPlugin = (opts.pancakesConfig && opts.pancakesConfig.clientPlugin) || {};
    var clientPluginLib = (opts.deploy ? clientPlugin.clientLibPath : clientPlugin.clientLibMinPath) || '';

    return function () {
        livereload.listen();

        nodemon({
            script: startScript,
            watch:  ['middleware', 'dist']
        })
            .on('restart', function () {
                if (shouldLiveReload) {
                    setTimeout(function () {
                        livereload.reload();
                    }, 2000);
                }
            });

        //gulp.watch(['middleware/**/*.js', 'services/**/*.js', 'utils/**/*.js'], ['test']);
        gulp.watch(['app/common/**/*.less'], ['cssbuild']);
        gulp.watch([clientPluginLib], ['jsbuild.pluginUtils']);
        gulp.watch(['utils/*.js'], ['jsbuild.utils']);
        gulp.watch(['services/resources/**/*.resource.js'], ['jsbuild.api']);

        _.each(opts.pancakesConfig.modulePlugins, function (plugin) {

//            gutil.log('got in plug with ' + plugin.rootDir + '/utils/*.js');

            gulp.watch([plugin.rootDir + '/utils/*.js'], ['jsbuild.utils']);
        });

        _.each(opts.appConfigs, function (appConfig, appName) {
            gulp.watch(['app/' + appName + '/**/*.less'], ['cssbuild']);

            gulp.watch([
                'app/' + appName + '/' + appName + '.app.js',
                'app/' + appName + '/ng.config/*.js',
                'app/' + appName + '/' + appName + '.app.js'
            ], ['jsbuild.' + appName + 'App']);
            gulp.watch([
                'app/' + appName + '/partials/*.partial.js',
                'app/' + appName + '/pages/*.page.js'
            ], ['jsbuild.' + appName + 'UI', 'jsbuild.' + appName + 'App']);
            gulp.watch(['app/' + appName + '/utils/*.js'], ['jsbuild.' + appName + 'Utils']);
            gulp.watch([
                'app/' + appName + '/filters/*.js',
                'app/' + appName + '/ng.directives/*.js',
                'app/' + appName + '/jng.directives/*.js'
            ], ['jsbuild.' + appName + 'Other']);
        });
    };
};<commit_msg>Making so in dev use non-minified plugin code<commit_after>/**
 * Author: Jeff Whelpley
 * Date: 5/1/15
 *
 * Livereload for website
 */
var _           = require('lodash');
var nodemon     = require('nodemon');
var livereload  = require('gulp-livereload');

module.exports = function (gulp, opts) {
    var startScript = opts.targetDir + '/start.js';
    var shouldLiveReload = opts.livereload && opts.livereload === 'true';
    var clientPlugin = (opts.pancakesConfig && opts.pancakesConfig.clientPlugin) || {};
    var clientPluginLib = (opts.deploy ? clientPlugin.clientLibMinPath : clientPlugin.clientLibPath) || '';

    return function () {
        livereload.listen();

        nodemon({
            script: startScript,
            watch:  ['middleware', 'dist']
        })
            .on('restart', function () {
                if (shouldLiveReload) {
                    setTimeout(function () {
                        livereload.reload();
                    }, 2000);
                }
            });

        //gulp.watch(['middleware/**/*.js', 'services/**/*.js', 'utils/**/*.js'], ['test']);
        gulp.watch(['app/common/**/*.less'], ['cssbuild']);
        gulp.watch([clientPluginLib], ['jsbuild.pluginUtils']);
        gulp.watch(['utils/*.js'], ['jsbuild.utils']);
        gulp.watch(['services/resources/**/*.resource.js'], ['jsbuild.api']);

        _.each(opts.pancakesConfig.modulePlugins, function (plugin) {

//            gutil.log('got in plug with ' + plugin.rootDir + '/utils/*.js');

            gulp.watch([plugin.rootDir + '/utils/*.js'], ['jsbuild.utils']);
        });

        _.each(opts.appConfigs, function (appConfig, appName) {
            gulp.watch(['app/' + appName + '/**/*.less'], ['cssbuild']);

            gulp.watch([
                'app/' + appName + '/' + appName + '.app.js',
                'app/' + appName + '/ng.config/*.js',
                'app/' + appName + '/' + appName + '.app.js'
            ], ['jsbuild.' + appName + 'App']);
            gulp.watch([
                'app/' + appName + '/partials/*.partial.js',
                'app/' + appName + '/pages/*.page.js'
            ], ['jsbuild.' + appName + 'UI', 'jsbuild.' + appName + 'App']);
            gulp.watch(['app/' + appName + '/utils/*.js'], ['jsbuild.' + appName + 'Utils']);
            gulp.watch([
                'app/' + appName + '/filters/*.js',
                'app/' + appName + '/ng.directives/*.js',
                'app/' + appName + '/jng.directives/*.js'
            ], ['jsbuild.' + appName + 'Other']);
        });
    };
};<|endoftext|>


<commit_before>angular.module('orderCloud')
    .factory('ocProductPricing', ocProductPricingService)
;

function ocProductPricingService($q, toastr, OrderCloud, ocConfirm) {
    var service = {
        AssignmentList: _assignmentList,
        AssignmentData: _assignmentData,
        AssignmentDataDetail: _assignmentDataDetail,
        CreateAssignment: _createAssignment,
        CreatePrice: _createPrice,
        PriceBreaks: {
            Create : _createPriceBreak,
            SetMinMax: _setMinMax,
            Delete: _deletePriceBreak,
            AddDisplayQuantity: _addDisplayQuantity
        }
    };

    function _assignmentList(productid, buyerid) {
        var deferred = $q.defer();

        OrderCloud.BuyerID.Set(undefined);

        var page = 1;
        var pageSize = 100;
        OrderCloud.Products.ListAssignments(productid, null, null, null, null, page, pageSize, null)
            .then(function(data) {
                var queue = [];
                var assignments = data;
                if (data.Meta.TotalPages > data.Meta.Page) {
                    page = data.Meta.Page;
                    while (page < data.Meta.TotalPages) {
                        page += 1;
                        queue.push(OrderCloud.Products.ListAssignments(productid, null, null, null, null, page, data.Meta.PageSize, null));
                    }
                    return $q.all(queue)
                        .then(function(results) {
                            angular.forEach(results, function(result) {
                                assignments.Items = [].concat(assignments.Items, result.Items);
                                assignments.Meta = result.Meta;
                            });
                            OrderCloud.BuyerID.Set(buyerid);
                            assignments.buyerlist = _.uniq(_.pluck(assignments.Items, 'BuyerID'));

                            deferred.resolve(assignments);
                        });
                } else{
                    OrderCloud.BuyerID.Set(buyerid);
                    assignments.buyerlist = _.uniq(_.pluck(assignments.Items, 'BuyerID'));
                    deferred.resolve(assignments);
                }
            });
        return deferred.promise;
    }

    function _assignmentData(assignments) {
        var deferred = $q.defer();

        var psQueue = [];
        var schedules = _.uniq(_.pluck(assignments.Items, 'PriceScheduleID'));

        angular.forEach(schedules, function(id) {
            psQueue.push(OrderCloud.PriceSchedules.Get(id));
        });
        $q.all(psQueue)
            .then(function(results) {
                angular.forEach(results, function(ps) {
                    angular.forEach(_.where(assignments.Items, {PriceScheduleID: ps.ID}), function(p) {
                        p.PriceSchedule = ps;
                    });
                });
                groupBy();
            });

        function groupBy() {
            var results = {};
            var priceSchedules = _.groupBy(assignments.Items, 'PriceScheduleID');
            angular.forEach(priceSchedules, function(assignments, key) {
                results[key] = {
                    PriceSchedule: assignments[0].PriceSchedule,
                    Buyers: [],
                    UserGroups: []
                };
                angular.forEach(assignments,function(details) {
                    if (details.BuyerID && !details.UserGroupID) {
                        results[key].Buyers.push(details.BuyerID);
                    }
                    else if (details.BuyerID && details.UserGroupID) {
                        results[key].UserGroups.push({BuyerID: details.BuyerID, UserGroupID: details.UserGroupID});
                    }
                });
            });

            deferred.resolve(results);
        }

        return deferred.promise;
    }

    function _assignmentDataDetail(assignmentData, priceScheduleID) {
        var deferred = $q.defer();
        var data = assignmentData[priceScheduleID];
        var result = {
            PriceSchedule: data.PriceSchedule,
            Buyers: []
        };

        var buyerChunks = chunks(_.uniq(data.Buyers.concat(_.uniq(_.pluck(data.UserGroups, 'BuyerID')))));
        var userGroupGroups = _.groupBy(data.UserGroups, 'BuyerID');
        var userGroupChunks = [];
        angular.forEach(userGroupGroups, function(group) {
            userGroupChunks = userGroupChunks.concat(chunks(group));
        });

        var buyerQueue = [];
        var userGroupQueue = [];

        angular.forEach(buyerChunks, function(chunk) {
            buyerQueue.push(OrderCloud.Buyers.List(null, null, null, null, null, {ID: chunk.join('|')}));
        });

        angular.forEach(userGroupChunks, function(chunk) {
            userGroupQueue.push((function() {
                var d = $q.defer();
                var buyerID = chunk[0].BuyerID;

                OrderCloud.UserGroups.List(null, null, null, null, null, {ID: _.pluck(chunk, 'UserGroupID').join('|')}, buyerID)
                    .then(function(data) {
                        angular.forEach(_.where(result.Buyers, {ID: buyerID}), function(buyer) {
                            if (!buyer.UserGroups) buyer.UserGroups = [];
                            buyer.UserGroups = buyer.UserGroups.concat(data.Items);
                        });
                        d.resolve();
                    });

                return d.promise;
            })());
        });

        $q.all(buyerQueue)
            .then(function(results) {
                angular.forEach(results, function(r) {
                    _.map(r.Items, function(buyer) {
                        buyer.Assigned = data.Buyers.indexOf(buyer.ID) > -1;
                    });
                    result.Buyers = result.Buyers.concat(r.Items);
                });
                getUserGroups();
            });

        function getUserGroups() {
            $q.all(userGroupQueue)
                .then(function(results) {
                    deferred.resolve(result);
                });
        }

        function chunks(list) {
            var i, j, listChunks = [], chunkSize = 10;
            for (i = 0, j = list.length; i < j; i += chunkSize) {
                listChunks.push(list.slice(i, i + chunkSize));
            }
            return listChunks;
        }

        return deferred.promise;
    }

    function _createAssignment(assignment) {
        var deferred = $q.defer();

        OrderCloud.Products.SaveAssignment(assignment)
            .then(function(data) {
                deferred.resolve(data);
            })
            .catch(function(ex) {
                if (ex.status == 409 && ex.data.Errors[0].ErrorCode == 'IdExists') {
                    ocConfirm.Confirm({
                            message: 'Another price schedule is already assigned to your selected party. Would you like to replace that assignment?'
                        })
                        .then(function() {
                            OrderCloud.Products.DeleteAssignment(assignment.ProductID, null, assignment.UserGroupID, assignment.BuyerID)
                                .then(function() {
                                    OrderCloud.Products.SaveAssignment(assignment)
                                        .then(function(data) {
                                            deferred.resolve(data);
                                        });
                                });
                        })
                        .catch(function() {
                            deferred.reject();
                        });
                }
                else {
                    toastr.error('There was an error creating your assignment. Please try again.', 'Error');
                    deferred.reject(ex);
                }
            });

        return deferred.promise;
    }

    function _createPrice(product, priceSchedule, selectedBuyer, selectedUserGroups) {
        var deferred = $q.defer();

        priceSchedule = _setMinMax(priceSchedule);

        OrderCloud.PriceSchedules.Create(priceSchedule)
            .then(function(ps) {
                var assignment = {
                    ProductID: product.ID,
                    PriceScheduleID: ps.ID,
                    BuyerID: selectedBuyer.ID
                };
                if (selectedBuyer && (selectedUserGroups == null || selectedUserGroups.length == 0 )) {
                    OrderCloud.Products.SaveAssignment(assignment)
                        .then(function(data){
                            deferred.resolve(data);
                        })
                        .catch(function (error) {
                            deferred.reject(error);
                        });
                }
                else if (selectedBuyer && selectedUserGroups.length > 0 ) {
                    var assignmentQueue = [];
                    angular.forEach(selectedUserGroups, function(usergroup) {
                        var userGroupAssignment = angular.copy(assignment);
                        userGroupAssignment.UserGroupID = usergroup.ID;
                        assignmentQueue.push(OrderCloud.Products.SaveAssignment(userGroupAssignment));
                    });
                    $q.all(assignmentQueue)
                        .then(function (data) {
                            deferred.resolve(data);
                        })
                        .catch(function (error) {
                            deferred.reject(error);
                        });
                }
            })
            .catch(function (ex) {
                deferred.reject(ex);
            });

        return deferred.promise;
    }

    function _createPriceBreak(priceSchedule, price, quantity) {
        var numberExist = _.findWhere(priceSchedule.PriceBreaks, {Quantity: quantity});
        if (quantity > priceSchedule.MaxQuantity) {
            toastr.error('Max quantity exceeded','Error');
        } else {
            numberExist === undefined ? priceSchedule.PriceBreaks.push({Price: price, Quantity: quantity}) : toastr.error('Quantity already exists. Please delete and re-enter quantity and price to edit', 'Error');
        }
        displayQuantity(priceSchedule);
        return _setMinMax(priceSchedule);
    }

    function _setMinMax(priceSchedule) {
        var quantities =  _.pluck(priceSchedule.PriceBreaks, 'Quantity');
        priceSchedule.MinQuantity = _.min(quantities);
        if (priceSchedule.RestrictedQuantity) {
            priceSchedule.MaxQuantity = _.max(quantities);
        }
        return priceSchedule;
    }

    function _deletePriceBreak(priceSchedule, index) {
        priceSchedule.PriceBreaks.splice(index, 1);
        return _setMinMax(priceSchedule);
    }

    function _addDisplayQuantity(priceSchedule) {
        displayQuantity(priceSchedule);
        return _setMinMax(priceSchedule);
    }

    function displayQuantity(priceSchedule) {
        //Organize the priceschedule array in order of quantity
        priceSchedule.PriceBreaks.sort(function(a,b) {return a.Quantity - b.Quantity});
        //find out the max quantity in the array
        var maxQuantity = Math.max.apply(Math,priceSchedule.PriceBreaks.map(function(object) {return object.Quantity}));
        // go through each item in the priceschedule array
        for (var i = 0; i < priceSchedule.PriceBreaks.length; i++) {
            //if max number is unique, display max number  with + symbol
            if (priceSchedule.PriceBreaks[i].Quantity == maxQuantity) {
                priceSchedule.PriceBreaks[i].displayQuantity = priceSchedule.PriceBreaks[i].Quantity + '+';
            } else {
                //otherwise get the range of numbers between the current index quantity , and the next index Quantity
                var itemQuantityRange = _.range(priceSchedule.PriceBreaks[i].Quantity, priceSchedule.PriceBreaks[i + 1].Quantity);
                itemQuantityRange;
                // If the difference between the range of numbers is only 1 . then just display that quantity number
                if (itemQuantityRange.length === 1) {
                    priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0];
                } else {
                    //the last quantity in the array of PriceBreaks minus the 1st quantity in the calculate range is less than or =1 , add only the first number in the Item
                    if (((priceSchedule.PriceBreaks[priceSchedule.PriceBreaks.length - 1]).Quantity - itemQuantityRange[0]) <= 1) {
                        priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0];
                        //displays range between two quantities in the array
                    } else {
                        priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0] + '-' + itemQuantityRange[itemQuantityRange.length - 1];
                    }
                }
            }
        }
    }

    return service;
}<commit_msg>Remove references to OrderCloud.BuyerID service<commit_after>angular.module('orderCloud')
    .factory('ocProductPricing', ocProductPricingService)
;

function ocProductPricingService($q, toastr, OrderCloud, ocConfirm) {
    var service = {
        AssignmentList: _assignmentList,
        AssignmentData: _assignmentData,
        AssignmentDataDetail: _assignmentDataDetail,
        CreateAssignment: _createAssignment,
        CreatePrice: _createPrice,
        PriceBreaks: {
            Create : _createPriceBreak,
            SetMinMax: _setMinMax,
            Delete: _deletePriceBreak,
            AddDisplayQuantity: _addDisplayQuantity
        }
    };

    function _assignmentList(productid) {
        var deferred = $q.defer();

        var page = 1;
        var pageSize = 100;
        OrderCloud.Products.ListAssignments(productid, null, null, null, null, page, pageSize, null)
            .then(function(data) {
                var queue = [];
                var assignments = data;
                if (data.Meta.TotalPages > data.Meta.Page) {
                    page = data.Meta.Page;
                    while (page < data.Meta.TotalPages) {
                        page += 1;
                        queue.push(OrderCloud.Products.ListAssignments(productid, null, null, null, null, page, data.Meta.PageSize, null));
                    }
                    return $q.all(queue)
                        .then(function(results) {
                            angular.forEach(results, function(result) {
                                assignments.Items = [].concat(assignments.Items, result.Items);
                                assignments.Meta = result.Meta;
                            });
                            assignments.buyerlist = _.uniq(_.pluck(assignments.Items, 'BuyerID'));

                            deferred.resolve(assignments);
                        });
                } else{
                    assignments.buyerlist = _.uniq(_.pluck(assignments.Items, 'BuyerID'));
                    deferred.resolve(assignments);
                }
            });
        return deferred.promise;
    }

    function _assignmentData(assignments) {
        var deferred = $q.defer();

        var psQueue = [];
        var schedules = _.uniq(_.pluck(assignments.Items, 'PriceScheduleID'));

        angular.forEach(schedules, function(id) {
            psQueue.push(OrderCloud.PriceSchedules.Get(id));
        });
        $q.all(psQueue)
            .then(function(results) {
                angular.forEach(results, function(ps) {
                    angular.forEach(_.where(assignments.Items, {PriceScheduleID: ps.ID}), function(p) {
                        p.PriceSchedule = ps;
                    });
                });
                groupBy();
            });

        function groupBy() {
            var results = {};
            var priceSchedules = _.groupBy(assignments.Items, 'PriceScheduleID');
            angular.forEach(priceSchedules, function(assignments, key) {
                results[key] = {
                    PriceSchedule: assignments[0].PriceSchedule,
                    Buyers: [],
                    UserGroups: []
                };
                angular.forEach(assignments,function(details) {
                    if (details.BuyerID && !details.UserGroupID) {
                        results[key].Buyers.push(details.BuyerID);
                    }
                    else if (details.BuyerID && details.UserGroupID) {
                        results[key].UserGroups.push({BuyerID: details.BuyerID, UserGroupID: details.UserGroupID});
                    }
                });
            });

            deferred.resolve(results);
        }

        return deferred.promise;
    }

    function _assignmentDataDetail(assignmentData, priceScheduleID) {
        var deferred = $q.defer();
        var data = assignmentData[priceScheduleID];
        var result = {
            PriceSchedule: data.PriceSchedule,
            Buyers: []
        };

        var buyerChunks = chunks(_.uniq(data.Buyers.concat(_.uniq(_.pluck(data.UserGroups, 'BuyerID')))));
        var userGroupGroups = _.groupBy(data.UserGroups, 'BuyerID');
        var userGroupChunks = [];
        angular.forEach(userGroupGroups, function(group) {
            userGroupChunks = userGroupChunks.concat(chunks(group));
        });

        var buyerQueue = [];
        var userGroupQueue = [];

        angular.forEach(buyerChunks, function(chunk) {
            buyerQueue.push(OrderCloud.Buyers.List(null, null, null, null, null, {ID: chunk.join('|')}));
        });

        angular.forEach(userGroupChunks, function(chunk) {
            userGroupQueue.push((function() {
                var d = $q.defer();
                var buyerID = chunk[0].BuyerID;

                OrderCloud.UserGroups.List(null, null, null, null, null, {ID: _.pluck(chunk, 'UserGroupID').join('|')}, buyerID)
                    .then(function(data) {
                        angular.forEach(_.where(result.Buyers, {ID: buyerID}), function(buyer) {
                            if (!buyer.UserGroups) buyer.UserGroups = [];
                            buyer.UserGroups = buyer.UserGroups.concat(data.Items);
                        });
                        d.resolve();
                    });

                return d.promise;
            })());
        });

        $q.all(buyerQueue)
            .then(function(results) {
                angular.forEach(results, function(r) {
                    _.map(r.Items, function(buyer) {
                        buyer.Assigned = data.Buyers.indexOf(buyer.ID) > -1;
                    });
                    result.Buyers = result.Buyers.concat(r.Items);
                });
                getUserGroups();
            });

        function getUserGroups() {
            $q.all(userGroupQueue)
                .then(function(results) {
                    deferred.resolve(result);
                });
        }

        function chunks(list) {
            var i, j, listChunks = [], chunkSize = 10;
            for (i = 0, j = list.length; i < j; i += chunkSize) {
                listChunks.push(list.slice(i, i + chunkSize));
            }
            return listChunks;
        }

        return deferred.promise;
    }

    function _createAssignment(assignment) {
        var deferred = $q.defer();

        OrderCloud.Products.SaveAssignment(assignment)
            .then(function(data) {
                deferred.resolve(data);
            })
            .catch(function(ex) {
                if (ex.status == 409 && ex.data.Errors[0].ErrorCode == 'IdExists') {
                    ocConfirm.Confirm({
                            message: 'Another price schedule is already assigned to your selected party. Would you like to replace that assignment?'
                        })
                        .then(function() {
                            OrderCloud.Products.DeleteAssignment(assignment.ProductID, null, assignment.UserGroupID, assignment.BuyerID)
                                .then(function() {
                                    OrderCloud.Products.SaveAssignment(assignment)
                                        .then(function(data) {
                                            deferred.resolve(data);
                                        });
                                });
                        })
                        .catch(function() {
                            deferred.reject();
                        });
                }
                else {
                    toastr.error('There was an error creating your assignment. Please try again.', 'Error');
                    deferred.reject(ex);
                }
            });

        return deferred.promise;
    }

    function _createPrice(product, priceSchedule, selectedBuyer, selectedUserGroups) {
        var deferred = $q.defer();

        priceSchedule = _setMinMax(priceSchedule);

        OrderCloud.PriceSchedules.Create(priceSchedule)
            .then(function(ps) {
                var assignment = {
                    ProductID: product.ID,
                    PriceScheduleID: ps.ID,
                    BuyerID: selectedBuyer.ID
                };
                if (selectedBuyer && (selectedUserGroups == null || selectedUserGroups.length == 0 )) {
                    OrderCloud.Products.SaveAssignment(assignment)
                        .then(function(data){
                            deferred.resolve(data);
                        })
                        .catch(function (error) {
                            deferred.reject(error);
                        });
                }
                else if (selectedBuyer && selectedUserGroups.length > 0 ) {
                    var assignmentQueue = [];
                    angular.forEach(selectedUserGroups, function(usergroup) {
                        var userGroupAssignment = angular.copy(assignment);
                        userGroupAssignment.UserGroupID = usergroup.ID;
                        assignmentQueue.push(OrderCloud.Products.SaveAssignment(userGroupAssignment));
                    });
                    $q.all(assignmentQueue)
                        .then(function (data) {
                            deferred.resolve(data);
                        })
                        .catch(function (error) {
                            deferred.reject(error);
                        });
                }
            })
            .catch(function (ex) {
                deferred.reject(ex);
            });

        return deferred.promise;
    }

    function _createPriceBreak(priceSchedule, price, quantity) {
        var numberExist = _.findWhere(priceSchedule.PriceBreaks, {Quantity: quantity});
        if (quantity > priceSchedule.MaxQuantity) {
            toastr.error('Max quantity exceeded','Error');
        } else {
            numberExist === undefined ? priceSchedule.PriceBreaks.push({Price: price, Quantity: quantity}) : toastr.error('Quantity already exists. Please delete and re-enter quantity and price to edit', 'Error');
        }
        displayQuantity(priceSchedule);
        return _setMinMax(priceSchedule);
    }

    function _setMinMax(priceSchedule) {
        var quantities =  _.pluck(priceSchedule.PriceBreaks, 'Quantity');
        priceSchedule.MinQuantity = _.min(quantities);
        if (priceSchedule.RestrictedQuantity) {
            priceSchedule.MaxQuantity = _.max(quantities);
        }
        return priceSchedule;
    }

    function _deletePriceBreak(priceSchedule, index) {
        priceSchedule.PriceBreaks.splice(index, 1);
        return _setMinMax(priceSchedule);
    }

    function _addDisplayQuantity(priceSchedule) {
        displayQuantity(priceSchedule);
        return _setMinMax(priceSchedule);
    }

    function displayQuantity(priceSchedule) {
        //Organize the priceschedule array in order of quantity
        priceSchedule.PriceBreaks.sort(function(a,b) {return a.Quantity - b.Quantity});
        //find out the max quantity in the array
        var maxQuantity = Math.max.apply(Math,priceSchedule.PriceBreaks.map(function(object) {return object.Quantity}));
        // go through each item in the priceschedule array
        for (var i = 0; i < priceSchedule.PriceBreaks.length; i++) {
            //if max number is unique, display max number  with + symbol
            if (priceSchedule.PriceBreaks[i].Quantity == maxQuantity) {
                priceSchedule.PriceBreaks[i].displayQuantity = priceSchedule.PriceBreaks[i].Quantity + '+';
            } else {
                //otherwise get the range of numbers between the current index quantity , and the next index Quantity
                var itemQuantityRange = _.range(priceSchedule.PriceBreaks[i].Quantity, priceSchedule.PriceBreaks[i + 1].Quantity);
                itemQuantityRange;
                // If the difference between the range of numbers is only 1 . then just display that quantity number
                if (itemQuantityRange.length === 1) {
                    priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0];
                } else {
                    //the last quantity in the array of PriceBreaks minus the 1st quantity in the calculate range is less than or =1 , add only the first number in the Item
                    if (((priceSchedule.PriceBreaks[priceSchedule.PriceBreaks.length - 1]).Quantity - itemQuantityRange[0]) <= 1) {
                        priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0];
                        //displays range between two quantities in the array
                    } else {
                        priceSchedule.PriceBreaks[i].displayQuantity = itemQuantityRange[0] + '-' + itemQuantityRange[itemQuantityRange.length - 1];
                    }
                }
            }
        }
    }

    return service;
}<|endoftext|>