<commit_before>/*
 * Nunjucks pattern engine for patternlab-node
 *
 * Dan White.
 * Licensed under the MIT license.
 *
 */

/*
 * ENGINE SUPPORT LEVEL:
 *
 * Mostly full. Partial calls and lineage hunting are supported.
 * Nunjucks does not support the mustache-specific syntax
 * extensions, style modifiers and pattern parameters, because
 * their use cases are addressed by the core Nunjucks feature set.
 * Pattern Lab's listitems feature is still written in the
 * mustache syntax.
 *
 */

'use strict';

var fs = require('fs-extra'),
  path = require('path'),
  plPath = process.cwd(),
  plConfig = require(path.join(plPath, 'patternlab-config.json')),
  nunjucks = require('nunjucks'),
  env = nunjucks.configure(plConfig.paths.source.patterns),
  partialRegistry = [];

////////////////////////////
// LOAD ANY USER NUNJUCKS CONFIGURATIONS
////////////////////////////
try {
  var nunjucksConfig = require(path.join(
    plPath,
    'patternlab-nunjucks-config.js'
  ));
  if (typeof nunjucksConfig == 'function') {
    nunjucksConfig(nunjucks, env);
  }
} catch (err) {}

////////////////////////////
// HELPER FUNCTIONS
// https://stackoverflow.com/questions/2116558/fastest-method-to-replace-all-instances-of-a-character-in-a-string
// Might do some research on the solution.
////////////////////////////
if (!String.prototype.replaceAll) {
  String.prototype.replaceAll = function(str1, str2, ignore) {
    return this.replace(
      new RegExp(
        str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, '\\$&'),
        ignore ? 'gi' : 'g'
      ),
      typeof str2 == 'string' ? str2.replace(/\$/g, '$$$$') : str2
    );
  };
}

////////////////////////////
// NUNJUCKS ENGINE
////////////////////////////
var engine_nunjucks = {
  engine: nunjucks,
  engineName: 'nunjucks',
  engineFileExtension: '.njk',

  //Important! Must be false for Nunjucks' block inheritance to work. Otherwise Nunjucks sees them as being defined more than once.
  expandPartials: false,

  // regexes, stored here so they're only compiled once
  findPartialsRE: /{%\s*(?:extends|include|import|from)\s+(?:'[^']+'|"[^"]+").*%}/g,
  findPartialKeyRE: /{%\s*(?:extends|include|import|from)\s+('[^']+'|"[^"]+")/,
  findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // still requires mustache style syntax because of how PL implements lists

  // render it
  renderPattern: function renderPattern(pattern, data) {
    try {
      // replace pattern names with their full path so Nunjucks can find them.
      pattern.extendedTemplate = this.replacePartials(pattern);
      var result = nunjucks.renderString(pattern.extendedTemplate, data);
      return Promise.resolve(result);
    } catch (err) {
      console.error('Failed to render pattern: ' + pattern.name);
    }
  },

  // find and return any Nunjucks style includes/imports/extends within pattern
  findPartials: function findPartials(pattern) {
    var matches = pattern.template.match(this.findPartialsRE);
    return matches;
  },

  // given a pattern, and a partial string, tease out the "pattern key" and return it.
  findPartial: function(partialString) {
    try {
      var partial = partialString.match(this.findPartialKeyRE)[1];
      partial = partial.replace(/["']/g, '');
      return partial;
    } catch (err) {
      console.error(
        'Error occured when trying to find partial name in: ' + partialString
      );
    }
  },

  // keep track of partials and their paths so we can replace the name with the path
  registerPartial: function(pattern) {
    // only register each partial once. Otherwise we'll eat up a ton of memory.
    if (partialRegistry.indexOf(pattern.patternPartial) === -1) {
      partialRegistry[pattern.patternPartial] = pattern.relPath.replace(
        /\\/g,
        '/'
      );
    }
  },

  replacePartials: function(pattern) {
    try {
      var partials = this.findPartials(pattern);
      if (partials !== null) {
        for (var i = 0; i < partials.length; i++) {
          // e.g. {% include "atoms-parent" %}
          var partialName = this.findPartial(partials[i]); // e.g. atoms-parent
          var partialFullPath = partialRegistry[partialName]; // e.g. 00-atoms/01-parent.njk
          var newPartial = partials[i].replaceAll(
            partialName,
            partialFullPath,
            true
          ); // e.g. {% include "00-atoms/01-parent.njk" %}
          pattern.extendedTemplate = pattern.extendedTemplate.replaceAll(
            partials[i],
            newPartial,
            true
          );
        }
      }
      return pattern.extendedTemplate;
    } catch (err) {
      console.error(
        'Error occurred in replacing partial names with paths for patern: ' +
          pattern.name
      );
    }
  },

  // still requires the mustache syntax because of the way PL handles lists
  findListItems: function(pattern) {
    var matches = pattern.template.match(this.findListItemsRE);
    return matches;
  },

  // handled by nunjucks. This is here to keep PL from erroring
  findPartialsWithStyleModifiers: function() {
    return null;
  },

  // handled by nunjucks. This is here to keep PL from erroring
  findPartialsWithPatternParameters: function() {
    return null;
  },

  spawnFile: function(config, fileName) {
    const paths = config.paths;
    const metaFilePath = path.resolve(paths.source.meta, fileName);
    try {
      fs.statSync(metaFilePath);
    } catch (err) {
      //not a file, so spawn it from the included file
      const localMetaFilePath = path.resolve(__dirname, '_meta/', fileName);
      const metaFileContent = fs.readFileSync(
        path.resolve(__dirname, '..', '_meta/', fileName),
        'utf8'
      );
      fs.outputFileSync(metaFilePath, metaFileContent);
    }
  },

  /**
   * Checks to see if the _meta directory has engine-specific head and foot files,
   * spawning them if not found.
   *
   * @param {object} config - the global config object from core, since we won't
   * assume it's already present
   */
  spawnMeta: function(config) {
    this.spawnFile(config, '_00-head.njk');
    this.spawnFile(config, '_01-foot.njk');
  },
};

module.exports = engine_nunjucks;
<commit_msg>Some clean up<commit_after>/*
 * Nunjucks pattern engine for patternlab-node
 *
 * Dan White.
 * Licensed under the MIT license.
 *
 */

/*
 * ENGINE SUPPORT LEVEL:
 *
 * Mostly full. Partial calls and lineage hunting are supported.
 * Nunjucks does not support the mustache-specific syntax
 * extensions, style modifiers and pattern parameters, because
 * their use cases are addressed by the core Nunjucks feature set.
 * Pattern Lab's listitems feature is still written in the
 * mustache syntax.
 *
 */

'use strict';

let fs = require('fs-extra'),
  path = require('path'),
  plPath = process.cwd(),
  plConfig = require(path.join(plPath, 'patternlab-config.json')),
  nunjucks = require('nunjucks'),
  env = nunjucks.configure(plConfig.paths.source.patterns),
  partialRegistry = [];

////////////////////////////
// LOAD ANY USER NUNJUCKS CONFIGURATIONS
////////////////////////////
try {
  let nunjucksConfig = require(path.join(
    plPath,
    'patternlab-nunjucks-config.js'
  ));
  if (typeof nunjucksConfig === 'function') {
    nunjucksConfig(nunjucks, env);
  }
} catch (err) {}

////////////////////////////
// HELPER FUNCTIONS
// https://stackoverflow.com/questions/2116558/fastest-method-to-replace-all-instances-of-a-character-in-a-string
// Might do some research on the solution.
////////////////////////////
if (!String.prototype.replaceAll) {
  String.prototype.replaceAll = function(str1, str2, ignore) {
    return this.replace(
      new RegExp(
        str1.replace(/([\/\,\!\\\^\$\{\}\[\]\(\)\.\*\+\?\|\<\>\-\&])/g, '\\$&'),
        ignore ? 'gi' : 'g'
      ),
      typeof str2 === 'string' ? str2.replace(/\$/g, '$$$$') : str2
    );
  };
}

////////////////////////////
// NUNJUCKS ENGINE
////////////////////////////
let engine_nunjucks = {
  engine: nunjucks,
  engineName: 'nunjucks',
  engineFileExtension: '.njk',

  //Important! Must be false for Nunjucks' block inheritance to work. Otherwise Nunjucks sees them as being defined more than once.
  expandPartials: false,

  // regexes, stored here so they're only compiled once
  findPartialsRE: /{%\s*(?:extends|include|import|from)\s+(?:'[^']+'|"[^"]+").*%}/g,
  findPartialKeyRE: /{%\s*(?:extends|include|import|from)\s+('[^']+'|"[^"]+")/,
  findListItemsRE: /({{#( )?)(list(I|i)tems.)(one|two|three|four|five|six|seven|eight|nine|ten|eleven|twelve|thirteen|fourteen|fifteen|sixteen|seventeen|eighteen|nineteen|twenty)( )?}}/g, // still requires mustache style syntax because of how PL implements lists

  // render it
  renderPattern: function renderPattern(pattern, data) {
    try {
      // replace pattern names with their full path so Nunjucks can find them.
      pattern.extendedTemplate = this.replacePartials(pattern);
      let result = nunjucks.renderString(pattern.extendedTemplate, data);
      return Promise.resolve(result);
    } catch (err) {
      console.error('Failed to render pattern: ' + pattern.name);
    }
  },

  // find and return any Nunjucks style includes/imports/extends within pattern
  findPartials: function findPartials(pattern) {
    let matches = pattern.template.match(this.findPartialsRE);
    return matches;
  },

  // given a pattern, and a partial string, tease out the "pattern key" and return it.
  findPartial: function(partialString) {
    try {
      let partial = partialString.match(this.findPartialKeyRE)[1];
      partial = partial.replace(/["']/g, '');
      return partial;
    } catch (err) {
      console.error(
        'Error occured when trying to find partial name in: ' + partialString
      );
    }
  },

  // keep track of partials and their paths so we can replace the name with the path
  registerPartial: function(pattern) {
    // only register each partial once. Otherwise we'll eat up a ton of memory.
    if (partialRegistry.indexOf(pattern.patternPartial) === -1) {
      partialRegistry[pattern.patternPartial] = pattern.relPath.replace(
        /\\/g,
        '/'
      );
    }
  },

  replacePartials: function(pattern) {
    try {
      let partials = this.findPartials(pattern);
      if (partials !== null) {
        for (let i = 0; i < partials.length; i++) {
          // e.g. {% include "atoms-parent" %}
          let partialName = this.findPartial(partials[i]); // e.g. atoms-parent
          let partialFullPath = partialRegistry[partialName]; // e.g. 00-atoms/01-parent.njk
          let newPartial = partials[i].replaceAll(
            partialName,
            partialFullPath,
            true
          ); // e.g. {% include "00-atoms/01-parent.njk" %}
          pattern.extendedTemplate = pattern.extendedTemplate.replaceAll(
            partials[i],
            newPartial,
            true
          );
        }
      }
      return pattern.extendedTemplate;
    } catch (err) {
      console.error(
        'Error occurred in replacing partial names with paths for patern: ' +
          pattern.name
      );
    }
  },

  // still requires the mustache syntax because of the way PL handles lists
  findListItems: function(pattern) {
    let matches = pattern.template.match(this.findListItemsRE);
    return matches;
  },

  // handled by nunjucks. This is here to keep PL from erroring
  findPartialsWithStyleModifiers: function() {
    return null;
  },

  // handled by nunjucks. This is here to keep PL from erroring
  findPartialsWithPatternParameters: function() {
    return null;
  },

  spawnFile: function(config, fileName) {
    const paths = config.paths;
    const metaFilePath = path.resolve(paths.source.meta, fileName);
    try {
      fs.statSync(metaFilePath);
    } catch (err) {
      //not a file, so spawn it from the included file
      const localMetaFilePath = path.resolve(__dirname, '_meta/', fileName);
      const metaFileContent = fs.readFileSync(
        path.resolve(__dirname, '..', '_meta/', fileName),
        'utf8'
      );
      fs.outputFileSync(metaFilePath, metaFileContent);
    }
  },

  /**
   * Checks to see if the _meta directory has engine-specific head and foot files,
   * spawning them if not found.
   *
   * @param {object} config - the global config object from core, since we won't
   * assume it's already present
   */
  spawnMeta: function(config) {
    this.spawnFile(config, '_00-head.njk');
    this.spawnFile(config, '_01-foot.njk');
  },
};

module.exports = engine_nunjucks;
<|endoftext|>


<commit_before>function loadData(url, callback) {
    $.ajax({
        dataType: 'json',
        type: 'GET',
        url: url
    }).done(callback).fail(function(jqXHR, textStatus, errorThrown) {
        var err = textStatus + ", " + errorThrown;
        console.log("Request Failed: " + err);
    });
}

function loadAllStats(callback) {
    loadData('/setfx/allStats?callback=?', callback);
}

function loadStats(callback) {
    loadData('/setfx/stats?callback=?', callback);
}

function loadBrentOil(callback) {
    loadData('/investing/brentOil?callback=?', callback);
}

function updateData(isUpdate) {
    loadAllStats(function(data, textStatus, jqXHR) {
        if (isUpdate) {
            $('#container').highcharts().series[0].setData(data.monto);
            $('#container').highcharts().series[1].setData(data.precio);
        } else {
            loadDolarChart(data);
        }
    });

    loadBrentOil(function(data, textStatus, jqXHR) {

        for (var m in data.events) {
            for (var g in data.events[m]) {
                evento = data.events[m][g];
                evento.text = evento.text.replace("VAR_TIMESTAMP", '').replace("href=\"", 'href=\"http://es.investing.com')
            };
        }

        // Set Data
        $("#cierreOil").text(data.attr.last_close_value);
        $("#priceOil").text(data.attr.last_value);

        // Show difference
        var difference = parseFloat(data.attr.last_value-data.attr.last_close_value).toFixed(2);
        if (difference > 0) {
            $("#priceOilChange").text(' +' + difference);
            $("#priceOilChange").attr('class', 'bg-success');
        } else {
            $("#priceOilChange").text(difference);
            $("#priceOilChange").attr('class', 'bg-danger');
        }

        // Show variation
        var variation = parseFloat((1-(data.attr.last_close_value/data.attr.last_value))*100).toFixed(2);
        if (variation > 0) {
            $("#priceOilVariation").text('   (+' + variation + '%)');
            $("#priceOilVariation").attr('class', 'bg-success');
        } else {
            $("#priceOilVariation").text('   (' + variation + '%)');
            $("#priceOilVariation").attr('class', 'bg-danger');
        }

        // Set Chart
        if (isUpdate) {
            $('#container-brent').highcharts().series[0].setData(data.candles);
        } else {
            loadBrentChart(data);
        }
    });

    loadStats(function(data, textStatus, jqXHR) {
        Object.keys(data).forEach(function(key) {
            if (!isIconIndicator(key)) {
                $("#" + key).text(data[key]);
            } else {
                $("#" + key).attr('class', '');
                if (data[key].toLowerCase() == 'up') {
                    $("#" + key).attr('class', 'glyphicon glyphicon-chevron-up');
                } else if (data[key].toLowerCase() == 'down') {
                    $("#" + key).attr('class', 'glyphicon glyphicon-chevron-down');
                } else {
                    $("#" + key).attr('class', 'glyphicon glyphicon-arrow-right');
                }
            }
        });
    });
}

function isIconIndicator(key) {
    switch (key) {
        case 'priceChange':
        case 'avgPriceChange':
        case 'trmPriceChange':
        case 'openPriceChange':
        case 'minPriceChange':
        case 'maxPriceChange':
            return true;
    }

    return false;
}

function loadDolarChart(data) {
    $('#container').highcharts({
        chart: {
            zoomType: 'x'
        },
        title: {
            text: 'Dólar Spot'
        },
        subtitle: {
            text: 'Fuente: http://www.set-fx.com/'
        },
        xAxis: {
            title: {
                enabled: true,
                text: 'Hours of the Day'
            },
            type: 'datetime',
            dateTimeLabelFormats: {
                hour: '%H:%M'
            },
            //tickInterval: 900 * 1000 // quince minutes
        },
        yAxis: [{
            labels: { // Primary yAxis
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            title: {
                text: 'Precio',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            opposite: true
                //max: 3250
        }, { // Secondary yAxis
            title: {
                text: 'Monto (Miles UDS)',
                style: {
                    color: Highcharts.getOptions().colors[0]
                }
            },
            labels: {
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[0]
                }
            }
            //max: 5000000
        }],
        tooltip: {
            shared: true
        },
        legend: {
            layout: 'vertical',
            align: 'left',
            x: 120,
            verticalAlign: 'top',
            y: 100,
            floating: true,
            backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
        },
        series: [{
            name: 'Monto',
            type: 'column',
            yAxis: 1,
            data: data.monto,
            tooltip: {
                valuePrefix: 'USD$'
            },
            //pointInterval: 900 * 1000 // quince minutes
        }, {
            name: 'Precio',
            type: 'spline',
            data: data.precio,
            tooltip: {
                valuePrefix: '$'
            },
            //pointInterval: 900 * 1000 // quince minutes
        }]
    });
}

function loadBrentChart(data) {
    $('#container-brent').highcharts({
        chart: {
            zoomType: 'x'
        },
        title: {
            text: 'Petróleo Brent'
        },
        subtitle: {
            text: 'Fuente: http://es.investing.com/commodities/brent-oil'
        },
        xAxis: {
            title: {
                enabled: true,
                text: 'Hours of the Day'
            },
            type: 'datetime',
            dateTimeLabelFormats: {
                hour: '%H:%M'
            },
            //tickInterval: 900 * 1000 // quince minutes
        },
        yAxis: [{
            labels: { // Primary yAxis
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            title: {
                text: 'Precio',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            opposite: true
                //max: 3250
        }],
        tooltip: {
            shared: true
        },
        legend: {
            layout: 'vertical',
            align: 'left',
            x: 120,
            verticalAlign: 'top',
            y: 100,
            floating: true,
            backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
        },
        plotOptions: {
            area: {
                fillColor: {
                    linearGradient: {
                        x1: 0,
                        y1: 0,
                        x2: 0,
                        y2: 1
                    },
                    stops: [
                        [0, Highcharts.getOptions().colors[0]],
                        [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                    ]
                },
                marker: {
                    radius: 2
                },
                lineWidth: 1,
                states: {
                    hover: {
                        lineWidth: 1
                    }
                },
                threshold: null
            }
        },
        series: [{
            name: 'Precio',
            type: 'area',
            id : 'dataseries',
            data: data.candles,
            tooltip: {
                valuePrefix: '$'
            }
            //pointInterval: 900 * 1000 // quince minutes
        }, {
            name: 'Eventos',
            type : 'flags',
            data : data.events.news,
            zIndex: 10,
            onSeries : 'dataseries',
            shape : 'circlepin',
            width : 16
        }, {
            type: "flags",
            onSeries: "dataseries",
            shape: "circlepin",
            data: data.events.ec,
            zIndex: 11
        }],
        tooltip: {
            useHTML: true
        }
    });
}

$(function() {

    Highcharts.setOptions({
        global: {
            useUTC: false
        }
    });

    updateData(false);

    // Update Data every 10 seconds
    setInterval(function() {
        updateData(true);
    }, 10000);

    // the button action
    $('#button').click(function() {
        loadAllStats(function(data, textStatus, jqXHR) {
            $('#container').highcharts().series[0].setData(data.monto);
            $('#container').highcharts().series[1].setData(data.precio);
        });
    });
});<commit_msg>Add data to track refresh.<commit_after>function loadData(url, callback) {
    $.ajax({
        dataType: 'json',
        type: 'GET',
        url: url
    }).done(callback).fail(function(jqXHR, textStatus, errorThrown) {
        var err = textStatus + ", " + errorThrown;
        console.log("Request Failed: " + err);
    });
}

function loadAllStats(callback) {
    loadData('/setfx/allStats?callback=?', callback);
}

function loadStats(callback) {
    loadData('/setfx/stats?callback=?', callback);
}

function loadBrentOil(callback) {
    loadData('/investing/brentOil?callback=?', callback);
}

function updateData(isUpdate) {
    // track page refresh
    ga('send', 'event', 'data', 'updateData', 'Data Refresh');
    loadAllStats(function(data, textStatus, jqXHR) {
        if (isUpdate) {
            $('#container').highcharts().series[0].setData(data.monto);
            $('#container').highcharts().series[1].setData(data.precio);
        } else {
            loadDolarChart(data);
        }
    });

    loadBrentOil(function(data, textStatus, jqXHR) {

        for (var m in data.events) {
            for (var g in data.events[m]) {
                evento = data.events[m][g];
                evento.text = evento.text.replace("VAR_TIMESTAMP", '').replace("href=\"", 'href=\"http://es.investing.com')
            };
        }

        // Set Data
        $("#cierreOil").text(data.attr.last_close_value);
        $("#priceOil").text(data.attr.last_value);

        // Show difference
        var difference = parseFloat(data.attr.last_value-data.attr.last_close_value).toFixed(2);
        if (difference > 0) {
            $("#priceOilChange").text(' +' + difference);
            $("#priceOilChange").attr('class', 'bg-success');
        } else {
            $("#priceOilChange").text(difference);
            $("#priceOilChange").attr('class', 'bg-danger');
        }

        // Show variation
        var variation = parseFloat((1-(data.attr.last_close_value/data.attr.last_value))*100).toFixed(2);
        if (variation > 0) {
            $("#priceOilVariation").text('   (+' + variation + '%)');
            $("#priceOilVariation").attr('class', 'bg-success');
        } else {
            $("#priceOilVariation").text('   (' + variation + '%)');
            $("#priceOilVariation").attr('class', 'bg-danger');
        }

        // Set Chart
        if (isUpdate) {
            $('#container-brent').highcharts().series[0].setData(data.candles);
        } else {
            loadBrentChart(data);
        }
    });

    loadStats(function(data, textStatus, jqXHR) {
        Object.keys(data).forEach(function(key) {
            if (!isIconIndicator(key)) {
                $("#" + key).text(data[key]);
            } else {
                $("#" + key).attr('class', '');
                if (data[key].toLowerCase() == 'up') {
                    $("#" + key).attr('class', 'glyphicon glyphicon-chevron-up');
                } else if (data[key].toLowerCase() == 'down') {
                    $("#" + key).attr('class', 'glyphicon glyphicon-chevron-down');
                } else {
                    $("#" + key).attr('class', 'glyphicon glyphicon-arrow-right');
                }
            }
        });
    });
}

function isIconIndicator(key) {
    switch (key) {
        case 'priceChange':
        case 'avgPriceChange':
        case 'trmPriceChange':
        case 'openPriceChange':
        case 'minPriceChange':
        case 'maxPriceChange':
            return true;
    }

    return false;
}

function loadDolarChart(data) {
    $('#container').highcharts({
        chart: {
            zoomType: 'x'
        },
        title: {
            text: 'Dólar Spot'
        },
        subtitle: {
            text: 'Fuente: http://www.set-fx.com/'
        },
        xAxis: {
            title: {
                enabled: true,
                text: 'Hours of the Day'
            },
            type: 'datetime',
            dateTimeLabelFormats: {
                hour: '%H:%M'
            },
            //tickInterval: 900 * 1000 // quince minutes
        },
        yAxis: [{
            labels: { // Primary yAxis
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            title: {
                text: 'Precio',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            opposite: true
                //max: 3250
        }, { // Secondary yAxis
            title: {
                text: 'Monto (Miles UDS)',
                style: {
                    color: Highcharts.getOptions().colors[0]
                }
            },
            labels: {
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[0]
                }
            }
            //max: 5000000
        }],
        tooltip: {
            shared: true
        },
        legend: {
            layout: 'vertical',
            align: 'left',
            x: 120,
            verticalAlign: 'top',
            y: 100,
            floating: true,
            backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
        },
        series: [{
            name: 'Monto',
            type: 'column',
            yAxis: 1,
            data: data.monto,
            tooltip: {
                valuePrefix: 'USD$'
            },
            //pointInterval: 900 * 1000 // quince minutes
        }, {
            name: 'Precio',
            type: 'spline',
            data: data.precio,
            tooltip: {
                valuePrefix: '$'
            },
            //pointInterval: 900 * 1000 // quince minutes
        }]
    });
}

function loadBrentChart(data) {
    $('#container-brent').highcharts({
        chart: {
            zoomType: 'x'
        },
        title: {
            text: 'Petróleo Brent'
        },
        subtitle: {
            text: 'Fuente: http://es.investing.com/commodities/brent-oil'
        },
        xAxis: {
            title: {
                enabled: true,
                text: 'Hours of the Day'
            },
            type: 'datetime',
            dateTimeLabelFormats: {
                hour: '%H:%M'
            },
            //tickInterval: 900 * 1000 // quince minutes
        },
        yAxis: [{
            labels: { // Primary yAxis
                format: '{value}',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            title: {
                text: 'Precio',
                style: {
                    color: Highcharts.getOptions().colors[1]
                }
            },
            opposite: true
                //max: 3250
        }],
        tooltip: {
            shared: true
        },
        legend: {
            layout: 'vertical',
            align: 'left',
            x: 120,
            verticalAlign: 'top',
            y: 100,
            floating: true,
            backgroundColor: (Highcharts.theme && Highcharts.theme.legendBackgroundColor) || '#FFFFFF'
        },
        plotOptions: {
            area: {
                fillColor: {
                    linearGradient: {
                        x1: 0,
                        y1: 0,
                        x2: 0,
                        y2: 1
                    },
                    stops: [
                        [0, Highcharts.getOptions().colors[0]],
                        [1, Highcharts.Color(Highcharts.getOptions().colors[0]).setOpacity(0).get('rgba')]
                    ]
                },
                marker: {
                    radius: 2
                },
                lineWidth: 1,
                states: {
                    hover: {
                        lineWidth: 1
                    }
                },
                threshold: null
            }
        },
        series: [{
            name: 'Precio',
            type: 'area',
            id : 'dataseries',
            data: data.candles,
            tooltip: {
                valuePrefix: '$'
            }
            //pointInterval: 900 * 1000 // quince minutes
        }, {
            name: 'Eventos',
            type : 'flags',
            data : data.events.news,
            zIndex: 10,
            onSeries : 'dataseries',
            shape : 'circlepin',
            width : 16
        }, {
            type: "flags",
            onSeries: "dataseries",
            shape: "circlepin",
            data: data.events.ec,
            zIndex: 11
        }],
        tooltip: {
            useHTML: true
        }
    });
}

$(function() {

    Highcharts.setOptions({
        global: {
            useUTC: false
        }
    });

    updateData(false);

    // Update Data every 10 seconds
    setInterval(function() {
        updateData(true);
    }, 10000);

    // the button action
    $('#button').click(function() {
        loadAllStats(function(data, textStatus, jqXHR) {
            $('#container').highcharts().series[0].setData(data.monto);
            $('#container').highcharts().series[1].setData(data.precio);
        });
    });
});<|endoftext|>


<commit_before>import Vue from '../../utils/vue'
import { getComponentConfig } from '../../utils/config'
import { requestAF } from '../../utils/dom'
import { isBoolean } from '../../utils/inspect'
import { toInteger } from '../../utils/number'
import BVTransition from '../../utils/bv-transition'
import normalizeSlotMixin from '../../mixins/normalize-slot'
import { BButtonClose } from '../button/button-close'

const NAME = 'BAlert'

// Convert `show` value to a number
const parseCountDown = show => {
  if (show === '' || isBoolean(show)) {
    return 0
  }
  show = toInteger(show, 0)
  return show > 0 ? show : 0
}

// Convert `show` value to a boolean
const parseShow = show => {
  if (show === '' || show === true) {
    return true
  }
  if (toInteger(show, 0) < 1) {
    // Boolean will always return false for the above comparison
    return false
  }
  return !!show
}

// Is a value number like (i.e. a number or a number as string)
const isNumericLike = value => !isNaN(toInteger(value))

// @vue/component
export const BAlert = /*#__PURE__*/ Vue.extend({
  name: NAME,
  mixins: [normalizeSlotMixin],
  model: {
    prop: 'show',
    event: 'input'
  },
  props: {
    variant: {
      type: String,
      default: () => getComponentConfig(NAME, 'variant')
    },
    dismissible: {
      type: Boolean,
      default: false
    },
    dismissLabel: {
      type: String,
      default: () => getComponentConfig(NAME, 'dismissLabel')
    },
    show: {
      type: [Boolean, Number, String],
      default: false
    },
    fade: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      countDownTimerId: null,
      countDown: 0,
      // If initially shown, we need to set these for SSR
      localShow: parseShow(this.show)
    }
  },
  watch: {
    show(newVal) {
      this.countDown = parseCountDown(newVal)
      this.localShow = parseShow(newVal)
    },
    countDown(newVal) {
      this.clearTimer()
      if (isNumericLike(this.show)) {
        // Ignore if this.show transitions to a boolean value.
        this.$emit('dismiss-count-down', newVal)
        if (this.show !== newVal) {
          // Update the v-model if needed
          this.$emit('input', newVal)
        }
        if (newVal > 0) {
          this.localShow = true
          this.countDownTimerId = setTimeout(() => {
            this.countDown--
          }, 1000)
        } else {
          // Slightly delay the hide to allow any UI updates
          this.$nextTick(() => {
            requestAF(() => {
              this.localShow = false
            })
          })
        }
      }
    },
    localShow(newVal) {
      if (!newVal && (this.dismissible || isNumericLike(this.show))) {
        // Only emit dismissed events for dismissible or auto dismissing alerts
        this.$emit('dismissed')
      }
      if (!isNumericLike(this.show) && this.show !== newVal) {
        // Only emit booleans if we weren't passed a number via `this.show`
        this.$emit('input', newVal)
      }
    }
  },
  created() {
    this.countDown = parseCountDown(this.show)
    this.localShow = parseShow(this.show)
  },
  mounted() {
    this.countDown = parseCountDown(this.show)
    this.localShow = parseShow(this.show)
  },
  beforeDestroy() {
    this.clearTimer()
  },
  methods: {
    dismiss() {
      this.clearTimer()
      this.countDown = 0
      this.localShow = false
    },
    clearTimer() {
      if (this.countDownTimerId) {
        clearInterval(this.countDownTimerId)
        this.countDownTimerId = null
      }
    }
  },
  render(h) {
    let $alert // undefined
    if (this.localShow) {
      let $dismissBtn = h()
      if (this.dismissible) {
        // Add dismiss button
        $dismissBtn = h(
          BButtonClose,
          { attrs: { 'aria-label': this.dismissLabel }, on: { click: this.dismiss } },
          [this.normalizeSlot('dismiss')]
        )
      }
      $alert = h(
        'div',
        {
          key: this._uid,
          staticClass: 'alert',
          class: {
            'alert-dismissible': this.dismissible,
            [`alert-${this.variant}`]: this.variant
          },
          attrs: { role: 'alert', 'aria-live': 'polite', 'aria-atomic': true }
        },
        [$dismissBtn, this.normalizeSlot('default')]
      )
      $alert = [$alert]
    }
    return h(BVTransition, { props: { noFade: !this.fade } }, $alert)
  }
})
<commit_msg>fix(b-alert): memory leak by using the correct method to clear the countdown timeout (#5158)<commit_after>import Vue from '../../utils/vue'
import { getComponentConfig } from '../../utils/config'
import { requestAF } from '../../utils/dom'
import { isBoolean } from '../../utils/inspect'
import { toInteger } from '../../utils/number'
import BVTransition from '../../utils/bv-transition'
import normalizeSlotMixin from '../../mixins/normalize-slot'
import { BButtonClose } from '../button/button-close'

const NAME = 'BAlert'

// Convert `show` value to a number
const parseCountDown = show => {
  if (show === '' || isBoolean(show)) {
    return 0
  }
  show = toInteger(show, 0)
  return show > 0 ? show : 0
}

// Convert `show` value to a boolean
const parseShow = show => {
  if (show === '' || show === true) {
    return true
  }
  if (toInteger(show, 0) < 1) {
    // Boolean will always return false for the above comparison
    return false
  }
  return !!show
}

// Is a value number like (i.e. a number or a number as string)
const isNumericLike = value => !isNaN(toInteger(value))

// @vue/component
export const BAlert = /*#__PURE__*/ Vue.extend({
  name: NAME,
  mixins: [normalizeSlotMixin],
  model: {
    prop: 'show',
    event: 'input'
  },
  props: {
    variant: {
      type: String,
      default: () => getComponentConfig(NAME, 'variant')
    },
    dismissible: {
      type: Boolean,
      default: false
    },
    dismissLabel: {
      type: String,
      default: () => getComponentConfig(NAME, 'dismissLabel')
    },
    show: {
      type: [Boolean, Number, String],
      default: false
    },
    fade: {
      type: Boolean,
      default: false
    }
  },
  data() {
    return {
      countDown: 0,
      countDownTimeout: null,
      // If initially shown, we need to set these for SSR
      localShow: parseShow(this.show)
    }
  },
  watch: {
    show(newVal) {
      this.countDown = parseCountDown(newVal)
      this.localShow = parseShow(newVal)
    },
    countDown(newVal) {
      this.clearCountDownInterval()
      if (isNumericLike(this.show)) {
        // Ignore if this.show transitions to a boolean value.
        this.$emit('dismiss-count-down', newVal)
        if (this.show !== newVal) {
          // Update the v-model if needed
          this.$emit('input', newVal)
        }
        if (newVal > 0) {
          this.localShow = true
          this.countDownTimeout = setTimeout(() => {
            this.countDown--
          }, 1000)
        } else {
          // Slightly delay the hide to allow any UI updates
          this.$nextTick(() => {
            requestAF(() => {
              this.localShow = false
            })
          })
        }
      }
    },
    localShow(newVal) {
      if (!newVal && (this.dismissible || isNumericLike(this.show))) {
        // Only emit dismissed events for dismissible or auto dismissing alerts
        this.$emit('dismissed')
      }
      if (!isNumericLike(this.show) && this.show !== newVal) {
        // Only emit booleans if we weren't passed a number via `this.show`
        this.$emit('input', newVal)
      }
    }
  },
  created() {
    this.countDown = parseCountDown(this.show)
    this.localShow = parseShow(this.show)
  },
  mounted() {
    this.countDown = parseCountDown(this.show)
    this.localShow = parseShow(this.show)
  },
  beforeDestroy() {
    this.clearCountDownInterval()
  },
  methods: {
    dismiss() {
      this.clearCountDownInterval()
      this.countDown = 0
      this.localShow = false
    },
    clearCountDownInterval() {
      if (this.countDownTimeout) {
        clearTimeout(this.countDownTimeout)
        this.countDownTimeout = null
      }
    }
  },
  render(h) {
    let $alert // undefined
    if (this.localShow) {
      let $dismissBtn = h()
      if (this.dismissible) {
        // Add dismiss button
        $dismissBtn = h(
          BButtonClose,
          { attrs: { 'aria-label': this.dismissLabel }, on: { click: this.dismiss } },
          [this.normalizeSlot('dismiss')]
        )
      }
      $alert = h(
        'div',
        {
          key: this._uid,
          staticClass: 'alert',
          class: {
            'alert-dismissible': this.dismissible,
            [`alert-${this.variant}`]: this.variant
          },
          attrs: { role: 'alert', 'aria-live': 'polite', 'aria-atomic': true }
        },
        [$dismissBtn, this.normalizeSlot('default')]
      )
      $alert = [$alert]
    }
    return h(BVTransition, { props: { noFade: !this.fade } }, $alert)
  }
})
<|endoftext|>


<commit_before>(function(){

	var Tabs = function(){
		this.$container = document.querySelector('.tabs');
		this.$elements 	= this.$container.querySelectorAll('.tabs-link');

		this.addEvents();
	};

	Tabs.prototype.addEventListeners = function( elements, event, method ) {
		var that 	= this;
		var _this 	= {};

		[].forEach.call(elements, function(element, index){
			_this = {
				that: that,
				index: index,
				element: element
			}

			element.addEventListener( event, method.bind(_this) );
		});
	};

	Tabs.prototype.addEvents = function() {
		var elements = this.$elements;

		this.addEventListeners( elements, 'keydown', this.onElementKeydown );
		this.addEventListeners( elements, 'click', this.onElementClick );
	};

})();

<commit_msg>method of onEventKeyDown<commit_after>(function(){

	var Tabs = function(){
		this.$container = document.querySelector('.tabs');
		this.$elements 	= this.$container.querySelectorAll('.tabs-link');

		this.addEvents();
	};

	Tabs.prototype.addEventListeners = function( elements, event, method ) {
		var that 	= this;
		var _this 	= {};

		[].forEach.call(elements, function(element, index){
			_this = {
				that: that,
				index: index,
				element: element
			}

			element.addEventListener( event, method.bind(_this) );
		});
	};

	Tabs.prototype.addEvents = function() {
		var elements = this.$elements;

		this.addEventListeners( elements, 'keydown', this.onElementKeydown );
		this.addEventListeners( elements, 'click', this.onElementClick );
	};

	Tabs.prototype.onElementKeydown = function(event) {
		event.preventDefault();

		var $current 	= this.element;
		var $prev 		= this.that.$elements[this.index-1]; //|| this.that.$elements[this.that.$elements.length-1];
		var $next 		= this.that.$elements[this.index+1]; //|| this.that.$elements[0];
		var $target 	= this.that.keyActivated(event, $prev, $next);

		if ($target) {
			this.that.deselect();
      		this.that.select($target);
		}

	};

})();

<|endoftext|>


<commit_before>/**
 * Check if given `slug` could conflict with existing routes or
 * if it's a reserved keyword.
 *
 * The list is mostly based on frontend `src/server/pages.js` file and
 * `src/pages/static` content.
 *
 * @param {String} slug
 */
export function isBlacklistedCollectiveSlug(slug) {
  return [
    'about',
    'chapters',
    'create',
    'discover',
    'faq',
    'hosts',
    'learn-more',
    'opensource',
    'privacypolicy',
    'redeem',
    'redeemed',
    'search',
    'signin',
    'subscriptions',
    'tos',
    'widgets',
  ].includes(slug);
}
<commit_msg>chore(Collective): Add more keywords to blacklisted slugs<commit_after>/**
 * Check if given `slug` could conflict with existing routes or
 * if it's a reserved keyword.
 *
 * The list is mostly based on frontend `src/server/pages.js` file and
 * `src/pages/static` content.
 *
 * @param {String} slug
 */
export function isBlacklistedCollectiveSlug(slug) {
  return [
    'about',
    'chapters',
    'create',
    'discover',
    'faq',
    'hosts',
    'learn-more',
    'opensource',
    'privacypolicy',
    'redeem',
    'redeemed',
    'search',
    'signin',
    'subscriptions',
    'tos',
    'widgets',
    'edit',
    'expenses',
    'orders',
  ].includes(slug);
}
<|endoftext|>


<commit_before>import path from 'path';
import webpack from 'webpack';

const PROD = process.env.NODE_ENV || 0;

module.exports = {
  devtool: PROD ? "source-map" : "eval",
  entry: {
    initial: './app/assets/scripts/Initial.js',
    home: './app/assets/scripts/Home.js'
  },
  output: {
    path: __dirname + '/app/assets/_compiled',
    publicPath: '/app/assets/_compiled',
    filename: '[name].js',
    chunkFilename: '[name]_[chunkhash].js'
  },
  plugins: PROD ? [
    new webpack.optimize.UglifyJsPlugin({
      output: {
        comments: false
      }
    })
  ] : [],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
};
<commit_msg>Revise source maps<commit_after>import path from 'path';
import webpack from 'webpack';

const PROD = process.env.NODE_ENV || 0;

module.exports = {
  devtool: PROD ? false : "source-map",
  entry: {
    initial: './app/assets/scripts/Initial.js',
    home: './app/assets/scripts/Home.js'
  },
  output: {
    path: __dirname + '/app/assets/_compiled',
    publicPath: '/app/assets/_compiled',
    filename: '[name].js',
    chunkFilename: '[name]_[chunkhash].js'
  },
  plugins: PROD ? [
    new webpack.optimize.UglifyJsPlugin({
      output: {
        comments: false
      }
    })
  ] : [],
  module: {
    loaders: [
      {
        test: /\.js$/,
        exclude: /node_modules/,
        loader: 'babel-loader'
      }
    ]
  }
};
<|endoftext|>


<commit_before>function modalEvents(button, modal, page ) {
    switch (button.data('action')) {
        case "new_user":
            modal.find('.modal-title').text('Registrar usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/new', { user_id: button.data('user_id')  }, function(){

            });
            break;
        case "user_profile":
            modal.find('.modal-title').text('Editar información del usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/profile', { user_id: button.data('user_id')  }, function(){
                $('#form_updateprofile').submit(function(event){
                    $.post('/user/update', $(this).serialize()).done(function (data) {
                        alert(data.message);
                        if (data.status=='Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "change_password":
            modal.find('.modal-title').text('Cambiar contraseña');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/change-password', { user_id: button.data('user_id')  }, function(){
                $('#form_updatepassword').submit(function (event) {
                    $.post('/user/update-password', $(this).serialize()).done(function (data) {
                        alert(data.message);
                        if(data.status=='Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "new_item":
            modal.find('.modal-title').text('Registrar artículo');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/new', {}, function(){
                $('#itemForm').submit(function(event) {
                    var n_articles = $('input[id=nArts]').val();
                    if (confirm("¿Está seguro que quiere registrar " + n_articles + " artículos?")){
                            $.post('/item/register', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if (data.status == 'Ok') {
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                }
                })
            });
            break;
        case "edit_item":
            modal.find('.modal-title').text('Editar artículos');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    // alert("Funciona, item: "+ $(this).data('item_id'));
                    $("#modal_content").load('/item/edit-item/',{ id: $(this).data('item_id') }, function () {
                        $('#itemForm').submit(function (event) {
                            $.post('/item/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        // Editar articulos
        case "edit_user":
            modal.find('.modal-title').text('Editar usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    // alert("Funciona, item: "+ $(this).data('item_id'));
                    $("#modal_content").load('/user/edit-user/',{ id: $(this).data('user_id') }, function () {
                        $('#updateUser').submit(function (event) {
                            $.post('/user/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        //stores
        case "new_store":
            modal.find('.modal-title').text('Registrar sucursal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/store/new', { /* post body data */ }, function(){
                $('#storeForm').submit(function(event){
                    $.post('/store/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        //terminals
        case "new_terminal":
            modal.find('.modal-title').text('Registrar terminal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/terminal/new', { /* post body data */ }, function(){
                $('#terminalForm').submit(function(event){
                    $.post('/terminal/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "edit_terminal":
            modal.find('.modal-title').text('Editar terminal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/terminal/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load('/terminal/edit-terminal/', {id: $(this).data('terminal_id')}, function () {
                        $('#terminalForm').submit(function (event) {
                            $.post('/terminal/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        case "edit_store":
            modal.find('.modal-title').text('Editar sucursal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/store/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load('/store/edit-store/', {id: $(this).data('store_id')}, function () {
                        $('#storeForm').submit(function (event) {
                            $.post('/store/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        case "new_sale":
            modal.find('.modal-title').text('Registrar venta');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/list/sale',{ page: page},function(){
                var select = $('input[name=id]').data('user_id');
                //alert("Usuario: "+ select.options[select.selectedIndex].value);
                var desc = $('input[name=optradioDesc]:checked').val();
                alert(desc);
                $(this).find('.list-group-item').click(function(){
                    if (confirm("¿Está seguro que quiere vender el artículo: " +  $(this).data('item_id'))){
                        // Selected discount
                        $.post('/carrito/new', {item_id:$(this).data('item_id'), user_id:select, desc:$('input[name=optradioDesc]:checked').val(),
                            terminal_id:$(this).data('terminal_id')}).done(function (data) {
                            alert(data.message);
                            if(data.status=='Ok'){
                                modal.modal('hide');
                            }
                        });
                        event.preventDefault();
                    }
                });
            });
            break;
        case "new_supplier":
            modal.find('.modal-title').text('Registrar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/supplier/new', { /* post body data */ }, function(){
                $('#supplierForm').submit(function(event){
                    $.post('/supplier/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "edit_supplier":
            modal.find('.modal-title').text('Editar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/supplier/list/', { page : page } , function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load("/supplier/edit-supplier/", {id: $(this).data('supplier_id')}, function(){
                        $('#supplierForm').submit(function (event) {
                            $.post('/supplier/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });

                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;

        case "reports":
            modal.find('.modal-title').text('Editar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/reports',{},function(){

            });
            break;
    }
}

$('#genericModal').on('show.bs.modal', function (event) {
    var button = $(event.relatedTarget);
    var modal = $(this);
    var page = 0;
    modalEvents(button, modal, page);
});

<commit_msg>alert<commit_after>function modalEvents(button, modal, page ) {
    switch (button.data('action')) {
        case "new_user":
            modal.find('.modal-title').text('Registrar usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/new', { user_id: button.data('user_id')  }, function(){

            });
            break;
        case "user_profile":
            modal.find('.modal-title').text('Editar información del usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/profile', { user_id: button.data('user_id')  }, function(){
                $('#form_updateprofile').submit(function(event){
                    $.post('/user/update', $(this).serialize()).done(function (data) {
                        alert(data.message);
                        if (data.status=='Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "change_password":
            modal.find('.modal-title').text('Cambiar contraseña');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/change-password', { user_id: button.data('user_id')  }, function(){
                $('#form_updatepassword').submit(function (event) {
                    $.post('/user/update-password', $(this).serialize()).done(function (data) {
                        alert(data.message);
                        if(data.status=='Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "new_item":
            modal.find('.modal-title').text('Registrar artículo');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/new', {}, function(){
                $('#itemForm').submit(function(event) {
                    var n_articles = $('input[id=nArts]').val();
                    if (confirm("¿Está seguro que quiere registrar " + n_articles + " artículos?")){
                            $.post('/item/register', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if (data.status == 'Ok') {
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                }
                })
            });
            break;
        case "edit_item":
            modal.find('.modal-title').text('Editar artículos');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    // alert("Funciona, item: "+ $(this).data('item_id'));
                    $("#modal_content").load('/item/edit-item/',{ id: $(this).data('item_id') }, function () {
                        $('#itemForm').submit(function (event) {
                            $.post('/item/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        // Editar articulos
        case "edit_user":
            modal.find('.modal-title').text('Editar usuario');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/user/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    // alert("Funciona, item: "+ $(this).data('item_id'));
                    $("#modal_content").load('/user/edit-user/',{ id: $(this).data('user_id') }, function () {
                        $('#updateUser').submit(function (event) {
                            $.post('/user/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        //stores
        case "new_store":
            modal.find('.modal-title').text('Registrar sucursal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/store/new', { /* post body data */ }, function(){
                $('#storeForm').submit(function(event){
                    $.post('/store/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        //terminals
        case "new_terminal":
            modal.find('.modal-title').text('Registrar terminal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/terminal/new', { /* post body data */ }, function(){
                $('#terminalForm').submit(function(event){
                    $.post('/terminal/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "edit_terminal":
            modal.find('.modal-title').text('Editar terminal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/terminal/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load('/terminal/edit-terminal/', {id: $(this).data('terminal_id')}, function () {
                        $('#terminalForm').submit(function (event) {
                            $.post('/terminal/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        case "edit_store":
            modal.find('.modal-title').text('Editar sucursal');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/store/list/',{ page: page }, function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load('/store/edit-store/', {id: $(this).data('store_id')}, function () {
                        $('#storeForm').submit(function (event) {
                            $.post('/store/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });
                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;
        case "new_sale":
            modal.find('.modal-title').text('Registrar venta');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/item/list/sale',{ page: page},function(){
                var select = $('input[name=id]').data('user_id');
                //alert("Usuario: "+ select.options[select.selectedIndex].value);
                var desc = $('input[name=optradioDesc]:checked').val();
                // alert(desc);
                $(this).find('.list-group-item').click(function(){
                    if (confirm("¿Está seguro que quiere vender el artículo: " +  $(this).data('item_id'))){
                        // Selected discount
                        $.post('/carrito/new', {item_id:$(this).data('item_id'), user_id:select, desc:$('input[name=optradioDesc]:checked').val(),
                            terminal_id:$(this).data('terminal_id')}).done(function (data) {
                            alert(data.message);
                            if(data.status=='Ok'){
                                modal.modal('hide');
                            }
                        });
                        event.preventDefault();
                    }
                });
            });
            break;
        case "new_supplier":
            modal.find('.modal-title').text('Registrar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/supplier/new', { /* post body data */ }, function(){
                $('#supplierForm').submit(function(event){
                    $.post('/supplier/register', $(this).serialize()).done(function (data){
                        alert(data.message);
                        if(data.status == 'Ok'){
                            modal.modal('hide');
                        }
                    });
                    event.preventDefault();
                });
            });
            break;
        case "edit_supplier":
            modal.find('.modal-title').text('Editar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/supplier/list/', { page : page } , function(){
                $(this).find('.list-group-item').click(function(){
                    $("#modal_content").load("/supplier/edit-supplier/", {id: $(this).data('supplier_id')}, function(){
                        $('#supplierForm').submit(function (event) {
                            $.post('/supplier/update', $(this).serialize()).done(function (data) {
                                alert(data.message);
                                if(data.status=='Ok'){
                                    modal.modal('hide');
                                }
                            });
                            event.preventDefault();
                        });
                    });
                });

                $('.pagination').find('li').click(function () {
                    modalEvents(button, modal, $(this).data('pagenumber'));
                });
            });
            break;

        case "reports":
            modal.find('.modal-title').text('Editar proveedor');
            modal.find('#modal_content').html("");
            modal.find('#modal_content').load('/reports',{},function(){

            });
            break;
    }
}

$('#genericModal').on('show.bs.modal', function (event) {
    var button = $(event.relatedTarget);
    var modal = $(this);
    var page = 0;
    modalEvents(button, modal, page);
});

<|endoftext|>


<commit_before>import React from 'react';
import { shallow, mount } from 'enzyme';
var sinon = require('sinon')
import QueryBuilder from './QueryBuilder';

describe('<QueryBuilder />', () => {

    it('should exist', () => {
        expect(QueryBuilder).to.exist;
    });

    describe('when rendered', () => {
        const query = {
            combinator: 'and',
            id: '111',
            rules: [
                {
                    id: '222',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }
            ]
        };
        it('calls componentWillMount', () => {
            sinon.spy(QueryBuilder.prototype, 'componentWillMount');
            const dom = mount(<QueryBuilder />);
            expect(QueryBuilder.prototype.componentWillMount.calledOnce).to.equal(true);
            dom.unmount();
        });
        it('calls componentDidMount', () => {
            sinon.spy(QueryBuilder.prototype, 'componentDidMount');
            const dom = mount(<QueryBuilder />);
            expect(QueryBuilder.prototype.componentDidMount.calledOnce).to.equal(true);
            dom.instance()._notifyQueryChange(()=>{},query);
            dom.update();
            expect(dom.props().query).to.equal(null);
        });
        it('should render the root RuleGroup', () => {
            const dom = shallow(<QueryBuilder />);
            expect(dom.find('RuleGroup')).to.have.length(1);
        });

        it('should show the list of combinators in the RuleGroup', () => {
            const dom = mount(<QueryBuilder />);
            const options = dom.find('select option');
            expect(options).to.have.length(2); // and, or
        });

    });

    describe('when initial query is provided', () => {
        let dom;

        beforeEach(() => {
            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];

            const query = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }
                ]
            };

            dom = mount(<QueryBuilder query={query} fields={fields} />);

        });

        afterEach(() => {
            if (dom) {
                dom.unmount();
            }
        });

        it('should contain a <Rule />', () => {

            const rule = dom.find('Rule');
            expect(rule).to.have.length(1);
        });

        it('should have the Rule with the correct props', () => {
            const rule = dom.find('Rule');

            expect(rule.props().field).to.equal('firstName');
            expect(rule.props().value).to.equal('Test');
            expect(rule.props().operator).to.equal('=');
        });

        it('should have a select control with the provided fields', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-fields option')).to.have.length(3);
        });

        it('should have a field selector with the correct field', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-fields select').props().value).to.equal('firstName');
        });

        it('should have an operator selector with the correct operator', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-operators select').props().value).to.equal('=');
        });

        it('should have an input control with the correct value', () => {
            const rule = dom.find('Rule');

            expect(rule.find('input').props().value).to.equal('Test');
        });

});
    describe('when new props are passed',()=>{
        it('calls componentWillRecieveProps', () => {

            const newFields = [
                { name: 'domainName', label: 'Domain Name' },
                { name: 'ownerName', label: 'Owner Name' },

            ];

            const newQuery = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'domainName',
                        value: 'www.example.com',
                        operator: '!='
                    }
                ]
            };
            //First mount with props
            sinon.spy(QueryBuilder.prototype, 'componentWillReceiveProps');
            const dom = mount(<QueryBuilder />);

            expect(QueryBuilder.prototype.componentWillReceiveProps.calledOnce).to.equal(false);

            //componentWillRecieveProps
            dom.setProps({
                query: newQuery,
                fields: newFields
            });
            expect(QueryBuilder.prototype.componentWillReceiveProps.calledOnce).to.equal(true);
            expect(dom.props().query).to.equal(newQuery);
            const rule = dom.find('Rule');
            expect(dom.find('RuleGroup')).to.have.length(1);
            expect(rule.find('input').props().value).to.equal('www.example.com');
        });

    });

    describe('when initial operators are provided', () => {

        let dom;
        beforeEach(() => {
            const operators = [
                { name: 'null', label: 'Custom Is Null' },
                { name: 'notNull', label: 'Is Not Null' },
                { name: 'in', label: 'In' },
                { name: 'notIn', label: 'Not In' },
            ];

            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];

            const query = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }
                ]
            };

            dom = mount(<QueryBuilder operators={operators}
                                      fields={fields}
                                      query={query} />);
        });
        it('should get operators for field', () => {
            let operators = dom.state('schema').getOperators('firstName');
            //console.log('OPS',operators);
            expect(operators.length).to.equal(4);
        });
        it('should use the given operators', () => {
            const operatorOptions = dom.find('Rule').find('.rule-operators option');

            expect(operatorOptions.length).to.equal(4);
        });

        it('should match the label of the first operator', () => {
            const operatorOption = dom.find('Rule').find('.rule-operators option').first();

            expect(operatorOption.text()).to.equal('Custom Is Null');
        });
    });

    describe('when calculating the level of a rule', function () {
        let dom;
        beforeEach(() => {
            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];
            const query = {
                combinator: 'and',
                id: '111',
                rules: [{
                    id: '222',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }, {
                    id: '333',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }, {
                    combinator: 'and',
                    id: '444',
                    rules: [{
                        id: '555',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }]
                }]
            };

            dom = mount(<QueryBuilder query={query} fields={fields} />);
        });

        it('should be 0 for the top level', function () {
            expect(dom.state('schema').getLevel('111')).to.equal(0);
            expect(dom.state('schema').getLevel('222')).to.equal(0);
            expect(dom.state('schema').getLevel('333')).to.equal(0);
        });

        it('should be 1 for the second level', function () {
            expect(dom.state('schema').getLevel('444')).to.equal(1);
            expect(dom.state('schema').getLevel('555')).to.equal(1);
        });

        it('should handle an invalid id', function () {
            expect(dom.state('schema').getLevel('546')).to.equal(-1);
        });
    });
});
<commit_msg>Call onQueryChange<commit_after>import React from 'react';
import { shallow, mount } from 'enzyme';
var sinon = require('sinon')
import QueryBuilder from './QueryBuilder';

describe('<QueryBuilder />', () => {

    it('should exist', () => {
        expect(QueryBuilder).to.exist;
    });

    describe('when rendered', () => {
        const query = {
            combinator: 'and',
            id: '111',
            rules: [
                {
                    id: '222',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }
            ]
        };
        it('calls componentWillMount', () => {
            sinon.spy(QueryBuilder.prototype, 'componentWillMount');
            const dom = mount(<QueryBuilder />);
            expect(QueryBuilder.prototype.componentWillMount.calledOnce).to.equal(true);
            dom.unmount();
        });
        it('calls componentDidMount', () => {
            sinon.spy(QueryBuilder.prototype, 'componentDidMount');
            const dom = mount(<QueryBuilder />);
            expect(QueryBuilder.prototype.componentDidMount.calledOnce).to.equal(true);

        });
        it('should render the root RuleGroup', () => {
            const dom = shallow(<QueryBuilder />);
            expect(dom.find('RuleGroup')).to.have.length(1);
        });

        it('should show the list of combinators in the RuleGroup', () => {
            const dom = mount(<QueryBuilder />);
            const options = dom.find('select option');
            expect(options).to.have.length(2); // and, or
        });
        it('should call  onQueryChange',()=>{

            const dom = mount(<QueryBuilder onQueryChange={()=>{return query}} />);
            dom.instance()._notifyQueryChange(()=>{});
            dom.update();
            expect(dom.props().query).to.equal(null);
        });

    });

    describe('when initial query is provided', () => {
        let dom;

        beforeEach(() => {
            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];

            const query = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }
                ]
            };

            dom = mount(<QueryBuilder query={query} fields={fields} />);

        });

        afterEach(() => {
            if (dom) {
                dom.unmount();
            }
        });

        it('should contain a <Rule />', () => {

            const rule = dom.find('Rule');
            expect(rule).to.have.length(1);
        });

        it('should have the Rule with the correct props', () => {
            const rule = dom.find('Rule');

            expect(rule.props().field).to.equal('firstName');
            expect(rule.props().value).to.equal('Test');
            expect(rule.props().operator).to.equal('=');
        });

        it('should have a select control with the provided fields', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-fields option')).to.have.length(3);
        });

        it('should have a field selector with the correct field', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-fields select').props().value).to.equal('firstName');
        });

        it('should have an operator selector with the correct operator', () => {
            const rule = dom.find('Rule');

            expect(rule.find('.rule-operators select').props().value).to.equal('=');
        });

        it('should have an input control with the correct value', () => {
            const rule = dom.find('Rule');

            expect(rule.find('input').props().value).to.equal('Test');
        });

});
    describe('when new props are passed',()=>{
        it('calls componentWillRecieveProps', () => {

            const newFields = [
                { name: 'domainName', label: 'Domain Name' },
                { name: 'ownerName', label: 'Owner Name' },

            ];

            const newQuery = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'domainName',
                        value: 'www.example.com',
                        operator: '!='
                    }
                ]
            };
            //First mount with props
            sinon.spy(QueryBuilder.prototype, 'componentWillReceiveProps');
            const dom = mount(<QueryBuilder />);

            expect(QueryBuilder.prototype.componentWillReceiveProps.calledOnce).to.equal(false);

            //componentWillRecieveProps
            dom.setProps({
                query: newQuery,
                fields: newFields
            });
            expect(QueryBuilder.prototype.componentWillReceiveProps.calledOnce).to.equal(true);
            expect(dom.props().query).to.equal(newQuery);
            const rule = dom.find('Rule');
            expect(dom.find('RuleGroup')).to.have.length(1);
            expect(rule.find('input').props().value).to.equal('www.example.com');
        });

    });

    describe('when initial operators are provided', () => {

        let dom;
        beforeEach(() => {
            const operators = [
                { name: 'null', label: 'Custom Is Null' },
                { name: 'notNull', label: 'Is Not Null' },
                { name: 'in', label: 'In' },
                { name: 'notIn', label: 'Not In' },
            ];

            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];

            const query = {
                combinator: 'and',
                id: '111',
                rules: [
                    {
                        id: '222',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }
                ]
            };

            dom = mount(<QueryBuilder operators={operators}
                                      fields={fields}
                                      query={query} />);
        });
        it('should get operators for field', () => {
            let operators = dom.state('schema').getOperators('firstName');
            //console.log('OPS',operators);
            expect(operators.length).to.equal(4);
        });
        it('should use the given operators', () => {
            const operatorOptions = dom.find('Rule').find('.rule-operators option');

            expect(operatorOptions.length).to.equal(4);
        });

        it('should match the label of the first operator', () => {
            const operatorOption = dom.find('Rule').find('.rule-operators option').first();

            expect(operatorOption.text()).to.equal('Custom Is Null');
        });
    });

    describe('when calculating the level of a rule', function () {
        let dom;
        beforeEach(() => {
            const fields = [
                { name: 'firstName', label: 'First Name' },
                { name: 'lastName', label: 'Last Name' },
                { name: 'age', label: 'Age' },
            ];
            const query = {
                combinator: 'and',
                id: '111',
                rules: [{
                    id: '222',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }, {
                    id: '333',
                    field: 'firstName',
                    value: 'Test',
                    operator: '='
                }, {
                    combinator: 'and',
                    id: '444',
                    rules: [{
                        id: '555',
                        field: 'firstName',
                        value: 'Test',
                        operator: '='
                    }]
                }]
            };

            dom = mount(<QueryBuilder query={query} fields={fields} />);
        });

        it('should be 0 for the top level', function () {
            expect(dom.state('schema').getLevel('111')).to.equal(0);
            expect(dom.state('schema').getLevel('222')).to.equal(0);
            expect(dom.state('schema').getLevel('333')).to.equal(0);
        });

        it('should be 1 for the second level', function () {
            expect(dom.state('schema').getLevel('444')).to.equal(1);
            expect(dom.state('schema').getLevel('555')).to.equal(1);
        });

        it('should handle an invalid id', function () {
            expect(dom.state('schema').getLevel('546')).to.equal(-1);
        });
    });
});
<|endoftext|>


<commit_before>const Error = require('@cardstack/plugin-utils/error');
const request = require('./lib/request');

exports.authenticate = async function(payload, params /*, userSearcher */) {
  if (!payload.authorizationCode) {
    throw new Error("missing required field 'authorizationCode'", {
      status: 400
    });
  }

  let payloadToGitHub = {
    client_id: params['client-id'],
    client_secret: params['client-secret'],
    code: payload.authorizationCode
  };
  if (payload.state) {
    payloadToGitHub.state = payload.state;
  }

  let data = JSON.stringify(payloadToGitHub);
  let options = {
    hostname: 'github.com',
    port: 443,
    path: '/login/oauth/access_token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(data),
      'Accept': 'application/json',
      'User-Agent': '@cardstack/github-auth'
    }
  };

  let { response, body: responseBody } = await request(options, data);
  if (response.statusCode !== 200) {
    throw new Error(responseBody.error, {
      status: response.statusCode
    });
  }

  options = {
    hostname: 'api.github.com',
    port: 443,
    path: '/user',
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'User-Agent': '@cardstack/github-auth',
      Authorization: `token ${responseBody.access_token}`
    }
  };

  let userResponse = await request(options);
  if (userResponse.response.statusCode !== 200) {
    throw new Error(responseBody.error, { status: response.statusCode });
  }
  return {
    user: userResponse.body
  };
};

exports.exposeConfig = function(params) {
  return {
    clientId: params['client-id']
  };
};

exports.defaultUserTemplate =  "{ \"id\": \"{{login}}\", \"attributes\": { \"name\": \"{{name}}\", \"email\":\"{{email}}\", \"avatar-url\":\"{{avatar_url}}\" }}";
<commit_msg>add type to default user template<commit_after>const Error = require('@cardstack/plugin-utils/error');
const request = require('./lib/request');

exports.authenticate = async function(payload, params /*, userSearcher */) {
  if (!payload.authorizationCode) {
    throw new Error("missing required field 'authorizationCode'", {
      status: 400
    });
  }

  let payloadToGitHub = {
    client_id: params['client-id'],
    client_secret: params['client-secret'],
    code: payload.authorizationCode
  };
  if (payload.state) {
    payloadToGitHub.state = payload.state;
  }

  let data = JSON.stringify(payloadToGitHub);
  let options = {
    hostname: 'github.com',
    port: 443,
    path: '/login/oauth/access_token',
    method: 'POST',
    headers: {
      'Content-Type': 'application/json',
      'Content-Length': Buffer.byteLength(data),
      'Accept': 'application/json',
      'User-Agent': '@cardstack/github-auth'
    }
  };

  let { response, body: responseBody } = await request(options, data);
  if (response.statusCode !== 200) {
    throw new Error(responseBody.error, {
      status: response.statusCode
    });
  }

  options = {
    hostname: 'api.github.com',
    port: 443,
    path: '/user',
    method: 'GET',
    headers: {
      'Accept': 'application/json',
      'User-Agent': '@cardstack/github-auth',
      Authorization: `token ${responseBody.access_token}`
    }
  };

  let userResponse = await request(options);
  if (userResponse.response.statusCode !== 200) {
    throw new Error(responseBody.error, { status: response.statusCode });
  }
  return {
    user: userResponse.body
  };
};

exports.exposeConfig = function(params) {
  return {
    clientId: params['client-id']
  };
};

exports.defaultUserTemplate =  "{ \"id\": \"{{login}}\", \"type\": \"github-users\", \"attributes\": { \"name\": \"{{name}}\", \"email\":\"{{email}}\", \"avatar-url\":\"{{avatar_url}}\" }}";
<|endoftext|>