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

require('streamline').register({cache: true});

var commander = require('commander');
var fs = require('fs');
var path = require('path');
var tty = require('tty');
var util = require('util');

var log = require('winston');
var colors = require('colors');
var eyes = require('eyes');
var Table = require('easy-table');

var utils = require('./utils');

require('./util/patch-winston');

var istty1 = tty.isatty(1);

function recordError(err) {
  if (err && err.stack) {
    try {
      fs.writeFileSync('azure_error', (new Date()) + ':\n' + 
          util.inspect(err) + '\n' + err.stack);
      (log.format().json ? log.error : log.info)('Error information has been recorded to azure_error');
    } catch(err2) {
      log.warn('Cannot save error information :' + util.inspect(err2));
    }
  }
}

var debug = process.env.AZURE_DEBUG === '1';
// Install global unhandled exception handler to make unexpected errors more user-friendly.
if (!debug) {
  process.on('uncaughtException', function (err) {
    clearProgress();

    // Exceptions should always be logged to the console
    var noConsole = false;
    if (!log['default'].transports.console) {
      noConsole = true;
      cli.output.add(cli.output.transports.Console);
    }

    var loggedFullError = false;
    if (err.message) {
      log.error(err.message);
    } else if (err.Message) {
      log.error(err.Message);
    } else {
      log.json('error', err);
      loggedFullError = true;
    }

    if (!loggedFullError) {
      if (err.stack) {
        log.verbose('stack', err.stack);
      }

      log.json('silly', err);
    }

    recordError(err);

    if (noConsole) {
      cli.output.remove(cli.output.transports.Console);
    }

    cli.exit('error', null, 1);
  });
}

///////////////////////////
// prepare output logger

// use cli output settings by default
log.cli();

log.format = function (options) {
  for (var i in log['default'].transports) {
    if (log['default'].transports.hasOwnProperty(i)) {
      var transport = log['default'].transports[i];
      if (arguments.length === 0) {
        return {
          json: transport.json,
          terse: transport.terse,
          level: transport.level,
          logo: log.format.logo
        };
      }

      if (options.json) {
        log.padLevels = false;
        log.stripColors = true;
        transport.json = true;
        transport.terse = true;
      } else {
        log.padLevels = true;
        log.stripColors = false;
        transport.json = false;
        transport.terse = false;
      }

      if (options.terse) {
        log.padLevels = false;
        transport.terse = true;
      }

      if (options.level) {
        transport.level = options.level;
      }

      if (options.logo) {
        log.format.logo = options.logo;
      }
    }
  }
};


log.json = function (level, data) {
  if (arguments.length == 1) {
    data = level;
    level = 'data';
  }

  if (log.format().json) {
    log.log(level, typeof data, data);
  } else {
    var lines = eyes.inspect(data, level, { stream: false });
    lines.split('\n').forEach(function (line) {
      // eyes all is "cyan" by default, so this property accessor will
      // fix the entry/exit color codes of the line. it's needed because we're
      // splitting the eyes formatting and inserting winston formatting where it
      // wasn't before.
      log.log(level, line[eyes.defaults.styles.all]);
    });
  }
};


log.table = function (level, data, transform) {
  if (arguments.length == 2) {
    transform = data;
    data = level;
    level = 'data';
  }

  if (log.format().json) {
    log.log(level, 'table', data);
  } else {
    var table = new Table();
    table.LeftPadder = Table.LeftPadder;
    table.padLeft = Table.padLeft;
    table.RightPadder = Table.RightPadder;
    table.padRight = Table.padRight;

    if (data && data.forEach) {
      data.forEach(function (item) { transform(table, item); table.newLine(); });
    } else if (data) {
      for (var item in data) {
        transform(table, item);
        table.newLine();
      }
    }

    var lines = table.toString();
    lines.substring(0, lines.length - 1).split('\n').forEach(function (line) {
      log.log(level, line);
    });
  }
};

// prepare root cli command
var cli = new commander.Command();

var progressChars = ['-', '\\', '|', '/'];
var progressIndex = 0;
var activeProgressTimer;

var clearBuffer = new Buffer(79, 'utf8');
clearBuffer.fill(' ');
clearBuffer = clearBuffer.toString();

function drawAndUpdateProgress() {
  fs.writeSync(1, '\r');
  process.stdout.write(progressChars[progressIndex].cyan);

  progressIndex = progressIndex + 1;
  if (progressIndex == progressChars.length) {
    progressIndex = 0;
  }
}

function clearProgress() {
  // do not output '+' if there is no progress
  if (cli.currentProgress) {
    if (activeProgressTimer) {
      clearInterval(activeProgressTimer);
      activeProgressTimer = null;
    }
    fs.writeSync(1, '\r+\n');
    cli.currentProgress = undefined;
  }
}


cli.progress = function(label) {
  var verbose = log.format().json || log.format().level === 'verbose' || log.format().level === 'silly';
  if (!istty1 || verbose)  {
    (verbose ? log.verbose : log.info)(label);
    return { end: function() {} };
  }
  
  // clear any previous progress
  clearProgress();

  // Clear the console
  fs.writeSync(1, '\r' + clearBuffer);
    
  // Draw initial progress
  drawAndUpdateProgress();

  // Draw label
  if (label) {
    fs.writeSync(1, ' ' + label);
  }
    
  activeProgressTimer = setInterval(function() {
    drawAndUpdateProgress();
  }, 200);

  cli.currentProgress = {
    end: function() {
      clearProgress();
    }
  };
    
  return cli.currentProgress;
};

cli.output = log;
enableNestedCommands(cli);


cli.exit = function (level, message, exitCode) {
  clearProgress();
  if (message) {
    log.log(level, message);
  }
  process.exit(exitCode);
};

function setupCommand(args, raw, topMost) {
  var verbose = 0;
  var json = 0;
  var category = '*';

  for (var i = 0, len = raw.length; i < len; ++i) {
    if (raw[i] === '--json') {
      ++json;
    } else if (raw[i] === '-v' || raw[i] === '--verbose') {
      ++verbose;
    } else if (category === '*') {
      category = raw[i];
    } else {
      args.push(raw[i]);
    }
  }

  var opts = { };
  if (verbose || json) {
    if (json) {
      opts.json = true;
      opts.level = 'data';
    }

    if (verbose == 1) {
      opts.json = false;
      opts.level = 'verbose';
    }

    if (verbose >= 2) {
      opts.json = false;
      opts.level = 'silly';
    }

    log.format(opts);
  } else if (topMost) {
    opts = {
      json: false,
      level: 'info'
    };

    log.format(opts);
  }

  return category;
}

function enableNestedCommands(command) {
  command.option('-v, --verbose', 'use verbose output');
  command.option('--json', 'use json output');

  command.categories = {};

  command.category = function (name) {
    var category = command.categories[name];
    if (!command.categories[name]) {
      category = command.categories[name] = new commander.Command();
      category.parent = this;
      category.name = name;
      category.helpInformation = categoryHelpInformation;
      enableNestedCommands(category);
    }

    return category;
  };

  command.on('*', function () {
    var args = command.rawArgs.slice(0, 2);
    var raw = command.normalize(command.rawArgs.slice(2));

    var category = setupCommand(args, raw, command.parent === undefined);

    if (!command.categories[category]) {
      log.error('\'' + category + '\' is not an azure command. See \'azure help\'.');
    } else {
      command.categories[category].parse(args);
      if (command.categories[category].args.length === 0) {
        args.push('-h');
        command.categories[category].parse(args);
      }
    }
  });
}

commander.Command.prototype.passwordOnce = function (currentStr, mask, callback) {
  var self = this;
  var buf = '';

  // default mask
  if ('function' === typeof mask) {
    callback = mask;
    mask = '';
  }

  if (!process.stdin.setRawMode) {
    process.stdin.setRawMode = tty.setRawMode;
  }

  process.stdin.resume();
  process.stdin.setRawMode(true);
  fs.writeSync(istty1 ? 1 : 2, currentStr);
  process.stdin.on('data', function(char) {
    // Exit on Ctrl+C keypress
    char = char.toString();
    if (char === '\003') {
      console.log('%s', buf);
      process.exit();
    }

    // Return password in the buffer on enter key press
    if (char === '\015') {
      process.stdin.pause();
      process.stdin.removeAllListeners('data');
      process.stdout.write('\n');
      process.stdin.setRawMode(false);

      return callback(buf);
    }
    
    // Backspace handling 
    // Windows usually sends '\b' (^H) while Linux sends '\x7f'
    if (char === '\b' || char === '\x7f') {
      if (buf) {
        buf = buf.slice(0, -1);
        for (var j = 0; j < mask.length; ++j) {
          process.stdout.write('\b \b'); // space the last char out
        }
      }

      return;
    }

    char = char.split('\015')[0]; // only use the first line if many (for paste)
    for(var i = 0; i < char.length; ++i) {
      process.stdout.write(mask); // output several chars (for paste)
    }

    buf += char;
  });
};

// Allow cli.password to accept empty passwords
commander.Command.prototype.password = function (str, mask, fn) {
  var self = this;

  // Prompt first time
  self.passwordOnce(str, mask, function (pass) {
    // Prompt for confirmation
    self.passwordOnce('Confirm password: ', mask, function (pass2) {
      if (pass === pass2) {
        fn (pass);
      } else {
        throw new Error('Passwords do not match.');
      }
    });
  });
};<commit_msg>Updating jsHint<commit_after>/**
* Copyright (c) Microsoft.  All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*   http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

require('streamline').register({cache: true});

var commander = require('commander');
var fs = require('fs');
var path = require('path');
var tty = require('tty');
var util = require('util');

var log = require('winston');
var colors = require('colors');
var eyes = require('eyes');
var Table = require('easy-table');

var utils = require('./utils');

require('./util/patch-winston');

var istty1 = tty.isatty(1);

function recordError(err) {
  if (err && err.stack) {
    try {
      fs.writeFileSync('azure_error', (new Date()) + ':\n' + 
          util.inspect(err) + '\n' + err.stack);
      (log.format().json ? log.error : log.info)('Error information has been recorded to azure_error');
    } catch(err2) {
      log.warn('Cannot save error information :' + util.inspect(err2));
    }
  }
}

var debug = process.env.AZURE_DEBUG === '1';
// Install global unhandled exception handler to make unexpected errors more user-friendly.
if (!debug) {
  process.on('uncaughtException', function (err) {
    clearProgress();

    // Exceptions should always be logged to the console
    var noConsole = false;
    if (!log['default'].transports.console) {
      noConsole = true;
      cli.output.add(cli.output.transports.Console);
    }

    var loggedFullError = false;
    if (err.message) {
      log.error(err.message);
    } else if (err.Message) {
      log.error(err.Message);
    } else {
      log.json('error', err);
      loggedFullError = true;
    }

    if (!loggedFullError) {
      if (err.stack) {
        log.verbose('stack', err.stack);
      }

      log.json('silly', err);
    }

    recordError(err);

    if (noConsole) {
      cli.output.remove(cli.output.transports.Console);
    }

    cli.exit('error', null, 1);
  });
}

///////////////////////////
// prepare output logger

// use cli output settings by default
log.cli();

log.format = function (options) {
  for (var i in log['default'].transports) {
    if (log['default'].transports.hasOwnProperty(i)) {
      var transport = log['default'].transports[i];
      if (arguments.length === 0) {
        return {
          json: transport.json,
          terse: transport.terse,
          level: transport.level,
          logo: log.format.logo
        };
      }

      if (options.json) {
        log.padLevels = false;
        log.stripColors = true;
        transport.json = true;
        transport.terse = true;
      } else {
        log.padLevels = true;
        log.stripColors = false;
        transport.json = false;
        transport.terse = false;
      }

      if (options.terse) {
        log.padLevels = false;
        transport.terse = true;
      }

      if (options.level) {
        transport.level = options.level;
      }

      if (options.logo) {
        log.format.logo = options.logo;
      }
    }
  }
};


log.json = function (level, data) {
  if (arguments.length == 1) {
    data = level;
    level = 'data';
  }

  if (log.format().json) {
    log.log(level, typeof data, data);
  } else {
    var lines = eyes.inspect(data, level, { stream: false });
    lines.split('\n').forEach(function (line) {
      // eyes all is "cyan" by default, so this property accessor will
      // fix the entry/exit color codes of the line. it's needed because we're
      // splitting the eyes formatting and inserting winston formatting where it
      // wasn't before.
      log.log(level, line[eyes.defaults.styles.all]);
    });
  }
};


log.table = function (level, data, transform) {
  if (arguments.length == 2) {
    transform = data;
    data = level;
    level = 'data';
  }

  if (log.format().json) {
    log.log(level, 'table', data);
  } else {
    var table = new Table();
    table.LeftPadder = Table.LeftPadder;
    table.padLeft = Table.padLeft;
    table.RightPadder = Table.RightPadder;
    table.padRight = Table.padRight;

    if (data && data.forEach) {
      data.forEach(function (item) { transform(table, item); table.newLine(); });
    } else if (data) {
      for (var item in data) {
        transform(table, item);
        table.newLine();
      }
    }

    var lines = table.toString();
    lines.substring(0, lines.length - 1).split('\n').forEach(function (line) {
      log.log(level, line);
    });
  }
};

// prepare root cli command
var cli = new commander.Command();

var progressChars = ['-', '\\', '|', '/'];
var progressIndex = 0;
var activeProgressTimer;

var clearBuffer = new Buffer(79, 'utf8');
clearBuffer.fill(' ');
clearBuffer = clearBuffer.toString();

function drawAndUpdateProgress() {
  fs.writeSync(1, '\r');
  process.stdout.write(progressChars[progressIndex].cyan);

  progressIndex = progressIndex + 1;
  if (progressIndex == progressChars.length) {
    progressIndex = 0;
  }
}

function clearProgress() {
  // do not output '+' if there is no progress
  if (cli.currentProgress) {
    if (activeProgressTimer) {
      clearInterval(activeProgressTimer);
      activeProgressTimer = null;
    }
    fs.writeSync(1, '\r+\n');
    cli.currentProgress = undefined;
  }
}


cli.progress = function(label) {
  var verbose = log.format().json || log.format().level === 'verbose' || log.format().level === 'silly';
  if (!istty1 || verbose)  {
    (verbose ? log.verbose : log.info)(label);
    return { end: function() {} };
  }
  
  // clear any previous progress
  clearProgress();

  // Clear the console
  fs.writeSync(1, '\r' + clearBuffer);
    
  // Draw initial progress
  drawAndUpdateProgress();

  // Draw label
  if (label) {
    fs.writeSync(1, ' ' + label);
  }
    
  activeProgressTimer = setInterval(function() {
    drawAndUpdateProgress();
  }, 200);

  cli.currentProgress = {
    end: function() {
      clearProgress();
    }
  };
    
  return cli.currentProgress;
};

cli.output = log;
enableNestedCommands(cli);


cli.exit = function (level, message, exitCode) {
  clearProgress();
  if (message) {
    log.log(level, message);
  }
  process.exit(exitCode);
};

function setupCommand(args, raw, topMost) {
  var verbose = 0;
  var json = 0;
  var category = '*';

  for (var i = 0, len = raw.length; i < len; ++i) {
    if (raw[i] === '--json') {
      ++json;
    } else if (raw[i] === '-v' || raw[i] === '--verbose') {
      ++verbose;
    } else if (category === '*') {
      category = raw[i];
    } else {
      args.push(raw[i]);
    }
  }

  var opts = { };
  if (verbose || json) {
    if (json) {
      opts.json = true;
      opts.level = 'data';
    }

    if (verbose == 1) {
      opts.json = false;
      opts.level = 'verbose';
    }

    if (verbose >= 2) {
      opts.json = false;
      opts.level = 'silly';
    }

    log.format(opts);
  } else if (topMost) {
    opts = {
      json: false,
      level: 'info'
    };

    log.format(opts);
  }

  return category;
}

function enableNestedCommands(command) {
  command.option('-v, --verbose', 'use verbose output');
  command.option('--json', 'use json output');

  command.categories = {};

  command.category = function (name) {
    var category = command.categories[name];
    if (!command.categories[name]) {
      category = command.categories[name] = new commander.Command();
      category.parent = this;
      category.name = name;
      category.helpInformation = categoryHelpInformation;
      enableNestedCommands(category);
    }

    return category;
  };

  command.on('*', function () {
    var args = command.rawArgs.slice(0, 2);
    var raw = command.normalize(command.rawArgs.slice(2));

    var category = setupCommand(args, raw, command.parent === undefined);

    if (!command.categories[category]) {
      log.error('\'' + category + '\' is not an azure command. See \'azure help\'.');
    } else {
      command.categories[category].parse(args);
      if (command.categories[category].args.length === 0) {
        args.push('-h');
        command.categories[category].parse(args);
      }
    }
  });
}

commander.Command.prototype.passwordOnce = function (currentStr, mask, callback) {
  var self = this;
  var buf = '';

  // default mask
  if ('function' === typeof mask) {
    callback = mask;
    mask = '';
  }

  if (!process.stdin.setRawMode) {
    process.stdin.setRawMode = tty.setRawMode;
  }

  process.stdin.resume();
  process.stdin.setRawMode(true);
  fs.writeSync(istty1 ? 1 : 2, currentStr);
  process.stdin.on('data', function (character) {
    // Exit on Ctrl+C keypress
    character = character.toString();
    if (character === '\003') {
      console.log('%s', buf);
      process.exit();
    }

    // Return password in the buffer on enter key press
    if (character === '\015') {
      process.stdin.pause();
      process.stdin.removeAllListeners('data');
      process.stdout.write('\n');
      process.stdin.setRawMode(false);

      return callback(buf);
    }
    
    // Backspace handling 
    // Windows usually sends '\b' (^H) while Linux sends '\x7f'
    if (character === '\b' || character === '\x7f') {
      if (buf) {
        buf = buf.slice(0, -1);
        for (var j = 0; j < mask.length; ++j) {
          process.stdout.write('\b \b'); // space the last character out
        }
      }

      return;
    }

    character = character.split('\015')[0]; // only use the first line if many (for paste)
    for(var i = 0; i < character.length; ++i) {
      process.stdout.write(mask); // output several chars (for paste)
    }

    buf += character;
  });
};

// Allow cli.password to accept empty passwords
commander.Command.prototype.password = function (str, mask, fn) {
  var self = this;

  // Prompt first time
  self.passwordOnce(str, mask, function (pass) {
    // Prompt for confirmation
    self.passwordOnce('Confirm password: ', mask, function (pass2) {
      if (pass === pass2) {
        fn (pass);
      } else {
        throw new Error('Passwords do not match.');
      }
    });
  });
};
{'fraction_non_alphanumeric': 0.15704743139987506, 'fraction_numerical': 0.0056706232880003845, 'mean_word_length': 2.5774454186006532, 'pattern_counts': {'":': 0, '<': 9, '<?xml version=': 0, '>': 5, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6453824', 'n_tokens_mistral': 6684, 'n_tokens_neox': 6501, 'n_words': 1668}