<commit_before>var fs    = require('fs');
var path  = require('path');
var argv  = require('optimist').argv;
var utils = require('./utils');

var loadJsonSync = function(filePath) {

  if( filePath ){
    try {
      var data = fs.readFileSync(filePath);
      return JSON.parse(data.toString());
    } catch (ex) {
      console.error('Error starting session server: ' + ex);
      process.exit(1);
    }
  }
  return {};
};

var config = loadJsonSync(argv.config);

var options = {};
options['host'] = argv.host || config.host || process.env.HOST || utils.getIP();
options['port'] = argv.port || config.port || process.env.PORT || 8080;
options['serverName'] = argv.serverName || process.env.SERVER_NAME;
options['secure'] = config.secure || process.env.SECURE || false; // true(HTTP) or false(HTTPS)

options['zookeeper'] = config.zookeeper || process.env.ZOOKEEPER;
options['redis'] = config.redis || process.env.REDIS;

var homeDir = config.home || process.env.HOME_DIR;
if (homeDir){
  if(homeDir.startsWith("/")){
    options['home'] = homeDir;
  }else{
    return console.error('\n\n [ERROR] home directory must to be full paths from root(/) \n\n');
  }
}

var httpsServerOptions;
if( config.ssl ) {
  httpsServerOptions = {
    key: fs.readFileSync(config.ssl.key),
    cert: fs.readFileSync(config.ssl.cert)
  }
}
options['httpsServerOptions'] = httpsServerOptions;

options['type'] = argv.type || config.type || process.env.TYPE || 'session';
if(argv.session) options['type'] = 'session';
if(argv.channel) options['type'] = 'channel';

var protocal = options.secure ? 'https://' : 'http://';  // Don't forget to change to https if needed

/* ONLY FOR SESSION SERVER */
if(options.type == 'session'){

  options['parsePath']        = config.parsePath || process.env.PARSE_PATH || '/parse';
  options['serverURL']        = config.serverURL || process.env.SERVER_URL || protocal + options.host + ':' + options.port + options.parsePath;
  options['publicServerURL']  = config.publicServerURL || process.env.PUBLIC_SERVER_URL || protocal + options.host + ':' + options.port + options.parsePath;

  options['mongodb']  = config.mongodb || process.env.MONGODB;
  options['app']      = config.app || process.env.APP_ID || 'STALK';
  options['master']   = config.master || process.env.MASTER_KEY || 's3cR3T';
  options['push']     = config.push || utils.getPushConfig();
  options['cloud']    = config.cloud || process.env.CLOUD || './lib/cloud/index.js';
  options['appName']  = config.appName || process.env.APP_NAME || options.app;
  options['verifyUserEmails'] = config.verifyUserEmails || !!+(process.env.VERIFY_USER_EMAILS) || false;
  options['aws']  = config.aws;
  options['routePath']        = config.routePath;

  if(config.emailAdapter) options['emailAdapter'] = config.emailAdapter;
  if(process.env.EMAIL_ADAPTER_FILE) options['emailAdapter'] = loadJsonSync(emailAdapterFile);

  if(config.static && config.static.folder){
    options['static'] = {
      path: config.static.path || '/public',
      folder: path.resolve(process.cwd(), config.static.folder)
    };
  }

  if(config.channelProtocol) options['channelProtocol'] = config.channelProtocol;
  if(config.filesAdapter) options['filesAdapter'] = config.filesAdapter;

} else {
  options['mongodb']  = config.mongodb || process.env.MONGODB;
  options['master']   = config.master || process.env.MASTER_KEY || 's3cR3T';
  options['app']      = config.app || process.env.APP_ID || 'STALK';
  options['push']     = config.push || utils.getPushConfig();
  options['appName']  = config.appName || process.env.APP_NAME || options.app;
}

options['logo'] = [
  " ",
  " ,  ",
  " |\\  ",
  " \\ | ",
  "  | \\ /          OPENSOURCE MESSENGER PROJECT",
  "   \\|/    _,                   "+options['type']+" server",
  "    /  __/ /      _____________   __   __ __  ",
  "   | _/ _.'      / __/_  __/ _ | / /  / //_/  ",
  "   |/__/        _\\ \\  / / / __ |/ /__/ ,<    ",
  "    \\          /___/ /_/ /_/ |_/____/_/|_|   ",
  " ",
  " "
].join('\n');

//console.log(options);
if (argv.config) console.log(argv.config, ' >> loaded, completed');

module.exports = options;
<commit_msg>Add option for proxy port<commit_after>var fs    = require('fs');
var path  = require('path');
var argv  = require('optimist').argv;
var utils = require('./utils');

var loadJsonSync = function(filePath) {

  if( filePath ){
    try {
      var data = fs.readFileSync(filePath);
      return JSON.parse(data.toString());
    } catch (ex) {
      console.error('Error starting session server: ' + ex);
      process.exit(1);
    }
  }
  return {};
};

var config = loadJsonSync(argv.config);

var options = {};
options['host'] = argv.host || config.host || process.env.HOST || utils.getIP();
options['port'] = argv.port || config.port || process.env.PORT || 8080;
options['proxyPort'] = argv.proxyPort || process.env.PROXY_PORT; // if use haproxy
options['serverName'] = argv.serverName || process.env.SERVER_NAME;
options['secure'] = config.secure || process.env.SECURE || false; // true(HTTP) or false(HTTPS)

options['zookeeper'] = config.zookeeper || process.env.ZOOKEEPER;
options['redis'] = config.redis || process.env.REDIS;

var homeDir = config.home || process.env.HOME_DIR;
if (homeDir){
  if(homeDir.startsWith("/")){
    options['home'] = homeDir;
  }else{
    return console.error('\n\n [ERROR] home directory must to be full paths from root(/) \n\n');
  }
}

var httpsServerOptions;
if( config.ssl ) {
  httpsServerOptions = {
    key: fs.readFileSync(config.ssl.key),
    cert: fs.readFileSync(config.ssl.cert)
  }
}
options['httpsServerOptions'] = httpsServerOptions;

options['type'] = argv.type || config.type || process.env.TYPE || 'session';
if(argv.session) options['type'] = 'session';
if(argv.channel) options['type'] = 'channel';

var protocal = options.secure ? 'https://' : 'http://';  // Don't forget to change to https if needed

/* ONLY FOR SESSION SERVER */
if(options.type == 'session'){

  options['parsePath']        = config.parsePath || process.env.PARSE_PATH || '/parse';
  options['serverURL']        = config.serverURL || process.env.SERVER_URL || protocal + options.host + ':' + options.port + options.parsePath;
  options['publicServerURL']  = config.publicServerURL || process.env.PUBLIC_SERVER_URL || protocal + options.host + ':' + options.port + options.parsePath;

  options['mongodb']  = config.mongodb || process.env.MONGODB;
  options['app']      = config.app || process.env.APP_ID || 'STALK';
  options['master']   = config.master || process.env.MASTER_KEY || 's3cR3T';
  options['push']     = config.push || utils.getPushConfig();
  options['cloud']    = config.cloud || process.env.CLOUD || './lib/cloud/index.js';
  options['appName']  = config.appName || process.env.APP_NAME || options.app;
  options['verifyUserEmails'] = config.verifyUserEmails || !!+(process.env.VERIFY_USER_EMAILS) || false;
  options['aws']  = config.aws;
  options['routePath']        = config.routePath;

  if(config.emailAdapter) options['emailAdapter'] = config.emailAdapter;
  if(process.env.EMAIL_ADAPTER_FILE) options['emailAdapter'] = loadJsonSync(emailAdapterFile);

  if(config.static && config.static.folder){
    options['static'] = {
      path: config.static.path || '/public',
      folder: path.resolve(process.cwd(), config.static.folder)
    };
  }

  if(config.channelProtocol) options['channelProtocol'] = config.channelProtocol;
  if(config.filesAdapter) options['filesAdapter'] = config.filesAdapter;

} else {
  options['mongodb']  = config.mongodb || process.env.MONGODB;
  options['master']   = config.master || process.env.MASTER_KEY || 's3cR3T';
  options['app']      = config.app || process.env.APP_ID || 'STALK';
  options['push']     = config.push || utils.getPushConfig();
  options['appName']  = config.appName || process.env.APP_NAME || options.app;
}

options['logo'] = [
  " ",
  " ,  ",
  " |\\  ",
  " \\ | ",
  "  | \\ /          OPENSOURCE MESSENGER PROJECT",
  "   \\|/    _,                   "+options['type']+" server",
  "    /  __/ /      _____________   __   __ __  ",
  "   | _/ _.'      / __/_  __/ _ | / /  / //_/  ",
  "   |/__/        _\\ \\  / / / __ |/ /__/ ,<    ",
  "    \\          /___/ /_/ /_/ |_/____/_/|_|   ",
  " ",
  " "
].join('\n');

//console.log(options);
if (argv.config) console.log(argv.config, ' >> loaded, completed');

module.exports = options;
<|endoftext|>


<commit_before>var util = require('util');
var init = exports;

process.on('uncaughtException', function (err) {
  console.error(err.stack);
});

/*
  async 한 모듈 초기화를 위한 유틸리티.
  가능한 async 한 부분에만 사용하고
  일반적인 정의들은 init.add 밖의 모듈 스코프에 두는 것이 부작용이 적다.
  일반 펑션을 init.add 안에 두면 init.add 간 펑션 사용에 문제가 발생.
*/

var funcs = [];
var tails = [];

init.reset = function () {
  funcs = [];
  tails = [];
}

init.add = function (func) {
  funcs.push(func);
};

init.tail = function (func) {
  tails.unshift(func);
};

init.run = function (done) {
  var i = 0;

  done = done || function (err) {
    if (err) throw err;
  };

  function run() {
    if (i == funcs.length) {
      funcs = [];
      tails = [];
      return done();
    }
    var func = funcs[i++];
    if (func.length == 0) {
      func();
      setImmediate(run);
    } else {
      func(function (err) {
        if (err) return done(err);
        setImmediate(run);
      });
    }
  };

  funcs = funcs.concat(tails);
  run();
};
<commit_msg>return exit code 1 for uncaught exception.<commit_after>var util = require('util');
var init = exports;

process.on('uncaughtException', function (err) {
  console.error(err.stack);
  process.exit(1);
});

/*
  async 한 모듈 초기화를 위한 유틸리티.
  가능한 async 한 부분에만 사용하고
  일반적인 정의들은 init.add 밖의 모듈 스코프에 두는 것이 부작용이 적다.
  일반 펑션을 init.add 안에 두면 init.add 간 펑션 사용에 문제가 발생.
*/

var funcs = [];
var tails = [];

init.reset = function () {
  funcs = [];
  tails = [];
}

init.add = function (func) {
  funcs.push(func);
};

init.tail = function (func) {
  tails.unshift(func);
};

init.run = function (done) {
  var i = 0;

  done = done || function (err) {
    if (err) throw err;
  };

  function run() {
    if (i == funcs.length) {
      funcs = [];
      tails = [];
      return done();
    }
    var func = funcs[i++];
    if (func.length == 0) {
      func();
      setImmediate(run);
    } else {
      func(function (err) {
        if (err) return done(err);
        setImmediate(run);
      });
    }
  };

  funcs = funcs.concat(tails);
  run();
};
<|endoftext|>


<commit_before>var tessel = require('tessel');
var hardware = tessel.port('d');

var uart = hardware.UART({baudrate: 19200});
var g3 = hardware.gpio(3)
          .output()
          .high();
var txCount = 0;
var rxCount = 0;

//////////////////////////////////////////////////////////////////////////////

function decode(array)
{
  var decoded = '';
  for (var i = 0; i < array.length; i++)
  {
    if (array[i] < 14)
      decoded += '\n'
    else
      decoded += String.fromCharCode(array[i]);
  }
  return decoded;
}

function printRecieved(r)
{
  message = decode(r)
  // if (message == '\n\nUNDER-VOLTAGE WARNNING\n\n')
  //   return
  console.log(rxCount, '\tRecieved:\n\t', message, '\n');
  rxCount++;
}

function send(cmd, verbose)
{
  verbose = verbose || 0;
  uart.write(cmd);
  if (verbose)
  {
    console.log(txCount, '\tSent:\n\t', cmd);
    txCount++;
  }
}

function SMS(number, message)
{
  number = String(number) || '15555555555';   //  sorry, not sorry, Jia
  message = message || 'text from a Tessel';

  setTimeout(function(){
    send('AT\r\n');
    setTimeout(function(){
      send('AT+CMGF=1\r\n');
      setTimeout(function(){
        send('AT+CMGS="' + number + '"\r\n');
        setTimeout(function(){
          send(message + '\r\n');
          setTimeout(function(){
            send([0x1A]);
            }, 2000);
          }, 750);
        }, 500);
      }, 500);
    }, 500);
}

function heyListen(reps)
{
  //  make sure the module is awake
  reps = reps || 3;
  for (var i = 0; i < reps; i++)
  {
    setTimeout(function(){
      send('AT', 1);
    }, 200 * (i + 1));
  }
}

function getNotificationSetting()
{
  send('AT+CGEREP?\r\n');
}

function setNotifications(mode, clearBuffer)
{
  /*
  mode
    0   buffer them
    1   discard
    2   buffer when you're in the middle of something, send when you're done

  clearBuffer
    0   keep the buffer
    1   flush
  */
  mode = mode || 0;                 //  off
  clearBuffer = clearBuffer || 0;   //  don't clear

  send('AT+CGEREP=' + mode + ',' + clearBuffer + '\r\n');
}

function getConnectionStatus()
{
  send('AT+CGATT?\r\n');
}

function setConnectionStatus(state)
{
  /*
  state
    0   off (disconnect)
    1   on (connect)
  */
  send('AT+CGATT=' + state + '\r\n');
}

function netlightGPRS(state)
{
  /*
  bind the netlight's flashing to the GPRS status

  state
    0   disable
    1   enable
    ?   what my state again?
  */
  state = state || '?';

  if (state == '?')           //  read
    send('AT+CSGS?');
  else                        //  write
    send('AT+CSGS=' + state);
}

function getNetworkInfo()
{
  //  cell network information
  send('AT+CNETSCAN\r\n');
}

function getWhitelist()
{
  //  who you can call/SMS
  send('AT+CWITELIST=?')
}

var lazyWhitelistIndex = 1;
function setWhitelist(mode, number, index)
{
  /*
  enable/disable the whitelist and/or add/remove a number to/from it

  mode
    0   off
    1   on
  number
    [some 10-digit number/string]
  index
    0   remove from the list
    1   add tot he list
  */
  mode = mode || 1;                     //  enable the whitelist
  number = number || 'X';               //  dummy
  index = index || lazyWhitelistIndex;  //  be lazy and let it keep track

  if (number != 'X')
    send('AT+CWITELIST=' + mode);
  else
  {
    send('AT+CWITELIST=' + mode + ',' + number + ',' + index);
    if (index == lazyWhitelistIndex)
      lazyWhitelistIndex ++;
  }
}

function netlight(state)
{
  /*
  turn it on or off

  state
    0   off
    1   on
  */

  state = state || 1;   //  on
  send('AT+CNETLIGHT=' + state + '\r\n');
}

function microphone(state)
{
  /*
  turn it on or off

  state
    0   mic on
    1   mic off
    ?   what stae am I in?
  */

  state = state || '?';   //  what state am I in?
  if (state != '?')
    state = '=' + String(state);
  send('AT+CEXTERNTONE' + state + '\r\n');
}

function setNetlightTiming(mode, on, off)
{
  /*
  don't like the default blinks? OK.

  defaults:
    1,53,790
    2,53,2990
    3,53,287

  mode
    1   when the module is disconnected
    2   when the module is connected
    3   when in PPP comms
    ?   get the state
  on
    [40 - 65535]  how long you want it on, in ms
  off
    [40 - 65535]  how long you want it off, in ms
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+SLEDS?\r\n');
  else                  //  write
  {
    on = on || 53;
    off = off || [790, 2990, 287][mode];
    send('AT+SLEDS=' + mode + ',' + on + ',' + off + '\r\n');
  }
}

function rejectMode(mode)
{
  /*
  do you want to answer incoming calls?

  mode
    0   enable
    1   fobid all
    2   forbid voice, enable CSD
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+GSMBUSY?\r\n');
  else                  //  write
    send('AT+GSMBUSY=' + mode + '\r\n');
}

function voiceCoding(mode)
{
  /*
  Get/set voice coding type? Not toatally sure what these do...

  mode
    0   FR
    1   EFR/FR
    2   HR/FR
    3   FR/HR
    4   HR/EFR
    5   EFR/HR
    6   AMR-FR/EFR,AMHR-HR
    7   AMR-FR/EFR,AMR-HR/HR
    8   AMR-HR/HR/AMR-FR/EFR
    9   AMR-HR/AMR-FR/EFR
    10  AMR-HR/AMR-FR/FR
    11  AMR-HR/HR/AMR-FR
    12  AMR-FR/AMR-HR
    13  AMR-FR/FR/AMR-HR
    14  AMR-FR/FR/AMR-HR/HR
    15  AMR-FR/EFR/FR/AMR-HR/HR
    16  AMR-HR/AMR-FR/EFR/FR/HR
    17  AMR-FR/AMR-HR/EFR/FR/HR
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+SVR?\r\n');
  else                  //  write
    send('AT+SVR=' + mode + '\r\n');
}

function audioSwitch(mode)
{
  /*
  control automatic audio channel switching

  mode
    0   disable + disable headset HOOK function
    1   enable + enable headset HOOK function
    2   disable + enable headset HOOK function
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+CAAS?\r\n');
  else                  //  write
    send('AT+CAAS=' + mode + '\r\n');
}

////////////////////////////////////////////////////////////////////////////////

process.on('message', function (data) {
  // console.log(data.substring(1, data.length-1));
  send(data.substring(1, data.length - 1) + "\r\n");
});

console.log('waiting for messages...');

uart.on('data', function(bytes) {
  printRecieved(bytes);
});

console.log('gogogo!');
tessel.sleep(50);
g3.low();
tessel.sleep(1200);
g3.high();
tessel.sleep(3000);

heyListen();

tessel.sleep(100);

// setInterval(function(){
//   send('AT+CMGR=1,1\r\n');
// }, 4000);

// setInterval(function(){
//   send('AT+CMGR=2,1\r\n');
// }, 5000);

// setInterval(function(){
//   send('AT+CMGR=3,1\r\n');
// }, 6000);

// setInterval(function(){
//   send('AT+CMGR=4,1\r\n');
// }, 7000);

// SMS(phone#,'messagetext');

//    for history's sake

// THIS BLOCK WORKED
// var characters = 'AT\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'AT+CMGF=1\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'AT+CMGS="15555555555"\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'text from a Tessel\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = [0x1A]
// send(characters);

<commit_msg>misc changes<commit_after>var tessel = require('tessel');
var hardware = tessel.port('d');

var uart = hardware.UART({baudrate: 19200});
var g3 = hardware.gpio(3)
          .output()
          .high();
var txCount = 0;
var rxCount = 0;

//////////////////////////////////////////////////////////////////////////////

function decode(array)
{
  var decoded = '';
  for (var i = 0; i < array.length; i++)
  {
    if (array[i] < 14)
      decoded += '\n'
    else
      decoded += String.fromCharCode(array[i]);
  }
  return decoded;
}

function printRecieved(r)
{
  message = decode(r)
  // if (message == '\n\nUNDER-VOLTAGE WARNNING\n\n')
  //   return
  console.log(rxCount, '\tRecieved:\n\t', message, '\n');
  rxCount++;
}

function send(cmd, verbose)
{
  verbose = verbose || 0;
  uart.write(cmd);
  if (verbose)
  {
    console.log(txCount, '\tSent:\n\t', cmd);
    txCount++;
  }
}

function SMS(number, message)
{
  number = String(number) || '15555555555';   //  sorry, not sorry, Jia
  message = message || 'text from a Tessel';

  setTimeout(function(){
    send('AT\r\n');
    setTimeout(function(){
      send('AT+CMGF=1\r\n');
      setTimeout(function(){
        send('AT+CMGS="' + number + '"\r\n');
        setTimeout(function(){
          send(message + '\r\n');
          setTimeout(function(){
            send([0x1A]);
            }, 3000);//2000);
          }, 2000);//750);
        }, 2000);//500);
      }, 2000);//500);
    }, 2000);//500);
}

function heyListen(reps)
{
  //  make sure the module is awake
  reps = reps || 3;
  for (var i = 0; i < reps; i++)
  {
    setTimeout(function(){
      send('AT', 1);
    }, 500 * (i + 1));
  }
}

function getNotificationSetting()
{
  send('AT+CGEREP?\r\n');
}

function setNotifications(mode, clearBuffer)
{
  /*
  mode
    0   buffer them
    1   discard
    2   buffer when you're in the middle of something, send when you're done

  clearBuffer
    0   keep the buffer
    1   flush
  */
  mode = mode || 0;                 //  off
  clearBuffer = clearBuffer || 0;   //  don't clear

  send('AT+CGEREP=' + mode + ',' + clearBuffer + '\r\n');
}

function getConnectionStatus()
{
  send('AT+CGATT?\r\n');
}

function setConnectionStatus(state)
{
  /*
  state
    0   off (disconnect)
    1   on (connect)
  */
  send('AT+CGATT=' + state + '\r\n');
}

function netlightGPRS(state)
{
  /*
  bind the netlight's flashing to the GPRS status

  state
    0   disable
    1   enable
    ?   what my state again?
  */
  state = state || '?';

  if (state == '?')           //  read
    send('AT+CSGS?');
  else                        //  write
    send('AT+CSGS=' + state);
}

function getNetworkInfo()
{
  //  cell network information
  send('AT+CNETSCAN\r\n');
}

function getWhitelist()
{
  //  who you can call/SMS
  send('AT+CWITELIST=?')
}

var lazyWhitelistIndex = 1;
function setWhitelist(mode, number, index)
{
  /*
  enable/disable the whitelist and/or add/remove a number to/from it

  mode
    0   off
    1   on
  number
    [some 10-digit number/string]
  index
    0   remove from the list
    1   add tot he list
  */
  mode = mode || 1;                     //  enable the whitelist
  number = number || 'X';               //  dummy
  index = index || lazyWhitelistIndex;  //  be lazy and let it keep track

  if (number != 'X')
    send('AT+CWITELIST=' + mode);
  else
  {
    send('AT+CWITELIST=' + mode + ',' + number + ',' + index);
    if (index == lazyWhitelistIndex)
      lazyWhitelistIndex ++;
  }
}

function netlight(state)
{
  /*
  turn it on or off

  state
    0   off
    1   on
  */

  state = state || 1;   //  on
  send('AT+CNETLIGHT=' + state + '\r\n');
}

function microphone(state)
{
  /*
  turn it on or off

  state
    0   mic on
    1   mic off
    ?   what stae am I in?
  */

  state = state || '?';   //  what state am I in?
  if (state != '?')
    state = '=' + String(state);
  send('AT+CEXTERNTONE' + state + '\r\n');
}

function setNetlightTiming(mode, on, off)
{
  /*
  don't like the default blinks? OK.

  defaults:
    1,53,790
    2,53,2990
    3,53,287

  mode
    1   when the module is disconnected
    2   when the module is connected
    3   when in PPP comms
    ?   get the state
  on
    [40 - 65535]  how long you want it on, in ms
  off
    [40 - 65535]  how long you want it off, in ms
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+SLEDS?\r\n');
  else                  //  write
  {
    on = on || 53;
    off = off || [790, 2990, 287][mode];
    send('AT+SLEDS=' + mode + ',' + on + ',' + off + '\r\n');
  }
}

function rejectMode(mode)
{
  /*
  do you want to answer incoming calls?

  mode
    0   enable
    1   fobid all
    2   forbid voice, enable CSD
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+GSMBUSY?\r\n');
  else                  //  write
    send('AT+GSMBUSY=' + mode + '\r\n');
}

function voiceCoding(mode)
{
  /*
  Get/set voice coding type? Not toatally sure what these do...

  mode
    0   FR
    1   EFR/FR
    2   HR/FR
    3   FR/HR
    4   HR/EFR
    5   EFR/HR
    6   AMR-FR/EFR,AMHR-HR
    7   AMR-FR/EFR,AMR-HR/HR
    8   AMR-HR/HR/AMR-FR/EFR
    9   AMR-HR/AMR-FR/EFR
    10  AMR-HR/AMR-FR/FR
    11  AMR-HR/HR/AMR-FR
    12  AMR-FR/AMR-HR
    13  AMR-FR/FR/AMR-HR
    14  AMR-FR/FR/AMR-HR/HR
    15  AMR-FR/EFR/FR/AMR-HR/HR
    16  AMR-HR/AMR-FR/EFR/FR/HR
    17  AMR-FR/AMR-HR/EFR/FR/HR
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+SVR?\r\n');
  else                  //  write
    send('AT+SVR=' + mode + '\r\n');
}

function audioSwitch(mode)
{
  /*
  control automatic audio channel switching

  mode
    0   disable + disable headset HOOK function
    1   enable + enable headset HOOK function
    2   disable + enable headset HOOK function
    ?   get current state
  */

  mode = mode || '?';

  if (mode == '?')      //  read
    send('AT+CAAS?\r\n');
  else                  //  write
    send('AT+CAAS=' + mode + '\r\n');
}

////////////////////////////////////////////////////////////////////////////////

var led1 = tessel.led(1).output().high();
var led2 = tessel.led(2).output().low();

setInterval(function () {
  led1.toggle();
  led2.toggle();
}, 250);

process.on('message', function (data) {
  // console.log(data.substring(1, data.length-1));
  send(data.substring(1, data.length - 1) + "\r\n");
});

console.log('waiting for messages...');

uart.on('data', function(bytes) {
  printRecieved(bytes);
});

console.log('gogogo!');
tessel.sleep(50);
// g3.low();
// tessel.sleep(1200);
// g3.high();
// tessel.sleep(3000);

heyListen();

tessel.sleep(100);

setTimeout(function () {
  SMS(15555555555, "test")
  }, 25000);

// setInterval(function(){
//   send('AT+CMGR=1,1\r\n');
// }, 4000);

// setInterval(function(){
//   send('AT+CMGR=2,1\r\n');
// }, 5000);

// setInterval(function(){
//   send('AT+CMGR=3,1\r\n');
// }, 6000);

// setInterval(function(){
//   send('AT+CMGR=4,1\r\n');
// }, 7000);

// SMS(phone#,'messagetext');

//    for history's sake

// THIS BLOCK WORKED
// var characters = 'AT\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'AT+CMGF=1\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'AT+CMGS="15555555555"\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = 'text from a Tessel\r\n'
// send(characters);
// tessel.sleep(2000);

// characters = [0x1A]
// send(characters);

<|endoftext|>


<commit_before>// if the database is empty on server start, create initial collection
Meteor.startup(function () {
  /*
  if (Sessions.find().count() === 0) {
    console.log('no sessions');
  } else {
    console.log(Sessions.find().count() + ' sessions');
  }
  */
});<commit_msg>removed unnecessary file<commit_after><|endoftext|>


<commit_before>const Route = require('route-parser');
const defaults = require('lodash/defaults');
const forEach = require('lodash/foreach');
const qs = require('qs');

let running = false;

function getCurrentUrl() {
    return document.location.pathname + document.location.search + document.location.hash;
}

function loadPage(options) {
    const url = options.pagePath;

    const pageUrl = (`pages/${url.split('?')[0].split('#')[0]}/index`)
        .split('//')
        .join('/');

    return window.System && Promise.resolve(System.import(pageUrl)).then(Page => Page());
}

function match() {
    const result = {};

    forEach(router.routes, (handler, pattern) => {
        const route = new Route(pattern);
        const params = route.match(getCurrentUrl());

        if (params) {
            result.handler = handler;
            result.params = params;
            result.route = route;
            return false;
        }
    });

    return result;
}

function onPopstate() {
    router.navigate(getCurrentUrl(), {
        replace: true,
    });
}

function getParams() {
    const route = match().route;
    const queryString = window.location.search.substring(1);
    const routeParams = route.match(getCurrentUrl());
    const queryParams = qs.parse(queryString);

    forEach(queryParams, (val, key) => {
        try {
            queryParams[key] = JSON.parse(val);
        } catch (e) {
            queryParams[key] = val;
        }
    });

    return defaults(routeParams, queryParams);
}

function setParams(params, options) {
    const route = match().route;
    let url = route.reverse(params);
    let routeParams = route.match(url);
    let queryParams = {};

    forEach(params, (val, key) => {
        if (!routeParams.hasOwnProperty(key)) {
            queryParams[key] = val;
        }
    });

    const queryString = qs.stringify(queryParams);

    if (queryString){
        url += `?${queryString}`;
    }

    if (window.location.hash){
        url += window.location.hash;
    }

    router.navigate(url, options);
}

function onClick(e) {
    if (checkLink(e.target)) {
        e.preventDefault();
        router.navigate(e.target.getAttribute('href'));
    }
}

function checkLink(linkElement) {
    if (!linkElement.getAttribute('href')) {
        return false;
    }

    if (linkElement.getAttribute('href').indexOf('http') === 0){
        return false;
    }

    if (linkElement.getAttribute('rel') === 'external') {
        return false;
    }
}

const router = {
    routes: {},

    start() {
        if (running) {
            return Promise.resolve();
        }

        this.routes['*pagePath'] = loadPage;

        window.addEventListener('popstate', onPopstate);
        document.addEventListener('click', onClick);

        const navigate = this.navigate(getCurrentUrl(), {
            replace: true,
        });

        running = true;

        return navigate;
    },

    stop() {
        running = false;

        window.removeEventListener('popstate', onPopstate);
        document.removeEventListener('click', onClick);
    },

    navigate(url, options) {
        if (running && getCurrentUrl() === url) {
            return false;
        }

        const opt = defaults(options || {}, {
            replace: false,
        });

        window.history[opt.replace ? 'replaceState' : 'pushState']({}, '', url);

        const route = match();

        return Promise.resolve(route.handler && route.handler(route.params)).catch(this.onError);
    },

    onError(error) {
        alert(error);
    },

    params(params, options) {
        return params ? setParams(params, options) : getParams();
    }
};

module.exports = router;

<commit_msg>change lodash modules names to camelcase<commit_after>const Route = require('route-parser');
const defaults = require('lodash/defaults');
const forEach = require('lodash/forEach');
const qs = require('qs');

let running = false;

function getCurrentUrl() {
    return document.location.pathname + document.location.search + document.location.hash;
}

function loadPage(options) {
    const url = options.pagePath;

    const pageUrl = (`pages/${url.split('?')[0].split('#')[0]}/index`)
        .split('//')
        .join('/');

    return window.System && Promise.resolve(System.import(pageUrl)).then(Page => Page());
}

function match() {
    const result = {};

    forEach(router.routes, (handler, pattern) => {
        const route = new Route(pattern);
        const params = route.match(getCurrentUrl());

        if (params) {
            result.handler = handler;
            result.params = params;
            result.route = route;
            return false;
        }
    });

    return result;
}

function onPopstate() {
    router.navigate(getCurrentUrl(), {
        replace: true,
    });
}

function getParams() {
    const route = match().route;
    const queryString = window.location.search.substring(1);
    const routeParams = route.match(getCurrentUrl());
    const queryParams = qs.parse(queryString);

    forEach(queryParams, (val, key) => {
        try {
            queryParams[key] = JSON.parse(val);
        } catch (e) {
            queryParams[key] = val;
        }
    });

    return defaults(routeParams, queryParams);
}

function setParams(params, options) {
    const route = match().route;
    let url = route.reverse(params);
    let routeParams = route.match(url);
    let queryParams = {};

    forEach(params, (val, key) => {
        if (!routeParams.hasOwnProperty(key)) {
            queryParams[key] = val;
        }
    });

    const queryString = qs.stringify(queryParams);

    if (queryString){
        url += `?${queryString}`;
    }

    if (window.location.hash){
        url += window.location.hash;
    }

    router.navigate(url, options);
}

function onClick(e) {
    if (checkLink(e.target)) {
        e.preventDefault();
        router.navigate(e.target.getAttribute('href'));
    }
}

function checkLink(linkElement) {
    if (!linkElement.getAttribute('href')) {
        return false;
    }

    if (linkElement.getAttribute('href').indexOf('http') === 0){
        return false;
    }

    if (linkElement.getAttribute('rel') === 'external') {
        return false;
    }
}

const router = {
    routes: {},

    start() {
        if (running) {
            return Promise.resolve();
        }

        this.routes['*pagePath'] = loadPage;

        window.addEventListener('popstate', onPopstate);
        document.addEventListener('click', onClick);

        const navigate = this.navigate(getCurrentUrl(), {
            replace: true,
        });

        running = true;

        return navigate;
    },

    stop() {
        running = false;

        window.removeEventListener('popstate', onPopstate);
        document.removeEventListener('click', onClick);
    },

    navigate(url, options) {
        if (running && getCurrentUrl() === url) {
            return false;
        }

        const opt = defaults(options || {}, {
            replace: false,
        });

        window.history[opt.replace ? 'replaceState' : 'pushState']({}, '', url);

        const route = match();

        return Promise.resolve(route.handler && route.handler(route.params)).catch(this.onError);
    },

    onError(error) {
        alert(error);
    },

    params(params, options) {
        return params ? setParams(params, options) : getParams();
    }
};

module.exports = router;

<|endoftext|>


<commit_before>'use strict';

const rendy = require('rendy');
const Entity = require('./common/entity');
const store = require('./common/store');

/* КОНСТАНТЫ (общие для клиента и сервера)*/

/* название программы */
const NAME = 'Cloud Commander';
const FS = '/fs';

const Path = store();

Path('/');

module.exports.FS = FS;
module.exports.apiURL = '/api/v1';
module.exports.MAX_FILE_SIZE = 500 * 1024;
module.exports.Entity = Entity;

module.exports.formatMsg = (msg, name, status = 'ok') => {
    if (name)
        name = '("' + name + '")';
    else
        name = '';

    return msg + ': ' + status + name;
};

/**
 * Функция возвращает заголовок веб страницы
 * @path
 */
module.exports.getTitle = (path) => {
    return  NAME + ' - ' + (path || Path());
};

/** Функция получает адреса каждого каталога в пути
 * возвращаеться массив каталогов
 * @param url -  адрес каталога
 */
function getPathLink(url, prefix, template) {
    if (!url)
        throw Error('url could not be empty!');

    if (!template)
        throw Error('template could not be empty!');

    const names = url
        .split('/')
        .slice(1, -1);

    const allNames = ['/', ...names];
    const length = allNames.length - 1;

    let path = '/';

    const pathHTML = allNames.map((name, index) => {
        const isLast = index === length;

        if (index)
            path += name + '/';

        if (index && isLast)
            return name + '/';

        const slash = index ? '/' : '';

        return rendy(template, {
            path,
            name,
            slash,
            prefix,
        });
    }).join('');

    return pathHTML;
}

/**
 * Функция строит таблицу файлв из JSON-информации о файлах
 * @param params - информация о файлах
 *
 */
module.exports.buildFromJSON = (params) => {
    const prefix = params.prefix;
    const template = params.template;
    const templateFile = template.file;
    const templateLink = template.link;
    const json = params.data;

    const {path, files} = json;

    const sort = params.sort || 'name';
    const order = params.order || 'asc';

    /*
     * Строим путь каталога в котором мы находимся
     * со всеми подкаталогами
     */
    const htmlPath = getPathLink(path, prefix, template.pathLink);

    let fileTable = rendy(template.path, {
        link        : prefix + FS + path,
        fullPath    : path,
        path        : htmlPath
    });

    let name = 'name';
    let size = 'size';
    let date = 'date';
    const owner = 'owner';
    const mode = 'mode';
    const arrow = order === 'asc' ?  '↑' : '↓';

    if (sort === 'name' && order !== 'asc')
        name += arrow;
    else if (sort === 'size')
        size += arrow;
    else if (sort === 'date')
        date += arrow;

    const header = rendy(templateFile, {
        tag         : 'div',
        attribute   : 'data-name="js-fm-header" ',
        className   : 'fm-header',
        type        : '',
        name,
        size,
        date,
        owner,
        mode,
    });

    /* сохраняем путь */
    Path(path);

    fileTable += header + '
';
    /* Если мы не в корне */
    if (path !== '/') {
        /* убираем последний слеш и каталог в котором мы сейчас находимся*/
        const lastSlash  = path.substr(path, path.lastIndexOf('/'));
        const dotDot = lastSlash.substr(lastSlash, lastSlash.lastIndexOf('/'));

        const link = prefix + FS + (dotDot || '/');

        const linkResult = rendy(template.link, {
            link,
            title       : '..',
            name        : '..'
        });

        const dataName = 'data-name="js-file-.." ';
        const attribute = 'draggable="true" ' + dataName;

        /* Сохраняем путь к каталогу верхнего уровня*/
        fileTable += rendy(template.file, {
            tag         : 'li',
            attribute,
            className   : '',
            type        : 'directory',
            name        : linkResult,
            size        : '<dir>',
            date        : '--.--.----',
            owner       : '.',
            mode        : '--- --- ---'
        });
    }

    fileTable += files.map((file) => {
        const link = prefix + FS + path + file.name;

        const type = getType(file.size);
        const size = getSize(file.size);

        const date = file.date || '--.--.----';
        const owner = file.owner || 'root';
        const mode = file.mode;

        const linkResult = rendy(templateLink, {
            link,
            title: file.name,
            name: Entity.encode(file.name),
            attribute: getAttribute(file.size)
        });

        const dataName = 'data-name="js-file-' + file.name + '" ';
        const attribute = 'draggable="true" ' + dataName;

        return rendy(templateFile, {
            tag: 'li',
            attribute,
            className: '',
            type,
            name: linkResult,
            size,
            date,
            owner,
            mode,
        });
    }).join('');

    fileTable += '
';

    return fileTable;
};

function getType(size) {
    if (size === 'dir')
        return 'directory';

    return 'text-file';
}

function getAttribute(size) {
    if (size === 'dir')
        return '';

    return 'target="_blank" ';
}

function getSize(size) {
    if (size === 'dir')
        return '<dir>';

    return size;
}

<commit_msg>chore(cloudfunc) formatMsg: default arguments<commit_after>'use strict';

const rendy = require('rendy');
const Entity = require('./common/entity');
const store = require('./common/store');

/* КОНСТАНТЫ (общие для клиента и сервера)*/

/* название программы */
const NAME = 'Cloud Commander';
const FS = '/fs';

const Path = store();

Path('/');

module.exports.FS = FS;
module.exports.apiURL = '/api/v1';
module.exports.MAX_FILE_SIZE = 500 * 1024;
module.exports.Entity = Entity;

module.exports.formatMsg = (msg, name, status) => {
    status = status || 'ok';

    if (name)
        name = '("' + name + '")';
    else
        name = '';

    return msg + ': ' + status + name;
};

/**
 * Функция возвращает заголовок веб страницы
 * @path
 */
module.exports.getTitle = (path) => {
    return  NAME + ' - ' + (path || Path());
};

/** Функция получает адреса каждого каталога в пути
 * возвращаеться массив каталогов
 * @param url -  адрес каталога
 */
function getPathLink(url, prefix, template) {
    if (!url)
        throw Error('url could not be empty!');

    if (!template)
        throw Error('template could not be empty!');

    const names = url
        .split('/')
        .slice(1, -1);

    const allNames = ['/', ...names];
    const length = allNames.length - 1;

    let path = '/';

    const pathHTML = allNames.map((name, index) => {
        const isLast = index === length;

        if (index)
            path += name + '/';

        if (index && isLast)
            return name + '/';

        const slash = index ? '/' : '';

        return rendy(template, {
            path,
            name,
            slash,
            prefix,
        });
    }).join('');

    return pathHTML;
}

/**
 * Функция строит таблицу файлв из JSON-информации о файлах
 * @param params - информация о файлах
 *
 */
module.exports.buildFromJSON = (params) => {
    const prefix = params.prefix;
    const template = params.template;
    const templateFile = template.file;
    const templateLink = template.link;
    const json = params.data;

    const {path, files} = json;

    const sort = params.sort || 'name';
    const order = params.order || 'asc';

    /*
     * Строим путь каталога в котором мы находимся
     * со всеми подкаталогами
     */
    const htmlPath = getPathLink(path, prefix, template.pathLink);

    let fileTable = rendy(template.path, {
        link        : prefix + FS + path,
        fullPath    : path,
        path        : htmlPath
    });

    let name = 'name';
    let size = 'size';
    let date = 'date';
    const owner = 'owner';
    const mode = 'mode';
    const arrow = order === 'asc' ?  '↑' : '↓';

    if (sort === 'name' && order !== 'asc')
        name += arrow;
    else if (sort === 'size')
        size += arrow;
    else if (sort === 'date')
        date += arrow;

    const header = rendy(templateFile, {
        tag         : 'div',
        attribute   : 'data-name="js-fm-header" ',
        className   : 'fm-header',
        type        : '',
        name,
        size,
        date,
        owner,
        mode,
    });

    /* сохраняем путь */
    Path(path);

    fileTable += header + '
';
    /* Если мы не в корне */
    if (path !== '/') {
        /* убираем последний слеш и каталог в котором мы сейчас находимся*/
        const lastSlash  = path.substr(path, path.lastIndexOf('/'));
        const dotDot = lastSlash.substr(lastSlash, lastSlash.lastIndexOf('/'));

        const link = prefix + FS + (dotDot || '/');

        const linkResult = rendy(template.link, {
            link,
            title       : '..',
            name        : '..'
        });

        const dataName = 'data-name="js-file-.." ';
        const attribute = 'draggable="true" ' + dataName;

        /* Сохраняем путь к каталогу верхнего уровня*/
        fileTable += rendy(template.file, {
            tag         : 'li',
            attribute,
            className   : '',
            type        : 'directory',
            name        : linkResult,
            size        : '<dir>',
            date        : '--.--.----',
            owner       : '.',
            mode        : '--- --- ---'
        });
    }

    fileTable += files.map((file) => {
        const link = prefix + FS + path + file.name;

        const type = getType(file.size);
        const size = getSize(file.size);

        const date = file.date || '--.--.----';
        const owner = file.owner || 'root';
        const mode = file.mode;

        const linkResult = rendy(templateLink, {
            link,
            title: file.name,
            name: Entity.encode(file.name),
            attribute: getAttribute(file.size)
        });

        const dataName = 'data-name="js-file-' + file.name + '" ';
        const attribute = 'draggable="true" ' + dataName;

        return rendy(templateFile, {
            tag: 'li',
            attribute,
            className: '',
            type,
            name: linkResult,
            size,
            date,
            owner,
            mode,
        });
    }).join('');

    fileTable += '
';

    return fileTable;
};

function getType(size) {
    if (size === 'dir')
        return 'directory';

    return 'text-file';
}

function getAttribute(size) {
    if (size === 'dir')
        return '';

    return 'target="_blank" ';
}

function getSize(size) {
    if (size === 'dir')
        return '<dir>';

    return size;
}

<|endoftext|>


<commit_before>const fs = require('fs');
const mongojs = require('mongojs');
const Discordie = require('discordie');
const handlebars = require('handlebars');
const Screenshot = require('screenshot-stream');
const winston = require('winston');

/** A Discord bot, which encourages players to join voice channels. */
class Kirito {
  constructor() {
    // Prepare discord api
    this.discordApi = new Discordie({autoReconnect: true});
    this.discordApi.connect({ token: process.env.AUTH_TOKEN });

    // Prepare database
    this.db = mongojs(process.env.DATABASE, ['users']);

    // Prepare application state
    this.connectedUsers = [];
    this.subscribeToEvents();
  }

  /**
   * Registers callback functions to certain events which are triggered
   * through the DiscordApi.
   */
  subscribeToEvents() {
    // Bind this into callback functions
    this.prepareBot = this.prepareBot.bind(this);
    this.joinServer = this.joinServer.bind(this);
    this.userConnected = this.userConnected.bind(this);
    this.userDisconnected = this.userDisconnected.bind(this);
    this.handleChatCommand = this.handleChatCommand.bind(this);

    // Subscribe to events
    this.discordApi.Dispatcher.on(discord.Events.GATEWAY_READY, this.prepareBot);
    this.discordApi.Dispatcher.on(discord.Events.GUILD_CREATE, this.joinServer);
    this.discordApi.Dispatcher.on(discord.Events.VOICE_CHANNEL_JOIN, this.userConnected);
    this.discordApi.Dispatcher.on(discord.Events.VOICE_CHANNEL_LEAVE, this.userDisconnected);
    this.discordApi.Dispatcher.on(discord.Events.MESSAGE_CREATE, this.handleChatCommand);
  }

  /**
   * Initializes the bot using the Discord API.
   */
  prepareBot() {
    this.discordApi.User.setGame('together with Asuna');
    this.addCurrentlyConnectedUsers();
  }

  /**
   * Adds all currently connected users to the list of connected users.
   */
  addCurrentlyConnectedUsers() {
    this.discordApi.Guilds.forEach((server) => {
      server.voiceChannels.forEach((channel) => {
        channel.members.forEach((user) => {
          this.addConnectedUser(user, server);
        });
      });
    });
  }

  /**
   * Prints an introduction message.
   * @param {Event} e - Discord API event.
   */
  joinServer(e) {
    e.guild.generalChannel.sendTyping();
    const introduction = [
      'Hi!',
      'I am Kirito, your personal voice chat coach. From now on, every time you join',
      'a voice channel on this Server you will receive experience and therefore level.',
      'Additionally, you can ask me things through so called commands. Currently,',
      'I know two commands. Command number one is `ping`, which obviously starts a',
      'table tennis match, and command number two is called `profile` where I will',
      'print an image of your current player profile.',
      '',
      'Enjoy your time in voice channels :).'
    ];
    e.guild.generalChannel.sendMessage(introduction);
  }

  /**
   * Handles users connecting to voice channels.
   * @param {Event} e - Discord API event.
   */
  userConnected(e) {
    this.addConnectedUser(e.user, e.channel.guild);
  }

  /**
   * Adds a user to the list of users in voice channels (connected users).
   * @param {Object} user - Discord API user object.
   * @param {Object} server - Discord API guild object.
   */
  addConnectedUser(user, server) {
    const rewardInterval = 60000;
    const experiencePerMinute = 1;
    const connectedUser = {};
    connectedUser.experienceTimer = setInterval(() => { this.addExperience(user, server, experiencePerMinute); }, rewardInterval);
    this.connectedUsers[user.id] = connectedUser;
    winston.log("info", 'User ' + user.username + ' connected to server ' + server.name + '.');
  }

  /**
   * Handles users disconnecting from voice channels.
   * @param {Event} e - Discord API event.
   */
  userDisconnected(e) {
    this.removeConnectedUser(e.user);
  }

  /**
   * Removes a user from the list of users in voice channels (connected users).
   * @param {Object} user - Discord API user object.
   */
  removeConnectedUser(user) {
    if (!this.connectedUsers[user.id]) {
      winston.log("warn", 'User ' + user.username + ' not found in list of online users.');
      return;
    }
    clearInterval(this.connectedUsers[user.id].experienceTimer);
    delete this.connectedUsers[user.id];
    winston.log("info", 'User ' + user.username + ' disconnected.');
  }

  /**
   * Adds experience to the user account.
   * @param {Object} user - Discord API user object.
   * @param {Object} server - Discord API guild object.
   * @param {Number} experience - Amount of experience to add.
   */
  addExperience(user, server, experience) {
    this.db.users.update({id: user.id}, { $setOnInsert: user, $inc: { experience } }, {upsert: true});
    this.db.users.update({id: user.id, 'servers.id': server.id}, {$inc: {'servers.$.experience': experience}} );
    this.db.users.update({id: user.id, 'servers.id': {$ne: server.id}}, { $push: {'servers': {id: server.id, experience}} }, (err, res) => {
      winston.log("info", 'Added ' + experience + ' experience to user ' + user.username + '.');
      winston.log("info", user.username + ' has now a total experience of ' + res.experience + '.');
    });
  }

  /**
   * Handles received chat messages and checks for chat commands.
   * @param {Event} e - Discord API event.
   */
  handleChatCommand(e) {
    switch (e.message.content) {
      case 'ping':
        e.message.channel.sendTyping();
        e.message.channel.sendMessage('pong');
        break;

      case 'profile':
        this.getProfile(e.message.author, (profile) => {
          e.message.channel.sendTyping();
          e.message.channel.uploadFile(profile, 'profile.png');
        });
        break;
    }
  }

  /**
   * Gathers necessary user data and prepares the image stream to print
   * a users profile.
   * @param {Object} user - Discord API user object.
   * @param {Callback} callback - Called when image stream is ready.
   */
  getProfile(user, callback) {
    const newUser = JSON.parse(JSON.stringify(user));
    newUser.experience = 0;
    winston.log("info", 'Printing profile for user ' + user.username + '.');
    this.db.users.findAndModify({query: {id: user.id}, update: { $setOnInsert: newUser }, upsert: true, new: true}, (err, result) => {
      const profileInformation = {
        username: user.username,
        level: this.calculateLevel(result.experience),
        levelProgress: this.calculateLevelProgress(result.experience),
        avatar: this.getAvatarUrl(user),
        servers: this.getAdditionalServerData(result.servers)
      };
      winston.log("info", 'username:' + user.username);
      winston.log("info", 'level:' + this.calculateLevel(result.experience));
      winston.log("info", 'experience:' + result.experience);
      winston.log("info", 'levelProgress:' + this.calculateLevelProgress(result.experience));
      winston.log("info", 'servers:' + this.getAdditionalServerData(result.servers));
      const profileHtmlFilename = 'profiles/' + user.id + '.html';
      this.createProfileHtml(profileHtmlFilename, profileInformation);
      const stream = this.createProfileImageStream(profileHtmlFilename);

      /**
       * Is called when the profile creation finished and the image stream
       * is ready.
       * @callback callback
       * @param {String} stream - Image stream containing the user profile.
       */
      callback(stream);
    });
  }

  /**
   * Calculates the level given a total amount of experience.
   * @param {Number} experience - Amount of experience.
   * @return {Number} Level corresponding to experience.
   */
  calculateLevel(experience) {
    return Math.floor(Math.sqrt(experience / 3 + 36) - 5);
  }

  /**
   * Calculates the progress of the current level given a total amount
   * of experience.
   * @param {Number} experience - Amount of experience.
   * @return {Number} Level progress in percent (0 - 100).
   */
  calculateLevelProgress(experience) {
    const userLevel = this.calculateLevel(experience);
    const currentLevelMinExperience = this.minLevelExperience(userLevel);
    const nextLevelMinExperience = this.minLevelExperience(userLevel + 1);
    const currentLevelExperience = nextLevelMinExperience - currentLevelMinExperience;
    const userLevelExperience = experience - currentLevelMinExperience;
    return userLevelExperience * 100 / currentLevelExperience;
  }

  /**
   * If the user has an avatar, the avatar is returned, otherwise an URL to
   * a default avatar is returned.
   * @param {Object} user - Discord API user object.
   * @return {String} Avatar URL.
   */
  getAvatarUrl(user) {
    let avatarUrl = '';
    if (user.avatar) {
      avatarUrl = 'https://cdn.discordapp.com/avatars/' + user.id + '/' + user.avatar + '.png';
    } else {
      const defaultAvatarIndex = Number(user.id) % 100;
      avatarUrl = './images/superheroes/heroes-and-villains-' + defaultAvatarIndex + '.png'
    }
    return avatarUrl;
  }

  /**
   * If the server has an icon, the icon is returned, otherwise an URL to
   * a default icon is returned.
   * @param {Object} server - Discord API server object.
   * @return {String} Icon URL.
   */
  getIconUrl(server) {
    let iconUrl = '';
    if (server.icon) {
      iconUrl = 'https://cdn.discordapp.com/icons/' + server.id + '/' + server.icon + '.png';
    } else {
      const defaultIconIndex = Number(server.id) % 100;
      iconUrl = './images/superheroes/heroes-and-villains-' + defaultIconIndex + '.png'
    }
    return iconUrl;
  }

  /**
   * Calculates the minimal amount of experience needed for a given level.
   * @param {Number} level - The level, which the experience is calculated for.
   * @return {Number} Amount of Experience needed for the level.
   */
  minLevelExperience(level) {
    return (3 * level * (level + 10) - 33);
  }

  /**
   * Fetches additional information for a given list of Discord servers
   * through the Discord API.
   * @param {Array} servers - List of objects containing Discord server ids.
   * @return {Array} List of Discord servers.
   */
  getAdditionalServerData(servers) {
    let serverList = [];
    if (!servers) return [];

    servers.map((currentServer) => {
      const server = this.discordApi.Guilds.get(currentServer.id);
      const databaseServer = JSON.parse(JSON.stringify(server));
      databaseServer.iconURL = this.getIconUrl(server);
      databaseServer.experience = currentServer.experience;
      serverList.push(databaseServer);
    });

    serverList.sort((a, b) => {b.experience - a.experience});
    return serverList;
  }

  /**
   * Creates a HTML profile file containing user information based on
   * a profile template.
   * @param {String} filename - Name and path of the HTML file.
   * @param {Object} profileInformation - Information to fill the HTML profile.
   */
  createProfileHtml(filename, profileInformation) {
    const templateFile = fs.readFileSync('Profile/Profile.html').toString();
    const template = handlebars.compile(templateFile);
    const html = template(profileInformation);
    fs.writeFileSync(filename, html);
  }

  /**
   * Creates an image stream given an HTML file.
   * @param {String} filename - Name and path of the HTML file.
   * @return {String} Image stream.
   */
  createProfileImageStream(filename) {
    return Screenshot(filename, '500x1000', {crop: true, selector: '.profile'});
  }

}

const kiritoInstance = new Kirito();
<commit_msg>Renamed API wrapper<commit_after>const fs = require('fs');
const mongojs = require('mongojs');
const Discordie = require('discordie');
const handlebars = require('handlebars');
const Screenshot = require('screenshot-stream');
const winston = require('winston');

/** A Discord bot, which encourages players to join voice channels. */
class Kirito {
  constructor() {
    // Prepare discord api
    this.discordApi = new Discordie({autoReconnect: true});
    this.discordApi.connect({ token: process.env.AUTH_TOKEN });

    // Prepare database
    this.db = mongojs(process.env.DATABASE, ['users']);

    // Prepare application state
    this.connectedUsers = [];
    this.subscribeToEvents();
  }

  /**
   * Registers callback functions to certain events which are triggered
   * through the DiscordApi.
   */
  subscribeToEvents() {
    // Bind this into callback functions
    this.prepareBot = this.prepareBot.bind(this);
    this.joinServer = this.joinServer.bind(this);
    this.userConnected = this.userConnected.bind(this);
    this.userDisconnected = this.userDisconnected.bind(this);
    this.handleChatCommand = this.handleChatCommand.bind(this);

    // Subscribe to events
    this.discordApi.Dispatcher.on(Discordie.Events.GATEWAY_READY, this.prepareBot);
    this.discordApi.Dispatcher.on(Discordie.Events.GUILD_CREATE, this.joinServer);
    this.discordApi.Dispatcher.on(Discordie.Events.VOICE_CHANNEL_JOIN, this.userConnected);
    this.discordApi.Dispatcher.on(Discordie.Events.VOICE_CHANNEL_LEAVE, this.userDisconnected);
    this.discordApi.Dispatcher.on(Discordie.Events.MESSAGE_CREATE, this.handleChatCommand);
  }

  /**
   * Initializes the bot using the Discord API.
   */
  prepareBot() {
    this.discordApi.User.setGame('together with Asuna');
    this.addCurrentlyConnectedUsers();
  }

  /**
   * Adds all currently connected users to the list of connected users.
   */
  addCurrentlyConnectedUsers() {
    this.discordApi.Guilds.forEach((server) => {
      server.voiceChannels.forEach((channel) => {
        channel.members.forEach((user) => {
          this.addConnectedUser(user, server);
        });
      });
    });
  }

  /**
   * Prints an introduction message.
   * @param {Event} e - Discord API event.
   */
  joinServer(e) {
    e.guild.generalChannel.sendTyping();
    const introduction = [
      'Hi!',
      'I am Kirito, your personal voice chat coach. From now on, every time you join',
      'a voice channel on this Server you will receive experience and therefore level.',
      'Additionally, you can ask me things through so called commands. Currently,',
      'I know two commands. Command number one is `ping`, which obviously starts a',
      'table tennis match, and command number two is called `profile` where I will',
      'print an image of your current player profile.',
      '',
      'Enjoy your time in voice channels :).'
    ];
    e.guild.generalChannel.sendMessage(introduction);
  }

  /**
   * Handles users connecting to voice channels.
   * @param {Event} e - Discord API event.
   */
  userConnected(e) {
    this.addConnectedUser(e.user, e.channel.guild);
  }

  /**
   * Adds a user to the list of users in voice channels (connected users).
   * @param {Object} user - Discord API user object.
   * @param {Object} server - Discord API guild object.
   */
  addConnectedUser(user, server) {
    const rewardInterval = 60000;
    const experiencePerMinute = 1;
    const connectedUser = {};
    connectedUser.experienceTimer = setInterval(() => { this.addExperience(user, server, experiencePerMinute); }, rewardInterval);
    this.connectedUsers[user.id] = connectedUser;
    winston.log("info", 'User ' + user.username + ' connected to server ' + server.name + '.');
  }

  /**
   * Handles users disconnecting from voice channels.
   * @param {Event} e - Discord API event.
   */
  userDisconnected(e) {
    this.removeConnectedUser(e.user);
  }

  /**
   * Removes a user from the list of users in voice channels (connected users).
   * @param {Object} user - Discord API user object.
   */
  removeConnectedUser(user) {
    if (!this.connectedUsers[user.id]) {
      winston.log("warn", 'User ' + user.username + ' not found in list of online users.');
      return;
    }
    clearInterval(this.connectedUsers[user.id].experienceTimer);
    delete this.connectedUsers[user.id];
    winston.log("info", 'User ' + user.username + ' disconnected.');
  }

  /**
   * Adds experience to the user account.
   * @param {Object} user - Discord API user object.
   * @param {Object} server - Discord API guild object.
   * @param {Number} experience - Amount of experience to add.
   */
  addExperience(user, server, experience) {
    this.db.users.update({id: user.id}, { $setOnInsert: user, $inc: { experience } }, {upsert: true});
    this.db.users.update({id: user.id, 'servers.id': server.id}, {$inc: {'servers.$.experience': experience}} );
    this.db.users.update({id: user.id, 'servers.id': {$ne: server.id}}, { $push: {'servers': {id: server.id, experience}} }, (err, res) => {
      winston.log("info", 'Added ' + experience + ' experience to user ' + user.username + '.');
      winston.log("info", user.username + ' has now a total experience of ' + res.experience + '.');
    });
  }

  /**
   * Handles received chat messages and checks for chat commands.
   * @param {Event} e - Discord API event.
   */
  handleChatCommand(e) {
    switch (e.message.content) {
      case 'ping':
        e.message.channel.sendTyping();
        e.message.channel.sendMessage('pong');
        break;

      case 'profile':
        this.getProfile(e.message.author, (profile) => {
          e.message.channel.sendTyping();
          e.message.channel.uploadFile(profile, 'profile.png');
        });
        break;
    }
  }

  /**
   * Gathers necessary user data and prepares the image stream to print
   * a users profile.
   * @param {Object} user - Discord API user object.
   * @param {Callback} callback - Called when image stream is ready.
   */
  getProfile(user, callback) {
    const newUser = JSON.parse(JSON.stringify(user));
    newUser.experience = 0;
    winston.log("info", 'Printing profile for user ' + user.username + '.');
    this.db.users.findAndModify({query: {id: user.id}, update: { $setOnInsert: newUser }, upsert: true, new: true}, (err, result) => {
      const profileInformation = {
        username: user.username,
        level: this.calculateLevel(result.experience),
        levelProgress: this.calculateLevelProgress(result.experience),
        avatar: this.getAvatarUrl(user),
        servers: this.getAdditionalServerData(result.servers)
      };
      winston.log("info", 'username:' + user.username);
      winston.log("info", 'level:' + this.calculateLevel(result.experience));
      winston.log("info", 'experience:' + result.experience);
      winston.log("info", 'levelProgress:' + this.calculateLevelProgress(result.experience));
      winston.log("info", 'servers:' + this.getAdditionalServerData(result.servers));
      const profileHtmlFilename = 'profiles/' + user.id + '.html';
      this.createProfileHtml(profileHtmlFilename, profileInformation);
      const stream = this.createProfileImageStream(profileHtmlFilename);

      /**
       * Is called when the profile creation finished and the image stream
       * is ready.
       * @callback callback
       * @param {String} stream - Image stream containing the user profile.
       */
      callback(stream);
    });
  }

  /**
   * Calculates the level given a total amount of experience.
   * @param {Number} experience - Amount of experience.
   * @return {Number} Level corresponding to experience.
   */
  calculateLevel(experience) {
    return Math.floor(Math.sqrt(experience / 3 + 36) - 5);
  }

  /**
   * Calculates the progress of the current level given a total amount
   * of experience.
   * @param {Number} experience - Amount of experience.
   * @return {Number} Level progress in percent (0 - 100).
   */
  calculateLevelProgress(experience) {
    const userLevel = this.calculateLevel(experience);
    const currentLevelMinExperience = this.minLevelExperience(userLevel);
    const nextLevelMinExperience = this.minLevelExperience(userLevel + 1);
    const currentLevelExperience = nextLevelMinExperience - currentLevelMinExperience;
    const userLevelExperience = experience - currentLevelMinExperience;
    return userLevelExperience * 100 / currentLevelExperience;
  }

  /**
   * If the user has an avatar, the avatar is returned, otherwise an URL to
   * a default avatar is returned.
   * @param {Object} user - Discord API user object.
   * @return {String} Avatar URL.
   */
  getAvatarUrl(user) {
    let avatarUrl = '';
    if (user.avatar) {
      avatarUrl = 'https://cdn.discordapp.com/avatars/' + user.id + '/' + user.avatar + '.png';
    } else {
      const defaultAvatarIndex = Number(user.id) % 100;
      avatarUrl = './images/superheroes/heroes-and-villains-' + defaultAvatarIndex + '.png'
    }
    return avatarUrl;
  }

  /**
   * If the server has an icon, the icon is returned, otherwise an URL to
   * a default icon is returned.
   * @param {Object} server - Discord API server object.
   * @return {String} Icon URL.
   */
  getIconUrl(server) {
    let iconUrl = '';
    if (server.icon) {
      iconUrl = 'https://cdn.discordapp.com/icons/' + server.id + '/' + server.icon + '.png';
    } else {
      const defaultIconIndex = Number(server.id) % 100;
      iconUrl = './images/superheroes/heroes-and-villains-' + defaultIconIndex + '.png'
    }
    return iconUrl;
  }

  /**
   * Calculates the minimal amount of experience needed for a given level.
   * @param {Number} level - The level, which the experience is calculated for.
   * @return {Number} Amount of Experience needed for the level.
   */
  minLevelExperience(level) {
    return (3 * level * (level + 10) - 33);
  }

  /**
   * Fetches additional information for a given list of Discord servers
   * through the Discord API.
   * @param {Array} servers - List of objects containing Discord server ids.
   * @return {Array} List of Discord servers.
   */
  getAdditionalServerData(servers) {
    let serverList = [];
    if (!servers) return [];

    servers.map((currentServer) => {
      const server = this.discordApi.Guilds.get(currentServer.id);
      const databaseServer = JSON.parse(JSON.stringify(server));
      databaseServer.iconURL = this.getIconUrl(server);
      databaseServer.experience = currentServer.experience;
      serverList.push(databaseServer);
    });

    serverList.sort((a, b) => {b.experience - a.experience});
    return serverList;
  }

  /**
   * Creates a HTML profile file containing user information based on
   * a profile template.
   * @param {String} filename - Name and path of the HTML file.
   * @param {Object} profileInformation - Information to fill the HTML profile.
   */
  createProfileHtml(filename, profileInformation) {
    const templateFile = fs.readFileSync('Profile/Profile.html').toString();
    const template = handlebars.compile(templateFile);
    const html = template(profileInformation);
    fs.writeFileSync(filename, html);
  }

  /**
   * Creates an image stream given an HTML file.
   * @param {String} filename - Name and path of the HTML file.
   * @return {String} Image stream.
   */
  createProfileImageStream(filename) {
    return Screenshot(filename, '500x1000', {crop: true, selector: '.profile'});
  }

}

const kiritoInstance = new Kirito();
<|endoftext|>


<commit_before>
/*

  Compilers.js

*/

// Require cache
var requires = (function() {
  var cache = {};
  return function(library) {
    return cache[library] || (cache[library] = require(library));
  }
})();

function Compiler(options) {
  this.library = options.library;
  this.compile = options.compile;
}

Compiler.prototype.isOk = function() {
  if (!this.library) return true;
  try {
    requires(this.library);
  } catch (err) {
    return false;
  }
  return true;
}

var compilers = {

  "coffee": new Compiler({
    library: "coffee-script",
    compile: function(str, next) {
      next(null, requires("coffee-script").compile(str));
    }
  }),

  "css": new Compiler({
    compile: function(str, next) {
      next(null, raw);
    }
  }),

  "js": new Compiler({
    compile: function(str, next) {
      next(null, raw);
    }
  }),

  "styl": new Compiler({
    library: "stylus",
    compile: function(str, next) {
      requires("stylus").render(str, next);
    }
  }),

  "ts": new Compiler({
    library: "typescript",
    compile: function(str, next) {
      next(null, requires("typescript").transpile(str));
    }
  })

};

module.exports = function(name) {
  return compilers[name];
}

<commit_msg>Compilers: removed (to be replaced with Motors module)<commit_after><|endoftext|>


<commit_before>! function (definition) {
  if (typeof window != "undefined") window.inquiry = definition;
  else if (typeof define == "function") define(definition);
  else module.exports = definition();
} (function () {
  var slice = [].slice;
/*
  function die () {
    console.log.apply(console, slice.call(arguments, 0));
    process.exit(1);
  }
  function say () { console.log.apply(console, slice.call(arguments, 0)) }
*/
  function parse (query, nesting, stop) {
    var i, I, args = [], rest = query, $,  expression = [], depth = 0, struct, source, args, slash = '/';
    while (rest && rest[0] != stop) {
      if (rest[0] != '/') {
        if (/^[![{]/.test(rest[0])) {
          rest = '/.' + rest;
        } else {
          rest = slash + rest;
        }
      }
      slash = '';
      // Skip leading whitespaces.
      //$ = /^(\s*)(.*)$/.exec(rest), index += $[1].length;
      // Match one or two slashes, followed by dots or a property name, plus an
      // optional predicate or subquery opener.
      $ = /^(\/{1,2})(\.\.|\.|(?:!(?![[{])|[^\]![{/`]|`.)*)((!?)([[{]))?(.*)/.exec(rest);
      //$ = /^(\/{1,2})(\.\.|\.|(?:[^![{/`]|`.)*)((?:![|!{|[|{)?)(.*)/.exec(rest);
      if (!$) throw new Error("bad pattern");
      $[2] = decodeURIComponent($[2].replace(/`%/g, '%25')).replace(/`(.)/, "$1");
      rest = $[6];
      struct = $.slice(1, 3);
      // Check for have a predicate or a sub-expression.
      switch ($[5]) {
      // We want to consume the contents of the curly braces that define a
      // predicate to construct a function body.
      case "{":
        // Depth is the number of curly braces we've encountered. We match curly
        // braces until it is time to pop.
        // **TODO**: Test against regular expressions. We are going to have to
        // document the one valid regular expression that we know of that we
        // cannot match: `/[/]/`.
        depth = 1;
        source = $[4] + '(';
        $ = /^(((?:[^'"}]*|'(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")*)})/.exec(rest);
        if (!$) throw new Error("bad pattern");
        source += $[2];
        rest = rest.substring($[1].length);
        depth = 0;
        source.replace(/\$(\d+)/g, function ($, number) {
          depth = Math.max(depth, +number);
        });
        args.length = 0;
        for (i = 0; i < nesting; i++) {
          var prefix = Array(i + 2).join('$');
          args.push(prefix);
          args.push(prefix + 'i');
        }
        for (i = 0; i < depth; i++) {
          args.push('$' + (i + 1));
        }
        args.push('return ' +  source + ')');
        struct.push((function (predicate) {
          return function (candidate, vargs) {
            return predicate.apply(candidate.object, [ candidate.object, candidate.i ].concat(vargs));
          }
        })(Function.apply(Function, args)), []);
        break;
      // We want to consume the contents of brackets as a sub-expression, so we
      // call ourselves recursively.
      case "[":
        struct.push((function (negate, subquery) {
          return function (candidate, args) {
            return negate ? ! subquery.call(candidate.object, candidate, [ candidate.object, candidate.i ].concat(args)).length
                          : subquery.call(candidate.object, candidate, [ candidate.object, candidate.i ].concat(args)).length;
          }
        })($[4] == '!', ($ = parse(rest, nesting + 1, "]"))[0]));
        rest = $[1].slice(1);
        break;
      default:
        struct.push(null);
      }
      expression.push(struct);
    }
    return [ function (candidate, vargs) {
      var candidates = [], stack = [ candidate ],
          star, name, key, i, j, I, predicate, path, object, params;
      for (i = 0, I = expression.length; i < I; i++) {
        name = expression[i][1], predicate = expression[i][2];
        while (stack.length) {
          candidate = stack.shift(), object = candidate.object, path = candidate.path;
          if (name in object) {
            candidates.push({ object: object[name], path: Array.isArray(path[0]) ? path : [ object ].concat(path) });
          } else if (name == '.') {
            candidates.push(candidate);
          } else if (name == '..') {
            var subpath = path.slice();
            candidates.unshift({ object: subpath.shift(), path: subpath, i: 0 });
          } else if (Array.isArray(object)) {
            for (j = object.length - 1; j > -1; --j) {
              stack.unshift({ object: object[j], path: [ object ].concat(path) });
            }
          } else if (~(star = name.indexOf('*'))) {
            for (key in object) {
              if (key.indexOf(name.substring(0, star)) == 0
                  && key.lastIndexOf(name.substring(star + 1) == key.length - (name.length - star))) {
                candidates.push({ object: object[key], path: Array.isArray(path[0]) ? path : [ object ].concat(path) });
                break;
              }
            }
          }
        }
        if (predicate) {
          while (candidates.length) {
            candidate = candidates.shift(), object = candidate.object;
            if (Array.isArray(object)) {
              for (j = object.length - 1; j > -1; --j) {
                candidates.unshift({ object: object[j], path: [ object ].concat(path), i: j });
              }
            } else if (predicate(candidate, vargs)) {
              stack.push(candidate);
            }
          }
        } else {
          stack.unshift.apply(stack, candidates.splice(0));
        }
      }
      for (i = stack.length - 1; i > -1; i--) stack[i] = stack[i].object;
      return stack;
    }, rest ];
  }
  return function (query) {
    var func = parse(query, 1)[0];
    return function (object) { return func({ object: object, path: [], i: 0 }, slice.call(arguments, 1)) };
  }
});
<commit_msg>Tidy path regex.<commit_after>! function (definition) {
  if (typeof window != "undefined") window.inquiry = definition;
  else if (typeof define == "function") define(definition);
  else module.exports = definition();
} (function () {
  var slice = [].slice;
/*
  function die () {
    console.log.apply(console, slice.call(arguments, 0));
    process.exit(1);
  }
  function say () { console.log.apply(console, slice.call(arguments, 0)) }
*/
  function parse (query, nesting, stop) {
    var i, I, args = [], rest = query, $,  expression = [], depth = 0, struct, source, args, slash = '/';
    while (rest && rest[0] != stop) {
      if (rest[0] != '/') {
        if (/^[![{]/.test(rest[0])) {
          rest = '/.' + rest;
        } else {
          rest = slash + rest;
        }
      }
      slash = '';
      // Skip leading whitespaces.
      //$ = /^(\s*)(.*)$/.exec(rest), index += $[1].length;
      // Match one or two slashes, followed by dots or a property name, plus an
      // optional predicate or subquery opener.
      $ = /^\/(\.\.|\.|(?:!(?![[{])|[^\]![{/`]|`.)*)((!?)([[{]))?(.*)/.exec(rest);
      //$ = /^(\/{1,2})(\.\.|\.|(?:[^![{/`]|`.)*)((?:![|!{|[|{)?)(.*)/.exec(rest);
      if (!$) throw new Error("bad pattern");
      struct = [ decodeURIComponent($[1].replace(/`%/g, '%25')).replace(/`(.)/, "$1") ]
      rest = $[5];
      // Check for have a predicate or a sub-expression.
      switch ($[4]) {
      // We want to consume the contents of the curly braces that define a
      // predicate to construct a function body.
      case "{":
        // Depth is the number of curly braces we've encountered. We match curly
        // braces until it is time to pop.
        // **TODO**: Test against regular expressions. We are going to have to
        // document the one valid regular expression that we know of that we
        // cannot match: `/[/]/`.
        depth = 1;
        source = $[3] + '(';
        $ = /^(((?:[^'"}]*|'(?:[^\\']|\\.)*'|"(?:[^\\"]|\\.)*")*)})/.exec(rest);
        if (!$) throw new Error("bad pattern");
        source += $[2];
        rest = rest.substring($[1].length);
        depth = 0;
        source.replace(/\$(\d+)/g, function ($, number) {
          depth = Math.max(depth, +number);
        });
        args.length = 0;
        for (i = 0; i < nesting; i++) {
          var prefix = Array(i + 2).join('$');
          args.push(prefix);
          args.push(prefix + 'i');
        }
        for (i = 0; i < depth; i++) {
          args.push('$' + (i + 1));
        }
        args.push('return ' +  source + ')');
        struct.push((function (predicate) {
          return function (candidate, vargs) {
            return predicate.apply(candidate.object, [ candidate.object, candidate.i ].concat(vargs));
          }
        })(Function.apply(Function, args)), []);
        break;
      // We want to consume the contents of brackets as a sub-expression, so we
      // call ourselves recursively.
      case "[":
        struct.push((function (negate, subquery) {
          return function (candidate, args) {
            return negate ? ! subquery.call(candidate.object, candidate, [ candidate.object, candidate.i ].concat(args)).length
                          : subquery.call(candidate.object, candidate, [ candidate.object, candidate.i ].concat(args)).length;
          }
        })($[3] == '!', ($ = parse(rest, nesting + 1, "]"))[0]));
        rest = $[1].slice(1);
        break;
      default:
        struct.push(null);
      }
      expression.push(struct);
    }
    return [ function (candidate, vargs) {
      var candidates = [], stack = [ candidate ],
          star, name, key, i, j, I, predicate, path, object, params;
      for (i = 0, I = expression.length; i < I; i++) {
        name = expression[i][0], predicate = expression[i][1];
        while (stack.length) {
          candidate = stack.shift(), object = candidate.object, path = candidate.path;
          if (name in object) {
            candidates.push({ object: object[name], path: Array.isArray(path[0]) ? path : [ object ].concat(path) });
          } else if (name == '.') {
            candidates.push(candidate);
          } else if (name == '..') {
            var subpath = path.slice();
            candidates.unshift({ object: subpath.shift(), path: subpath, i: 0 });
          } else if (Array.isArray(object)) {
            for (j = object.length - 1; j > -1; --j) {
              stack.unshift({ object: object[j], path: [ object ].concat(path) });
            }
          } else if (~(star = name.indexOf('*'))) {
            for (key in object) {
              if (key.indexOf(name.substring(0, star)) == 0
                  && key.lastIndexOf(name.substring(star + 1) == key.length - (name.length - star))) {
                candidates.push({ object: object[key], path: Array.isArray(path[0]) ? path : [ object ].concat(path) });
                break;
              }
            }
          }
        }
        if (predicate) {
          while (candidates.length) {
            candidate = candidates.shift(), object = candidate.object;
            if (Array.isArray(object)) {
              for (j = object.length - 1; j > -1; --j) {
                candidates.unshift({ object: object[j], path: [ object ].concat(path), i: j });
              }
            } else if (predicate(candidate, vargs)) {
              stack.push(candidate);
            }
          }
        } else {
          stack.unshift.apply(stack, candidates.splice(0));
        }
      }
      for (i = stack.length - 1; i > -1; i--) stack[i] = stack[i].object;
      return stack;
    }, rest ];
  }
  return function (query) {
    var func = parse(query, 1)[0];
    return function (object) { return func({ object: object, path: [], i: 0 }, slice.call(arguments, 1)) };
  }
});
<|endoftext|>


<commit_before>/* eslint-env node, jest */
jest.mock('../achievements');
jest.mock('moment');

const moment = require('moment');
const sushi = require('./index.js');
const Slack = require('../lib/slackMock.js');

let slack = null;

beforeEach(() => {
	slack = new Slack();
	sushi(slack);

	moment.mockImplementation(() => ({
		utcOffset: () => ({
			day: () => 1,
		})
	}));
});

it('reacts to "おすし"', () => new Promise((resolve) => {
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('sushi');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'おすし',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to ":korosuzo:"', () => new Promise((resolve) => {
	const table = {no_good: false, cookies146: false};
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(Object.keys(table)).toContain(name); // FIXME
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		table[name] = true;
		if(Object.values(table).every(x=>x)) {
			resolve();
		}
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: ':korosuzo:',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('marks :x::four: to "sushi"x4', () => new Promise((resolve) => {
	const table = {sushi: false, x: false, four: false};
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(Object.keys(table)).toContain(name); // FIXME
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		table[name] = true;
		if(Object.values(table).every(x=>x)) {
			resolve();
		}
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'sushisushisushisushi',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "\u3059\u0328"', () => new Promise((resolve) => {
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('sushi');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: '\u3059\u0328',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "寿司ランキング 確認"', () => new Promise((resolve) => {
	slack.on('chat.postMessage', ({username, channel, text}) => {
		expect(username).toBe('sushi-bot');
		expect(channel).toBe("D00000000");
		expect(text).toContain('あなたのすし数は1個');
		expect(text).toContain('現在の順位は');
		resolve();
	});

	(async () => {
		const promise = new Promise(resolve => {
			slack.on('reactions.add', ({name, timestamp}) => {
				if (timestamp === slack.fakeTimestamp && name === 'sushi') {
					resolve();
				}
			});
		});

		slack.rtmClient.emit('message', {
			channel: slack.fakeChannel,
			text: 'sushi',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});

		await promise;

		slack.rtmClient.emit('message', {
			channel: "D00000000",
			text: '寿司ランキング 確認',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});
	})();
}));

it('reacts to "凍結ランキング 確認"', () => new Promise((resolve) => {
	slack.on('chat.postMessage', ({username, channel, text}) => {
		expect(username).toBe('sushi-bot');
		expect(channel).toBe("D00000000");
		expect(text).toContain('あなたの凍結回数は1回');
		expect(text).toContain('現在の順位は');
		resolve();
	});

	(async () => {
		const promise = new Promise(resolve => {
			const table = {no_good: false, cookies146: false};
			slack.on('reactions.add', ({name, timestamp}) => {
				if (timestamp === slack.fakeTimestamp && table.hasOwnProperty(name)) {
					table[name] = true;
				}
				if(Object.values(table).every(x=>x)) {
					resolve();
				}
			});
		});

		slack.rtmClient.emit('message', {
			channel: slack.fakeChannel,
			text: '死',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});

		await promise;

		slack.rtmClient.emit('message', {
			channel: "D00000000",
			text: '凍結ランキング 確認',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});
	})();
}));

it('reacts to "あさ！" with :100: at 8:59:59', () => new Promise((resolve) => {
	moment.mockImplementation(() => ({
		utcOffset: () => ({
			hour: () => 8,
			minutes: () => 59,
			seconds: () => 59,
		})
	}));

	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('100');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'あさ！',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "あさ！" with :95: at 9:00:01', () => new Promise((resolve) => {
	moment.mockImplementation(() => ({
		utcOffset: () => ({
			hour: () => 9,
			minutes: () => 0,
			seconds: () => 1,
		})
	}));

	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('95');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'あさ！',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));
<commit_msg>write test<commit_after>/* eslint-env node, jest */
jest.mock('../achievements');
jest.mock('moment');

const moment = require('moment');
const sushi = require('./index.js');
const Slack = require('../lib/slackMock.js');

let slack = null;

beforeEach(() => {
	slack = new Slack();
	sushi(slack);

	moment.mockImplementation(() => ({
		utcOffset: () => ({
			day: () => 1,
		})
	}));
});

it('reacts to "おすし"', () => new Promise((resolve) => {
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('sushi');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'おすし',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to ":korosuzo:"', () => new Promise((resolve) => {
	const table = {no_good: false, cookies146: false};
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(Object.keys(table)).toContain(name); // FIXME
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		table[name] = true;
		if(Object.values(table).every(x=>x)) {
			resolve();
		}
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: ':korosuzo:',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('marks :x::four: to "sushi"x4', () => new Promise((resolve) => {
	const table = {sushi: false, x: false, four: false};
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(Object.keys(table)).toContain(name); // FIXME
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		table[name] = true;
		if(Object.values(table).every(x=>x)) {
			resolve();
		}
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'sushisushisushisushi',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "\u3059\u0328"', () => new Promise((resolve) => {
	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('sushi');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: '\u3059\u0328',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "寿司ランキング 確認"', () => new Promise((resolve) => {
	slack.on('chat.postMessage', ({username, channel, text}) => {
		expect(username).toBe('sushi-bot');
		expect(channel).toBe("D00000000");
		expect(text).toContain('あなたのすし数は1個');
		expect(text).toContain('現在の順位は');
		resolve();
	});

	(async () => {
		const promise = new Promise(resolve => {
			slack.on('reactions.add', ({name, timestamp}) => {
				if (timestamp === slack.fakeTimestamp && name === 'sushi') {
					resolve();
				}
			});
		});

		slack.rtmClient.emit('message', {
			channel: slack.fakeChannel,
			text: 'sushi',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});

		await promise;

		slack.rtmClient.emit('message', {
			channel: "D00000000",
			text: '寿司ランキング 確認',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});
	})();
}));

it('reacts to "凍結ランキング 確認"', () => new Promise((resolve) => {
	slack.on('chat.postMessage', ({username, channel, text}) => {
		expect(username).toBe('sushi-bot');
		expect(channel).toBe("D00000000");
		expect(text).toContain('あなたの凍結回数は1回');
		expect(text).toContain('現在の順位は');
		resolve();
	});

	(async () => {
		const promise = new Promise(resolve => {
			const table = {no_good: false, cookies146: false};
			slack.on('reactions.add', ({name, timestamp}) => {
				if (timestamp === slack.fakeTimestamp && table.hasOwnProperty(name)) {
					table[name] = true;
				}
				if(Object.values(table).every(x=>x)) {
					resolve();
				}
			});
		});

		slack.rtmClient.emit('message', {
			channel: slack.fakeChannel,
			text: '死',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});

		await promise;

		slack.rtmClient.emit('message', {
			channel: "D00000000",
			text: '凍結ランキング 確認',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});
	})();
}));

it('reacts to "あさ！" with :100: at 8:59:59', () => new Promise((resolve) => {
	moment.mockImplementation(() => ({
		utcOffset: () => ({
			hour: () => 8,
			minutes: () => 59,
			seconds: () => 59,
		})
	}));

	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('100');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'あさ！',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "あさ！" with :95: at 9:00:01', () => new Promise((resolve) => {
	moment.mockImplementation(() => ({
		utcOffset: () => ({
			hour: () => 9,
			minutes: () => 0,
			seconds: () => 1,
		})
	}));

	slack.on('reactions.add', ({name, channel, timestamp}) => {
		expect(name).toBe('95');
		expect(channel).toBe(slack.fakeChannel);
		expect(timestamp).toBe(slack.fakeTimestamp);
		resolve();
	});

	slack.rtmClient.emit('message', {
		channel: slack.fakeChannel,
		text: 'あさ！',
		user: slack.fakeUser,
		ts: slack.fakeTimestamp,
	});
}));

it('reacts to "起床ランキング 確認', () => new Promise((resolve) => {
	moment.mockImplementation(() => ({
		utcOffset: () => ({
			hour: () => 10,
			minutes: () => 0,
			seconds: () => 0,
		})
	}));
	slack.on('chat.postMessage', ({username, channel, text}) => {
		expect(username).toBe('sushi-bot');
		expect(channel).toBe("D00000000");
		expect(text).toContain('あなたの起床点数は80点');
		expect(text).toContain('現在の順位は');
		resolve();
	});

	(async () => {
		const promise = new Promise(resolve => {
			slack.on('reactions.add', ({name, timestamp}) => {
				if (timestamp === slack.fakeTimestamp && name === '80') {
					resolve();
				}
			});
		});

		slack.rtmClient.emit('message', {
			channel: slack.fakeChannel,
			text: 'あさ',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});

		await promise;

		slack.rtmClient.emit('message', {
			channel: "D00000000",
			text: '起床ランキング 確認',
			user: slack.fakeUser,
			ts: slack.fakeTimestamp,
		});
	})();
}));
<|endoftext|>


<commit_before><commit_msg>Synchronized package.json's version number with the CLI's version (-V).<commit_after><|endoftext|>


<commit_before>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

import type {Layout, LayoutEvent} from 'CoreEventTypes';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type React from 'React';
import type {ViewStyleProp} from 'StyleSheet';
import type {TVViewProps} from 'TVViewPropTypes';
import type {
  AccessibilityComponentType,
  AccessibilityTrait,
  AccessibilityRole,
  AccessibilityStates,
} from 'ViewAccessibility';

export type ViewLayout = Layout;
export type ViewLayoutEvent = LayoutEvent;

type DirectEventProps = $ReadOnly<{|
  onAccessibilityAction?: ?Function,
  onAccessibilityTap?: ?Function,
  onLayout?: ?(event: LayoutEvent) => void,
  onMagicTap?: ?Function,
|}>;

type TouchEventProps = $ReadOnly<{|
  onTouchCancel?: ?Function,
  onTouchCancelCapture?: ?Function,
  onTouchEnd?: ?Function,
  onTouchEndCapture?: ?Function,
  onTouchMove?: ?Function,
  onTouchMoveCapture?: ?Function,
  onTouchStart?: ?Function,
  onTouchStartCapture?: ?Function,
|}>;

type GestureResponderEventProps = $ReadOnly<{|
  onMoveShouldSetResponder?: ?Function,
  onMoveShouldSetResponderCapture?: ?Function,
  onResponderGrant?: ?Function,
  onResponderMove?: ?Function,
  onResponderReject?: ?Function,
  onResponderRelease?: ?Function,
  onResponderStart?: ?Function,
  onResponderTerminate?: ?Function,
  onResponderTerminationRequest?: ?Function,
  onStartShouldSetResponder?: ?Function,
  onStartShouldSetResponderCapture?: ?Function,
|}>;

type AndroidViewProps = $ReadOnly<{|
  nativeBackgroundAndroid?: ?Object,
  nativeForegroundAndroid?: ?Object,

  /* Deprecated transform prop. Use the transform style prop instead */
  rotation?: empty,
  /* Deprecated transform prop. Use the transform style prop instead */
  scaleX?: empty,
  /* Deprecated transform prop. Use the transform style prop instead */
  scaleY?: empty,
  /* Deprecated transform prop. Use the transform style prop instead */
  translateX?: empty,
  /* Deprecated transform prop. Use the transform style prop instead */
  translateY?: empty,
|}>;

export type ViewProps = $ReadOnly<{|
  ...DirectEventProps,
  ...GestureResponderEventProps,
  ...TouchEventProps,
  ...AndroidViewProps,

  // There's no easy way to create a different type if (Platform.isTV):
  // so we must include TVViewProps
  ...TVViewProps,

  accessible?: ?boolean,
  accessibilityLabel?: ?(
    | null
    | React$PropType$Primitive<any>
    | Stringish
    | $ReadOnlyArray<any>
    | any
  ),
  accessibilityHint?: ?Stringish,
  accessibilityActions?: ?$ReadOnlyArray<string>,
  accessibilityComponentType?: ?AccessibilityComponentType,
  accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'),
  importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'),
  accessibilityIgnoresInvertColors?: ?boolean,
  accessibilityTraits?: ?(
    | AccessibilityTrait
    | $ReadOnlyArray<AccessibilityTrait>
  ),
  accessibilityRole?: ?AccessibilityRole,
  accessibilityStates?: ?AccessibilityStates,
  accessibilityViewIsModal?: ?boolean,
  accessibilityElementsHidden?: ?boolean,
  children?: ?React.Node,
  testID?: ?string,
  nativeID?: ?string,
  hitSlop?: ?EdgeInsetsProp,
  pointerEvents?: ?('auto' | 'box-none' | 'box-only' | 'none'),
  style?: ?ViewStyleProp,
  removeClippedSubviews?: ?boolean,
  renderToHardwareTextureAndroid?: ?boolean,
  shouldRasterizeIOS?: ?boolean,
  collapsable?: ?boolean,
  needsOffscreenAlphaCompositing?: ?boolean,
|}>;
<commit_msg>RN: Improve ViewPropTypes<commit_after>/**
 * Copyright (c) 2015-present, Facebook, Inc.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE file in the root directory of this source tree.
 *
 * @format
 * @flow
 */

'use strict';

import type {Layout, LayoutEvent} from 'CoreEventTypes';
import type {EdgeInsetsProp} from 'EdgeInsetsPropType';
import type React from 'React';
import type {ViewStyleProp} from 'StyleSheet';
import type {TVViewProps} from 'TVViewPropTypes';
import type {
  AccessibilityComponentType,
  AccessibilityTrait,
  AccessibilityRole,
  AccessibilityStates,
} from 'ViewAccessibility';

export type ViewLayout = Layout;
export type ViewLayoutEvent = LayoutEvent;

type DirectEventProps = $ReadOnly<{|
  onAccessibilityAction?: ?Function,
  onAccessibilityTap?: ?Function,
  onLayout?: ?(event: LayoutEvent) => void,
  onMagicTap?: ?Function,
|}>;

type TouchEventProps = $ReadOnly<{|
  onTouchCancel?: ?Function,
  onTouchCancelCapture?: ?Function,
  onTouchEnd?: ?Function,
  onTouchEndCapture?: ?Function,
  onTouchMove?: ?Function,
  onTouchMoveCapture?: ?Function,
  onTouchStart?: ?Function,
  onTouchStartCapture?: ?Function,
|}>;

type GestureResponderEventProps = $ReadOnly<{|
  onMoveShouldSetResponder?: ?Function,
  onMoveShouldSetResponderCapture?: ?Function,
  onResponderGrant?: ?Function,
  onResponderMove?: ?Function,
  onResponderReject?: ?Function,
  onResponderRelease?: ?Function,
  onResponderStart?: ?Function,
  onResponderTerminate?: ?Function,
  onResponderTerminationRequest?: ?Function,
  onStartShouldSetResponder?: ?Function,
  onStartShouldSetResponderCapture?: ?Function,
|}>;

type AndroidViewProps = $ReadOnly<{|
  nativeBackgroundAndroid?: ?Object,
  nativeForegroundAndroid?: ?Object,
|}>;

export type ViewProps = $ReadOnly<{|
  ...DirectEventProps,
  ...GestureResponderEventProps,
  ...TouchEventProps,
  ...AndroidViewProps,

  // There's no easy way to create a different type if (Platform.isTV):
  // so we must include TVViewProps
  ...TVViewProps,

  accessible?: ?boolean,
  accessibilityLabel?: ?Stringish,
  accessibilityHint?: ?Stringish,
  accessibilityActions?: ?$ReadOnlyArray<string>,
  accessibilityComponentType?: ?AccessibilityComponentType,
  accessibilityLiveRegion?: ?('none' | 'polite' | 'assertive'),
  importantForAccessibility?: ?('auto' | 'yes' | 'no' | 'no-hide-descendants'),
  accessibilityIgnoresInvertColors?: ?boolean,
  accessibilityTraits?: ?(
    | AccessibilityTrait
    | $ReadOnlyArray<AccessibilityTrait>
  ),
  accessibilityRole?: ?AccessibilityRole,
  accessibilityStates?: ?AccessibilityStates,
  accessibilityViewIsModal?: ?boolean,
  accessibilityElementsHidden?: ?boolean,
  children?: ?React.Node,
  testID?: ?string,
  nativeID?: ?string,
  hitSlop?: ?EdgeInsetsProp,
  pointerEvents?: ?('auto' | 'box-none' | 'box-only' | 'none'),
  style?: ?ViewStyleProp,
  removeClippedSubviews?: ?boolean,
  renderToHardwareTextureAndroid?: ?boolean,
  shouldRasterizeIOS?: ?boolean,
  collapsable?: ?boolean,
  needsOffscreenAlphaCompositing?: ?boolean,
|}>;
<|endoftext|>