<commit_before>/**
 * @file Contains logic to actually pivot data
*/

/**
 * @description Format data into an array of objects where the headers are the keys
 * @param {!Array|Object} data Array of arrays or an object
 * @returns {Array<Object>} Formatted object
*/
export function fixDataFormat(data, rows = []) {
  if (!Array.isArray(data) || !data.length) return [];

  let formattedData = [];

  if (typeof data[0] === 'object' && !Array.isArray(data[0])) {
    formattedData = data;
  } else {
    formattedData = data.reduce((dataCol, row, i, arr) => {
      if (i !== 0) {
        if (Array.isArray(row)) {
          dataCol.push(row.reduce((acc, curr, index) =>{
            acc[arr[0][index]] = curr;
            return acc;
          }, {}));
        } else {
          dataCol.push({[arr[0]]: row});
        }
      }
      return dataCol;
    }, []);
  }

  // sorting data initially to prevent changes in data ordering
  if (rows.length > 0) {
    return rows.reduceRight((acc, row) => {
      return acc.sort((a, b) => {
        return a[row] > b[row];
      });
    }, formattedData);
  }

  return formattedData.sort((a, b) => {
    return JSON.stringify(a) > JSON.stringify(b);
  });
}

/**
 * @description Groups the data into an object by the provided category
 * @param {!Array<Object>} data Array of objects
 * @param {string} groupBy Category to group by
 * @returns {Object} Each key in the object is one the category groups
*/
export function groupByCategory(data, groupBy) {
  return data.reduce((acc, curr) =>{
    const category = curr[groupBy];

    if (!acc[category]) acc[category] = [];
    acc[category].push(curr);
    return acc;
  }, {});
}

/**
 * @description Performs groupByCategory recursively (nesting objects within objects)
 * @param {!Array<Object>} data Array of objects
 * @param {Array} groups Items to categorize by
 * @param {Object} acc The accumulated results
 * @returns {Object} Deeply nested object
 * where each key is one the category groups
*/
export function groupByCategories(data, groups = [], acc = {}) {
  /**
   * base case - if data is empty
   * or if there are no more groups to group by
   * return result
  */
  if (data.length === 0 || groups.length === 0) return data;

  const groupedData = groupByCategory(data, groups[0]);
  const groupedDataKeys = Object.keys(groupedData);
  const children = Object.values(groupedData);

  for (let i = 0; i < children.length; i++) {
    acc[groupedDataKeys[i]] = groupByCategories(
        children[i], groups.slice(1), acc[groupedDataKeys[i]]);
  }

  return acc;
}

/**
 * @description Builds the column headers and a map to each header
 * @param {!Array<Object>} data Array of objects
 * @param {Array} cols Columns to pivot on
 * @param {string} firstColumn A string to place in the first column header
 * @returns {Object} columnHeaders (array of arrays) and mapToHeader (object)
*/
export function createColumnHeaders(data, cols = [], firstColumn = '') {
  if (cols.length === 0) {
    return {
      columnHeaders: [firstColumn],
      mapToHeader: null,
    };
  }

  const mapToHeader = groupByCategories(data, cols);
  const columnHeaders = [];
  let mapPos = 1;

  (function columnHeaderRecursion(data, pos = 0, headerMap) {
    /** base case - at actual data as opposed to another grouping */
    if (typeof data !== 'object' || Array.isArray(data)) return 1;

    const currKeys = Object.keys(data);
    let sumLength = 0;

    for (let i = 0; i < currKeys.length; i++) {
      const currLength = columnHeaderRecursion(
          data[currKeys[i]], pos + 1, headerMap[currKeys[i]]);

      if (Array.isArray(data[currKeys[i]])) {
        headerMap[currKeys[i]] = mapPos;
        mapPos += 1;
      }

      columnHeaders[pos] = typeof columnHeaders[pos] === 'undefined' ?
        [firstColumn].concat(Array(currLength).fill(currKeys[i])) :
        columnHeaders[pos].concat(Array(currLength).fill(currKeys[i]));

      sumLength += currLength;
    }

    return sumLength;

  }(mapToHeader, 0, mapToHeader));

  return {
    columnHeaders,
    mapToHeader,
  };
}

/**
 * @description Reduces an array of values to a result
 * @param {!Array} arr The array to reduce
 * @param {?requestCallback|string} accCat Callback, category to reduce, or null
 * @param {string} accType Reduce type (count, average, min, max, etc) or initial value
 * @param {*} accValue Initial value - string, number, array, or object
 * @returns {*} Reduced value
 * @todo Move accumulator to its own file since it will continue to grow
*/
export function accumulator(arr, accCat, accType, accValue) {
  if (typeof accCat === 'undefined') accType = 'count';
  else if (typeof accCat === 'function') accValue = accType || 0;

  return arr.reduce((acc, curr, index, array) => {
    if (typeof accCat === 'function') return accCat(acc, curr, index, array);

    switch (accType) {
      case ('average'): {
        acc += Number(curr[accCat]) / arr.length;

        return acc;
      }

      case ('count'): {
        acc += 1;

        return acc;
      }

      case ('min'): {
        if (index === 0) acc = Number(curr[accCat]);
        else if (curr[accCat] < acc) acc = Number(curr[accCat]);

        return acc;
      }

      case ('max'): {
        if (index === 0) acc = Number(curr[accCat]);
        else if (curr[accCat] > acc) acc = Number(curr[accCat]);

        return acc;
      }

      case ('sum'): {
        acc += Number(curr[accCat]);

        return acc;
      }

      default: {
        acc += 1;

        return acc;
      }
    }
  }, accValue || 0);
}

/**
 * @description Check that categories to pivot on actually exist
 * @param {!Object} actualCats Categories that actually exist in the data
 * @param {!Array<string>} selectedCats Categories to pivot selected by user
 * @throws Will throw an error if the category does not exist
*/
export function checkPivotCategories(actualCats, selectedCats) {
  const errMessage = selectedCats.filter((selectedCat) => {
    return !(selectedCat in actualCats);
  });

  if (errMessage.length > 0) {
    throw new Error('Check that these selected pivot categories exist: ' +
      errMessage.join(', '));
  }
}

export function tableCreator(data, rows = [], cols = [], accCatOrCB,
  accTypeOrInitVal, rowHeader) {

  /** if data is empty, return empty array */
  if (data.length === 0) {
    return {
      rawData: [],
      table: [],
    };
  };

  /** if rows/cols are not arrays, return throw an error */
  if (!Array.isArray(rows) || !Array.isArray(cols)) {
    throw new Error('rowsToPivot and colsToPivot must be of type array');
  }

  checkPivotCategories(data[0], rows);
  checkPivotCategories(data[0], cols);

  if (typeof rowHeader === 'undefined') {
    rowHeader = typeof accCatOrCB !== 'function' ?
      `${accTypeOrInitVal} ${accCatOrCB}` :
      'Custom Agg';
  }

  const columnData = createColumnHeaders(data, cols, rowHeader);
  const columnHeaders = Array.isArray(columnData.columnHeaders[0]) ?
    columnData.columnHeaders :
    [columnData.columnHeaders.concat(rowHeader)];
  const mapToHeader = columnData.mapToHeader;
  const headerLength = columnHeaders[0].length;
  const formattedColumnHeaders = columnHeaders.map((value, depth) => {
    return {
      value,
      depth,
      type: 'colHeader',
      row: depth,
    };
  });

  let dataRows = [];
  let rawData = [];
  let prevKey = null;

  function rowRecurse(rowGroups, depth, rowHeaders = []) {
    for (const key in rowGroups) {
      if (Array.isArray(rowGroups[key])) {
        const recursedData = groupByCategories(rowGroups[key], cols);

        prevKey = null;

        (function recurseThroughMap(dataPos, map) {
          if (Array.isArray(dataPos)) {
            if (key === prevKey) {
              const datum = dataRows[dataRows.length - 1].value;

              datum[map] = accumulator(dataPos, accCatOrCB, accTypeOrInitVal);
              dataRows[dataRows.length - 1].value = datum;

              const rawDataDatum = rawData[rawData.length - 1].value;

              rawDataDatum[map] = dataPos;
              rawData[rawData.length - 1].value = rawDataDatum;
            } else {
              prevKey = key;
              const datum = [key].concat(
                Array(map - 1).fill(''),
                accumulator(dataPos, accCatOrCB, accTypeOrInitVal),
                Array(headerLength - (map + 1)).fill('')
              );
              const rawDataDatum = [key].concat(
                Array(map - 1).fill(''),
                [dataPos],
                Array(headerLength - (map + 1)).fill('')
              );

              rawData.push({
                value: rawDataDatum,
                type: 'data',
                depth,
              });
              dataRows.push({
                value: datum,
                type: 'data',
                depth,
                row: dataRows.length + formattedColumnHeaders.length,
              });
            }
          } else {
            for (const innerKey in dataPos) {
              recurseThroughMap(dataPos[innerKey], map[innerKey]);
            }
          }
        })(recursedData, mapToHeader || 1);

      } else {
        const rowHeaderValue = rowHeaders.shift();
        const value = rowHeaderValue ?
            rowHeaderValue.value :
            [key].concat(Array(headerLength - 1).fill(''));

        dataRows.push({
          value,
          depth,
          type: 'rowHeader',
          row: dataRows.length + formattedColumnHeaders.length,
        });
        rawData.push({
          value,
          depth,
          type: 'rowHeader',
        });

        rowRecurse(rowGroups[key], depth + 1, rowHeaders);
      }
    }
  }

  let dataGroups = [];

  if (rows.length > 0) {
    for (let i = 0; i < rows.length; i++) {
      // possible memoization opportunity
      rowRecurse(groupByCategories(data, rows.slice(0, i + 1)), 0, dataGroups);
      dataGroups = Object.assign([], dataRows);
      if (i + 1 < rows.length) {
        dataRows = [];
        rawData = [];
        prevKey = null;
      }
    }
  } else if (cols.length > 0) {
    for (let i = 0; i < cols.length; i++) {
      rowRecurse(groupByCategories(data, cols.slice(0, i + 1)), 0, dataGroups);
      dataGroups = Object.assign([], dataRows);
      if (i + 1 < cols.length) {
        dataRows = [];
        rawData = [];
        prevKey = null;
      }
    }
  } else {
    dataRows.push({
      value: [rowHeader, accumulator(data, accCatOrCB, accTypeOrInitVal)],
      type: 'data',
      row: 1,
      depth: 0,
    });
    rawData = data.map((value) => {
      return {
        value,
        type: 0,
        row: 1,
        depth: 0,
      };
    });
  }

  return {
    table: formattedColumnHeaders.concat(dataRows),
    rawData: formattedColumnHeaders.concat(rawData),
  };

}
<commit_msg>adds row count total<commit_after>/**
 * @file Contains logic to actually pivot data
*/

/**
 * @description Format data into an array of objects where the headers are the keys
 * @param {!Array|Object} data Array of arrays or an object
 * @returns {Array<Object>} Formatted object
*/
export function fixDataFormat(data, rows = []) {
  if (!Array.isArray(data) || !data.length) return [];

  let formattedData = [];

  if (typeof data[0] === 'object' && !Array.isArray(data[0])) {
    formattedData = data;
  } else {
    formattedData = data.reduce((dataCol, row, i, arr) => {
      if (i !== 0) {
        if (Array.isArray(row)) {
          dataCol.push(row.reduce((acc, curr, index) =>{
            acc[arr[0][index]] = curr;
            return acc;
          }, {}));
        } else {
          dataCol.push({[arr[0]]: row});
        }
      }
      return dataCol;
    }, []);
  }

  // sorting data initially to prevent changes in data ordering
  if (rows.length > 0) {
    return rows.reduceRight((acc, row) => {
      return acc.sort((a, b) => {
        return a[row] > b[row];
      });
    }, formattedData);
  }

  return formattedData.sort((a, b) => {
    return JSON.stringify(a) > JSON.stringify(b);
  });
}

/**
 * @description Groups the data into an object by the provided category
 * @param {!Array<Object>} data Array of objects
 * @param {string} groupBy Category to group by
 * @returns {Object} Each key in the object is one the category groups
*/
export function groupByCategory(data, groupBy) {
  return data.reduce((acc, curr) =>{
    const category = curr[groupBy];

    if (!acc[category]) acc[category] = [];
    acc[category].push(curr);
    return acc;
  }, {});
}

/**
 * @description Performs groupByCategory recursively (nesting objects within objects)
 * @param {!Array<Object>} data Array of objects
 * @param {Array} groups Items to categorize by
 * @param {Object} acc The accumulated results
 * @returns {Object} Deeply nested object
 * where each key is one the category groups
*/
export function groupByCategories(data, groups = [], acc = {}) {
  /**
   * base case - if data is empty
   * or if there are no more groups to group by
   * return result
  */
  if (data.length === 0 || groups.length === 0) return data;

  const groupedData = groupByCategory(data, groups[0]);
  const groupedDataKeys = Object.keys(groupedData);
  const children = Object.values(groupedData);

  for (let i = 0; i < children.length; i++) {
    acc[groupedDataKeys[i]] = groupByCategories(
        children[i], groups.slice(1), acc[groupedDataKeys[i]]);
  }

  return acc;
}

/**
 * @description Builds the column headers and a map to each header
 * @param {!Array<Object>} data Array of objects
 * @param {Array} cols Columns to pivot on
 * @param {string} firstColumn A string to place in the first column header
 * @returns {Object} columnHeaders (array of arrays) and mapToHeader (object)
*/
export function createColumnHeaders(data, cols = [], firstColumn = '') {
  if (cols.length === 0) {
    return {
      columnHeaders: [firstColumn],
      mapToHeader: null,
    };
  }

  const mapToHeader = groupByCategories(data, cols);
  const columnHeaders = [];
  let mapPos = 1;

  (function columnHeaderRecursion(data, pos = 0, headerMap) {
    /** base case - at actual data as opposed to another grouping */
    if (typeof data !== 'object' || Array.isArray(data)) return 1;

    const currKeys = Object.keys(data);
    let sumLength = 0;

    for (let i = 0; i < currKeys.length; i++) {
      const currLength = columnHeaderRecursion(
          data[currKeys[i]], pos + 1, headerMap[currKeys[i]]);

      if (Array.isArray(data[currKeys[i]])) {
        headerMap[currKeys[i]] = mapPos;
        mapPos += 1;
      }

      columnHeaders[pos] = typeof columnHeaders[pos] === 'undefined' ?
        [firstColumn].concat(Array(currLength).fill(currKeys[i])) :
        columnHeaders[pos].concat(Array(currLength).fill(currKeys[i]));

      sumLength += currLength;
    }

    return sumLength;

  }(mapToHeader, 0, mapToHeader));

  return {
    columnHeaders,
    mapToHeader,
  };
}

/**
 * @description Reduces an array of values to a result
 * @param {!Array} arr The array to reduce
 * @param {?requestCallback|string} accCat Callback, category to reduce, or null
 * @param {string} accType Reduce type (count, average, min, max, etc) or initial value
 * @param {*} accValue Initial value - string, number, array, or object
 * @returns {*} Reduced value
 * @todo Move accumulator to its own file since it will continue to grow
*/
export function accumulator(arr, accCat, accType, accValue) {
  if (typeof accCat === 'undefined') accType = 'count';
  else if (typeof accCat === 'function') accValue = accType || 0;

  return arr.reduce((acc, curr, index, array) => {
    if (typeof accCat === 'function') return accCat(acc, curr, index, array);

    switch (accType) {
      case ('average'): {
        acc += Number(curr[accCat]) / arr.length;

        return acc;
      }

      case ('count'): {
        acc += 1;

        return acc;
      }

      case ('min'): {
        if (index === 0) acc = Number(curr[accCat]);
        else if (curr[accCat] < acc) acc = Number(curr[accCat]);

        return acc;
      }

      case ('max'): {
        if (index === 0) acc = Number(curr[accCat]);
        else if (curr[accCat] > acc) acc = Number(curr[accCat]);

        return acc;
      }

      case ('sum'): {
        acc += Number(curr[accCat]);

        return acc;
      }

      default: {
        acc += 1;

        return acc;
      }
    }
  }, accValue || 0);
}

/**
 * @description Check that categories to pivot on actually exist
 * @param {!Object} actualCats Categories that actually exist in the data
 * @param {!Array<string>} selectedCats Categories to pivot selected by user
 * @throws Will throw an error if the category does not exist
*/
export function checkPivotCategories(actualCats, selectedCats) {
  const errMessage = selectedCats.filter((selectedCat) => {
    return !(selectedCat in actualCats);
  });

  if (errMessage.length > 0) {
    throw new Error('Check that these selected pivot categories exist: ' +
      errMessage.join(', '));
  }
}

export function tableCreator(data, rows = [], cols = [], accCatOrCB,
  accTypeOrInitVal, rowHeader) {

  /** if data is empty, return empty array */
  if (data.length === 0) {
    return {
      rawData: [],
      table: [],
    };
  };

  /** if rows/cols are not arrays, return throw an error */
  if (!Array.isArray(rows) || !Array.isArray(cols)) {
    throw new Error('rowsToPivot and colsToPivot must be of type array');
  }

  checkPivotCategories(data[0], rows);
  checkPivotCategories(data[0], cols);

  if (typeof rowHeader === 'undefined') {
    rowHeader = typeof accCatOrCB !== 'function' ?
      `${accTypeOrInitVal} ${accCatOrCB}` :
      'Custom Agg';
  }

  const columnData = createColumnHeaders(data, cols, rowHeader);
  const columnHeaders = Array.isArray(columnData.columnHeaders[0]) ?
    columnData.columnHeaders :
    [columnData.columnHeaders.concat(rowHeader)];
  const mapToHeader = columnData.mapToHeader;
  const headerLength = columnHeaders[0].length;
  const formattedColumnHeaders = columnHeaders.map((value, depth) => {
    return {
      value,
      depth,
      type: 'colHeader',
      row: depth,
    };
  });

  let dataRows = [];
  let rawData = [];
  let prevKey = null;

  function rowRecurse(rowGroups, depth, rowHeaders = []) {
    for (const key in rowGroups) {
      if (Array.isArray(rowGroups[key])) {
        const recursedData = groupByCategories(rowGroups[key], cols);

        prevKey = null;

        (function recurseThroughMap(dataPos, map) {
          if (Array.isArray(dataPos)) {
            if (key === prevKey) {
              const datum = dataRows[dataRows.length - 1].value;

              datum[map] = accumulator(dataPos, accCatOrCB, accTypeOrInitVal);
              dataRows[dataRows.length - 1].value = datum;

              const rawDataDatum = rawData[rawData.length - 1].value;

              rawDataDatum[map] = dataPos;
              rawData[rawData.length - 1].value = rawDataDatum;
            } else {
              prevKey = key;
              const datum = [key].concat(
                Array(map - 1).fill(''),
                accumulator(dataPos, accCatOrCB, accTypeOrInitVal),
                Array(headerLength - (map + 1)).fill('')
              );
              const rawDataDatum = [key].concat(
                Array(map - 1).fill(''),
                [dataPos],
                Array(headerLength - (map + 1)).fill('')
              );

              rawData.push({
                value: rawDataDatum,
                type: 'data',
                depth,
              });
              dataRows.push({
                value: datum,
                type: 'data',
                depth,
                row: dataRows.length + formattedColumnHeaders.length,
              });
            }
          } else {
            for (const innerKey in dataPos) {
              recurseThroughMap(dataPos[innerKey], map[innerKey]);
            }
          }
        })(recursedData, mapToHeader || 1);

      } else {
        const rowHeaderValue = rowHeaders.shift();
        const value = rowHeaderValue ?
            rowHeaderValue.value :
            [key].concat(Array(headerLength - 1).fill(''));

        dataRows.push({
          value,
          depth,
          type: 'rowHeader',
          row: dataRows.length + formattedColumnHeaders.length,
        });
        rawData.push({
          value,
          depth,
          type: 'rowHeader',
        });

        rowRecurse(rowGroups[key], depth + 1, rowHeaders);
      }
    }
  }

  let dataGroups = [];

  if (rows.length > 0) {
    for (let i = 0; i < rows.length; i++) {
      // possible memoization opportunity
      rowRecurse(groupByCategories(data, rows.slice(0, i + 1)), 0, dataGroups);
      dataGroups = Object.assign([], dataRows);
      if (i + 1 < rows.length) {
        dataRows = [];
        rawData = [];
        prevKey = null;
      }
    }
  } else if (cols.length > 0) {
    for (let i = 0; i < cols.length; i++) {
      rowRecurse(groupByCategories(data, cols.slice(0, i + 1)), 0, dataGroups);
      dataGroups = Object.assign([], dataRows);
      if (i + 1 < cols.length) {
        dataRows = [];
        rawData = [];
        prevKey = null;
      }
    }
  } else {
    dataRows.push({
      value: [rowHeader, accumulator(data, accCatOrCB, accTypeOrInitVal)],
      type: 'data',
      row: 1,
      depth: 0,
    });
    rawData = data.map((value) => {
      return {
        value,
        type: 0,
        row: 1,
        depth: 0,
      };
    });
  }

  function completedTableAccumulator(rows) {
    if (rows.length > 0) {
      return rows.reduce((acc, { type, value }) => {
        if (type === 'data') {
          value.forEach((val, index) => {
            if (index > 0) {
              acc[index] = val !== '' ? acc[index] + 1 : acc[index];
            }
          });
        }
        return acc;
      }, [''].concat(Array(rows[0].value.length - 1).fill(0)));
    }

    return [];
  }

  const summedRows = {value: completedTableAccumulator(dataRows), type: 'sum'};

  return {
    table: formattedColumnHeaders.concat(dataRows, summedRows),
    rawData: formattedColumnHeaders.concat(rawData),
  };

}
<|endoftext|>


<commit_before>var fs = require("fs");
var exec = require("child_process").exec;
var path = require("path");

var _ = require("lodash");
var Bacon = require("baconjs");

var Logger = require("./logger.js");
var conf = require("./models/configuration.js");

function getOpenCommand() {
  Logger.debug("Get the right command to open a tab in a browser…")
  switch(process.platform) {
    case "darwin":
      return Bacon.constant("open " + conf.CONSOLE_TOKEN_URL);
    case "linux":
      return Bacon.constant("xdg-open" + conf.CONSOLE_TOKEN_URL);
    default:
      return new Bacon.Error("Unsupported platform: " + process.platform);
  }
}

function runCommand(command) {
  Logger.debug("Open the token management page in a browser…")
  return Bacon.fromBinder(function(sink) {
    exec(command, function(error, stdout, stderr) {
      if(error || stderr) {
        sink(new Bacon.Error(error || stderr));
      }
      else {
        sink(stdout);
      }
      sink(new Bacon.End());
    });

    return function(){};
  });
}

function ask(question) {
  var readline = require("readline").createInterface({
    input: process.stdin,
    output: process.stdout
  });

  return Bacon.fromCallback(_.partial(readline.question.bind(readline), question)).doAction(readline.close.bind(readline));
}

function getOAuthData() {
  Logger.debug("Ask for tokens…");
  var s_token = ask("Enter CLI token: ");
  var s_secret = s_token.flatMapLatest(_.partial(ask, "Enter CLI secret: "));

  return Bacon.combineTemplate({
    token: s_token,
    secret: s_secret
  });
}

function writeLoginConfig(oauthData) {
  Logger.debug("Write the tokens in the configuration file…")
  return Bacon.fromNodeCallback(_.partial(fs.writeFile, conf.CONFIGURATION_FILE, JSON.stringify(oauthData)));
}

var login = module.exports = function(api) {
  var yargs = login.yargs();
  var argv = yargs.argv;

  if(argv.help) {
    yargs.showHelp();
    return;
  }

  Logger.debug("Try to login to Clever-Cloud…")
  var result = getOpenCommand()
    .flatMapLatest(runCommand)
    .flatMapLatest(getOAuthData)
    .flatMapLatest(writeLoginConfig)
    .map(conf.CONFIGURATION_FILE + " has been updated.");

  result.onValue(Logger.println);
  result.onError(Logger.error);
};

login.usage = "Usage: $0 login";
login.yargs = function() {
  return require("yargs")
    .usage(login.usage)
    .options("help", {
      alias: "h",
      boolean: true,
      description: "Show an help message"
    });
};
<commit_msg>login: fix opening the console on the linux platform.<commit_after>var fs = require("fs");
var exec = require("child_process").exec;
var path = require("path");

var _ = require("lodash");
var Bacon = require("baconjs");

var Logger = require("./logger.js");
var conf = require("./models/configuration.js");

function getOpenCommand() {
  Logger.debug("Get the right command to open a tab in a browser…")
  switch(process.platform) {
    case "darwin":
      return Bacon.constant("open " + conf.CONSOLE_TOKEN_URL);
    case "linux":
      return Bacon.constant("xdg-open " + conf.CONSOLE_TOKEN_URL);
    default:
      return new Bacon.Error("Unsupported platform: " + process.platform);
  }
}

function runCommand(command) {
  Logger.debug("Open the token management page in a browser…")
  return Bacon.fromBinder(function(sink) {
    exec(command, function(error, stdout, stderr) {
      if(error || stderr) {
        sink(new Bacon.Error(error || stderr));
      }
      else {
        sink(stdout);
      }
      sink(new Bacon.End());
    });

    return function(){};
  });
}

function ask(question) {
  var readline = require("readline").createInterface({
    input: process.stdin,
    output: process.stdout
  });

  return Bacon.fromCallback(_.partial(readline.question.bind(readline), question)).doAction(readline.close.bind(readline));
}

function getOAuthData() {
  Logger.debug("Ask for tokens…");
  var s_token = ask("Enter CLI token: ");
  var s_secret = s_token.flatMapLatest(_.partial(ask, "Enter CLI secret: "));

  return Bacon.combineTemplate({
    token: s_token,
    secret: s_secret
  });
}

function writeLoginConfig(oauthData) {
  Logger.debug("Write the tokens in the configuration file…")
  return Bacon.fromNodeCallback(_.partial(fs.writeFile, conf.CONFIGURATION_FILE, JSON.stringify(oauthData)));
}

var login = module.exports = function(api) {
  var yargs = login.yargs();
  var argv = yargs.argv;

  if(argv.help) {
    yargs.showHelp();
    return;
  }

  Logger.debug("Try to login to Clever-Cloud…")
  var result = getOpenCommand()
    .flatMapLatest(runCommand)
    .flatMapLatest(getOAuthData)
    .flatMapLatest(writeLoginConfig)
    .map(conf.CONFIGURATION_FILE + " has been updated.");

  result.onValue(Logger.println);
  result.onError(Logger.error);
};

login.usage = "Usage: $0 login";
login.yargs = function() {
  return require("yargs")
    .usage(login.usage)
    .options("help", {
      alias: "h",
      boolean: true,
      description: "Show an help message"
    });
};
<|endoftext|>


<commit_before>import toDate from './lib/toDate';
import toFloat from './lib/toFloat';
import toInt from './lib/toInt';
import toBoolean from './lib/toBoolean';
import equals from './lib/equals';
import contains from './lib/contains';
import matches from './lib/matches';

import isEmail from './lib/isEmail';
import isURL from './lib/isURL';
import isMACAddress from './lib/isMACAddress';
import isIP from './lib/isIP';
import isFQDN from './lib/isFQDN';

import isBoolean from './lib/isBoolean';

import isAlpha from './lib/isAlpha';
import isAlphanumeric from './lib/isAlphanumeric';
import isNumeric from './lib/isNumeric';
import isPort from './lib/isPort';
import isLowercase from './lib/isLowercase';
import isUppercase from './lib/isUppercase';

import isAscii from './lib/isAscii';
import isFullWidth from './lib/isFullWidth';
import isHalfWidth from './lib/isHalfWidth';
import isVariableWidth from './lib/isVariableWidth';
import isMultibyte from './lib/isMultibyte';
import isSurrogatePair from './lib/isSurrogatePair';

import isInt from './lib/isInt';
import isFloat from './lib/isFloat';
import isDecimal from './lib/isDecimal';
import isHexadecimal from './lib/isHexadecimal';
import isDivisibleBy from './lib/isDivisibleBy';

import isHexColor from './lib/isHexColor';

import isISRC from './lib/isISRC';

import isMD5 from './lib/isMD5';
import isHash from './lib/isHash';

import isJSON from './lib/isJSON';
import isEmpty from './lib/isEmpty';

import isLength from './lib/isLength';
import isByteLength from './lib/isByteLength';

import isUUID from './lib/isUUID';
import isMongoId from './lib/isMongoId';

import isAfter from './lib/isAfter';
import isBefore from './lib/isBefore';

import isIn from './lib/isIn';

import isCreditCard from './lib/isCreditCard';

import isISIN from './lib/isISIN';
import isISBN from './lib/isISBN';
import isISSN from './lib/isISSN';

import isMobilePhone from './lib/isMobilePhone';

import isCurrency from './lib/isCurrency';

import isISO8601 from './lib/isISO8601';
import isISO31661Alpha2 from './lib/isISO31661Alpha2';

import isBase64 from './lib/isBase64';
import isDataURI from './lib/isDataURI';
import isMimeType from './lib/isMimeType';

import isLatLong from './lib/isLatLong';
import isPostalCode from './lib/isPostalCode';

import ltrim from './lib/ltrim';
import rtrim from './lib/rtrim';
import trim from './lib/trim';
import escape from './lib/escape';
import unescape from './lib/unescape';
import stripLow from './lib/stripLow';
import whitelist from './lib/whitelist';
import blacklist from './lib/blacklist';
import isWhitelisted from './lib/isWhitelisted';

import normalizeEmail from './lib/normalizeEmail';

import toString from './lib/util/toString';

const version = '9.4.1';

const validator = {
  version,
  toDate,
  toFloat,
  toInt,
  toBoolean,
  equals,
  contains,
  matches,
  isEmail,
  isURL,
  isMACAddress,
  isIP,
  isFQDN,
  isBoolean,
  isAlpha,
  isAlphanumeric,
  isNumeric,
  isPort,
  isLowercase,
  isUppercase,
  isAscii,
  isFullWidth,
  isHalfWidth,
  isVariableWidth,
  isMultibyte,
  isSurrogatePair,
  isInt,
  isFloat,
  isDecimal,
  isHexadecimal,
  isDivisibleBy,
  isHexColor,
  isISRC,
  isMD5,
  isHash,
  isJSON,
  isEmpty,
  isLength,
  isByteLength,
  isUUID,
  isMongoId,
  isAfter,
  isBefore,
  isIn,
  isCreditCard,
  isISIN,
  isISBN,
  isISSN,
  isMobilePhone,
  isPostalCode,
  isCurrency,
  isISO8601,
  isISO31661Alpha2,
  isBase64,
  isDataURI,
  isMimeType,
  isLatLong,
  ltrim,
  rtrim,
  trim,
  escape,
  unescape,
  stripLow,
  whitelist,
  blacklist,
  isWhitelisted,
  normalizeEmail,
  toString,
};

export default validator;
<commit_msg>Update index.js<commit_after>import toDate from './lib/toDate';
import toFloat from './lib/toFloat';
import toInt from './lib/toInt';
import toBoolean from './lib/toBoolean';
import equals from './lib/equals';
import contains from './lib/contains';
import matches from './lib/matches';

import isEmail from './lib/isEmail';
import isURL from './lib/isURL';
import isMACAddress from './lib/isMACAddress';
import isIP from './lib/isIP';
import isFQDN from './lib/isFQDN';

import isBoolean from './lib/isBoolean';

import isAlpha from './lib/isAlpha';
import isAlphanumeric from './lib/isAlphanumeric';
import isNumeric from './lib/isNumeric';
import isPort from './lib/isPort';
import isLowercase from './lib/isLowercase';
import isUppercase from './lib/isUppercase';

import isAscii from './lib/isAscii';
import isFullWidth from './lib/isFullWidth';
import isHalfWidth from './lib/isHalfWidth';
import isVariableWidth from './lib/isVariableWidth';
import isMultibyte from './lib/isMultibyte';
import isSurrogatePair from './lib/isSurrogatePair';

import isInt from './lib/isInt';
import isFloat from './lib/isFloat';
import isDecimal from './lib/isDecimal';
import isHexadecimal from './lib/isHexadecimal';
import isDivisibleBy from './lib/isDivisibleBy';

import isHexColor from './lib/isHexColor';

import isISRC from './lib/isISRC';

import isMD5 from './lib/isMD5';
import isHash from './lib/isHash';

import isJSON from './lib/isJSON';
import isEmpty from './lib/isEmpty';

import isLength from './lib/isLength';
import isByteLength from './lib/isByteLength';

import isUUID from './lib/isUUID';
import isMongoId from './lib/isMongoId';

import isAfter from './lib/isAfter';
import isBefore from './lib/isBefore';

import isIn from './lib/isIn';

import isCreditCard from './lib/isCreditCard';

import isISIN from './lib/isISIN';
import isISBN from './lib/isISBN';
import isISSN from './lib/isISSN';

import isMobilePhone from './lib/isMobilePhone';

import isCurrency from './lib/isCurrency';

import isISO8601 from './lib/isISO8601';
import isISO31661Alpha2 from './lib/isISO31661Alpha2';
import isISO31661Alpha3 from './lib/isISO31661Alpha3';

import isBase64 from './lib/isBase64';
import isDataURI from './lib/isDataURI';
import isMimeType from './lib/isMimeType';

import isLatLong from './lib/isLatLong';
import isPostalCode from './lib/isPostalCode';

import ltrim from './lib/ltrim';
import rtrim from './lib/rtrim';
import trim from './lib/trim';
import escape from './lib/escape';
import unescape from './lib/unescape';
import stripLow from './lib/stripLow';
import whitelist from './lib/whitelist';
import blacklist from './lib/blacklist';
import isWhitelisted from './lib/isWhitelisted';

import normalizeEmail from './lib/normalizeEmail';

import toString from './lib/util/toString';

const version = '9.4.1';

const validator = {
  version,
  toDate,
  toFloat,
  toInt,
  toBoolean,
  equals,
  contains,
  matches,
  isEmail,
  isURL,
  isMACAddress,
  isIP,
  isFQDN,
  isBoolean,
  isAlpha,
  isAlphanumeric,
  isNumeric,
  isPort,
  isLowercase,
  isUppercase,
  isAscii,
  isFullWidth,
  isHalfWidth,
  isVariableWidth,
  isMultibyte,
  isSurrogatePair,
  isInt,
  isFloat,
  isDecimal,
  isHexadecimal,
  isDivisibleBy,
  isHexColor,
  isISRC,
  isMD5,
  isHash,
  isJSON,
  isEmpty,
  isLength,
  isByteLength,
  isUUID,
  isMongoId,
  isAfter,
  isBefore,
  isIn,
  isCreditCard,
  isISIN,
  isISBN,
  isISSN,
  isMobilePhone,
  isPostalCode,
  isCurrency,
  isISO8601,
  isISO31661Alpha2,
  isISO31661Alpha3,
  isBase64,
  isDataURI,
  isMimeType,
  isLatLong,
  ltrim,
  rtrim,
  trim,
  escape,
  unescape,
  stripLow,
  whitelist,
  blacklist,
  isWhitelisted,
  normalizeEmail,
  toString,
};

export default validator;
<|endoftext|>


<commit_before>var urls = require("urls"),
    urlPath = require("url_path"),
    type = require("type"),
    EventEmitter = require("event_emitter");

var page = new EventEmitter(),

    location = global.location || {},

    pageListening = false,
    pageHtml5Mode = false,
    pageOrigin = location.origin,
    pageBase = location.pathname || "/",
    pageCurrentPath = "",
    pageHistory = [],

    sameOrigin_url = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
    sameOrigin_parts = sameOrigin_url.exec(location.href),

    supportsHtml5Mode = global.history && global.history.pushState,
    supportsEventListener = type.isNative(document.addEventListener),

    addEvent, removeEvent;

function sameOrigin(href) {
    var parts, urlPort, testPort;

    if (!urlPath.isAbsoluteURL(href)) return true;

    parts = sameOrigin_url.exec(href.toLowerCase());

    if (!parts) return false;

    urlPort = sameOrigin_parts[3];
    testPort = parts[3];

    return !(
        (parts[1] !== sameOrigin_parts[1]) ||
        (parts[2] !== sameOrigin_parts[2]) || !(
            (testPort === urlPort) ||
            (!testPort && (urlPort === "80" || urlPort === "443")) ||
            (!urlPort && (testPort === "80" || testPort === "443"))
        )
    );
}

if (supportsEventListener) {
    addEvent = function(elem, name, handler) {
        elem.addEventListener(name, handler, false);
        return handler;
    };

    removeEvent = function(elem, name, handler) {
        elem.removeEventListener(name, handler, false);
        return true;
    };
} else {
    addEvent = function(elem, name, handler) {

        function boundedHandler(e) {

            return handler.call(elem, e);
        }

        elem[name + handler] = boundedHandler;
        elem.attachEvent("on" + name, boundedHandler);

        return handler;
    };

    removeEvent = function(elem, name, handler) {
        elem.detachEvent("on" + name, elem[name + handler]);
        return true;
    };
}

page.init = page.listen = function() {
    if (pageListening === false) {
        pageListening = true;

        addEvent(global, "click", onclick);
        addEvent(global, "popstate", onpopstate);
        addEvent(global, "hashchange", onhashchange);

        page.emit("listen");
        page.go((pageHtml5Mode ? urlPath.relative(pageBase, location.pathname + location.search) : location.hash.slice(1)) || "/");
    }

    return page;
};

page.close = function() {
    if (pageListening === true) {
        pageListening = false;

        removeEvent(global, "click", onclick);
        removeEvent(global, "popstate", onpopstate);
        removeEvent(global, "hashchange", onhashchange);

        page.emit("close");
    }

    return page;
};

page.html5Mode = function(value) {
    if (value != null && supportsHtml5Mode) {
        pageHtml5Mode = !!value;
    }
    return pageHtml5Mode;
};

page.base = function(value) {
    if (type.isString(value)) {
        pageBase = value;
    }
    return pageBase;
};

page.go = function(path) {
    var ctx = {},
        fullUrl = urls.parse(pageOrigin + path, true);

    ctx.fullUrl = fullUrl;
    ctx.pathname = fullUrl.pathname;
    ctx.query = fullUrl.query;

    replaceState(ctx, path);

    page.emit("request", ctx);

    return page;
};

page.back = function() {
    if (pageHistory.length) {
        page.go(pageHistory.pop());
    }

    return page;
};

function replaceState(ctx, path) {
    pageHistory.push(pageCurrentPath);
    pageCurrentPath = path;

    if (pageHtml5Mode) {
        history.replaceState(ctx, ctx.fullUrl.path, urlPath.join(pageBase, path));
    } else {
        location.hash = path;
    }
}

function onpopstate(e) {
    if (pageHtml5Mode && e.state) {
        page.go(e.state.fullUrl.path);
    }
}

function onhashchange() {
    var path = location.hash.slice(1) || "/";

    if (!pageHtml5Mode && pageCurrentPath !== path) {
        page.go(path);
    }
}

function onclick(e) {
    var el, link;

    if (which(e) !== 1) return;
    if (e.metaKey || e.ctrlKey || e.shiftKey) return;
    if (e.defaultPrevented) return;

    el = e.target;
    link = el.getAttribute("href");

    if (!link || el.target) return;
    if (link[0] === "#") link = link.slice(1);
    if (link && (link.indexOf("mailto:") > -1 || link.indexOf("tel:") > -1)) return;

    if (el.href && !sameOrigin(el.href)) return;
    if (urlPath.isAbsoluteURL(link) && !sameOrigin(link)) return;

    e.preventDefault();
    page.go(urls.parse(link).path);
}

function which(e) {
    e = e || global.event;
    return e.which == null ? +e.button : +e.which;
}

module.exports = page;
<commit_msg>updates<commit_after>var urls = require("urls"),
    urlPath = require("url_path"),
    type = require("type"),
    EventEmitter = require("event_emitter");

var page = new EventEmitter(),

    location = global.location || {},

    pageListening = false,
    pageHtml5Mode = false,
    pageOrigin = location.origin,
    pageBase = location.pathname || "/",
    pageCurrentPath = "",
    pageHistory = [],

    sameOrigin_url = /^([\w.+-]+:)(?:\/\/(?:[^\/?#]*@|)([^\/?#:]*)(?::(\d+)|)|)/,
    sameOrigin_parts = sameOrigin_url.exec(location.href),

    supportsHtml5Mode = (function() {
        var userAgent = global.navigator.userAgent;
        if (
            (userAgent.indexOf("Android 2.") !== -1 || userAgent.indexOf("Android 4.0") !== -1) &&
            userAgent.indexOf("Mobile Safari") !== -1 &&
            userAgent.indexOf("Chrome") === -1
        ) {
            return false;
        }

        return (window.history && 'pushState' in window.history);
    }()),

    supportsEventListener = type.isNative(document.addEventListener),
    addEvent, removeEvent;

function sameOrigin(href) {
    var parts, urlPort, testPort;

    if (!urlPath.isAbsoluteURL(href)) return true;

    parts = sameOrigin_url.exec(href.toLowerCase());

    if (!parts) return false;

    urlPort = sameOrigin_parts[3];
    testPort = parts[3];

    return !(
        (parts[1] !== sameOrigin_parts[1]) ||
        (parts[2] !== sameOrigin_parts[2]) || !(
            (testPort === urlPort) ||
            (!testPort && (urlPort === "80" || urlPort === "443")) ||
            (!urlPort && (testPort === "80" || testPort === "443"))
        )
    );
}

if (supportsEventListener) {
    addEvent = function(elem, name, handler) {
        elem.addEventListener(name, handler, false);
        return handler;
    };

    removeEvent = function(elem, name, handler) {
        elem.removeEventListener(name, handler, false);
        return true;
    };
} else {
    addEvent = function(elem, name, handler) {

        function boundedHandler(e) {

            return handler.call(elem, e);
        }

        elem[name + handler] = boundedHandler;
        elem.attachEvent("on" + name, boundedHandler);

        return handler;
    };

    removeEvent = function(elem, name, handler) {
        elem.detachEvent("on" + name, elem[name + handler]);
        return true;
    };
}

page.init = page.listen = function() {
    if (pageListening === false) {
        pageListening = true;

        addEvent(global, "click", onclick);
        addEvent(global, "popstate", onpopstate);
        addEvent(global, "hashchange", onhashchange);

        page.emit("listen");
        page.go((pageHtml5Mode ? urlPath.relative(pageBase, location.pathname + location.search) : location.hash.slice(1)) || "/");
    }

    return page;
};

page.close = function() {
    if (pageListening === true) {
        pageListening = false;

        removeEvent(global, "click", onclick);
        removeEvent(global, "popstate", onpopstate);
        removeEvent(global, "hashchange", onhashchange);

        page.emit("close");
    }

    return page;
};

page.html5Mode = function(value) {
    if (value != null && supportsHtml5Mode) {
        pageHtml5Mode = !!value;
    }
    return pageHtml5Mode;
};

page.base = function(value) {
    if (type.isString(value)) {
        pageBase = value;
    }
    return pageBase;
};

page.go = function(path) {
    var ctx = {},
        fullUrl = urls.parse(pageOrigin + path, true);

    ctx.fullUrl = fullUrl;
    ctx.pathname = fullUrl.pathname;
    ctx.query = fullUrl.query;

    replaceState(ctx, path);

    page.emit("request", ctx);

    return page;
};

page.hasHistory = function() {

    return pageHistory.length !== 0;
};

page.back = function() {
    if (pageHistory.length) {
        page.go(pageHistory.pop());
    }

    return page;
};

function replaceState(ctx, path) {
    pageHistory.push(pageCurrentPath);
    pageCurrentPath = path;

    if (pageHtml5Mode) {
        history.replaceState(ctx, ctx.fullUrl.path, urlPath.join(pageBase, path));
    } else {
        location.hash = path;
    }
}

function onpopstate(e) {
    if (pageHtml5Mode && e.state) {
        page.go(e.state.fullUrl.path);
    }
}

function onhashchange() {
    var path = location.hash.slice(1) || "/";

    if (!pageHtml5Mode && pageCurrentPath !== path) {
        page.go(path);
    }
}

function onclick(e) {
    var el, link;

    if (which(e) !== 1) return;
    if (e.metaKey || e.ctrlKey || e.shiftKey) return;
    if (e.defaultPrevented) return;

    el = e.target;
    link = el.getAttribute("href");

    if (!link || el.target) return;
    if (link[0] === "#") link = link.slice(1);
    if (link && (link.indexOf("mailto:") > -1 || link.indexOf("tel:") > -1)) return;

    if (el.href && !sameOrigin(el.href)) return;
    if (urlPath.isAbsoluteURL(link) && !sameOrigin(link)) return;

    e.preventDefault();
    page.go(urls.parse(link).path);
}

function which(e) {
    e = e || global.event;
    return e.which == null ? +e.button : +e.which;
}

module.exports = page;
<|endoftext|>


<commit_before>export default require('./context_menu')
<commit_msg>chore(src): remove unused index.js file<commit_after><|endoftext|>


<commit_before>import {Observable as O} from "rx"
import React from "react"
import DOM from "react-dom"
import h from "react-hyperscript"
import selmatch from "matches-selector"

const zipObj = pairs => {
  const o = {}
  pairs.forEach(([k, v]) => o[k] = v)
  return o
}

const keys = x => x ? Object.keys(x) : []

const values = obj => keys(obj).map(k => obj[k])

const extend = Object.assign

const matches = (ev, sel) => !sel || (ev.target && selmatch(ev.target, sel))

const shallowEq = (a, b) => {
  const aKeys = keys(a), bKeys = keys(b)
  if (aKeys.length !== bKeys.length) return false
  for (let i = 0; i < aKeys.length; i++) {
    if (a[aKeys[i]] !== b[aKeys[i]]) return false
  }
  return true
}

const rm = (arr, obj) => {
  const idx = arr.indexOf(obj)
  if (idx !== -1) arr.splice(idx, 1)
  return arr.length
}

const reactEvents =
  "onCopy onCut onPaste onKeyDown onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit " +
  "onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit " +
  "onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave " +
  "onMouseMove onMouseOut onMouseOver onMouseUp onTouchCancel onTouchEnd onTouchMove onTouchStart " +
  "onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded " +
  "onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress " +
  "onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting " +
  "onSelect onScroll onWheel onLoad onError"

const nativeEventMapping = {
  dblclick: "onDoubleClick"
}

const eventsByName =
  zipObj(reactEvents.split(" ").map(e => [e.replace(/^on/, "").toLowerCase(), e]))

const reactEventName = eventName => {
  return eventsByName[eventName] || nativeEventMapping[eventName] || eventName
}

/*
 * Mutable multicasting proxy object that allows (de)registering
 * observers and broadcasting 'next' and 'completed' events to them
 */
function MulticastProxy() {
  this.obs = []
  this.next = this.next.bind(this)
  this.dispose = this.dispose.bind(this)
}
extend(MulticastProxy.prototype, {
  add(obs) {
    this.obs.push(obs)
  },
  rm(obs) {
    return rm(this.obs, obs) === 0
  },
  next(ev) {
    this.obs.forEach(o => o.next(ev))
  },
  dispose() {
    this.obs.forEach(o => o.completed())
    this.obs = []
  }
})

/*
 * Event source that listens to React element lifecycle methods and
 * allows subscribing to element's events, managing the event listener
 * attachment/detachment under the hood.
 */
function EventSource() {
  this.elems = []
  this.proxies = {}
}
extend(EventSource.prototype, {
  mount(elem) {
    if (this.elems.indexOf(elem) === -1) {
      this.elems.push(elem)
      if (keys(this.proxies).length > 0) {
        this.refreshListeners([elem])
      }
    }
  },
  unmount(elem) {
    if (rm(this.elems, elem) === 0) {
      const p = this.proxies
      this.proxies = []
      values(p).forEach(proxy => proxy.dispose())
    }
  },
  refreshListeners(elems) {
    elems = elems || this.elems
    const p = this.proxies
    const listeners = zipObj(keys(p).map(k => [reactEventName(k), p[k].next]))
    elems.forEach(elem => {
      if (!elem.state || !shallowEq(elem.state.listeners, listeners)) {
        elem.setState({listeners})
      }
    })
  },
  subscribe(selector, eventName) {
    const observer = o => ({
      next: ev => matches(ev, selector) && o ? o.onNext(ev) : null,
      completed: () => o && o.onCompleted()
    })
    const isNew = !(eventName in this.proxies)
    const proxy = isNew ? (this.proxies[eventName] = new MulticastProxy()) : this.proxies[eventName]
    return O.create(o => {
      const obs = observer(o)
      proxy.add(obs)
      if (isNew) {
        this.refreshListeners()
      }
      return () => proxy.rm(obs) && delete this.proxies[eventName]
    })
  }
})

const Prepared = React.createClass({
  componentDidMount() {
    this.props.events.mount(this)
  },
  componentWillReceiveProps(nextProps) {
    if (nextProps.events !== this.props.events) {
      this.props.events.unmount(this)
      nextProps.events.mount(this)
    }
  },
  componentWillUnmount() {
    this.props.events.unmount(this)
  },
  render() {
    return !this.state ? this.props.children
      : React.cloneElement(this.props.children, this.state.listeners)
  }
})

export default function makeReactDOM(rootElem) {
  return function ReactDOM() {
    function prepare(vdom$) {
      return vdom$
        .map(vdom => vdom.type === Prepared ? vdom
          : React.createElement(Prepared, {events: new EventSource()}, vdom))
        .shareReplay(1)
    }

    function events(vdom$, selector, eventName) {
      return vdom$.merge(O.never()).flatMap(vdom => {
        if (vdom.type !== Prepared) {
          console.warn(                                 // eslint-disable-line
            "DOM.events :: VDOM is not prepared for event listening.",
            "Perhaps you forgot to call DOM.prepare(vdom$)?"
          )
          return O.empty()
        } else {
          return vdom.props.events.subscribe(selector, eventName)
        }
      })
    }

    const Transforms = {
      React,
      h,
      events,
      prepare
    }

    function executor(vdom$) {
      const $root = typeof rootElem === "string" ? document.querySelector(rootElem) : rootElem
      return vdom$.subscribe(vdom => {
        DOM.render(vdom, $root)
      })
    }

    return [Transforms, executor]
  }
}

// for testing package
export const __resources = {
  MulticastProxy,
  EventSource,
  Prepared,
  eventsByName,
  matches
}
<commit_msg>Remove obsolete test exports<commit_after>import {Observable as O} from "rx"
import React from "react"
import DOM from "react-dom"
import h from "react-hyperscript"
import selmatch from "matches-selector"

const zipObj = pairs => {
  const o = {}
  pairs.forEach(([k, v]) => o[k] = v)
  return o
}

const keys = x => x ? Object.keys(x) : []

const values = obj => keys(obj).map(k => obj[k])

const extend = Object.assign

const matches = (ev, sel) => !sel || (ev.target && selmatch(ev.target, sel))

const shallowEq = (a, b) => {
  const aKeys = keys(a), bKeys = keys(b)
  if (aKeys.length !== bKeys.length) return false
  for (let i = 0; i < aKeys.length; i++) {
    if (a[aKeys[i]] !== b[aKeys[i]]) return false
  }
  return true
}

const rm = (arr, obj) => {
  const idx = arr.indexOf(obj)
  if (idx !== -1) arr.splice(idx, 1)
  return arr.length
}

const reactEvents =
  "onCopy onCut onPaste onKeyDown onKeyPress onKeyUp onFocus onBlur onChange onInput onSubmit " +
  "onClick onContextMenu onDoubleClick onDrag onDragEnd onDragEnter onDragExit " +
  "onDragLeave onDragOver onDragStart onDrop onMouseDown onMouseEnter onMouseLeave " +
  "onMouseMove onMouseOut onMouseOver onMouseUp onTouchCancel onTouchEnd onTouchMove onTouchStart " +
  "onAbort onCanPlay onCanPlayThrough onDurationChange onEmptied onEncrypted onEnded " +
  "onError onLoadedData onLoadedMetadata onLoadStart onPause onPlay onPlaying onProgress " +
  "onRateChange onSeeked onSeeking onStalled onSuspend onTimeUpdate onVolumeChange onWaiting " +
  "onSelect onScroll onWheel onLoad onError"

const nativeEventMapping = {
  dblclick: "onDoubleClick"
}

const eventsByName =
  zipObj(reactEvents.split(" ").map(e => [e.replace(/^on/, "").toLowerCase(), e]))

const reactEventName = eventName => {
  return eventsByName[eventName] || nativeEventMapping[eventName] || eventName
}

/*
 * Mutable multicasting proxy object that allows (de)registering
 * observers and broadcasting 'next' and 'completed' events to them
 */
function MulticastProxy() {
  this.obs = []
  this.next = this.next.bind(this)
  this.dispose = this.dispose.bind(this)
}
extend(MulticastProxy.prototype, {
  add(obs) {
    this.obs.push(obs)
  },
  rm(obs) {
    return rm(this.obs, obs) === 0
  },
  next(ev) {
    this.obs.forEach(o => o.next(ev))
  },
  dispose() {
    this.obs.forEach(o => o.completed())
    this.obs = []
  }
})

/*
 * Event source that listens to React element lifecycle methods and
 * allows subscribing to element's events, managing the event listener
 * attachment/detachment under the hood.
 */
function EventSource() {
  this.elems = []
  this.proxies = {}
}
extend(EventSource.prototype, {
  mount(elem) {
    if (this.elems.indexOf(elem) === -1) {
      this.elems.push(elem)
      if (keys(this.proxies).length > 0) {
        this.refreshListeners([elem])
      }
    }
  },
  unmount(elem) {
    if (rm(this.elems, elem) === 0) {
      const p = this.proxies
      this.proxies = []
      values(p).forEach(proxy => proxy.dispose())
    }
  },
  refreshListeners(elems) {
    elems = elems || this.elems
    const p = this.proxies
    const listeners = zipObj(keys(p).map(k => [reactEventName(k), p[k].next]))
    elems.forEach(elem => {
      if (!elem.state || !shallowEq(elem.state.listeners, listeners)) {
        elem.setState({listeners})
      }
    })
  },
  subscribe(selector, eventName) {
    const observer = o => ({
      next: ev => matches(ev, selector) && o ? o.onNext(ev) : null,
      completed: () => o && o.onCompleted()
    })
    const isNew = !(eventName in this.proxies)
    const proxy = isNew ? (this.proxies[eventName] = new MulticastProxy()) : this.proxies[eventName]
    return O.create(o => {
      const obs = observer(o)
      proxy.add(obs)
      if (isNew) {
        this.refreshListeners()
      }
      return () => proxy.rm(obs) && delete this.proxies[eventName]
    })
  }
})

const Prepared = React.createClass({
  componentDidMount() {
    this.props.events.mount(this)
  },
  componentWillReceiveProps(nextProps) {
    if (nextProps.events !== this.props.events) {
      this.props.events.unmount(this)
      nextProps.events.mount(this)
    }
  },
  componentWillUnmount() {
    this.props.events.unmount(this)
  },
  render() {
    return !this.state ? this.props.children
      : React.cloneElement(this.props.children, this.state.listeners)
  }
})

export default function makeReactDOM(rootElem) {
  return function ReactDOM() {
    function prepare(vdom$) {
      return vdom$
        .map(vdom => vdom.type === Prepared ? vdom
          : React.createElement(Prepared, {events: new EventSource()}, vdom))
        .shareReplay(1)
    }

    function events(vdom$, selector, eventName) {
      return vdom$.merge(O.never()).flatMap(vdom => {
        if (vdom.type !== Prepared) {
          console.warn(                                 // eslint-disable-line
            "DOM.events :: VDOM is not prepared for event listening.",
            "Perhaps you forgot to call DOM.prepare(vdom$)?"
          )
          return O.empty()
        } else {
          return vdom.props.events.subscribe(selector, eventName)
        }
      })
    }

    const Transforms = {
      React,
      h,
      events,
      prepare
    }

    function executor(vdom$) {
      const $root = typeof rootElem === "string" ? document.querySelector(rootElem) : rootElem
      return vdom$.subscribe(vdom => {
        DOM.render(vdom, $root)
      })
    }

    return [Transforms, executor]
  }
}
<|endoftext|>


<commit_before>class StringReader {
  constructor(input) {
    this.input = input;
    this.buffer = '';
    this.reset();
  }

  reset() {
    this.currentIndex = 0;
    this.clearBuffer();
  }

  clearBuffer() {
    this.buffer = '';
  }

  readUntil(character, omitCharacter, notFoundFn) {
    var c, counter, i, len, skip;
    if (omitCharacter == null) {
      omitCharacter = false;
    }
    while (true) {
      if (this.end()) {
        if (notFoundFn) {
          notFoundFn(this.buffer);
        }
        break;
      }
      if (character.length === 1) {
        if (this.input[this.currentIndex] === character) {
          break;
        }
      } else {
        skip = true;
        counter = 0;
        for (i = 0, len = character.length; i < len; i++) {
          c = character[i];
          if (!(this.input[this.currentIndex + counter] !== c)) {
            continue;
          }
          skip = false;
          break;
        }
        counter++;
        if (skip) {
          break;
        }
      }
      this.buffer += this.input[this.currentIndex];
      this.currentIndex++;
    }
    if (omitCharacter) {
      this.currentIndex += character.length;
    }
    return this.buffer;
  }

  readLine(notFoundFn) {
    return readUntil('\n', true, notFoundFn);
  }

  end() {
    return this.currentIndex >= this.input.length;
  }
}

export default StringReader;
<commit_msg>Fix lint errors<commit_after>class StringReader {
  constructor(input) {
    this.input = input;
    this.buffer = '';
    this.reset();
  }

  reset() {
    this.currentIndex = 0;
    this.clearBuffer();
  }

  clearBuffer() {
    this.buffer = '';
  }

  readUntil(character, omitCharacter, notFoundFn) {
    /* eslint-disable no-constant-condition */

    const omitChar = (omitCharacter == null) ? false : omitCharacter;

    while (true) {
      if (this.end()) {
        if (notFoundFn) {
          notFoundFn(this.buffer);
        }
        break;
      }
      if (character.length === 1) {
        if (this.input[this.currentIndex] === character) {
          break;
        }
      } else {
        let skip = true;
        let counter = 0;
        for (let i = 0, len = character.length; i < len; i++) {
          const c = character[i];

          if (!(this.input[this.currentIndex + counter] !== c)) {
            continue;
          }
          skip = false;
          break;
        }
        counter++;
        if (skip) {
          break;
        }
      }
      this.buffer += this.input[this.currentIndex];
      this.currentIndex++;
    }
    if (omitChar) {
      this.currentIndex += character.length;
    }
    return this.buffer;
  }

  readLine(notFoundFn) {
    return this.readUntil('\n', true, notFoundFn);
  }

  end() {
    return this.currentIndex >= this.input.length;
  }
}

export default StringReader;
<|endoftext|>


<commit_before>var text = ""; // Last text of sentence

$('#textanalyser').autocompleteTrigger({
    triggerStart: '#',
    triggerEnd: '',
    source: autocompleteCallback
});

// TODO - hide this in a scope
function analyzeSentence(sentence, finalize)
{
    var ret = TextAnalyser2(sentence, finalize);
    switch (ret.state) {
    case ANALYSIS_NODE_START:
        $('.typeselection').css({top:window.innerHeight/2-115,left:window.innerWidth/2-325});
        $('.typeselection').html('

Use [TAB] key to pick a type

');
        break;
    case ANALYSIS_LINK:
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
        break;
    }
    //REINITIALISE GRAPH (DUMB BUT IT WORKS)
    graph.removeNodes("temp");
    graph.removeLinks("temp");
    for (var k in ret.nodes) {
        var n = ret.nodes[k];
        graph.addNode(n.id, n.type, n.state);
    }
    for (var k in ret.links) {
        var l = ret.links[k];
        graph.addLink(l.sourceId, l.targetId, l.name, l.state, ret.drop_conjugator_links);
    }

    //UPDATE GRAPH ONCE
    graph.update();

    if (finalize) {
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
    }
}

$("#textanalyser").keypress(function(e) {
     if (graph.history !== undefined) {
         graph.history.record_keystrokes(KEYSTROKE_WHERE_TEXTANALYSIS, [e.which]);
     }
     if (e.which == 13) {
        if(!suggestionChange) {
            text = $('#textanalyser').val();
            $('#textanalyser').val("");
            analyzeSentence(text, true);
            typeStack = [];
        } else {
            suggestionChange = false;
        }
        return false;
    }

    if (e.which == 37) {//RIGHT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }
    if (e.which == 39) { //LEFT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }

});

$(document).keydown(function(e) {

    if (graph.history !== undefined) {
        graph.history.record_keystrokes(KEYSTROKE_WHERE_DOCUMENT, [e.KeyCode]);
    }
    if (e.keyCode == 9) {//TAB
        e.preventDefault();
        changeType("down", lastnode);
        return false;
    }

    if (e.keyCode == 37) {//UP
          $('html, body').scrollLeft(0);
    }
    if (e.keyCode == 39) {//DOWN
          $('html, body').scrollLeft(0);
    }

    if (e.keyCode == 38) {//UP
        suggestionChange = true;
    }
    if (e.keyCode == 40) {//DOWN
        suggestionChange = true;
    }

    if (e.keyCode == 9) {//TAB
        return false;
    }

});

function textSelect(inp, s, e) {
    e = e || s;
    if (inp.createTextRange) {
        var r = inp.createTextRange();
        r.collapse(true);
        r.moveEnd('character', e);
        r.moveStart('character', s);
        r.select();
    }else if(inp.setSelectionRange) {
        inp.focus();
        inp.setSelectionRange(s, e);
    }
}

function changeType(arg, id) {
    if(!id)id="new node";
    if (arg === 'up') {
        if (typeindex < 4) typeindex++;
        else typeindex = 0;
        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);
    } else {
        if (typeindex > 0) typeindex--;
        else typeindex = 4;

        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);

    }
    graph.updateGraph();
}

/* TODO: don't use interval by default but only if keys are comming to fast (but still - 5 ms??) */
window.setInterval(function() {
    if ($('#textanalyser').val() != text) {

        if(text.length*8 > 500)$('#textanalyser').css('width',text.length*8+20);
        // text changed
        text = $('#textanalyser').val();
        analyzeSentence(text, false);
        suggestionChange = false;
    }
}, 5);

<commit_msg>textanalysis-ui: Fixes #42 - remove helper text when sentence is edited then deleted<commit_after>var text = ""; // Last text of sentence

$('#textanalyser').autocompleteTrigger({
    triggerStart: '#',
    triggerEnd: '',
    source: autocompleteCallback
});

// TODO - hide this in a scope
function analyzeSentence(sentence, finalize)
{
    var ret = TextAnalyser2(sentence, finalize);
    switch (ret.state) {
    case ANALYSIS_NODE_START:
        $('.typeselection').css({top:window.innerHeight/2-115,left:window.innerWidth/2-325});
        $('.typeselection').html('

Use [TAB] key to pick a type

');
        break;
    case ANALYSIS_LINK:
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
        break;
    }
    //REINITIALISE GRAPH (DUMB BUT IT WORKS)
    graph.removeNodes("temp");
    graph.removeLinks("temp");
    for (var k in ret.nodes) {
        var n = ret.nodes[k];
        graph.addNode(n.id, n.type, n.state);
    }
    for (var k in ret.links) {
        var l = ret.links[k];
        graph.addLink(l.sourceId, l.targetId, l.name, l.state, ret.drop_conjugator_links);
    }

    //UPDATE GRAPH ONCE
    graph.update();

    if (finalize || sentence.length == 0) {
        $('.typeselection').css('top', -300);
        $('.typeselection').css('left', 0);
    }
}

$("#textanalyser").keypress(function(e) {
     if (graph.history !== undefined) {
         graph.history.record_keystrokes(KEYSTROKE_WHERE_TEXTANALYSIS, [e.which]);
     }
     if (e.which == 13) {
        if(!suggestionChange) {
            text = $('#textanalyser').val();
            $('#textanalyser').val("");
            analyzeSentence(text, true);
            typeStack = [];
        } else {
            suggestionChange = false;
        }
        return false;
    }

    if (e.which == 37) {//RIGHT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }
    if (e.which == 39) { //LEFT
        $('body').scrollLeft(0);
        e.stopPropagation();
        return false;
    }

});

$(document).keydown(function(e) {

    if (graph.history !== undefined) {
        graph.history.record_keystrokes(KEYSTROKE_WHERE_DOCUMENT, [e.KeyCode]);
    }
    if (e.keyCode == 9) {//TAB
        e.preventDefault();
        changeType("down", lastnode);
        return false;
    }

    if (e.keyCode == 37) {//UP
          $('html, body').scrollLeft(0);
    }
    if (e.keyCode == 39) {//DOWN
          $('html, body').scrollLeft(0);
    }

    if (e.keyCode == 38) {//UP
        suggestionChange = true;
    }
    if (e.keyCode == 40) {//DOWN
        suggestionChange = true;
    }

    if (e.keyCode == 9) {//TAB
        return false;
    }

});

function textSelect(inp, s, e) {
    e = e || s;
    if (inp.createTextRange) {
        var r = inp.createTextRange();
        r.collapse(true);
        r.moveEnd('character', e);
        r.moveStart('character', s);
        r.select();
    }else if(inp.setSelectionRange) {
        inp.focus();
        inp.setSelectionRange(s, e);
    }
}

function changeType(arg, id) {
    if(!id)id="new node";
    if (arg === 'up') {
        if (typeindex < 4) typeindex++;
        else typeindex = 0;
        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);
    } else {
        if (typeindex > 0) typeindex--;
        else typeindex = 4;

        graph.editType(id, null, nodetypes[typeindex]);
        $('.typeselection').html('

' + "Chosen Type: " + nodetypes[typeindex] + '

');
        graph.findCoordinates(lastnode,null);

    }
    graph.updateGraph();
}

/* TODO: don't use interval by default but only if keys are comming to fast (but still - 5 ms??) */
window.setInterval(function() {
    if ($('#textanalyser').val() != text) {

        if(text.length*8 > 500)$('#textanalyser').css('width',text.length*8+20);
        // text changed
        text = $('#textanalyser').val();
        analyzeSentence(text, false);
        suggestionChange = false;
    }
}, 5);

<|endoftext|>


<commit_before>var fs          = require('fs'),
		octonode    = require('octonode'),
		path        = require('path'),
		child       = require('child_process'),
		pkg_config  = require('config-tree'),
		colors			= require('colors');

// Github authentication
var config,
		gh_client,
		gh_entity;

var sh_commands = require('./sh-commands.js');

/*    I N I T  C O M M A N D S   */
function configClient(){
	var dir = path.dirname(__dirname);
	pkg_config.sprout(dir, 'kestrel');
}

/*    C R E A T I O N  C O M M A N D S   */
function setGitHubOrgType(gh_c){
	if (config.github.type == 'org'){
		return gh_c.org(config.github.account_name);
	} else if (config.github.type == 'individual'){
		return gh_c.me();
	}
}
function gitInit(current_dir, cb){
	child.exec( sh_commands.init(config.github.login_method, config.github.account_name, current_dir), cb );
}
function createGitHubRepo(repo_name, cb){
	gh_entity.repo({
	  "name": repo_name,
	  "private": config.github.private_repos
	}, function(err, response){
		cb(err, response);
	});
}
function createGitHubHook(repo_name, cb){
	var gh_repo = gh_client.repo(config.github.account_name + '/' + repo_name);

	gh_repo.hook({
	  "name": "web",
	  "active": true,
	  "events": ["push", "status"],
	  "config": {
	    "url": config.server.url
	  }
	}, function(err, response){
		cb(err, response);
	});
}
function setConfig(set_gh){
  var home_dir = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE,
  		conf_dir_path = home_dir + '/.conf',
  		config_path = home_dir + '/.conf/kestrel-config.json',
  		conf_dir_exists = fs.existsSync( conf_dir_path ),
  		config_exists = fs.existsSync( config_path );

  if (!conf_dir_exists) throw '~/.conf folder not found. Please run `swoop config`.'
  if (!config_exists) throw '~/.conf/kestrel-config.json not found. Please run `swoop config`.'

  config = config || require(config_path);
	if (set_gh){
		gh_client = gh_client || octonode.client(config.github.access_token);
		gh_entity = gh_entity || setGitHubOrgType(gh_client);
	}
	return config;
}
function initAll(){
	setConfig(true);
	var current_dir = path.basename(path.resolve('./'));
	gitInit(current_dir, function(err1, stdout, stderr){
		(err1) ? console.log('Step 1/3: Warning:'.yellow + ' Git remote origin already set. You should manually run `' + 'git remote set-url origin ' + sh_commands.init(config.github.login_method, config.github.account_name, current_dir).split('origin ')[1] + '`') : console.log('Step 1/3: Git init\'ed and origin set!'.green);

		createGitHubRepo(current_dir, function(err2, response){
			(err2) ? console.log('Step 2/3: GitHub repo creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'\nStated reason:', err2.message) : console.log('Step 2/3: GitHub repo created!'.green);

			createGitHubHook(current_dir, function(err3){
				(err3) ? console.log('Step 3/3: GitHub hook creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'/settings/hooks'.cyan+'\nStated reason:', err3.message) : console.log('Step 3/3: GitHub hook created.'.green + ' Once you push you can preview it at:\n  ' + config.server.url.split(':').slice(0,2).join(':') + ':3000/' + current_dir);
			});

		});
	});
}

function initHook(){
	setConfig(true);
	var current_dir = path.basename(path.resolve('./'));
	createGitHubHook(current_dir, function(err){
		(err) ? console.log('Step 1/1: GitHub hook creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'/settings/hooks'.cyan+'\nStated reason:', err.message) : console.log('Step 1/1: GitHub hook created.'.green + ' Once you push you can preview it at:\n  ' + config.server.url.split(':').slice(0,2).join(':') + ':3000/' + current_dir);
	});
}

/*    D E P L O Y   C O M M A N D S   */
function checkGitStatus(gitStatus){
	gitStatus = gitStatus.trim();
	var ahead_regex = new RegExp('ahead'),
			behind_regex = new RegExp('behind');

	// If the status has more than one line, we have uncommitted changes
	if (gitStatus.split('\n').length > 1) return 'uncommitted';
	// If the status has the word ahead and behind then we have to pull and push
	if (ahead_regex.exec(gitStatus) && behind_regex.exec(gitStatus)) return 'ahead_and_behind';
	// Allow for deployment if we are ahead
	if (ahead_regex.exec(gitStatus)) return 'clean';
	// if (ahead_regex.exec(gitStatus)) return 'ahead';
	// Don't allow for deployment if we are behind. This condition will rarely be triggered and will also be caught by git itself when your push fails
	if (behind_regex.exec(gitStatus)) return 'behind';
	return 'clean';
}
function deployLastCommit(bucket_environment, trigger_type, trigger, local_path, remote_path){
  setConfig(true);
	var current_dir   = path.resolve('./');

	var trigger_commit_msg  = bucket_environment + '::' + trigger + '::' + local_path + '::' + remote_path,
			scrubbed_commit_msg = '::published:' + bucket_environment + ':' + trigger_type + '::';

	// Make sure the working branch has no outstanding commits and is neither ahead or behind
	// Normally outstanding commits wouldn't be a problem, but the push flag allows for an empty commit
	// So if we had untracked or uncommitted files, it would just push the last commit.
	child.exec( sh_commands.status(), function(err0, stdout0, stderr0){
		if (err0 !== null) throw stderr1;
		var branch_status = checkGitStatus(stdout0);
		// If stdout is blank, we have nothing to commit
		if (branch_status == 'clean') {
			// // Add the trigger as a commit message and push
			child.exec( sh_commands.deployLastCommit(trigger_commit_msg), function(err1, stdout1, stderr1){
				if (err1 !== null) {
					// Erase the commit that has the trigger because the trigger push didn't go through
					// This error is usually caused by being behind the remote
					child.exec( sh_commands.revertToPreviousCommit(), function(err10, stdout10, stderr10){
						if (err10) throw stderr1 + '\nAND\n' + err10;
						throw stderr1;
					});
				}
				console.log('Push successful!'.green, stdout1.trim());

				// EDIT: Let's get rid of the scrub push, it's bad practice and it adds an extra push that the server has to respond to.
				// Replace the trigger in the commit message with a scrubbed message saying that it was published and with what message
				// child.exec( sh_commands.scrubLastCommit(scrubbed_commit_msg), function(err2, stdout2, stderr2){
				// 	if (err2 !== null) throw stderr2;
				// 	console.log('Scrub push successful!'.green, stdout2.trim());
				// });
			});
		} else {
			if (branch_status == 'uncommitted') throw 'Error!'.red + ' You have uncommitted changes on this branch.' + ' Please commit and push your changes before attempting to deploy.'.yellow;
			if (branch_status == 'ahead_and_behind') throw 'Error'.red + ' You have unpushed commits on this branch and your local branch is behind your remote.' + ' Please pull and then push your changes before attempting to deploy.'.yellow;
			// EDIT: It's okay if they haven't push their commits. Like the edit above to the scrub push, removing this step will result in fewer pushes for the server to respond to. This alert is currently not being triggered because the branch status no longer as a condition where it is set to ahead.
			// if (branch_status == 'ahead') throw 'Error!'.red + ' You have unpushed commits on this branch.' + ' Please push your changes before attempting to deploy.'.yellow;
			if (branch_status == 'behind') throw 'Error!'.red + ' Your local branch is behind your remote.' + ' Please pull, merge and push before attempting to deploy.'.yellow;
		}
	});
}

/*    C R E A T E  A R C H I V E  B R A N C H   */
function addToArchive(branches){
  setConfig(true);
  var repo_name = path.basename(path.resolve('./'));
	child.exec( sh_commands.archive(config.github.login_method, config.github.account_name, config.archive.repo_name, branches), function(err, stdout, stderr){
		(err) ? console.log('Archive failed!'.red, 'Stated reason:' + err.message) : console.log('Success!'.green + ' `' + branches.split(':')[0] + '` branch of `' + repo_name + ' `archived as `' + branches.split(':')[1] + '` on the `' + config.archive.repo_name + '` repo.\n  https://github.com/' + config.github.account_name + '/' + config.archive.repo_name + '/tree/' + branches.split(':')[1] + '\n' + 'Note:'.cyan + ' Your existing repo has not been deleted. Please do that manually through GitHub:\n  https://github.com/' + config.github.account_name + '/' + repo_name + '/settings')
	});
}

function reportError(err, msg){
	console.log(msg, '\nReason:');
	throw err;
}

module.exports = {
	setConfig: setConfig,
	config: configClient,
	init: initAll,
	deploy: deployLastCommit,
	hook: initHook,
	archive: addToArchive
}<commit_msg>We no longer require pushing before swoop deploying<commit_after>var fs          = require('fs'),
		octonode    = require('octonode'),
		path        = require('path'),
		child       = require('child_process'),
		pkg_config  = require('config-tree'),
		colors			= require('colors');

// Github authentication
var config,
		gh_client,
		gh_entity;

var sh_commands = require('./sh-commands.js');

/*    I N I T  C O M M A N D S   */
function configClient(){
	var dir = path.dirname(__dirname);
	pkg_config.sprout(dir, 'kestrel');
}

/*    C R E A T I O N  C O M M A N D S   */
function setGitHubOrgType(gh_c){
	if (config.github.type == 'org'){
		return gh_c.org(config.github.account_name);
	} else if (config.github.type == 'individual'){
		return gh_c.me();
	}
}
function gitInit(current_dir, cb){
	child.exec( sh_commands.init(config.github.login_method, config.github.account_name, current_dir), cb );
}
function createGitHubRepo(repo_name, cb){
	gh_entity.repo({
	  "name": repo_name,
	  "private": config.github.private_repos
	}, function(err, response){
		cb(err, response);
	});
}
function createGitHubHook(repo_name, cb){
	var gh_repo = gh_client.repo(config.github.account_name + '/' + repo_name);

	gh_repo.hook({
	  "name": "web",
	  "active": true,
	  "events": ["push", "status"],
	  "config": {
	    "url": config.server.url
	  }
	}, function(err, response){
		cb(err, response);
	});
}
function setConfig(set_gh){
  var home_dir = process.env.HOME || process.env.HOMEPATH || process.env.USERPROFILE,
  		conf_dir_path = home_dir + '/.conf',
  		config_path = home_dir + '/.conf/kestrel-config.json',
  		conf_dir_exists = fs.existsSync( conf_dir_path ),
  		config_exists = fs.existsSync( config_path );

  if (!conf_dir_exists) throw '~/.conf folder not found. Please run `swoop config`.'
  if (!config_exists) throw '~/.conf/kestrel-config.json not found. Please run `swoop config`.'

  config = config || require(config_path);
	if (set_gh){
		gh_client = gh_client || octonode.client(config.github.access_token);
		gh_entity = gh_entity || setGitHubOrgType(gh_client);
	}
	return config;
}
function initAll(){
	setConfig(true);
	var current_dir = path.basename(path.resolve('./'));
	gitInit(current_dir, function(err1, stdout, stderr){
		(err1) ? console.log('Step 1/3: Warning:'.yellow + ' Git remote origin already set. You should manually run `' + 'git remote set-url origin ' + sh_commands.init(config.github.login_method, config.github.account_name, current_dir).split('origin ')[1] + '`') : console.log('Step 1/3: Git init\'ed and origin set!'.green);

		createGitHubRepo(current_dir, function(err2, response){
			(err2) ? console.log('Step 2/3: GitHub repo creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'\nStated reason:', err2.message) : console.log('Step 2/3: GitHub repo created!'.green);

			createGitHubHook(current_dir, function(err3){
				(err3) ? console.log('Step 3/3: GitHub hook creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'/settings/hooks'.cyan+'\nStated reason:', err3.message) : console.log('Step 3/3: GitHub hook created.'.green + ' Once you push you can preview it at:\n  ' + config.server.url.split(':').slice(0,2).join(':') + ':3000/' + current_dir);
			});

		});
	});
}

function initHook(){
	setConfig(true);
	var current_dir = path.basename(path.resolve('./'));
	createGitHubHook(current_dir, function(err){
		(err) ? console.log('Step 1/1: GitHub hook creation failed!'.red + ' `Validation Failed` could mean it already exists.'.yellow + '\nCheck here: ' + 'https://github.com/'.cyan+config.github.account_name.cyan+'/'.cyan+current_dir.cyan+'/settings/hooks'.cyan+'\nStated reason:', err.message) : console.log('Step 1/1: GitHub hook created.'.green + ' Once you push you can preview it at:\n  ' + config.server.url.split(':').slice(0,2).join(':') + ':3000/' + current_dir);
	});
}

/*    D E P L O Y   C O M M A N D S   */
function checkGitStatus(gitStatus){
	gitStatus = gitStatus.trim();
	var ahead_regex = new RegExp('ahead'),
			behind_regex = new RegExp('behind');

	// If the status has more than one line, we have uncommitted changes
	if (gitStatus.split('\n').length > 1) return 'uncommitted';
	// If the status has the word ahead and behind then we have to pull and push
	if (ahead_regex.exec(gitStatus) && behind_regex.exec(gitStatus)) return 'ahead_and_behind';
	// Allow for deployment if we are ahead
	if (ahead_regex.exec(gitStatus)) return 'clean';
	// if (ahead_regex.exec(gitStatus)) return 'ahead';
	// Don't allow for deployment if we are behind. This condition will rarely be triggered and will also be caught by git itself when your push fails
	if (behind_regex.exec(gitStatus)) return 'behind';
	return 'clean';
}
function deployLastCommit(bucket_environment, trigger_type, trigger, local_path, remote_path){
  setConfig(true);
	var current_dir   = path.resolve('./');

	var trigger_commit_msg  = bucket_environment + '::' + trigger + '::' + local_path + '::' + remote_path,
			scrubbed_commit_msg = '::published:' + bucket_environment + ':' + trigger_type + '::';

	// Make sure the working branch has no outstanding commits and is neither ahead or behind
	// Normally outstanding commits wouldn't be a problem, but the push flag allows for an empty commit
	// So if we had untracked or uncommitted files, it would just push the last commit.
	child.exec( sh_commands.status(), function(err0, stdout0, stderr0){
		if (err0 !== null) throw stderr1;
		var branch_status = checkGitStatus(stdout0);
		// If stdout is blank, we have nothing to commit
		if (branch_status == 'clean') {
			// // Add the trigger as a commit message and push
			child.exec( sh_commands.deployLastCommit(trigger_commit_msg), function(err1, stdout1, stderr1){
				if (err1 !== null) {
					// Erase the commit that has the trigger because the trigger push didn't go through
					// This error is usually caused by being behind the remote
					child.exec( sh_commands.revertToPreviousCommit(), function(err10, stdout10, stderr10){
						if (err10) throw stderr1 + '\nAND\n' + err10;
						throw stderr1;
					});
				}
				console.log('Push successful!'.green, stdout1.trim());

				// EDIT: Let's get rid of the scrub push, it's bad practice and it adds an extra push that the server has to respond to.
				// Replace the trigger in the commit message with a scrubbed message saying that it was published and with what message
				// child.exec( sh_commands.scrubLastCommit(scrubbed_commit_msg), function(err2, stdout2, stderr2){
				// 	if (err2 !== null) throw stderr2;
				// 	console.log('Scrub push successful!'.green, stdout2.trim());
				// });
			});
		} else {
			if (branch_status == 'uncommitted') throw 'Error!'.red + ' You have uncommitted changes on this branch.' + ' Please commit your changes before attempting to deploy.'.yellow;
			if (branch_status == 'ahead_and_behind') throw 'Error'.red + ' You have unpushed commits on this branch and your local branch is behind your remote.' + ' Please pull and then push your changes before attempting to deploy.'.yellow;
			// EDIT: It's okay if they haven't push their commits. Like the edit above to the scrub push, removing this step will result in fewer pushes for the server to respond to. This alert is currently not being triggered because the branch status no longer as a condition where it is set to ahead.
			// if (branch_status == 'ahead') throw 'Error!'.red + ' You have unpushed commits on this branch.' + ' Please push your changes before attempting to deploy.'.yellow;
			if (branch_status == 'behind') throw 'Error!'.red + ' Your local branch is behind your remote.' + ' Please pull, merge and push before attempting to deploy.'.yellow;
		}
	});
}

/*    C R E A T E  A R C H I V E  B R A N C H   */
function addToArchive(branches){
  setConfig(true);
  var repo_name = path.basename(path.resolve('./'));
	child.exec( sh_commands.archive(config.github.login_method, config.github.account_name, config.archive.repo_name, branches), function(err, stdout, stderr){
		(err) ? console.log('Archive failed!'.red, 'Stated reason:' + err.message) : console.log('Success!'.green + ' `' + branches.split(':')[0] + '` branch of `' + repo_name + ' `archived as `' + branches.split(':')[1] + '` on the `' + config.archive.repo_name + '` repo.\n  https://github.com/' + config.github.account_name + '/' + config.archive.repo_name + '/tree/' + branches.split(':')[1] + '\n' + 'Note:'.cyan + ' Your existing repo has not been deleted. Please do that manually through GitHub:\n  https://github.com/' + config.github.account_name + '/' + repo_name + '/settings')
	});
}

function reportError(err, msg){
	console.log(msg, '\nReason:');
	throw err;
}

module.exports = {
	setConfig: setConfig,
	config: configClient,
	init: initAll,
	deploy: deployLastCommit,
	hook: initHook,
	archive: addToArchive
}
<|endoftext|>


<commit_before>import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import { BrowserRouter } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers/index';
import './style.scss';

const store = createStore(
  reducers,
  window.__INITIAL_STATE,
  applyMiddleware(
    thunkMiddleware
  )
);

delete window.__INITIAL_STATE;

const render = () => {
  const routes = require('./routes/index').default; // eslint-disable-line global-require
  ReactDOM.render(
    <AppContainer>
      <Provider store={store}>
        <BrowserRouter>
          {renderRoutes(routes)}
        </BrowserRouter>
      </Provider>
    </AppContainer>,
    document.getElementById('root')
  );
};

render();

if (module.hot) {
  module.hot.accept('./routes/index', render);
  module.hot.accept('./reducers/index', () => {
    const nextRootReducer = require('./reducers/index'); // eslint-disable-line global-require
    store.replaceReducer(nextRootReducer);
  });
}
<commit_msg>Update routes<commit_after>import React from 'react';
import ReactDOM from 'react-dom';
import { AppContainer } from 'react-hot-loader';
import { Provider } from 'react-redux';
import { renderRoutes } from 'react-router-config';
import { BrowserRouter } from 'react-router-dom';
import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import reducers from './reducers/index';
import './style.scss';

const store = createStore(
  reducers,
  window.__INITIAL_STATE,
  applyMiddleware(
    thunkMiddleware
  )
);

delete window.__INITIAL_STATE;

const render = () => {
  const routes = require('./routes/index').default; // eslint-disable-line global-require
  ReactDOM.render(
    <AppContainer>
      <Provider store={store}>
        <BrowserRouter>
          {renderRoutes(routes)}
        </BrowserRouter>
      </Provider>
    </AppContainer>,
    document.getElementById('root')
  );
};

render();

if (module.hot) {
  module.hot.accept('./routes/index', render);
  module.hot.accept('./reducers/index', () => {
    const nextRootReducer = require('./reducers/index').default; // eslint-disable-line global-require
    store.replaceReducer(nextRootReducer);
  });
}
<|endoftext|>